Repository navigation
test(claims): expand the golden behavioral contract to GOLDEN-19 - #179
Merged
Merged
Conversation
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This was referenced Oct 21, 2026
The shared fixture carried nine cases and the Go harness asserted a hard-coded count plus a hard-coded prefix list. Ten contract gaps had no Go coverage at all, and four error codes (MALFORMED_CLAIM, TENANT_MISMATCH, INVALID_EVENT_ID, UNKNOWN_STATUS) were referenced by zero test files. Adds GOLDEN-10..19 covering the four error codes and the legal edges VALIDATING->EXCEPTION, EXCEPTION->INVESTIGATION_REQUIRED, INVESTIGATION_REQUIRED->WAITING_FOR_EVIDENCE, WAITING_FOR_EVIDENCE->HITL, HITL->ACTION_PENDING and ACTION_PENDING->ACTIONED, each asserting the error category, the resulting state and version, that the input claim is not mutated, and the audit effect. The harness no longer hard-codes a case count: goldenExpectationByID is a coverage registry matched against the fixture in both directions, and a fixture case without Go coverage fails the contract test. The known fixture-schema inconsistencies (decorative terminal_state and audit_actions fields, and the GOLDEN-01 terminal_state conflict) are deferred and documented in the package header rather than silently rewritten. Cases 01-09 are byte-identical; the fixture was edited additively only. Test-only: no production Go file, Python artifact, CI workflow, or dependency change. Release status remains NOT QUALIFIED.
Aparnap2
force-pushed
the
test/golden-contract-expansion
branch
from
October 21, 2026 06:47
df3309a to
b0c9c7a
Compare
Aparnap2
marked this pull request as ready for review
October 21, 2026 06:52
Aparnap2
added a commit
that referenced
this pull request
Oct 21, 2026
The rebase onto main@7ad446c (which merged #180 and #179) made three statements in this change false as written: - The ADR, the decision-log entry and KL-18 all said the cross-language fixture 'contains nine cases'. After #179 it contains nineteen. None of the nineteen covers EXPIRED, so the substantive claim is unchanged; only the count was stale. - The ADR's Base line still named main@254c4b9; it is now written against main@7ad446c. - The Context said 'no document in this repository ever ratified it'. This ADR ratifies it, so the claim needs its temporal qualifier. The statemachine.go reference is likewise now stated as 'before this ADR', since this change corrects that header. Also fixes KL-18's position: it was inserted between KL-16 and KL-17 instead of after KL-17, so the register's rows were out of order. Co-Authored-By: opencode <no-reply@opencode.ai>
Aparnap2
added a commit
that referenced
this pull request
Oct 21, 2026
* docs(adr): ratify the claim expiry contract (ADR-011, S5/APA-26) EXPIRED has been implemented, wired, tested and deployed for a long time, but no document in this repository ever ratified it. Its semantics were attested only by code comments citing a Linear id the repo does not record, while the file calling itself the specification of this lifecycle did not contain the status at all. ADR-011 records the approved semantics: EXPIRED is terminal-for-round (no out-edges; terminality by absence from claims.Transitions), reachable only as HITL -> EXPIRED or ACTION_PENDING -> EXPIRED (HITL-wait timeout). Timeout expiry can never approve, reject, close, escalate or otherwise decide a claim; post-expiry APPROVE/REJECT/ESCALATE/HOLD are illegal and APPROVE from HITL was already illegal. Re-drive after expiry requires an explicit new decision/round, never an implicit edge. Reconciled documentation: - statemachine.go's header no longer claims the file is 'the Go port of the Python specification' - packages/domain/state_machine.py is a demoted artifact, not a mirror, and does not define EXPIRED. Comment-only change. - AGENT_OPERATING_CONTRACT.md item 5 now lists EXPIRED in the chain. - packages/domain/state_machine.py's docstring states it is superseded for lifecycle semantics and is not a mirror. Docstring-only change. - 09_DECISION_LOG.md and 06_PROGRESS.md carry the decision. - KNOWN_LIMITATIONS.md gains KL-18 registering the narrower Python graph rather than reconciling it silently. No lifecycle behaviour changed. The implementation already behaved this way and the existing tests already pin it: claims/expiry_red_test.go, handlers/decision_expiry_test.go (4 PG-gated), repository/postgres/hitl_expiry_test.go. The statemachine.go comment about golden case 08 is also inaccurate but is deliberately left alone: that correction is a separate focused change. Co-Authored-By: opencode <no-reply@opencode.ai> * docs(adr): correct ADR-011 facts after rebasing onto #179 The rebase onto main@7ad446c (which merged #180 and #179) made three statements in this change false as written: - The ADR, the decision-log entry and KL-18 all said the cross-language fixture 'contains nine cases'. After #179 it contains nineteen. None of the nineteen covers EXPIRED, so the substantive claim is unchanged; only the count was stale. - The ADR's Base line still named main@254c4b9; it is now written against main@7ad446c. - The Context said 'no document in this repository ever ratified it'. This ADR ratifies it, so the claim needs its temporal qualifier. The statemachine.go reference is likewise now stated as 'before this ADR', since this change corrects that header. Also fixes KL-18's position: it was inserted between KL-16 and KL-17 instead of after KL-17, so the register's rows were out of order. Co-Authored-By: opencode <no-reply@opencode.ai> --------- Co-authored-by: opencode <no-reply@opencode.ai>
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.
What changed
Two files, test-only:
fixtures/golden_cases.jsonGOLDEN-10..19). Cases 01–09 byte-identical (machine-verified),versionunchanged at1.0.0, nothing removed, no existing expected value rewritten.apps/api/internal/claims/parity_test.goNo production Go file, Python artifact, CI workflow, dependency, or doc changed. Base:
main@254c4b92dddf59a758a133c1edbf7618dcc011b2. Commit:df3309a.The gaps this closes
MALFORMED_CLAIM,TENANT_MISMATCH,INVALID_EVENT_IDandUNKNOWN_STATUSwere referenced by zero Go test files. Six legal edges had no asserted coverage either — becauseClaimStatusInvestigationRequiredandClaimStatusWaitingForEvidenceappeared in no test file at all.Re-derived edge counts (the previously reported "8 of 13" was wrong on both sides): the graph has 14 legal edges; 4 were asserted in any Go file before this change (one of them PostgreSQL-gated only); 10 were asserted nowhere; one of those is covered by open PR #178, leaving 9 genuinely uncovered on this base. This change covers 6 of the 9. DB-independent legal-edge assertions go from 3 → 9.
GOLDEN-10-malformed-claimMALFORMED_CLAIM(was 0 coverage)MALFORMED_CLAIM; malformed precedes tenant mismatchGOLDEN-11-tenant-mismatchTENANT_MISMATCH(was 0)TENANT_MISMATCH, and it wins over blank event-id, stale version and illegal edgeGOLDEN-12-invalid-event-idINVALID_EVENT_ID(was 0)INVALID_EVENT_ID; wins over version and legalityGOLDEN-13-unknown-statusUNKNOWN_STATUS(was 0)UNKNOWN_STATUS, notILLEGAL_TRANSITION; version check precedes the status checkGOLDEN-14-validating-to-exceptionVALIDATING → EXCEPTIONEXCEPTION, v1→v2, key recorded, input unmutated, one audit eventGOLDEN-15-exception-to-investigationEXCEPTION → INVESTIGATION_REQUIREDINVESTIGATION_REQUIRED, v2, one audit eventGOLDEN-16-investigation-to-waiting-evidenceINVESTIGATION_REQUIRED → WAITING_FOR_EVIDENCEWAITING_FOR_EVIDENCE, v2, one audit eventGOLDEN-17-waiting-evidence-to-hitlWAITING_FOR_EVIDENCE → HITLHITL, v2, one audit eventGOLDEN-18-hitl-to-action-pendingHITL → ACTION_PENDINGACTION_PENDING, v2, one audit eventGOLDEN-19-action-pending-to-actionedACTION_PENDING → ACTIONEDACTIONED, v2, one audit eventEvery expectation is derived from the documented check order in
statemachine.go(malformed → tenant → event-id → idempotent replay → version → known status → legality), the transition graph, and the canonical chain indocs/AGENT_OPERATING_CONTRACT.md. No business rule was invented.The harness no longer maintains a second count
goldenExpectationByIDis a 19-entry coverage registry of hardcoded literals, matched against the fixture in both directions: every fixture id appears exactly once, every registered id is present exactly once, every fixture case has Go coverage, and every case's fixtureexpectedequals the hardcoded Go expectation. A fixture case without coverage now fails (fixture case %q has no Go coverage) instead of passing silently. The previouslen(doc.Cases) != 9assertion and the nine-entry prefix list are gone.Each new case re-asserts the fixture's inputs against hardcoded literals, runs the scenario through the direct Go APIs, asserts the observed outcome against hardcoded literals, then asserts the fixture's
expectedagainst the same literals. Proven live rather than echoed: mutating the fixture broke the tests, and separately mutating the Go expectation broke them with the observed value reported — the expected side is real implementation output, not a fixture echo.Verification
Run by me against real PostgreSQL (
claimops-postgres,claimops_appwithrolsuper=f, rolbypassrls=f, so RLS is genuinely enforced):The PG-gated suites that the authoring agent could not reach were run for real and pass:
TestClaimSubmit_*(6/6),TestDecision_ExpireFromHITL_Live,TestDecision_ExpireFromNonHITL_Rejected_Live,TestDecision_DuplicateIsReplay,TestDecision_ConcurrentIdenticalOneMutation,TestDecision_ConcurrentDifferentEventsConflict,TestHITL_ExpiredExcludedFromPending.Not run (services absent, not silently skipped): Mockoon contract tests (gate returns 404 on
GET /v1/policies/POL-001), localgcp GCS/Pub/Sub, GCW emulator, and the Groq live-LLM matrix. The authoring agent'sgofmtbinary andgo clean -testcachewere blocked by its shell policy; formatting was verified withgo fmtplus a read-onlygo/formatequivalent, and every run used-count=1, which bypasses the test cache.uv/ruff/pytestwere not run — no Python changed.Findings — deferred, not encoded
statemachine.go:12-14claims golden case 08 witnesses "stale-version wins over legality", but case 08's edgeREGISTERED → DOCUMENTS_RECEIVEDis legal, so it witnesses only that a stale version is rejected. The precedence is real (check 5 precedes check 7) but unwitnessed in Go.expected.audit_actionsis["claim.status.transition"]— the Python action string — while Go emits"claim.transitioned". Asserting the fixture's value in Go would fail. The new cases therefore useaudit_count(language-independent: both implementations record exactly one audit event per successful transition) instead of the action string.terminal_statedeferred): the field is read by neither implementation and its meaning differs across cases; GOLDEN-01's value ("VALIDATING") contradicts the outcome both suites assert (REGISTERED, v2). Correcting it would require ratifying a definition no ADR or contract establishes, so it is documented in theparity_test.gopackage header rather than silently rewritten. (The one contract-supported correction would be GOLDEN-01 →"REGISTERED"; say the word and it can be applied with the reasoning stated.)Status == "" || Version < 1 || Tenant == ""; the Python spec tests absence (None), not emptiness, and its model makes version < 1 and a blank tenant unconstructible, sostatus=""would beUNKNOWN_STATUSthere rather thanMALFORMED_CLAIM.GOLDEN-10therefore encodes the authoritative Go definition and cannot be satisfied by the Python spec artifact. This warrants its own issue.Residual, not silently dropped: edges
REGISTERED → DOCUMENTS_RECEIVED,DOCUMENTS_RECEIVED → VALIDATINGandVERIFIED → CLOSEDremain unasserted;ACTIONED → VERIFIEDremains PostgreSQL-gated; theSTALE_VERSION-before-ILLEGAL_TRANSITIONprecedence remains unwitnessed (F1);READY_FOR_REVIEWterminality remains delegated to PR #178 (no overlap with this change — no terminality assertion and noREADY_FOR_REVIEWedge here, and no symbol collisions).Status
Test-only, deterministic (fixed literal ids, fixed literal dates, exact int64 paise; no
uuid4(), notime.Now(), no randomness, no environment-dependent expectation, no secrets, no patient data). Not authorized to merge — opened as a draft. Release status NOT QUALIFIED; this change qualifies nothing and closes no entry indocs/KNOWN_LIMITATIONS.md.