Sprint Item
#4 of 8 — Medium severity — land first Tuesday (PR 1 of 2)
Block Relations
|
|
| Blocked by |
— (independent of Monday #1–#3 chain) |
| Blocks |
#5 — multi-worker failure should return a structured {error, code} from this helper |
| Repo/day |
Independent of #6–#8 |
Calendar Day
Tuesday, July 21, 2026 (PR 1 of 2)
Planned Effort
3 story points (Medium) — sprint item #4
Problem
/api/search returns {"error", "code"} via _search_error (api/search.py:51-56). Every other blueprint returns a bare {"error"} with no machine-readable code. Integrators cannot distinguish failures programmatically outside of search — the error contract is honored in one place and broken everywhere else.
Goal
One PR adding a shared error-body helper (mirroring _search_error) and routing every blueprint through it, so each failure carries a stable, distinct code alongside the existing human error string, with statuses preserved.
Scope
Part A — shared helper
- Add a helper in
api/flask_config.py (api/flask_config.py:25-34) mirroring _search_error: returns {"error": <human string>, "code": <stable code>} with the correct HTTP status.
Part B — route the blueprints through it
Give each distinct failure a distinct, stable code in:
api/workspaces.py
api/composers.py
api/export_api.py
api/config_api.py
api/pdf.py
Preserve existing HTTP statuses and human strings. /api/validate-path keeps its current shape with code added (no breaking shape change).
Part C — test
- A test asserts representative endpoints return the expected
code for a known failure.
Out of scope
Acceptance Criteria
Verification
cd C:\Users\Jasen\CppAliance\cppa-cursor-browser
.\.venv\Scripts\Activate.ps1
mypy --strict .
pytest -q -k "error or code"
pytest -q
Sprint Item
#4 of 8 — Medium severity — land first Tuesday (PR 1 of 2)
Block Relations
{error, code}from this helperCalendar Day
Tuesday, July 21, 2026 (PR 1 of 2)
Planned Effort
3 story points (Medium) — sprint item #4
Problem
/api/searchreturns{"error", "code"}via_search_error(api/search.py:51-56). Every other blueprint returns a bare{"error"}with no machine-readablecode. Integrators cannot distinguish failures programmatically outside of search — the error contract is honored in one place and broken everywhere else.Goal
One PR adding a shared error-body helper (mirroring
_search_error) and routing every blueprint through it, so each failure carries a stable, distinctcodealongside the existing humanerrorstring, with statuses preserved.Scope
Part A — shared helper
api/flask_config.py(api/flask_config.py:25-34) mirroring_search_error: returns{"error": <human string>, "code": <stable code>}with the correct HTTP status.Part B — route the blueprints through it
Give each distinct failure a distinct, stable
codein:api/workspaces.pyapi/composers.pyapi/export_api.pyapi/config_api.pyapi/pdf.pyPreserve existing HTTP statuses and human strings.
/api/validate-pathkeeps its current shape withcodeadded (no breaking shape change).Part C — test
codefor a known failure.Out of scope
fix/multiworker-set-workspace-honesty) — it will use acodefrom this helper, but the endpoint-behavior change is owned there./api/search's existing envelope (it is the reference shape).Acceptance Criteria
api/workspaces.py,composers.py,export_api.py,config_api.py,pdf.pyinclude a stablecodealongsideerror./api/validate-pathshape preserved withcodeadded.code.mypy --strict+ tests green; CI green; PR approved by at least 1 reviewer.Verification