Repository navigation
feat(OMN-10407): durable-evidence gate before Linear Done transition - #467
Conversation
Adds a pure-logic DurableEvidenceGate service in node_dod_verify that refuses Linear Done when the durable evidence trail is local-only. OMN-9855 incident shape (2026-04-30): - Worker probed implementation already on omnibase_core/main (PR #949) - Generated DoD receipt LOCALLY at evidence/OMN-9855/dod_report.json, never committed - Updated Linear dod_evidence text to point at PR #949 - onex_change_control/main still had stale contract citing superseded #926 - Linear flipped Done; durable trail unverifiable from origin alone The gate enforces three checks before any Linear Done transition: 1. RECEIPT_TRACKED — evidence/<TICKET>/dod_report.json must be tracked on onex_change_control/main (not just present on disk). 2. CONTRACT_CITES_MERGE_COMMIT — every cited pr_url has gh-state MERGED and mergeCommit.oid matches the cited commit_sha. Closed/superseded PRs HARD FAIL. 3. CONTRACT_ON_OCC_MAIN — the contract version on OCC main contains the real merge-commit citation. Stale main HARD FAIL with explicit "open an OCC PR first" remediation hint. Failure raises DurableEvidenceGateError carrying the structured ModelDurableEvidenceGateResult; the first failed check supplies the remediation hint. Architecture: - Pure-logic gate + Protocol-typed probes (GitTrackedProbe, GhPrViewProbe, ContractOnRefLoader). Tests inject deterministic stubs. - New schema module model_durable_evidence_gate.py is pure (no I/O, no env, no time) per onex_change_control D-008 schema purity rules. - Production probe wiring (subprocess-backed git ls-tree / gh pr view / yaml load on git ref) is intentionally out of scope for this slice; follow-up ticket will wire the gate into the FSM phase ordering. DoD evidence: - 16 unit tests cover untracked receipt, superseded PR, wrong SHA, stale main, missing-on-main, structured error raise, citation extraction (top-level + nested + dedup + malformed), URL parser. - All 2783 non-kafka non-integration omnimarket tests pass. - mypy --strict clean on src/omnimarket/nodes/node_dod_verify/. - ruff format + check clean; pre-commit hooks all green.
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThis pull request introduces a new "durable evidence gate" feature that validates whether a Linear ticket can transition to Done status. The implementation includes a contract specification, Pydantic models for structured results, a service that orchestrates three verification checks (receipt tracking, GitHub PR merge status, contract integrity), and comprehensive test coverage. Changes
Sequence DiagramsequenceDiagram
participant Client as Caller
participant Gate as DurableEvidenceGate
participant Tracker as GitTrackedProbe
participant GH as GhPrViewProbe
participant OCC as ContractOnRefLoader
Client->>Gate: evaluate(ticket_id, contract, receipt_path, contract_path)
activate Gate
Note over Gate: Check 1: Receipt Tracking
Gate->>Tracker: is_tracked(receipt_path, "main")
Tracker-->>Gate: tracked: bool
Note over Gate: Check 2: PR Merge Status & SHA
Gate->>Gate: extract_cited_merge_commits(contract)
Gate->>GH: gh_pr_view(repo, pr_number)
GH-->>Gate: {state, merge_commit_oid}
Gate->>Gate: validate merge_commit_oid == cited_sha
Note over Gate: Check 3: Contract on OCC Main
Gate->>OCC: load_contract_on_ref(contract_path, "main")
OCC-->>Gate: occ_contract
Gate->>Gate: extract_cited_merge_commits(occ_contract)
Gate->>Gate: verify local citations ⊆ occ citations
Gate->>Gate: aggregate results → ModelDurableEvidenceGateResult
Gate-->>Client: result (PASS or FAIL with check messages)
deactivate Gate
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Review rate limit: 0/5 reviews remaining, refill in 5 minutes and 28 seconds. Comment |
|
| Verdict | Meaning | Blocks merge? |
|---|---|---|
passed |
No critical/error findings | No |
blocked |
CRITICAL or ERROR findings found | Yes |
degraded |
All models unavailable (infra) | No (pilot) |
Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8524)
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/omnimarket/nodes/node_dod_verify/services/durable_evidence_gate.py`:
- Around line 148-151: The deduplication currently keys on raw pr_url so
semantically-equivalent citations like "/pull/123" and "/pull/123/files" are
treated as different; update the logic that builds the dedupe key (the code that
creates key = (pr_url, sha) and uses seen.add key) to first normalize the PR
identity by calling parse_pr_url(pr_url) (or the existing normalizing helper)
and use the normalized PR URL/ID together with sha when constructing key; apply
the same change to the second occurrence around the block that references
gh_pr_view() and CONTRACT_ON_OCC_MAIN so both dedupe sites compare normalized
citations.
- Around line 141-159: The loop currently accepts any string `sha` and passes it
to ModelCitedMergeCommit which raises on malformed short SHAs; before creating
ModelCitedMergeCommit (after parse_pr_url(...) and before using `key = (pr_url,
sha)` or appending), validate `sha` (e.g. ensure it matches a hex SHA pattern
like 7–40 hex chars) and if it doesn't match, continue/skip that candidate so
malformed short SHAs are ignored rather than causing a ValidationError;
alternatively wrap ModelCitedMergeCommit construction in a try/except for the
validation error and continue on exception to achieve the same behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f868430c-5850-436a-a52e-b9001a4d23c5
📒 Files selected for processing (4)
contracts/OMN-10407.yamlsrc/omnimarket/nodes/node_dod_verify/models/model_durable_evidence_gate.pysrc/omnimarket/nodes/node_dod_verify/services/durable_evidence_gate.pytests/unit/nodes/node_dod_verify/test_durable_evidence_gate.py
CR Major #1 (durable_evidence_gate.py:~141-159): extract_cited_merge_commits accepted any string sha and let ModelCitedMergeCommit (min_length=7) raise ValidationError on malformed short SHAs — contract violation vs the docstring's "malformed citations are skipped" promise. Added _SHA_RE guard ([0-9a-fA-F]{7,40}) before parse_pr_url; malformed SHAs are now silently skipped. Regression test: test_extract_skips_malformed_short_sha. CR Major #2 (same file, dedupe + cross-set comparison): Citation dedupe and CONTRACT_ON_OCC_MAIN comparison were keyed on raw pr_url, so /pull/123 and /pull/123/files for the same PR were treated as distinct citations — caused double gh_pr_view() calls AND false CONTRACT_ON_OCC_MAIN hard-fails when local and OCC main spelled the same PR differently. Switched both keys to the normalized identity (repo, pr_number, sha). Regression tests: test_url_variants_dedupe_to_same_citation and test_url_variants_across_local_and_main_do_not_hard_fail. deploy-gate root cause: Action matcher src/*/nodes/**/*.py flagged the pure-logic gate service as a runtime path. Added dod-005 to contracts/OMN-10407.yaml documenting the deploy posture honestly: this slice is pure logic + Protocol probes, no container/topic touched, and concrete probe wiring + FSM integration ship in a follow-up ticket carrying its own deploy evidence. check_value contains "deploy" so the gate recognizes intent. NO skip token used. Verification: - 70/70 node_dod_verify unit tests green (was 67, +3 new). - Full uv run pytest tests/ -m "not kafka and not integration": 2786 passed / 0 failed (was 2783). - uv run ruff format/check, uv run mypy --strict on node_dod_verify/, all clean. - OMNIBASE_INFRA_PATH=... pre-commit run --all-files: all hooks pass. - Local replay of validate_pr_deploy_required.py against the three changed files now returns DEPLOY GATE PASSED. CR fingerprints (CodeRabbit auto-resolves on resolution): phantom:medusa:ocelot:97a9ca79-253e-49f4-bb67-27581b204d27 4e71b3a2
Context
Cites OMN-10407.
OMN-9855 incident (2026-04-30): a worker transitioned the Linear ticket to Done after:
omnibase_core/main(PR feat(OMN-12323): implement ticketing runtime handlers #949 merged 2026-04-27).onex_change_control/evidence/OMN-9855/dod_report.jsonLOCALLY, never committing it.dod_evidencedescription to point at PR feat(OMN-12323): implement ticketing runtime handlers #949.Result: Linear was green but
onex_change_control/mainstill had the OLD contract citing superseded PR #926. The durable evidence trail was broken — Linear-Done state was performative and unverifiable from origin alone.What this PR does
Adds a pure-logic
DurableEvidenceGateservice innode_dod_verifythat refuses Linear Done when any of three checks fails:evidence/<TICKET>/dod_report.jsonmust be tracked ononex_change_control/main(not just present on disk).pr_urlhas gh-stateMERGEDandmergeCommit.oidmatches the citedcommit_sha. Closed/superseded PRs HARD FAIL.Failure raises
DurableEvidenceGateErrorcarrying the structuredModelDurableEvidenceGateResult; the first failed check supplies the remediation hint.Architecture
GitTrackedProbe,GhPrViewProbe,ContractOnRefLoader). Tests inject deterministic stubs.model_durable_evidence_gate.pyis pure (no I/O, env, time) per OCC D-008 schema-purity rules.git ls-tree,gh pr view --json mergeCommit, yaml-load-on-git-ref) is intentionally out of scope for this slice. A follow-up ticket will wire concrete probes and integrate the gate into the ticket-pipeline FSM phase ordering immediately before any Linear Done transition.DoD evidence
dod-001—uv run pytest tests/unit/nodes/node_dod_verify/test_durable_evidence_gate.py -v(16 tests pass).dod-002—test_untracked_receipt_hard_fails(covers OMN-9855 incident shape).dod-003—test_contract_cites_superseded_pr_hard_fails(closed PR cited).dod-004—test_stale_occ_main_hard_fails(main has older contract version).Receipt-Gate citation: OMN-10407 (this ticket); evidence captured in
contracts/OMN-10407.yaml.Verification
tests/unit/nodes/node_dod_verify/suite is 67/67 green.uv run pytest tests/ -m "not kafka and not integration"is 2783 passed / 0 failed.uv run mypy src/omnimarket/nodes/node_dod_verify/ --strictclean.uv run ruff checkanduv run ruff format --checkclean.pre-commit run --all-filesgreen (withOMNIBASE_INFRA_PATHset per cross-repo lint).Test plan
mergeCommit.oidmismatches → HARD FAILenforce()raisesDurableEvidenceGateErrorcarrying structured resultSummary by CodeRabbit
New Features
Tests