fix(qa): the receipt's cash-anchor obligation derives from the executed plan, and a fabricated decline fails (closes #677) - #694
Merged
Conversation
…ed plan, and a fabricated decline fails (closes #677) A light-tier weekly_review's plan legitimately carries input.cash_anchor.status == "not_applicable" (reason light_tier), but ROUTE_CONTRACTS["weekly_review"]["cash_anchor"] demanded exactly one cash_anchor_checked event unconditionally. The only way such a session could pass verify was a fabricated declined event asserting a question that was never asked -- the exact dishonesty this tool exists to prevent (#230). Per the maintainer disposition: cash_anchor_checked is owed only when the executed plan says the route had a cash-anchor opportunity; zero events is the honest trace for a not_applicable plan, and an event recorded anyway is a named contradiction rather than accepted evidence. - tools/ux_receipt.py: `start` gains an optional --cash-anchor-status, transcribed from input.cash_anchor.status the same way route already is. verify_rows reads it from the trace's own declaration instead of branching on the route alone: not_applicable requires zero cash_anchor_checked events and fails closed on any that exist; omitting the flag preserves the original unconditional reading, so every receipt written before this field existed still verifies unchanged. - references/ux-receipt.md: documents the new flag and the narrowed verify semantics for first_review/weekly_review. - tests/test_interaction_trajectory.py: covers a complete light-tier weekly_review trace verifying with no cash event, a non-light plan still failing on a missing event, a fabricated decline against a not_applicable plan failing as a named contradiction, the CLI round-trip for the new flag (present and omitted), and an unsupported status value failing closed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Summary
A light-tier
weekly_review's executed plan legitimately carriesinput.cash_anchor.status == "not_applicable"(reasonlight_tier), butROUTE_CONTRACTS["weekly_review"]["cash_anchor"]demanded exactly onecash_anchor_checkedevent unconditionally, with no tier branch. The only way such a session could passverifywas a fabricateddeclinedevent asserting a question that was never asked — the exact dishonesty this tool exists to prevent (#230).Per the maintainer disposition on #677:
cash_anchor_checkedis required only when the executed Review Plan says the route had a cash-anchor opportunity.input.cash_anchor.status == "not_applicable"means zero cash-anchor events is the honest trace.not_applicableplus aprovided/declinedevent is contradictory and must fail.What changed
skills/fomo-kernel/tools/ux_receipt.py:startgains an optional--cash-anchor-status(choices:anchored/partial/absent/not_applicable), transcribed from the plan'sinput.cash_anchor.statusthe same wayrouteitself already is — a declared, archived fact on the trace, not something this tool re-derives.verify_rowsreads it from the trace's own declaration row instead of branching on the route alone:not_applicablerequires zerocash_anchor_checkedevents and fails closed, naming a contradiction, if one exists anyway. Omitting the flag preserves the original unconditional reading (exactly one event required), so every receipt written before this field existed still verifies unchanged. A newCASH_ANCHOR_STATUSESconstant mirrors the engine's real enum, and the value is validated unconditionally (like every other declared enum) so a hand-built or hand-edited trace with a garbage value fails the same way an unsupported route does.skills/fomo-kernel/references/ux-receipt.md: documents the new flag onstart, expands the cash-anchor section to state the full obligation model (structuralFalseonsnapshot_review/test_drivevs. the new per-trace narrowing onfirst_review/weekly_review), and updates theverifysummary paragraph accordingly.tests/test_interaction_trajectory.py: adds alight_tier_weekly_rows()fixture and eight new tests (see Proofs below), inserted alongside the existing "Cash anchor ([feat·design] Pre-review data-sanity check: confirm cash anchor (and flag known-incomplete data) before the motive questions #357)" test section.Scope is deliberately narrow: verifier/receipt semantics only. No change to
engine/review.py's_cash_anchor_status, card rendering, or any runtime/product behavior — a light-tier weekly review still asks nothing and shows nothing different than before.references/data-contract.md,references/interaction-delivery.md, anddocs/qa-runbook.mdgate 3 were all checked against the mirrored-surfaces row and found already accurate for this fact (see report in the issue thread / session notes); none needed edits.Proofs (from the disposition)
weekly_reviewtrace verifies with no cash event —test_light_tier_weekly_review_verifies_with_no_cash_event, exercising the exact shape the issue reproduced with (opener, question, both card stages, rule choice, findings, owner verdict) under--require-owner-verdict --require-findings. A companion test (test_first_review_with_declared_not_applicable_status_also_verifies_with_no_cash_event) confirms the mechanism isn't special-cased to one route.test_non_light_plan_still_requires_the_cash_anchor_event_when_absent, declaringanchored/partial/absentand confirming the original "exactly one" requirement is untouched.test_light_tier_weekly_review_with_fabricated_decline_fails.cpbackup/restore,__pycache__cleared, mutated tree import-checked before each run):not_applicablebranch entirely) reddens 3 tests, including proof 1's own test:pass) reddens exactly proof 3's test, with zero collateral:verify_rowsreturns[]for the fabricated-decline trace — it would have verified.)PASS: all 49 suites passed.(python3 tests/run_all.py), both before and after a clean rebase onto latestorigin/main.Test plan
python3 tests/run_all.py— 49/49 suites passpython3 tests/test_interaction_trajectory.py— 137/137 tests pass (130 pre-existing + 7 new)python3 qa/tests/test_skill_commands.py— 16/16 pass (doc/CLI drift checks, including the replay of every documentedux_receipt.pycommand)🤖 Generated with Claude Code