Enforce data quality at the recording choke point, and fix the Codex session-link defect - #211
Merged
Merged
Conversation
added 2 commits
September 13, 2026 16:16
The rules, the single enforcement point, the MCP surface that carries them to agents, and the fix this PR is named for. **The rules** (semantic_rules.py — read this file first). Each rule carries the measurement that justifies it: a title must render (R1); control characters are collapsed before the length cap (R2); a terminal section carries its outcome (R4); a check names something a reviewer could re-run or is objectively anchored (R5); a check's name identifies it, because supersession keys on it (R6). **One enforcement point** (service.py). _enforce_semantic_rules is called from record_event, the single writer every lane funnels through, so no surface can store what another refuses. Machine-recorded events — imported usage, session observations, finding dispositions — are deliberately out of scope: no agent authored them, so a refusal would drop a fact instead of correcting a report. **The fix** (hooks.py). Codex had no SessionStart hook and the context validator hardcoded client == "claude-code", so a captured Codex context was discarded anyway. Measured consequence: 1,161 sections with ZERO carrying a client_session_id, and 61% of work never joining to the usage that paid for it. Contexts are now per-client, so one client cannot overwrite another's ids. **The MCP surface** (mcp.py). Descriptors for client_session_id, client_transcript_id and project_dir, which had no description at all despite deciding whether imported usage ever joins. And agentacct_work_status, because next_step and blocker were write-only — accepted, stored, returned by no tool. **Extraction** (client_usage.py). Codex usage rows carried no revision watermark (0 of 372 against 2005 of 2005 for claude), so whole-second ties parked as conflicts that could never clear. Claude identity budget 256 KiB -> 2 MiB: 94.87% -> 100% of 6,274 real transcripts resolve, at no measurable cost. **Display alignment** (display_budget.py and three call sites). Field caps and the space each field renders into were chosen independently, so a summary was handed to a card that renders a two-line label. Measured cost, replayed against the real ledger: 9 of 1,521 records refused (0.59%), every one genuinely incomplete — no outcome, no evidence pointer and no exit code. Zero legitimate reports refused. Most test files here are mechanical fixture completion: the rules require fields most fixtures never carried. 1,503 added lines against 85 removed, and worth skipping in review.
design-plans/data-quality/ holds the reasoning behind the rules rather than just the rules: the findings with each measurement, the rule catalogue where every rule states what justifies it and what false-positive budget it must meet, the text and display analyses, an assessment of what the app does and does not deliver, the hook and MCP audit, and a review guide. Three tools, all read-only against the live store: * audit-agent-data.py — aggregate audit of the real ledger, plus a --replay mode that sends every stored record back through the live write path so a rule that refuses legitimate work shows up as a number rather than an opinion * complete-test-fixtures.py — the AST-guided fixture completion used across 44 test files in the previous commit. It refuses to write a file that does not parse, and building it surfaced four bugs in itself, each documented in the file * verify-fixes.py — 30 checks that drive the real code paths a client drives and exit non-zero if any claim fails. Its output is committed at design-plans/data-quality/evidence/VERIFICATION.txt
FZ2000
force-pushed
the
data-quality
branch
3 times, most recently
from
September 13, 2026 23:53
76d45ba to
704fe30
Compare
Two things a reviewer and a reader both hit. The guide still described a 168-file stacked diff. This PR is 74 files and three commits, so the reading order, the skip list and the numbers are now stated against the current base, every figure measured on this head: 74 files; eleven product files at 1,127 insertions; 40 modified test files at +305/-86 against the four new suites at 1,218 lines and 1,467 tests; 4,348 tests green at each code commit (0a03525 verified in a clean worktree) and 4,349 at the head; 30/30 verify-fixes checks; 9 replay refusals of 1,541. It also gains a "what this PR does not prove" section: no live Codex session has run through the new hook, the rules bind only new writes, the 54-character card budget is geometric rather than screen-measured, summary quality is still the largest gap, and no human has reviewed the app since these changes. Its commands were checked by running them: both tools import agentacct, so the guide, the verify-fixes docstring and the audit docstring now name .venv/bin/python instead of a bare python3 (which stops at "import fastapi" on a system interpreter). The fixture tool is stdlib-only and says so. The receipt fix: the evidence-coverage definition printed by the CLI, the TUI and every exported Markdown receipt read "X of Y checkable steps carry a passing check". That is a formula written for a reader of the source, shipped to a reader of the receipt, and it sits in both published worked examples, where it reads as a renderer bug. It now states the rule in words, the worked examples are regenerated from the receipt engine rather than hand-edited, and test_receipt_markdown.py fails on any "N of M"-shaped token in a rendered receipt. The counting copy that is still wrong ("1 checks", "touched 3 file(s)", "1 step(s) ran in subagents") is filed as item 6 in ASSESSMENT.md section 7 with the exact lines: it spans Python and Swift, and the reference images that draw it can only be re-recorded on macOS 26.6.
FZ2000
force-pushed
the
data-quality
branch
from
September 13, 2026 23:53
704fe30 to
0cdc17a
Compare
`design-plans/data-quality/tools/demo-data-quality.py` shows the loop a user and an agent are actually in, then goes looking for what is still wrong. Parts 1-3 drive the real code paths on temporary stores and print the exact text each side sees: the Codex SessionStart context, the refusal an agent gets for a completed section with no summary (verbatim, with the corrected call in it), the two-word retry refused, process prose accepted, the outcome sentence accepted and joined to its session, and then what the card and the receipt render. The evidence lane follows the same shape, including the two cases that keep it honest: `files: ["."]` stores nothing and cannot satisfy reproducibility, blank before/after summaries are not evidence, and the run-scoped outcome lane says "no runs found" until a run exists. Part 3 is adversarial: all three write lanes refuse the same record with the same message, control characters, an ANSI escape, a right-to-left override, emoji and a 4-byte character never reach the store, a 200-character title is refused rather than truncated, and the false-positive guard shows a legitimate unicode, multiline record still landing. Part 4 is not a certificate. It runs the opposite way round: five known defects are reported live, with counts, and a line says the design record is stale if one stops reproducing. Today it confirms all five - a one-check receipt renders as "1 checks" and every count prints as "3 file(s)"/"1 command(s)", 28 of 542 real work-item titles exceed the card's 54 characters, 61.3% of work items carry no usage record and 76.0% no evidence, most stored summaries still describe process rather than outcome, and the 5 stored terminal sections with no summary are still there because the rules bind new writes only. `tests/test_data_quality_demo.py` runs Parts 1-3 in CI, so the demo cannot rot into a document, and asserts the demo keeps naming its own limits. The demo's own summary ends "Part 4 is why this is not perfect" - the artifact makes no perfection claim, and the review guide says to read Part 4 before believing Parts 1-3.
…e wrong code audit-agent-data.py lacked the src/ path prelude its sibling tools use, so --replay resolved `agentacct` to whatever was installed. Against a checkout predating the rules (the editable install points at design/setup-work-overhaul, which has no semantic_rules), `agentacct.mcp` still imports, the write path has no rules, every record is accepted, and the tool prints "refused: 0" while `choke_point_replay` quietly reports "skipped" — a green against the wrong code, the exact failure mode this tool exists to catch. - Put this checkout's src/ first, like verify-fixes.py and demo-data-quality.py, so --replay tests THIS tree by default. - Add an `agentacct_under_test` provenance block naming the imported package and whether `agentacct.semantic_rules` is present. - When the rules cannot be imported, emit an explicit `error` in both replay blocks and exit non-zero (3) instead of reporting a false `refused: 0`. Verified: with no PYTHONPATH the tool now reports 9/1548 refused (previously a false 0); with the rules module blocked it exits 3 with a clear error. Sibling tools still run clean and nothing imports this script. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013w9bhGCPP2g37g4xiehwDV
This was referenced Sep 15, 2026
Open
# Conflicts: # src/agentacct/install_guide.py # src/agentacct/service.py
- client_usage: main landed the same per-session revision watermark for Codex usage rows (`rollout_revision_at` / `source_revision_basis`), so the merged constructor passed `source_revision_at` twice and no longer parsed. Keep main's watermark and drop this branch's `_codex_session_revision_at` copy. - install_guide: keep main's whole-job-done capstone as its own bullet (its test forbids evidence words in that line) and fold the "record it when unsure" rule into the opening bullet, so the shared block stays within the ten-line budget the guide tests enforce. - test_text_hygiene: main's Diagnostics verifiers added a third recorded `state` fallback in tui.py (`_source_lozenge`); inventory it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Collaborator
Author
|
Merged
Locally: 4483 passed. The one local failure, 🤖 Generated with Claude Code |
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
76 files, 4 commits, no stack
mainnow contains the branch this builds on (#190 merged), so this is a standalone PR: no stacked diff, no 28k-line file list. The eleven product files are 1,127 insertions; the rest is tests, docs and tooling.The two code commits pass the full suite on their own — 4,348 tests each, the first verified in a clean worktree. The head runs 4,351.
Watch it work, then watch it fail
Parts 1-3 walk the loop an agent and a user are actually in, on temporary stores, printing the exact text each side sees: the Codex
SessionStartcontext; the refusal for a completed section with no summary (verbatim, with the corrected call inside it); the two-word retry refused; process prose accepted; the outcome sentence accepted and joined to its session; then what the card and the receipt render. The evidence lane follows, includingfiles: ["."](which stores nothing and cannot count), blank before/after summaries (not evidence), and the run-scoped outcome lane sayingno runs founduntil a run exists. Part 3 is adversarial: all three lanes refuse the same record with the same message, and control characters, ANSI escapes, an RTL override, emoji and a 4-byte character never reach the store — while a legitimate unicode, multiline record still lands.tests/test_data_quality_demo.pyruns these in CI, so the demo cannot rot into a document.Part 4 is a falsification run, not a certificate. It goes looking for what is still broken and reports what it finds, live, with counts — and says the design record is stale if one stops reproducing. On the installed ledger today it confirms all five:
1 checks; every count prints3 file(s)/1 command(s)The demo's own summary ends "Part 4 is why this is not perfect", and the review guide says to read Part 4 before believing Parts 1-3.
The bug, stated in one line
A Codex session could record 1,161 sections and not one would carry a
client_session_id— so 61% of recorded work never joined to the usage that paid for it.Cause: two defects stacked, neither the agent's fault.
SessionStarthook — the event that carries session identity. Codex exposes eight hook events; only two were used.client == "claude-code", so a captured Codex context would have been discarded anyway. The MCP inheritance gate and the slot loader repeated the same check.Before → after, on the real code path
Codex-shaped
SessionStart, then a section recorded with no ids of its own:client_session_idNone"codex-session-verify"clientNone"codex"client_context_sourceclaude_code_hook(hook-derived, not claimed exact)Reproduce it rather than trusting this description
Drives the real code paths a client drives, prints every value observed, exits non-zero if any claim fails. Throwaway stores only; touches no installed app, live store or client config. Output committed at
design-plans/data-quality/evidence/VERIFICATION.txt.Covers: the Codex hook installing and its context being inherited; the upgrade path for a machine with the old config (wrapper replaced, not duplicated — a duplicate double-records tool activity); all three lanes refusing the same incomplete records while accepting complete ones; the read-back loop; the contract line budget; display budgets; and a replay of every stored record (9 of 1,541 refused, 0.58%, all genuinely incomplete, zero false positives).
Where to spend review attention
Full map in
design-plans/data-quality/REVIEW_GUIDE.md. The short version:semantic_rules.py(new, 367 lines) — the whole change in one file, each rule carrying the measurement that justifies it. Decide here whether the rules are right.service.py(+48) — one function called fromrecord_event, which is why no lane can bypass the rules. The guards are the interesting part: what is deliberately out of scope.hooks.py(+94/−26) — where the headline defect lived.Skim: most of
mcp.py(+377/−28) is schema text; the two substantive blocks are the client-context validator and theagentacct_work_statusimplementation. Skip: the 40 existing test files (+290/−86, about seven mechanical fixture lines each) —complete-test-fixtures.pydid that work and is worth reading once instead. The four new suites are where the test weight is: 1,218 lines, 1,467 tests.The rules
Enforced once for every lane. Each is a refusal an agent can fix in one retry:
files: ["."](which stores nothing) cannot countMeasured cost across all rules: 9 of 1,541 replayed records refused (0.58%), all genuinely incomplete. Zero legitimate reports refused.
What else is in here
Extraction. Codex usage rows carried no revision watermark (0 of 372 vs 2005 of 2005 for claude), so whole-second ties parked as conflicts that could never clear. Claude identity budget 256 KiB → 2 MiB: 94.87% → 100% of 6,274 real transcripts resolve, at no measurable cost (0.8 s for all 6,595 files either way).
agentacct_work_status.next_stepandblockerwere write-only — asked for, stored, and returned by no tool, so an agent could not recover a previous session's continuation or notice its own unfinished work. Also:client_session_id,client_transcript_idandproject_dirhad no description at all despite deciding whether usage ever joins.Display alignment. Field caps and the space each field renders into were chosen independently, so a summary was handed to a card that renders a two-line label. Budgets are now shared in one module and disclosed in the schema.
One unfilled placeholder. The evidence-coverage definition printed by the CLI, the TUI and every exported Markdown receipt read
X of Y checkable steps carry a passing check— a formula written for a reader of the source, shipped to a reader of the receipt, and sitting in both published worked examples where it reads as a renderer bug. It now states the rule in words, the examples are regenerated from the receipt engine, and a test fails on anyN of M-shaped token in a rendered receipt.Honest limits
Still open, ranked
1 checks · 1 passed · 0 failed,touched 3 file(s),1 step(s) ran in subagents. Eight Python sites and four in the app change together or not at all, and the reference images that draw them can only be re-recorded on macOS 26.6 — filed as item 6 inASSESSMENT.md§7 rather than half-done.🤖 Generated with Claude Code