M9: MCP Hub locale/correlation propagation, real Hub health check, fix stale test image
Fixed two concrete gaps in the MCP knowledge-search endpoint: no locale field existed at all (now nl-BE/en-GB/fr-BE, wired to the knowledge provider's existing language param), and the correlation ID was always freshly minted, ignoring any inbound X-Correlation-Id header. Added a shared dependency and applied it to all four MCP endpoints so Fleet Ops's own audit log preserves the Hub's real correlation ID end to end. MCP_HUB_BASE_URL/MCP_PROVIDER_ID were declared in .env.example but never read anywhere. Since the Hub's own registration is catalog-driven (it never needs Fleet Ops to push a registration call), wired mcp_hub_base_url for a real Hub reachability health check instead of an unneeded self-registration call. Renamed Fleet Ops's own internal audit tool labels mobilityops_* -> fleet_ops_* (mirrored in contracts/mcp-tools.json with mobilityops_* kept as deprecated aliases); documented that the live Hub connector's own dotted tool namespace is a separate, Hub-owned naming layer, deliberately not touched. Automation page's MCP card now shows real evidence (last tool/client/count/ timestamp, honest no-evidence state) instead of just the registration flag. Also fixed a real methodology gap found mid-session: compose.yaml's api service has no bind mount, so `docker compose run --rm api` silently tests a stale image until rebuilt. Re-ran every local gate after rebuilding; fixed one genuinely stale test assertion and two lint line-length errors surfaced by that rebuild. 176 tests passing, ruff clean, mypy clean (50 files). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
2ae2044e3a
commit
727c19a779
+53
-4
@@ -57,6 +57,7 @@ M7 — complete. All milestones (M0–M7) done, plus a full post-M7 final-accept
|
||||
- Inspection `public_ref` is assigned as `INSP-{count+1:04d}` from a live count query (not gap-safe, fine for a PoC single-writer demo, would need a sequence for real concurrency-safe numbering).
|
||||
- Found and fixed during browser verification (not caught by pytest, since it's a UI-only defect): `ReturnForm` originally held its own `result` state and was conditionally rendered only when `booking.status === "active"`; once the return succeeded the booking flipped to `returned` and React unmounted the form before the user ever saw the result panel. Fixed by lifting the result into `BookingDetail` (`ReturnResultPanel` is now a sibling, not nested in `ReturnForm`). Also found: `OutboxEvent.event_id`'s Python-side `default=uuid.uuid4` on the mapped_column only applies at flush/commit time, so reading `event.event_id` before `db.commit()` returned `None` (rendered as the literal string "None" in the result panel); fixed by assigning `event_id=uuid.uuid4()` explicitly at construction. Lesson: SQLAlchemy column `default=` callables are not available on the in-memory Python object until flush — never rely on the generated value for a same-transaction response body without an explicit `db.flush()` or an explicit Python-side assignment.
|
||||
- Operational note for this environment: `docker compose run --rm api ...` (used for tests/lint) only starts a throwaway one-off container — it does **not** update the long-running `api`/`web` service containers. After any code change meant to be verified live (browser, curl), `docker compose up -d --build <service>` is required, not just `docker compose build`.
|
||||
- **Sharper version of the note above, found the hard way (2026-08-05)**: `compose.yaml`'s `api` service has **no bind mount** for `./backend` — application code is baked into the image at build time only. `docker compose run --rm api pytest/ruff/mypy` reuses whatever image was last built; it does **not** pick up host file edits at all, not even for a throwaway container. Editing code and immediately running `docker compose run --rm api pytest` without an intervening `docker compose build api` silently tests/lints the *old* code and can report a false "all green." Always `docker compose build api` before the first local gate run after a code change in a session (subsequent runs against the same build are fine). Caught this only because a new test file's test count didn't match after several rounds of edits; re-ran the full local gate suite after rebuilding and found one genuinely stale test assertion (below) — nothing else was actually broken, but this was luck, not verification, until the rebuild.
|
||||
|
||||
## Completed evidence
|
||||
|
||||
@@ -1755,7 +1756,55 @@ deployed line — `master` is stale, 19 commits behind). Full audit at
|
||||
clean; `mypy app` — clean (50 files); `cd frontend && npm run build` — clean.
|
||||
- Committed `34df66d`, pushed to `origin/feat/fleet-ops-final-integrations`. Not yet
|
||||
deployed to the live Fleet Ops instance at this point in the session.
|
||||
- **Exact next action**: deploy this revision to `http://192.168.10.150:1236`; Batch 4
|
||||
(MCP Hub — confirm Fleet Ops-side config wiring, tool naming, locale param, correlation
|
||||
ID propagation); Batch 5 (AI Operations Brief using the demo knowledge provider since
|
||||
RAGcore stays off; GUI activity showcase; final regression; evidence write-up).
|
||||
- Deployed to `http://192.168.10.150:1236` (`git archive` + scp + `docker compose up
|
||||
--build -d db api web`, following the established deployment convention). Browser-
|
||||
verified live: Attention Queue tier grouping, Today's Movements curated seed mix (2
|
||||
returns + 2 departures after a real demo reset), About Demo progressive disclosure,
|
||||
Duplicate Merge match/conflict summary + preview all render correctly.
|
||||
- **Found and fixed a real methodology gap mid-session**: `compose.yaml`'s `api` service
|
||||
has no bind mount, so `docker compose run --rm api pytest/ruff/mypy` was silently
|
||||
testing a stale image for an unknown portion of this session (only caught because a new
|
||||
test's collected-count didn't match). Rebuilt and re-ran every local gate from that
|
||||
point on; found exactly one genuinely stale test assertion (`ragcore_sync["built"]` —
|
||||
correctly `True` now, not `False`, since workflow 3 really is built) and two line-length
|
||||
lint errors in the new seed test, both fixed. See the sharper operational note added
|
||||
next to the original `docker compose run` warning above.
|
||||
|
||||
## Batch 4 — MCP Hub (2026-08-05)
|
||||
|
||||
- `MCP_HUB_BASE_URL`/`MCP_PROVIDER_ID` were declared in `.env.example` but never read by
|
||||
`Settings` anywhere — dead config. Since the Hub's own registration is catalog-driven
|
||||
(it reconciles its catalog into the gateway; Fleet Ops never pushes a registration
|
||||
call — confirmed via the Hub-side investigation), wiring them for self-registration
|
||||
would have built an unneeded feature. Wired `mcp_hub_base_url` for something Fleet Ops
|
||||
actually needs instead: a real, bounded (1.5s timeout) Hub reachability health check,
|
||||
surfaced as `hub_reachable` on `/api/v1/integrations/status` and the Automation page.
|
||||
- Fixed two real, concrete gaps in `mcp_integrations.py`'s `search-knowledge` endpoint
|
||||
matching the task brief's own description almost verbatim: no `locale` field existed at
|
||||
all (now `nl-BE`/`en-GB`/`fr-BE`, wired straight through to the knowledge provider,
|
||||
which already supported a `language` param — just never received one), and the
|
||||
correlation ID was **always** freshly minted (`uuid.uuid4()`), ignoring any inbound
|
||||
`X-Correlation-Id` header. Added a shared `get_correlation_id` dependency (valid inbound
|
||||
UUID preserved end-to-end into Fleet Ops's own audit log; fresh UUID only when absent/
|
||||
invalid) and applied it to all four MCP endpoints, not just search-knowledge.
|
||||
- Fleet Ops's own internal audit tool labels renamed `mobilityops_*` → `fleet_ops_*`
|
||||
(`fleet_ops_get_operations_summary`, `.list_attention_vehicles`, `.get_vehicle_details`,
|
||||
`.search_knowledge`) and mirrored in `contracts/mcp-tools.json` (with `mobilityops_*`
|
||||
kept as `deprecated_aliases`, per the task's own "don't break existing clients"
|
||||
instruction). Note: the **live** ITWorx MCP Hub connector publishes these under its own
|
||||
dotted namespace (`mobilityops.operations.summary` etc.) — that naming is Hub-owned and
|
||||
was deliberately not touched (separate repo, active concurrent session there, and
|
||||
already verified live per the Hub-side investigation); `docs/10-mcp-hub-integration.md`
|
||||
now documents both naming layers explicitly so this isn't read as a contradiction.
|
||||
- Automation page's MCP card now shows real evidence (last tool/client/call count/
|
||||
timestamp, honest "registered but no calls yet" state) instead of only the
|
||||
registration-enabled boolean, plus the new Hub-reachability badge.
|
||||
- New tests: `test_search_knowledge_respects_requested_locale`,
|
||||
`test_search_knowledge_preserves_inbound_correlation_id`,
|
||||
`test_operations_summary_mints_correlation_id_when_none_supplied`.
|
||||
- Evidence: `docker compose run --rm api pytest -q` — **176 passed** (against a verified
|
||||
fresh rebuild); `ruff check .` — clean; `mypy app` — clean (50 files); `cd frontend &&
|
||||
npm run build` — clean.
|
||||
- **Exact next action**: commit and deploy Batch 4; Batch 5 (AI Operations Brief using the
|
||||
demo knowledge provider since RAGcore stays off; GUI activity showcase optional-after-
|
||||
demo-complete; final regression across all gates; `artifacts/final-integrations/final-summary.md`).
|
||||
|
||||
Reference in New Issue
Block a user