R05

The likely common cause is caller-environment contamination of acceptance identity, not review-stage logic. This is a static diagnosis; I did not reproduce the reported incidents or run tests.

In src/gzkit/acceptance_execution.py::input_digest, the hash includes file bytes, the normative brief/parent contract, Python/platform, and every environment entry except _, PWD, OLDPWD, SHLVL, and PYTHONPYCACHEPREFIX. Consequently, changing an agent-session identifier alone changes the digest. tests/policy/test_env_usage.py::ENV_VAR_ALLOWLIST explicitly identifies CLAUDE_SESSION_ID and CLAUDE_CODE_SESSION_ID as session metadata; neither is excluded from acceptance hashing.

acceptance_store.py::_validate_new_review compares the review’s digest with a freshly computed digest in the importing process and emits “Review describes stale file contents” on any difference. That wording misidentifies environment differences as file changes. Both specification and adversarial reviews pass through this same check. acceptance_status independently recomputes the same hash, so fixing import alone would leave proof readiness falsely stale. prove also uses it before and after execution.

pipeline_dispatch.py::_acceptance_review_frame asks reviewers to use supplied proof identities or obtain status JSON. commands/obpi_acceptance.py::_status_report exposes a digest computed in its own process. These boundaries allow otherwise identical work to acquire different identities across controller, reviewer, and importer environments.

Recommend a bounded repair to shared freshness calculation: explicitly separate non-semantic session/transport bookkeeping from execution-affecting inputs. Add narrowly justified exclusions for established session metadata, retain conservative treatment of other variables, and document the boundary. Do not remove environment binding wholesale or simply substitute the submitted digest for recomputation. The exact additional transport variables should come from a sanitized comparison of the failing environments; that evidence is unavailable here. If using component diagnostics, reveal changed categories or names, never raw environment values.

The repair must preserve these obligations:

  • Canonical requirement roster, kinds, statements, brief scope, and parent contract remain binding. History-only changes remain non-invalidating.
  • Source/test/configuration additions, edits, and deletions remain detectable without Git. Relevant runtime/environment changes still invalidate proof.
  • BEHAVIOR proof still requires executed selectors, effective production controls, restoration, and green baseline; other kinds retain live canonical resolvers.
  • Receipt provenance, independent reviewer identity, exact proof IDs, and original finding/closure relationships remain enforced. A fresh proof ID cannot inherit earlier approvals, even with identical inputs.
  • Ledger history remains immutable; status and pipeline markers cannot grant credit. A changed digest policy needs explicit recovery for older proof records, not rewritten receipts or silently assigned approval.

Coupled surfaces are acceptance_execution, store ingestion/readiness, reducer input comparisons, CLI status/review handoff, spec/quality prompt framing, adversarial pipeline instructions, and freshness documentation. Downstream consumers include obpi_stages Stage-2 checks, obpi_precomplete::_check_acceptance_records, and obpi_complete::_current_adversarial_event. Verify them through the shared mechanism rather than adding stage-specific bypasses. The existing environment-invalidation test expresses conservative intent and must retain a meaningful positive control.

Proposed verification:

  1. Hold files, contract, execution-affecting environment, Python, and platform constant; vary established session variables across separate processes. Assert equal digests, successful imports for spec, quality, and adversarial records, and correct Stage-2/Stage-4 readiness. Include adding/removing metadata, not only changing values.
  2. Independently vary production bytes, test oracle, configuration, parent decision, requirement statement/roster, and a behavior-affecting environment value. Old reviews must fail import or readiness as appropriate, with no successful-review append on rejection.
  3. Preserve history-only edits and ledger/receipt append stability. Confirm new proof identity revokes prior approvals/closures, and malformed provenance or unresolved mapped findings still blocks advancement.
  4. Exercise CLI producer → receipt ingestion → precompletion/completion consumers, not merely a patched digest helper. Existing integration fixtures use synthetic review captures in one process and do not witness cross-process environment stability.

Remaining uncertainty: I found the shared failure mechanism but not the actual incident environments or receipts, so the precise triggering variable and absence of simultaneous runtime changes are unproven. No implementation or governance workflow was executed.

Read inventory (paths relative to /tmp/gzkit-three-pillars-discovery/C; excerpts where applicable): src/gzkit/{acceptance.py,acceptance_execution.py,acceptance_store.py,pipeline_dispatch.py}; src/gzkit/commands/{obpi_acceptance.py,obpi_precomplete.py,obpi_stages.py,obpi_complete.py}; tests/{test_acceptance_execution.py,test_acceptance_store.py,test_acceptance_integration.py,policy/test_env_usage.py}; docs/governance/{acceptance-obligations.md,trust-doctrine.md,state-doctrine.md,advisory-rules-audit.md}; docs/user/manpages/obpi-acceptance.md; .gzkit/skills/gz-obpi-pipeline/SKILL.md; .gzkit/insights/agent-insights.jsonl (search excerpt); and /tmp/gzkit-three-pillars-inputs/R05.md. Broader searches returned incidental snippets, not whole-file reads; one oversized output was truncated. Shell/read tool calls: 10 total, including task read and this answer write.