fix(ingest): run the MCP stdio transport against a real server, and repair its error contract (kø-x)
`stdio_call_tool` shipped never having been executed end to end — docs said so explicitly. Running it found a real defect: `stdio_client` and `ClientSession` are each an anyio task group, and anyio re-packages anything leaving one in a `BaseExceptionGroup`. Both errors the transport raises from inside the session (`mcp_tool_error`, `mcp_non_text_content`) therefore reached callers as exception groups, never as the `IngestError` the whole Door A path catches and switches on by `code`. No canned-tool test could see this: they never enter a task group. `_unwrap_ingest_error` recovers the owned error and re-raises it; anything unowned is re-raised untouched, so this narrows an exception group rather than blanket-catching. Duck-typed on `.exceptions` because `except*`/`ExceptionGroup` are 3.11+ and this project supports >=3.10. Verified against a REAL server subprocess (a local process costs no model tokens, so the repo's cost discipline is untouched; the contract tests still spawn nothing): `examples/ingest-golden-mcp/` + `tests/test_ingest_golden_mcp.py` — byte-identical golden extraction mirroring the http/sql goldens, plus the tool-error and missing-`server_ref` branches. Also recorded: a server on the ingest path must expose a NULL-ARGUMENT tool, so `datasource.build_mcp_server` cannot serve it (`retrieve_cost_docs(query)` has a required parameter, verified to return an error result). The two are separate seams by design. Load-bearing MEASURED, five mutations all RED: detach the unwrap · detach `initialize()` · make the error code generic · detach the `isError` branch · change one byte of the served body. 612 -> 615 tests. ruff + format + mypy clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WiY53sm8JFqk7NN75g5wRS
This commit is contained in:
parent
126807aee7
commit
9dc3722161
9 changed files with 272 additions and 9 deletions
14
CLAUDE.md
14
CLAUDE.md
|
|
@ -53,6 +53,20 @@ Python ≥3.10. MAF (`agent-framework-core` 1.9.0). Pakkehåndtering: `uv`. To b
|
|||
`IngestStampError` — mens hver halvdel alene er lovlig (kuratert innhold kan bære ett
|
||||
provenance-felt). Validering, ALDRI reparasjon: ingenting skrives. Uten dette kunne en kuratert fil
|
||||
bli stille slettet av en senere re-materialisering, som fjerner nøyaktig det som bærer stempelet.
|
||||
- **`IngestError` må overleve anyio-task-gruppene (kø-(x), 2026-08-03):** `stdio_client` og
|
||||
`ClientSession` er hver sin task group, og anyio pakker ALT som forlater en av dem i en
|
||||
`BaseExceptionGroup`. Derfor nådde `stdio_call_tool`s egne feil (`mcp_tool_error`,
|
||||
`mcp_non_text_content`) kalleren som en exception group — aldri som `IngestError`, som er typen
|
||||
hele Door A fanger og switcher på via `code`. `_unwrap_ingest_error` pakker ut og re-raiser den
|
||||
eide feilen; alt annet re-raises URØRT (innsnevring, aldri blanket re-raise). Duck-typet på
|
||||
`.exceptions`, fordi `except*`/`ExceptionGroup` er 3.11+ og repoet er `>=3.10`. **Ingen
|
||||
canned-tool-test kunne fanget dette** — de går aldri inn i en task group; defekten dukket opp
|
||||
første gang koden faktisk ble kjørt. En MCP-server på ingest-stien må eksponere en
|
||||
**null-argument-tool** (URL-en bærer begge koordinatene, tool kalles med `{}`), så
|
||||
`datasource.build_mcp_server` kan IKKE serve den — `retrieve_cost_docs(query)` har et påkrevd
|
||||
argument og returnerer et error-result. De to er separate sømmer med vilje. Load-bearing MÅLT
|
||||
(`tests/test_ingest_golden_mcp.py`), fem mutasjoner alle røde: detach unwrappingen · detach
|
||||
`initialize()` · gjør feilkoden generisk · detach `isError`-grenen · endre ett byte av bodyen.
|
||||
- **Stoppkriterier + budsjett-tak påkrevd ved oppstart** (fail-fast, aldri ubegrenset loop).
|
||||
- **Group Chat maker-checker** som debatt-default (IKKE Magentic, som er eksperimentell).
|
||||
- **To falsifiserere, samme kandidat (Steg 3/4, målbilde §2/§6):** den deterministiske validatoren
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue