fix(ooda): idempotent done-gate PR emission — one PR per goal (#4166/#4189) - #4334
fix(ooda): idempotent done-gate PR emission — one PR per goal (#4166/#4189)#4334rysweet wants to merge 1 commit into
Conversation
…4189) The OODA/overseer done-gate opened a fresh done-gate PR every cycle for a goal whose engineer had exited leaving an open, unmerged PR — flooding the repo (3x coin-benchmark #4326/#4329/#4332, 4x kgpacks-parity #4324/#4328/#4330/#4333). Dispatch lacked any dedup keyed on durable goal identity. Make goal->engineer done-gate emission idempotent on stable goal identity: - Durable primary guard: new `goal_pr_emissions` ledger (schema v1->v2, forward-only, additive) with `record_goal_pr_emission` upsert (ON CONFLICT(goal_key) DO UPDATE) and an indexed `find_open_goal_pr_emission` open-lookup. UNIQUE(repo, pr_number) turns a second goal claiming the same PR into a visible conflict, not a silent duplicate. Rows are never deleted — a completed PR transitions `state`, so an emission outlives its engineer. - Advisory secondary seam: pure, total, no-panic dedup bricks (`goal_dedup_key`, `parse_goal_key_trailer`, `find_open_pr_for_goal`) plus a `GoalPrRef` DTO and a `PrGhClient::list_open_goal_prs` default so `gh` open-PR reconciliation can adopt a pre-existing PR by the `Simard-Goal-Key:` body trailer (primary) or `engineer/{key}-` branch convention (fallback). The goal key is a one-way, boundary-safe sha256 of goal identity, never the goal title, so distinct goals are unaffected. Additive and non-breaking (default `list_open_goal_prs` returns empty; existing fakes compile unchanged); structured tracing + OTel only, no stray print!, no Bridge naming. Regression coverage: 6 ledger contract tests, 27 dedup unit tests, and a 3-case integration test proving same-goal cycles emit exactly one PR while distinct goals each dispatch. Docs: concept, how-to runbook, and ledger API reference, all linked from the index and mkdocs nav. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
📊 Coverage Summary
Coverage data from CI run. Test files matching |
✅ Verification: merge-ready endorsement (done-gate idempotency)Validated against the OODA done-gate idempotency requirements. This PR fully resolves the near-duplicate done-gate PR churn (#4328/#4330/#4333 kgpacks-rs; #4326/#4329/#4332 COIN). Verification results
Only outstanding item: |
📐 DB design review (Step 5c) — schema validated, one doc-drift nitValidated the ⚠ Non-blocking doc drift — the design markdown in this PR describes a schema that differs from the implemented migration in
Suggest aligning the markdown to the implementation (drop |
🔒 Security requirements review (Step 5d) — no blocking findingsReviewed against the OODA done-gate idempotency trust boundaries: SQLite ledger, the AuthZ: Input validation: trailer parse is total/no-panic, line-anchored, case-sensitive, exact Data protection: SQL fully parameterized ( Subprocess: Residual risk (Low, accepted): a spoofed Verdict: merge-ready from a security standpoint. No code changes required. |
✅ Step 8 (Implement) — validation: #4334 fully resolves the done-gate duplication; merge-readyPer the OODA-core done-gate idempotency brief (Problem #2; #4166/#4189), this PR is the correct and complete fix. A competing/duplicate implementation was deliberately not opened (the anti-pattern this PR exists to prevent); the parallel workstream instead validated #4334 and is driving it to merge. Requirement coverage
Hygiene (grep-clean on added src/tests): no Status: MERGEABLE / mergeStateStatus CLEAN, all required checks green (coverage, pre-commit, install-real, e2e-dashboard, cargo-audit/deny/vet, npm-audit, scripts-tests). Recommendation: approve & merge #4334. Once landed, the duplicate symptom PRs (#4328/#4330/#4333 kgpacks-parity; #4326/#4329/#4332 coin-benchmark) can be closed as operator cleanup — they are symptoms, not fix targets. Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com |
|
Crusty review — PRIORITY root-cause, but needs rebase + scope-check before it can merge. This is the keystone for the done-gate churn: without idempotent one-PR-per-goal emission, the OODA loop opened a flood of near-duplicate done-gate PRs (currently ~9 open for the COIN and kgpacks-rs goals alone — #4332/#4329/#4326/#4322, #4330/#4333/#4324/#4328). Landing this stems the flood at the source, after which most of those per-goal PRs can be closed rather than merged. Two blockers before merge:
Once rebased, reconciled with #4742, and scoped down: crusty → merge-ready → CI green → merge. This one should jump the queue — it makes the rest of the cluster closable. |
Problem
The OODA/overseer done-gate opened a fresh done-gate PR every cycle for a goal whose engineer had exited leaving an open, unmerged PR — flooding the repo (3× coin-benchmark #4326/#4329/#4332, 4× kgpacks-parity #4324/#4328/#4330/#4333). Goal→engineer dispatch had no idempotency keyed on durable goal identity.
Tracking issues: #4166, #4189.
Fix
Make done-gate emission idempotent on stable goal identity (never the goal title):
goal_pr_emissionsledger (typed-OODA schema v1→v2, forward-only, additive):record_goal_pr_emissionupsert (ON CONFLICT(goal_key) DO UPDATE)find_open_goal_pr_emissionopen-lookupUNIQUE(repo, pr_number)turns a second goal claiming the same PR into a visible conflict, not a silent duplicatestate, so an emission outlives its engineergoal_dedup_key,parse_goal_key_trailer,find_open_pr_for_goal) + aGoalPrRefDTO and aPrGhClient::list_open_goal_prsdefault, so aghopen-PR reconciliation can adopt a pre-existing PR by theSimard-Goal-Key:body trailer (primary) or theengineer/{key}-branch convention (fallback).Safety / hygiene
list_open_goal_prsreturns empty, existing fakes compile unchanged; distinct goals are unaffected.print!/println!, no Bridge naming.Tests
UNIQUE(repo,pr_number)conflict, migration idempotent across reopen)Full lib suite green (8889 passed),
cargo fmt --checkclean,cargo clippy --all-targets --all-features -D warningsclean.Docs
Concept, how-to runbook, and ledger API reference, all linked from the index and mkdocs nav.
Fixes #4166
Fixes #4189
Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com