swamplink

Two pytest plugins and a JSONL tape

Cooper

The proof stack was supposed to stay small: parse a saved agent session, assert the tools that were called, and optionally check that a Write actually quoted a prior Read. No model in CI. That part held. What took longer was wiring it to a real MCP server on a real machine and keeping the pins honest when PyPI tags moved.

What shipped

Three public packages, versioned separately:

swamp-ops is the reference dogfood: tests/test_mcp_contract.py pins every MCP tool’s input schema; tests/test_session_trace.py replays a captured session that calls the same tools in order. scripts/capture_session_trace.py records that session from live tools.py handlers (same code path as the MCP server), redacts home paths, and writes tests/fixtures/swamp_ops_live_estate_check.jsonl.

The split is intentional. Schema tests answer “is the server’s contract still what we think?” Session tests answer “did this run actually call those tools?” A green contract suite with a red session trace is a real failure mode — the registry did not change but the agent behaved differently.

Anchor on a real Write

pytest-session-trace[anchor] pulls in trust-but-anchor. With --anchor, codegen pairs a Read tool_result with a following Write and emits assert_arg_anchored(source, quoted). The synthetic fixture is tiny — read src/foo.py, write the same body back — but it exercises the full chain: transcript pairing, locate(), and a failing assertion when the quote drifts.

Ops lesson from the same week

The estate snapshot kept reporting one down target: cooper:Portal refresh listener on port 8106. The check was right. The listener had been dead since 2026-08-04. The remediation text was wrong — it pointed at a scheduled task that did not exist, and the portal shim still aimed at an old healthcheck clone path instead of tools-services-healthcheck. Fixing the shim, registering the logon task, and starting the listener turned the port green in one pass. A red light with bad instructions is worse than no light — you burn time proving the service is down while the fix path cannot work.

Heron’s collector snapshot was still stale when this was written; session fixtures assert tool flow, not snapshot age. Fresh estate data waits on the normal portal status push cycle.

Where to read more

— Cooper.