Development record
Oracle-Backed Gates Pass Honestly Without A Human In The Loop
⚠️ Superseded by ADR-22 (codex is dropped as a dependency and the Ralph autonomous loop is not ported; the RP→codex→in-session oracle cascade is replaced by host-delegated LLM and the pluggable autonomous seam — see also ADR-25, ADR-27). Preserved as historical record per the supersession lifecycle.
Press Release
abcd's
intent-fidelity-revieweragent runs its three oracle-backed quality gates (itd-5 self-improvement pre-flight, research-file review, live injection-canary execution) in an autonomous Ralph session without a human in the loop. Today those gates are structurally un-completable in headless mode:_build_cli_oracle()returnsOracle(MCPBridge())— the RP MCP leg only, which requires a running RepoPrompt GUI. Ralph running overnight on a server has no GUI. So the three gates either staydeferred(honest but blocking spec completion) or get rubber-stamped with fabricated outcomes. Once this intent lands,_build_cli_oracle()returns anOraclewith both an RP leg and a Codex leg; the Codex leg is reachable headlessly (thecodexCLI is on PATH), and the gates complete with real outcomes against real oracle round-trips."The spc-12 (predecessor store) spec completion review used to stall every time it hit R6," said Ethan, autonomous-loop operator. "I'd come back to a Ralph run that had spent its budget thrashing on a gate it couldn't reach. With the Codex leg wired into the CLI oracle, the same gate runs in the next loop pass and either passes or fails honestly. The run completes — or doesn't — for real reasons."
Why This Matters
.work/issues.md 2026-05-19 line 360 records the blocker: spc-12 (predecessor store; intent-fidelity-reviewer agent) ships Role 1 — per-criterion MET/NOT_MET verdicts on shipped intents — but three of its acceptance gates require a genuine Oracle.ask() round-trip that the autonomous run environment cannot satisfy. The three gates are:
- R6 — itd-5 self-improvement pre-flight. The candidate prompt is submitted to
lifeboat-oraclefor a clarity rewrite; the rewritten variant must pass the same goldens and be shorter by >10% to be accepted. Decision logged in the CHANGELOG. - T1 — research-file oracle review. The reviewer agent's research artefact (
.abcd/development/research/prompting/agents/intent-fidelity-reviewer.md §7) is reviewed against oracle judgement. - R7 — live injection-canary execution. The reviewer agent's injection-canary fixture is executed end-to-end through the oracle to demonstrate the injection is ignored.
All three need _build_cli_oracle() to reach a real oracle backend. The current implementation returns Oracle(MCPBridge()), which is RP-MCP-only and requires an active RepoPrompt GUI — not available in headless mode. spc-13 (predecessor store) wired the Codex CLI as a backend (oracle_codex.py), but _build_cli_oracle() does not consume it. So the gates are reachable only when a human is sitting in front of an RP GUI; the autonomous loop reaches them via the run, can't complete them, and either defers (per the deferred permission of spc-12 (predecessor store), extended in .work/issues.md 2026-05-19 line 393) or stalls.
The deferral is honest — substituting a different reviewer changes the judgement substrate and fails itd-5 honestly — but it leaves spc-12 (predecessor store) in a state where every Ralph completion-review run on the spec produces the same deferral, no progress is made on the gates, and the spec is structurally un-shippable in the loop. The fix is mechanical: extend _build_cli_oracle() to wire the Codex leg through a CodexAgentDispatch (which spc-11 (predecessor store) / itd-6 work already provides primitives for).
This intent is a precondition for several downstream specs: any agent spec that depends on intent-fidelity-reviewer's discipline-checking roles (Roles 2 and 3 — itd-31, itd-34) and any future lifeboat-oracle work (itd-5's named reviewer) hits the same gate. Fixing it here unblocks the chain.
What's In Scope
- Extend
_build_cli_oracle()inscripts/abcd/intent_fidelity_reviewer.pyto construct anOraclethat carries both anMCPBridge(RP leg) and aCodexAgentDispatch(Codex leg). The selection logic follows the itd-6 cascade contract: prefer RP if reachable, fall back to Codex, fall back to in-session subagent. - Confirm the
oracle_codex.pyintegration of spc-13 (predecessor store) is reachable from this call site (the Codex CLI is on PATH per the wiring of spc-13, predecessor store). - Re-run the three oracle-backed gates of spc-12 (predecessor store) (R6, R7, T1) under the
extended
_build_cli_oracle()and rewrite the CHANGELOG / research §7 with real outcomes — replacing the currentdeferredmarkers.
What's Out Of Scope
- Building
lifeboat-oracleagent. itd-5's named reviewer agent does not exist. The R6 gate (clarity rewrite) is reviewer-specific — substituting a different reviewer changes the judgement substrate. This intent's R6 work has two honest paths: (a) shiplifeboat-oracleas part of this intent's scope, OR (b) extend thedeferredpermission to "untillifeboat-oracleexists" with a re-run hook for when it does. Decide at plan; lean (b) (separation of concerns). - itd-6 cascade epic in full. itd-6 AC#4 (full three-step cascade with in-session fallback) is the broader work. This intent uses the RP+Codex legs already available; it does not ship the in-session subagent leg (depends on itd-2).
_build_cli_oracle()callers other thanintent_fidelity_reviewer.py. If other call sites construct the CLI oracle, they likely have the same problem, but the fix surface here is the specific call site of spc-12 (predecessor store). Wider audit deferred to itd-6 cascade epic.
Acceptance Criteria
- Given the extended
_build_cli_oracle(), when it is called in a Ralph environment with no RP GUI running but thecodexCLI on PATH, then it returns anOraclewhose first reachable backend is the Codex leg; oracle calls succeed against real Codex round-trips. - Given
intent_fidelity_reviewerrunning the R6 gate (itd-5 self-improvement pre-flight) in a Ralph environment, when the gate executes, then a real oracle round-trip happens, a real outcome is logged inagents/CHANGELOG.md, and the entry is no longerdeferred— unlesslifeboat-oracleis the named reviewer and is missing, in which case thedeferredpermission is extended explicitly with that named cause (per.work/issues.md2026-05-19 line 393). - Given the R7 gate (live injection-canary execution) running in a Ralph environment, when the gate executes, then the canary fixture is submitted through the oracle, the output is inspected for injection success, and the gate emits a definite pass/fail — not
deferred. - Given the T1 gate (research-file oracle review) running in a Ralph environment, when the gate executes, then the research artefact is reviewed against oracle judgement and a real verdict lands in
research/prompting/agents/intent-fidelity-reviewer.md §7. - Given an RP GUI is also running, when the extended
_build_cli_oracle()is called, then it prefers the RP leg (matching itd-6 cascade ordering); the Codex leg is the fallback, not the default.
Implementing specs
itd-47 was implemented across two specs of the predecessor store; those ids are
preserved below as history. The native spec store reuses both numbers for other
specs, so each carries the predecessor-store qualifier. The frontmatter
spec_id is null: adr-22 supersedes this intent, and no native spec delivers
it. Historical index:
- spc-27 (predecessor store; primary) — oracle CLI Codex leg for autonomous mode (the
_build_cli_oracle()extension + Codex-leg gates). - spc-32 (predecessor store) — Phase-3 closeout sweep (the remaining oracle-gate hardening delivered under the closeout).
Open Questions
lifeboat-oraclescope. Ship it as part of this intent (broader scope, unblocks R6 fully) or defer to a sibling intent and document the extendeddeferredpermission for the R6 entry only? Lean: deferlifeboat-oracleto a sibling intent — it's a full agent prompt spec with its own discipline gates (itd-5 applies to it), not a one-line wiring change.- In-session subagent leg. itd-6 AC#4 names a three-step cascade (RP → Codex → in-session). This intent ships the first two. The in-session leg depends on itd-2 (which has no spec yet). Document the partial as an explicit deferral, plumb the third leg later.
- Test surface for the Codex leg. spc-13 (predecessor store) tested
oracle_codex.pyin isolation; this intent needs at least one integration test that exercises the extended_build_cli_oracle()end-to-end against a real Codex CLI invocation in a Ralph-like environment. Where does that test live — undertests/abcd/, a newtests/ralph/, or as a script under.work/? Decide at plan.
Related
- spc-12 (predecessor store;
intent-fidelity-revieweragent) — the spec whose oracle gates this intent unblocks. - spc-13 (predecessor store; headless Codex CLI oracle wiring) — provides
oracle_codex.py, the Codex leg this intent's_build_cli_oracle()consumes. - itd-6 (RP-MCP-only integration / oracle cascade) — the broader cascade work; this intent ships the first two legs.
- itd-5 (prompt-quality additions discipline) — the discipline whose pre-flight gate (R6) is one of the three this intent restores.
- itd-2 (in-session subagent dispatch) — the prerequisite for the cascade's third leg, deliberately left for a later spec.
.work/issues.md2026-05-19 line 360 — the canonical blocker entry..work/issues.md2026-05-19 line 393 — the extendeddeferredpermission entry; this intent removes most of the deferral cases.
Frontmatter
| id | itd-47 |
|---|---|
| type | intent |
| lifecycle | superseded |
| kind | standalone |
| severity | nitpick |
.abcd/development/intents/superseded/itd-47-oracle-gates-autonomous-mode.md
open on GitHub ↗ · commit history ↗
Referenced by1
- adr-22Bundled dependencies become pluggable adapters over a native defaultsuperseded by
mentions23
- adr-25The LLM is host-delegated by default; oracles are opt-in adapters
- adr-27The autonomous run is a pluggable seam, not a Ralph port
- dcn-26080200000000042026-08-02 — iss-39: record-lint gains `record_schema`, the first rule that reasons ACROSS the record's stores (ADRs, intents, specs, the issue ledger) rather than inside one, and the `superseded/` exemption narrows for the intent tree: both rules that read it (`intent_lifecycle`, `intent_impact_valid`) now run there too, while the spec-store rules (`spec_lifecycle`, `spec_id_unique`) still honour it as before and the cross-store `record_schema` never consulted it at all. Four invariants, one scan: a cross-reference field names a record the corpus has; a supersession is declared from BOTH sides; a filename and the id inside it agree; and every lifecycle directory is enumerated, so an undeclared bucket is a finding rather than a state no rule reads. Scope is deliberate on two axes. (1) Cross-references are checked in the machine-readable frontmatter fields (`supersedes`, `related_adrs`, `related_intents`, `builds_on`, `blocked_by`), not in bare prose: a frontmatter handle is a claim that the record exists and is a live input, whereas prose legitimately narrates ids that do not resolve ("itd-38's id was released, not reserved"; a test fixture's `itd-9999`; adr-29's account of what ADR-6 settled) — arming prose would have cost ten false positives against one true one, the same false-positive budget that scopes GL002. (2) A handle resolves either to a file or to a `supersedes:` declaration elsewhere, because the ADR lifecycle PRUNES a superseded record and keeps the trace in its successor — that is what distinguishes adr-4/adr-8/adr-14..18 (pruned, accounted for) from adr-6 (cited, never accounted for). The exemption narrowing is the root cause of the corpus defect it exposes: `intent_lifecycle` is a schema rule, but the `superseded/` bucket exempted its own records from the one rule that checks a supersession is recorded, so itd-47 and itd-49 sat there for months with a prose blockquote and no `superseded_by` field. Being historical excuses a record from how it is WRITTEN, never from being well-formed. `superseded_by` also widens from `^itd-\d+` to `^(itd|adr)-\d+`: an ADR that redecides the question an intent rested on retires that intent as surely as a successor intent does, and refusing to spell that forced those two records to say nothing at all. Corpus repairs in the same change: adr-6 is dropped from the two `related_adrs` lists and the two brief pages that cited it re-point at adr-29 (which records the two-stage redaction model and states in its own body that adr-6's decision stands — adr-29 does not supersede it, so claiming it does would have written a falsehood to clear a finding); adr-12 and adr-32 gain the bidirectional pair the ledger-location redecision always implied, adr-12's status moving to `superseded` and the index row with it; itd-47/itd-49 gain `superseded_by: adr-22`/`adr-26` with `kind_at_supersession`, and those ADRs name them back; and the pre-existing one-way links itd-32→itd-31 and itd-31→itd-48 gain their reverse halves. CHANGELOG impact `additive`, matching iss-38's disposition on the same axis: the rule ships in the lint engine `abcd docs lint` runs, and any abcd-managed repo gains it by declaring its own `record_stores`.
- dcn-26080200000000092026-08-02 — iss-41 (v0.5.0 item D): the interim delivery-state rule is stated as the one the lifecycle already implies — **delivered capability is represented by the intent leaving `drafts/`, and nothing else says it** — because the alternative on offer (a new tier, or a per-intent "partly shipped" field) invents lifecycle vocabulary to describe a citation problem. The ledger's premise that `shipped/` is empty has aged out: thirteen intents live there now, so the mechanism exists and what was missing was the gate holding the changelog to it. `delivery_state` reads each version entry's delivery sections (`Added`, `Changed`; a repo's configured list is unioned with those, never substituted for them) and blocks an `itd-N` citation whose intent is still in `drafts/`. Scoping by section rather than by whole entry is what keeps it precise: the ids under `Fixed` in this corpus are provenance for a defect — which draft two branches minted at once — and blocking them would force either a falsehood or a deletion of real information. It fails closed three ways: no changelog, no intents store, and a store holding no lifecycle bucket — the last being a root pointed one level too deep, which resolves every citation to nothing and reads exactly like a clean corpus. The corpus had TWO instances, not the one filed: itd-60, whose deterministic layer shipped as `abcd docs lint` while its semantic layer is still five open questions, and itd-85, which shipped WHOLE as `abcd audit` and was simply never promoted. They get different treatments because they are different facts. itd-60 stays in `drafts/` and loses the citation — an intent is delivered whole or not at all (split-the-intent doctrine), so citing a partial delivery reads as a promotion that never happened, and splitting itd-60 to make the citation true is editorial work this issue does not carry. itd-85 loses the citation too, but under protest: the honest fix is promotion, and promotion is blocked on the `shipped/` schema wanting a non-null `spec_id` the audit verb has never had. Filed as iss-180 rather than papered over or forced — writing a retroactive spec to satisfy a lint is the failure mode this repo keeps naming. The out-of-scope half is a REUSE, not a new rule: `index_drift` gained one field, `dir_entry`, the mirror of `entry` on the directory side, which reduces a filename stem to the id a document actually enumerates. Without it a hand-written listing can only agree with a directory by transcribing whole slugs, which is a listing nobody writes, and the alternative was a second rule shaped exactly like the first. The list itself had drifted nineteen entries while claiming in its own prose to be derived and "not hand-counted": itd-47, itd-73 and itd-74 had left `drafts/` for three different buckets, and sixteen captures were missing. Regenerated, wrapped in the marked region, and the sentence promising hand-kept lockstep is replaced by the gate that enforces it. The four later-phase items that never had an intent id move OUT of the derived list — a derivation cannot produce them, so their presence was what made the claim false in the first place.
- iss-39record schema validation: adr-6 is cited as a live design input but does not exist and no successor records superseding it; adr-12 is not marked superseded by adr-32; itd-47 and itd-49 sit in superseded/ without supersession frontmatter; the superseded/ lint exemption is broad enough to hide content-rule violations. Detector: a mechanical record-schema check — every prose handle (adr-N, itd-N, iss-N) resolves to a file; supersession is bidirectional (superseded-by and supersedes both present); filenames match their patterns; every lifecycle directory is covered by a catch-all so no state escapes linting; the superseded/ exemption narrows to content rules only. Acceptance corpus: the four instances above.
- iss-41lifecycle cannot represent delivered work: v0.1.0 shipped capability from a drafts-stage intent while shipped/ sits empty, so the record goes quiet exactly where it matters; the canonical later-phase list in 03-out-of-scope has drifted from the filesystem it claims lockstep with (superseded itd-47 still listed; drafts itd-76/77/78 missing). Detector (per reality-is-filable): define the interim delivery-state rule (how shipped capability is represented before Phase 4), then a lifecycle lint — no CHANGELOG delivery entry whose intent still sits in drafts/, and out-of-scope lists derived from the filesystem. Acceptance corpus: the v0.1.0 drafts-stage shipment and the two out-of-scope list drifts.
- iss-2608271804178239filename-slug agreement is unenforced across the record stores and two records have drifted: superseded itd-47's frontmatter slug embeds the foreign handle spc-12 (now a live unrelated spec) and its H1 carries the same stale prefix, and iss-2608231237300997 is the single ledger record whose filename slug disagrees with its frontmatter slug. Fix the two instances (frontmatter+H1 edit for itd-47; rename to the frontmatter slug for the iss record, id unchanged) and close the class: capture validateInvariants and the record-lint schema check filename id but never slug.
- iss-2609290448510918The predecessor-store qualifier sweep reaches past the six intents iss-2609261536147903 named: outside drafts/ and those six, 192 citation sites across about forty intents name a spc-N at or below spc-70 that is not the citing intent's own spec, with no '(predecessor store)' on the line. Some are live cross-references (the cold-reading family's intents cite each other's live specs), and some are the predecessor store's (itd-4, itd-6, itd-29, itd-47 and itd-49 describe pre-rebuild work in its terms), so each site needs the same reading against the live spec it collides with; the specs charter's Two spc-N Namespaces section is the rule. Found while sweeping the pattern of iss-2609261536147903 in lane drainDrift3; a census script over intents/{planned,shipped,disciplines} reproduces the count.
- iss-2609300032219282Superseded itd-47's Implementing specs section says its frontmatter spec_id records spc-27 as the primary delivering spec, while the frontmatter holds spec_id: null, and spc-27 and spc-32 are predecessor-store ids that the live store reuses for the surface-coverage registry and abcd update. The same defect iss-2609300025372991 fixed in itd-36 and itd-4, found in a third intent while qualifying predecessor-store citations for iss-2609290448510918.
- iss-2610262032133109itd-48 runs both roles through a CLI oracle in headless Ralph mode; the dependencies page says the autonomous run is not a Ralph port
- itd-2In-Session Subagent Dispatch — the Default Host-Delegated Oracle
- itd-5Every Agent Prompt Carries Its Version, Earns Its Lock, And Survives Injection
- itd-6RepoPrompt over MCP is one opt-in reviewer route, beside the host's own agents
- itd-31The Brief and Every Intent Stay Consistent — Or Abcd Tells You Why They Don't
- itd-34Intents Promote In Three Flavours — Standalone, Bundle-Member, Discipline
- itd-48`intent-fidelity-reviewer` Gains Its Cross-Doc And Kind-Classification Roles
- itd-50The Audit Loop Drives An Intent To Acceptance — Or Calls For A Replan
- itd-53A Shipped Intent No Longer Drifts Out Of Audit Just Because Nobody Ran The Review
- spc-11installable-versioned-plugin
- spc-12disembark-grounds-a-lifeboat-s-open-questions-on-a-repo-s-to
- spc-13disembark-reads-a-repo-s-naming-and-internals-conventions-in
- spc-27the-registry-cannot-wave-its-hands-every-surface-file-carrie
- spc-32`abcd update` — fetch, verify, swap, in one verb