Skip to content

Commit 54cac7c

Browse files
committed
docs(20.2): add ERR-01..ERR-04 requirements and traceability
TEST-05 scoped structured upstream errors to drug_database and nutrient_file; ERR-01 generalises it to all 271 tools. Roadmap entry updated to 1/1 plans.
1 parent 2ac1952 commit 54cac7c

2 files changed

Lines changed: 15 additions & 4 deletions

File tree

.planning/REQUIREMENTS.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,14 @@ Backfilled 2026-07-25 alongside the phase, which was inserted as urgent work wit
179179
- [x] **TEST-02**: A test may tolerate an upstream outage only by asserting the error code is transient (`UPSTREAM_ERROR`, `RATE_LIMITED`, `UPSTREAM_UNAVAILABLE`); `NOT_FOUND` or `INVALID_INPUT` on a call that should succeed fails loudly
180180
- [x] **TEST-03**: Reintroducing a masking idiom fails the DEFAULT unit suite, not only a live run (`tests/test_integration_test_quality.py`)
181181
- [x] **TEST-04**: A test that genuinely cannot assert in every branch declares itself with `@pytest.mark.tolerates_upstream_error(reason=...)`; the reason is mandatory and exemptions are capped at 10% of the suite
182-
- [x] **TEST-05**: Every tool returns a structured error envelope on upstream failure and never raises — enforced for drug_database and nutrient_file via `shared/envelope.py:upstream_guard`
182+
- [x] **TEST-05**: Every tool returns a structured error envelope on upstream failure and never raises — enforced for drug_database and nutrient_file via `shared/envelope.py:upstream_guard` (generalised to all 271 tools by ERR-01)
183+
184+
### Error Classification (Phase 20.2)
185+
186+
- [x] **ERR-01**: Every `@tool` is covered by a catch-all — `@upstream_guard`, a broad `except Exception`/`httpx.HTTPError`, or a module helper that has one. Catching only `httpx.HTTPStatusError` does not count: it covers a 500 but not a timeout, connect error or malformed body
187+
- [x] **ERR-02**: Reintroducing an uncovered tool fails the DEFAULT unit suite (`tests/test_tool_error_handling.py`), and the detector carries a self-test so it cannot pass vacuously
188+
- [x] **ERR-03**: A malformed upstream body is classified as an upstream failure, never as caller error — `shared/http.py:api_get` raises `httpx.DecodingError` (an `HTTPError`, not a `ValueError`) so it bypasses `except ValueError -> INVALID_INPUT` arms
189+
- [x] **ERR-04**: Genuine argument-validation `ValueError`s still return `INVALID_INPUT` — the decode fix does not swallow real caller errors
183190

184191
### MCP Prompts and Resources
185192

@@ -461,6 +468,10 @@ Primary portal is **data.novascotia.ca** — a **Socrata** (Tyler Technologies)
461468
| TEST-03 | Phase 20.1 | Complete |
462469
| TEST-04 | Phase 20.1 | Complete |
463470
| TEST-05 | Phase 20.1 | Complete |
471+
| ERR-01 | Phase 20.2 | Complete |
472+
| ERR-02 | Phase 20.2 | Complete |
473+
| ERR-03 | Phase 20.2 | Complete |
474+
| ERR-04 | Phase 20.2 | Complete |
464475
| PR-01 | Phase 40 | Complete |
465476
| PR-02 | Phase 40 | Complete |
466477
| PR-03 | Phase 40 | Complete |

.planning/ROADMAP.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -330,13 +330,13 @@ Plans:
330330
### Phase 20.2: Normalize tool error handling and guard malformed upstream JSON (INSERTED)
331331

332332
**Goal:** Make every module classify an upstream failure as an upstream failure. `shared/http.py:api_get` returns `response.json()` with no decode guard, so an HTTP 200 carrying an HTML error page raises `json.JSONDecodeError` — a `ValueError` subclass — which lands in the `except ValueError -> INVALID_INPUT` arm of statcan, ircc, manitoba, saskatchewan, nova_scotia, british_columbia and datastore. A real outage is reported as caller error, and `assert_live_or_transient` (which tolerates only UPSTREAM_ERROR / RATE_LIMITED / UPSTREAM_UNAVAILABLE) fails live tests with a misleading code. The guard cannot simply be added at the source: `httpx.DecodingError` is an `HTTPError` but **not** an `HTTPStatusError`, and 5 of 24 modules (bank_of_canada, ckan, ircc, ontario, recalls) catch only `HTTPStatusError` — so a naive central fix converts a mislabelled error into an unhandled one, which is strictly worse and is precisely what Phase 20.1 removed. The work is therefore: normalize the handler shape across all 24 modules first, then add one decode guard in `api_get`. Doing this before Phases 21-39 means ~19 future modules inherit the correct shape instead of enlarging the cleanup.
333-
**Requirements**: TBD
333+
**Requirements**: ERR-01..ERR-04
334334
**Depends on:** Phase 20.1
335-
**Plans:** 0 plans
335+
**Plans:** 1/1 plans complete
336336

337337
Plans:
338338

339-
- [ ] TBD (run /gsd-plan-phase 20.2 to break down)
339+
- [x] 20.2-01-PLAN.md — Catch-all coverage for every tool + decode guard in api_get
340340

341341
### Phase 21: New Brunswick Government Open Data
342342

0 commit comments

Comments
 (0)