|
| 1 | +--- |
| 2 | +phase: 20.1-finish-integration-de-masking |
| 3 | +verified: 2026-07-25T00:00:00Z |
| 4 | +status: passed |
| 5 | +score: 5/5 requirements verified; 18/18 baseline failures fixed; 62 -> 0 masking idioms |
| 6 | +requirements_covered: 5/5 |
| 7 | +automated_gate: passed |
| 8 | +--- |
| 9 | + |
| 10 | +# Phase 20.1: Finish integration de-masking — Verification Report |
| 11 | + |
| 12 | +**Phase Goal:** Eliminate every masking idiom from the live integration suite, fix |
| 13 | +the real defects that de-masking exposes, and make the pattern unable to return. |
| 14 | + |
| 15 | +**Status:** PASSED |
| 16 | + |
| 17 | +--- |
| 18 | + |
| 19 | +## Goal Achievement |
| 20 | + |
| 21 | +| # | Truth | Status | Evidence | |
| 22 | +|---|-------|--------|----------| |
| 23 | +| 1 | Zero masking idioms remain | ✓ VERIFIED | `tests/test_integration_test_quality.py` passes; 62 violations at phase start, 0 now | |
| 24 | +| 2 | Exactly one declared exemption, with a reason | ✓ VERIFIED | `test_chronic_disease_sex_filter_on_dataset_without_sex` — AMI has no sex column upstream | |
| 25 | +| 3 | Reintroduction fails the DEFAULT unit suite | ✓ VERIFIED | Guard runs under `uv run pytest` with no marker; 9 guard tests pass | |
| 26 | +| 4 | Tolerance requires asserting a transient code | ✓ VERIFIED | `assert_live_or_transient` in `tests/integration/conftest.py`; NOT_FOUND on a should-succeed call fails | |
| 27 | +| 5 | All 18 baseline failures resolved | ✓ VERIFIED | Per-cluster live runs, all green (see below) | |
| 28 | +| 6 | Tools return envelopes, never raise | ✓ VERIFIED | `upstream_guard` on all 16 drug_database + nutrient_file tools | |
| 29 | +| 7 | Coverage stays above the 95% gate | ✓ VERIFIED | 97.07% | |
| 30 | + |
| 31 | +## Requirements Coverage |
| 32 | + |
| 33 | +TEST-01 (every path asserts), TEST-02 (transient codes only), TEST-03 (unit-suite |
| 34 | +enforcement), TEST-04 (mandatory exemption reason + 10% cap), TEST-05 (structured |
| 35 | +upstream errors) — all satisfied and asserted by tests, not by inspection. |
| 36 | + |
| 37 | +## Baseline |
| 38 | + |
| 39 | +Measured 2026-07-25: **18 failed / 170 passed in 122s**. (An earlier attempt |
| 40 | +appeared to hang for 20 minutes at 37s CPU — a transient network stall, not a |
| 41 | +hang. The corrected measurement replaced the stale June 17-failure list, which |
| 42 | +the CONTEXT explicitly warned not to trust.) |
| 43 | + |
| 44 | +| Cluster | n | Verdict | Resolution | |
| 45 | +|---|---|---|---| |
| 46 | +| BOC | 5 | Test + doc drift | April reshape was intentional (485afdb); tests and docs aligned | |
| 47 | +| StatCan | 5 | 2 defects, 2 drift, 1 maintenance window | NOT_FOUND for empty coords; UPSTREAM_UNAVAILABLE tolerated | |
| 48 | +| York Region | 3 | Test drift | Feature-collection dict is the correct shape | |
| 49 | +| Toronto TTC | 2 | **Real — permanently dead** | GTFS URL resolved from CKAN by slug | |
| 50 | +| IRCC | 2 | 1 defect, 1 unreachable branch | Datastore JSON encoding; Literal rejection asserted | |
| 51 | +| SDMX | 1 | **Real** | Malformed empty body no longer blamed on the caller | |
| 52 | + |
| 53 | +## Nine real defects found and fixed |
| 54 | + |
| 55 | +De-masking was the point, and it worked — these were all shipping behind green tests: |
| 56 | + |
| 57 | +1. **Every named-location weather lookup returned NOT_FOUND** (Toronto, Vancouver); |
| 58 | + only lat/lon worked. Searched 50 of 844 cities. |
| 59 | +2. **`wx_get_climate_trends` never returned a filtered record** — wrong field names |
| 60 | + for the ahccd-trends collection, and the fixture carried the same wrong keys. |
| 61 | +3. **Every ArcGIS Hub "list everything" call failed** — `q=` is HTTP 400 on all five |
| 62 | + portals tested. Shared client; affected four modules. |
| 63 | +4. **York Region text filters matched nothing** for mixed-case input — 0 rows vs 420. |
| 64 | +5. **StatCan coordinate with no series crashed on Pydantic validation**, surfaced as |
| 65 | + an upstream fault. |
| 66 | +6. **Empty SDMX results are malformed JSON upstream**, reported as INVALID_INPUT — |
| 67 | + blaming the caller for StatCan's broken output. |
| 68 | +7. **Both TTC tools were dead, not flaky** — pinned dataset and resource uuids both |
| 69 | + 404 after a republish. 9,361 stops returned after the fix. |
| 70 | +8. **The datastore refused nested values**, defeating its own cross-module purpose. |
| 71 | +9. **16 tools had zero exception handling**, so timeouts escaped as raw ToolErrors. |
| 72 | + |
| 73 | +Three of these (2, 4, and the fixtures behind 2) are the *same* self-referential |
| 74 | +pattern found in StatCan during the preceding reconciliation: tests and fixtures |
| 75 | +written to agree with the code rather than the API. |
| 76 | + |
| 77 | +## Verification Commands |
| 78 | + |
| 79 | +``` |
| 80 | +uv run pytest --cov=src/mcp_canada --cov-fail-under=95 # 3124 passed, 97.07% |
| 81 | +uv run pytest tests/test_integration_test_quality.py # 9 passed |
| 82 | +uv run ruff check tests/ src/ # 94 (baseline was 96) |
| 83 | +``` |
| 84 | + |
| 85 | +Per-cluster live runs, all green: weather 38, BC 9, York Region 8, Alberta 7, |
| 86 | +BOC + cross-module 14, StatCan + SDMX 27, Toronto 10, IRCC 6, NS/QC/StatCan/IRCC 58, |
| 87 | +Drug + Nutrient 17. |
| 88 | + |
| 89 | +## Definition of Done (D-02) |
| 90 | + |
| 91 | +Met. Every baseline failure is fixed rather than deferred — the explicit goal was |
| 92 | +no repeat of quick task 1's silent 17-item deferral. |
| 93 | + |
| 94 | +**Caveat on full-suite runs:** the Health Canada Drug API is slow enough that a |
| 95 | +back-to-back run of all 339 live tests can time out on Drug/Nutrient scenarios |
| 96 | +that pass in isolation. That is upstream rate-limiting under load, not a defect — |
| 97 | +and since `upstream_guard` now converts those timeouts into structured |
| 98 | +`UPSTREAM_ERROR` envelopes, the hardened assertions classify them correctly |
| 99 | +instead of dying on an unhandled exception. |
| 100 | + |
| 101 | +**Verdict:** PASSED. |
0 commit comments