Pipeline Gaps — 4-Layer Context, Verify Gate, and FirstMate Dispatch
Pipeline Gaps — 4-Layer Context, Verify Gate, and FirstMate Dispatch
Date: 2026-08-11 Status: Completed Plan type: feat Depth: Deep
Completed 2026-08-12. All five units (U1–U5) are implemented, committed, and live-proven through the school-loop issue path (see the U7–U9 compound plan and the U1–U6 landing manifest). This document remains as the historical spec; further changes are tracked in
docs/plans/2026-08-12-002-refactor-dirty-tree-product-slices-plan.md.
Summary
Close the five verified gaps between what the school-loop issue path exercises today and the full pedagogical stack: thread a per-cycle session_id so Layer 3 archival fires, checkpoint-commit sanitized trajectories so Layer 2 has history on fresh checkouts, make the verify gate loud instead of silently inert, dispatch student tasks through the proven FirstMate crew, bring the Entire pre-merge review into the live path, and correct campus.md's overclaims. Direct-Orca execution and the CTO/COO review remain the fallback and the unchanged upper half of the pipeline.
Problem Frame (historical baseline, before the 2026-08-11 reconciliation)
The wayfinder map (.scratch/wayfinder-map-pipeline-gaps.md) confirmed on disk that the live issue path (issue_bridge → director.run_task → review → score) exercises only a thin slice of the system:
- Layer 3 is dead.
enrich_promptincludes archival context only whensession_idis set (context_orchestrator.py:78), andrun_taskalready carries the parameter (director.py:582) — but drops it at theenrich_promptcall (director.py:714), and the bridge never passes one (issue_bridge.py:475).data/consolidation/does not exist. - Layer 2 is empty on every fresh checkout.
data/trajectories/is not tracked; each school-loop cycle starts in a fresh checkout with zero trajectory history, so the file-RAG no-ops. - Compiler-before-critic was decorative at discovery time.
verify_gate.py:160shells out tonix develop flake.nix#verifyShell; before the 2026-08-11 runner/toolchain fix, Nix was not installed on the Mac runner, so the gate silently returned the non-blockingNonepath every cycle. The current production preflight policy is documented below. - The crew engine is unplugged. The FirstMate→Orca→Hermes cycle is proven end-to-end (live drill, 2026-08-11) but never invoked from the issue path; campus.md claims it is wired.
- Docs lie. The campus.md Operational Reality table marks FirstMate and the verify gate as "✅ Wired".
- Entire review is documented but dormant.
src/qodo_pre_merge.py:133runsentire reviewas a pre-merge sensor (conductor.py:341-359), but only in the async conductor path — never in the school-loop's sync path — and skips in practice:_get_entire_path()is a bareshutil.which("entire")(src/qodo_pre_merge.py:40-42), so Orca worktree shells without~/.local/binon PATH return "skipped". school-core has no.entire/checkpoint tracking (the intent-aware half), while sound-royale-* repos do.
Requirements
Context layers
- R1. The bridge threads a per-cycle
session_idthroughdirector.run_task, which forwards it toenrich_prompt, so Layer 3 archival context is included when a consolidation exists for that session. - R2.
data/trajectories/is committed to git, sanitized via the existing checkpoint pattern, so fresh school-loop checkouts see trajectory history. - R3.
data/consolidation/is seeded (directory plus initial index) so the Layer 3 write path has a home.
Verify gate
- R4. The production school-loop preflight treats missing Nix or an unevaluable
flake.nix#verifyShellas a visible infrastructure failure and exits the execute job; the hosted board-publishing job still runs from committed state. The reusable Python gate returns a visible soft-skip for direct/manual callers instead of silently returningNone. - R5. The verify gate runs hermetically via the flake whenever the toolchain is present; Determinate Nix is the required Mac-runner prerequisite (a uv fallback would be a separate future policy/code change).
- R6.
VERIFY_GATE_STRICT=1makes an unrunnable reusable gate fatal at the issue level, including no discovered verify commands or an internal gate exception. This is separate from the workflow preflight, which is already hard-fail.
Dispatch
- R7. The student-task path dispatches through FirstMate (
fm-spawn, orca backend) and reads back the deliverable (report.md+ terminal status line) when crew dispatch is enabled. - R8. On crew spawn failure, grace-expired
blockedstate, or poll timeout, the bridge falls back to direct-Orca in the same cycle; if that also fails, the existing retry-once semantics carry the issue. - R9. CTO/COO two-judge review and scoring run unchanged on the crew deliverable.
Docs
- R10. campus.md's Operational Reality table reflects actual wiring: FirstMate = wired behind a flag, the school-loop verify preflight = hard-fail on missing infrastructure while the reusable gate remains visible soft-skip unless strict mode is enabled, Layer 3 = live.
Pre-merge review (Entire)
- R11. Entire runs as a non-blocking pre-merge sensor in the live issue path, before the two-judge review, with findings surfaced on the issue's board/comment and cycle log.
- R12. The entire CLI is discoverable in worktree contexts and school-core has session tracking enabled (
.entire/), so the intent-aware review is active rather than skipped. - R13. The stale
qodo_naming is removed (module/function renamed toentire_), keeping the bookbag-compatible return shape.
Key Technical Decisions
KTD-1: Thread session_id, don't build a new session system
Decision: Derive a per-cycle session_id (e.g. loop-<YYYYMMDD-HHMM>) in the bridge, pass it through run_task, and forward it at the enrich_prompt call site.
Rationale: The plumbing exists end to end — run_task has the parameter (director.py:582), the orchestrator gates on it (context_orchestrator.py:78) and has _archival_context. The work is two pass-throughs plus a caller, not new session machinery.
KTD-2: Trajectory durability reuses the checkpoint pattern
Decision: Add data/trajectories/ to the existing sanitize + git add -f + [skip ci] checkpoint in school-loop.yml (.github/workflows/school-loop.yml:154-173), capping history to the last N cycles or per-cycle summaries.
Rationale: Identical pattern to scores/retry, already proven in production. Trajectories are the Layer 2 corpus; without them every fresh checkout is amnesiac. The cap keeps git history bounded.
KTD-3: Separate workflow infrastructure failure from reusable gate soft-skip
Decision: The production school-loop preflight fails the execute job when Nix or flake.nix#verifyShell is unavailable. The hosted loop job remains independent and publishes the last committed board state. The reusable verify_gate.py API remains visible soft-skip by default for direct/manual callers; VERIFY_GATE_STRICT=1 escalates that result to an issue failure.
Rationale: The scheduled production path promises compiler-before-critic, so it must not process issues while the compiler environment is absent. The library-level soft-skip remains useful for tests, diagnostics, and callers that choose graceful degradation; it is explicit and never mistaken for a passed verification.
KTD-4: FirstMate wraps the student-task path behind a flag
Decision: New crew_dispatch.py scaffolds a brief, runs fm-spawn --backend orca (scout mode for the pilot), polls the status file, reads report.md, and tears down with the documented orca-bug workaround. Enabled by crew_enabled (default on in school-loop, off in the unit-test env).
Rationale: The crew cycle is proven; a flag keeps the 30+ bridge tests hermetic (they patch director.run_task). Direct-Orca stays as fallback so retry-once carries any crew failure. Review lenses are untouched because the deliverable shape (report.md) feeds the same review.
KTD-5: Docs truth lands with the code it describes
Decision: campus.md rows are corrected in the same change as the wiring they describe.
Rationale: The map proved two "✅ Wired" rows were false. Docs that overclaim cost the next on-call real debugging time.
KTD-6: Entire is a non-blocking sensor, not a gate
Decision: Keep the degrade-gracefully semantics; fix discovery and enablement instead of making Entire blocking.
Rationale: Same policy as KTD-3 — a missing CLI must never kill the school cycle. Entire catches mechanical issues (unused vars, type narrowing) the LLM judges miss, so its findings inform them; it doesn't veto them.
KTD-7: Crew deliverable enters through run_task, not around it (deepened 2026-08-11)
Decision: run_task gains an optional provided_student_output param; when set, it substitutes for the internal student call_model (director.py:649), and the two-judge review + scoring run unchanged on it. Crew-done issues call run_task(..., provided_student_output=report_text); crew failures call plain run_task (direct-Orca fallback).
Rationale: Review and scoring live inside run_task (director.py:954), so "skip run_task and keep the review" is not achievable without duplicating that machinery. A single optional param keeps the bridge's call shape, makes R9 literally true, and is testable in isolation — same pattern as the existing skip_review/skip_readiness params.
KTD-8: In-flight registry prevents duplicate crew dispatch (deepened 2026-08-11)
Decision: crew_dispatch persists every spawn to data/crew_runs.json with portable fields (crew_id, issue, status, started_at, and a boolean worktree-present marker), committed via the checkpoint pattern like data/retry_issues.json. The path-bearing orca_worktree_id stays in an ignored FM-local sidecar on the runner; it is never checkpointed. The bridge skips issues with a running record; a next-spawn sweep removes stale entries via the sidecar identity or retains the record with a warning when that identity is unavailable.
Rationale: The cron cadence (*/5) is shorter than a crew task (up to 15 min), so overlapping cycles are the norm, not the exception. Without a registry, two cycles crew-dispatch the same issue and both poll GitHub/AgentMail — the duplicate-work and API-limit concern. The registry makes crew dispatch exactly-once across cycles with zero extra API calls (status polling is local file reads).
High-Level Technical Design
Target issue path after all units:
GitHub issue
└─ issue_bridge.process
├─ clone_repo + build_codebase_context (thin context, unchanged)
├─ crew_dispatch (U7–U9, crew_enabled): (new)
│ brief → fm-spawn (orca) → poll status → report.md → teardown
│ └─ done ─▶ run_task(..., provided_student_output=report) [KTD-7]
│ └─ fail ─▶ plain run_task (direct-Orca fallback, R8)
├─ director.run_task(prompt, domain, difficulty, session_id=cycle_id) [U1]
│ └─ enrich_prompt(..., session_id)
│ ├─ L0 ccc search (present on Mac, no-ops elsewhere)
│ ├─ L1 serena LSP (present on Mac, no-ops elsewhere)
│ ├─ L2 trajectories RAG (now seeded from git) [U2]
│ └─ L3 archival context (now fires) [U1]
├─ _run_verify_gate (loud WARN / strict fatal) [U3]
├─ Entire pre-merge sensor (non-blocking, findings surfaced) [U6]
├─ _run_two_judge_review CTO+COO (unchanged, runs on crew deliverable)
└─ evaluate_and_update → scores.json + trajectories → checkpoint [U2]
Crew lifecycle (U7–U9), with all external effects behind crew_dispatch:
bridge ─run(crew_dispatch)─▶ scaffold brief ─▶ fm-spawn --backend orca --scout
│ (FM_HOME/data/<id>/brief.md) │
│ ◀── CrewResult ◀───────── poll $STATE/<id>.status │
│ (status, report_path, working:|resolved: → keep polling │
│ teardown_ok) paused: → keep polling (self-clear) │
│ └─ data/crew_runs.json blocked:|needs-decision: → 60s grace │
│ in-flight registry done:|failed: → terminal │
│ + next-spawn sweep (timeout 15 min, interval ~15s) │
│ + orca worktree rm └─ read FM_HOME/data/<id>/report.md │
├─ done ──▶ run_task(..., provided_student_output=report) [U8 seam]
└─ CrewUnavailableError / blocked / timeout ─▶ plain run_task (direct-Orca) ─▶ retry-once
Implementation Units
U1. Thread session_id through the issue path — R1, R3
issue_bridge.py(~:475): derive a per-cyclesession_id, pass torun_task.director.py(:714): forwardsession_idintoenrich_prompt.context_orchestrator.py: acceptsession_idonenrich_promptand call_archival_contextwhen set.- Seed
data/consolidation/(directory + initial index, tracked). - Tests: bridge passes the session id;
run_taskforwards it;enrich_promptreturns archival context when a consolidation exists for that session.
U2. Trajectory durability — R2
.github/workflows/school-loop.yml: adddata/trajectories/to the sanitize list and thegit add -fcheckpoint; the checkpoint step trims stale trajectory files (keep the last N cycles) before committing.scripts/sanitize_data.py: confirm trajectory files are scrubbed by the existing PII regexes.- Tests: sanitize round-trip on a trajectory fixture that includes a
/Users/<name>path (the PII class that leaked before); checkpoint step trims stale trajectories and references the glob.
U3. Verify gate loudness + runner toolchain — R4, R5, R6
verify_gate.py: detect the Nix binary; when absent or no commands are discoverable, return a visible soft-skip by default and honorVERIFY_GATE_STRICT=1as an issue-level fatal escalation..github/workflows/school-loop.yml: hard-fail the execute preflight when Nix orflake.nix#verifyShellis unavailable; keep the hosted board job independent so it still publishes committed state.- Ops: Determinate Nix is a required prerequisite on the Mac runner. A uv fallback is not part of the current acceptance bar and would require a separate design.
- Tests: gate soft-skip and strict escalation remain covered; workflow structure asserts both hard preflight exits and independent board publishing.
U4. FirstMate dispatch in the issue path — R7, R8, R9 (umbrella)
Umbrella unit for the crew path, split into claimable units U7–U9 on
2026-08-11 (bead school-core-0x9.4 tracks the umbrella; sub-beads track
U7–U9). The crew cycle itself is proven standalone (live drill 2026-08-10;
scripts/fm_doctor.sh preflight already wired into the execute job); these
units wire it into issue_bridge behind crew_enabled (default on in
school-loop, off in the unit-test env) with direct-Orca fallback.
- U7 —
crew_dispatch.pymodule: the FirstMate lifecycle wrapper. - U8 — bridge wiring behind
crew_enabled+ fallback. - U9 — crew surfacing + docs truth.
U7. crew_dispatch.py — the FirstMate lifecycle module — R7
Goal: A self-contained, unit-testable wrapper that scaffolds a scout brief,
spawns a crewmate via fm-spawn --backend orca, polls the status file to a
terminal state, reads report.md, and tears down best-effort. Independent of
the bridge; U8 consumes it.
Dependencies: None (standalone; scripts/fm_doctor.sh is the ops gate,
already wired).
Files:
crew_dispatch.py(new) —CrewResult+ lifecycle functionstests/test_crew_dispatch.py(new)
Approach: Follow the F4 contract grounded in ~/.local/share/firstmate:
status file at $FM_HOME/state/<id>.status, meta at $FM_HOME/state/<id>.meta
(backend, worktree, terminal, window), deliverable at
$FM_HOME/data/<id>/report.md (scout mode; DATA="${FM_DATA_OVERRIDE:-$FM_HOME/data}"
verified in bin/fm-spawn.sh:214). Surface contract decisions:
CrewResultdataclass:crew_id,status(done/timeout/blocked/failed/spawn_failed),report_path,fallback_reason,teardown_ok.- Six-state status machine +
resolved:closer (verified inbin/fm-brief.sh:300-345):working:/resolved:/unknown → keep polling;blocked:/needs-decision:→ short grace (~60s) thenCrewResult.status = blocked(fallback_reasonblocked);paused:→ keep polling (declared external wait that clears on its own — the 15-min timeout bounds it; no grace fallback);done:/failed:→ terminal.resolved:after ablocked:/paused:/needs-decision:clears the block and resumes polling. - Cadence is event-driven, not heartbeat (verified: the brief tells the crewmate "report sparingly: only phase changes a supervisor would act on"). A crewmate appends
blocked:once and then stops writing — so a long grace is pure delay; ~60s only catches a fast self-resolved:race before falling back. - Spawn failure → raise a typed
CrewUnavailableError(the bridge catches it for fallback); poll timeout andfailed:status → returnCrewResultwith a non-done status. crew_idderived from the U1 cycle id (fm-<cycle_session_id>-<issue>— seconds granularity) so overlapping cycles can't collide on$FM_HOME/state/<id>files.- In-flight registry + sweep (KTD-8): persist every spawn to
data/crew_runs.jsonusing portable fields (crew_id, issue, status, started_at, and worktree-present marker). Keep the path-bearing Orca identity in an ignored FM-local sidecar, not in the checkpointed file. On each spawn, sweep stalerunning/blockedentries older than N cycles via the sidecar identity andorca worktree rm; log and retain on cleanup refusal or missing local identity. Status polling is local file reads — zero API cost. - Poll interval ~15s, 15-minute timeout by default, overridable in tests.
- Teardown:
fm-teardown.shis ALWAYS refused for orca (verified 2026-08-11): orca worktree ids are<repoId>::<path>(live sample1b3e3f14-…::/Users/brandonbennett/…), andfm_backend_validate_task_endpoint(fm-teardown.sh:431) gates every orca teardown onfm_backend_endpoint_atom_valid(fm-backend.sh:505-506), which only accepts[A-Za-z0-9._@%+-]—::and/never pass. So the sweep and any immediate cleanup MUST callorca worktree rm --worktree "id:<id>" --forcedirectly (the exact callfm_backend_orca_remove_worktreeuses,orca.sh:184), neverfm-teardown.sh. Store the create-returnedworktree-idverbatim increw_runs.jsonfor this. - Sweep path PROVEN live (2026-08-11) — two disposable worktrees created via the exact backend invocation (
orca worktree create --repo "id:<repo-id>" --name <id> --no-parent --setup skip --json), thenorca worktree rm --worktree "id:<id>" --force --jsonreturned{"removed": true}for both a bare worktree AND a worktree with a live attached terminal. Verified clean at all three levels: orca worktree list (absent),git worktree list(absent), filesystem (dir gone); terminal cleaned too; git branch pruned. No debris left (worktree count returned to pre-drill 17). A single command handles the terminal-attached case — no separate terminal kill needed. - All subprocess calls behind one thin
_run()helper so tests patch a single seam.
Patterns to follow: scripts/fm_doctor.sh FM_HOME resolution
($HOME/.hermes/school-core-fm-config); verify_gate.py's subprocess +
typed-verdict shape; house test style in tests/test_verify_gate.py.
Test scenarios:
- Happy path: status file transitions
working:→done:;report.mdexists →status == done,report_pathset,teardown_okTrue. - Poll timeout: status file never reaches a terminal line; short overridden timeout →
status == timeout, no report read. - Spawn failure:
fm-spawnexits non-zero →CrewUnavailableErrorraised. failed:status: terminal linefailed:→status == failed(not timeout).blocked:status:blocked:present → short-grace poll continues; grace (~60s) expires →status == blocked.needs-decision:status: same asblocked:(no human in the loop) → grace thenstatus == blocked.paused:status:paused:present → keep polling to the 15-min timeout, NO grace fallback (declared external wait clears on its own).resolved:closer:blocked:thenresolved:→ resumes polling (block cleared, not terminal).- Unknown status line: e.g.
checkpointing:→ keep polling until timeout, not treated as terminal. crew_iduniqueness: two consecutive spawns (same minute) yield distinct ids when the cycle ids differ.- In-flight registry: spawn writes
data/crew_runs.jsonentry; terminal status updates it; stale-entry sweep invokesorca worktree rmand logs on refusal. - Brief scaffold:
FM_HOME/data/<id>/brief.mdcontains the task text and the scout deliverable contract (report.md). - Teardown orca bug:
fm-teardownrefuses (mock the atom-invalid refusal) → logs,teardown_ok False, no exception. - Report missing:
done:but noreport.md→report_path None+ visible warning, not a crash.
Verification: tests/test_crew_dispatch.py green; module imports
standalone; no bridge changes in this unit.
U8. Bridge wiring behind crew_enabled with direct-Orca fallback — R7, R8, R9
Goal: Route the student-task path through the crew module when enabled, with the same-cycle direct-Orca fallback and retry-once carry specified by R8.
Dependencies: U7 (module + in-flight registry).
Files:
director.py— add optionalprovided_student_output: str = Nonetorun_task; when set, use it in place of the internal studentcall_model(director.py:649) so review + scoring run unchanged on the crew deliverable (R9). Invalid withisolated_phases(assert or document).issue_bridge.py—crew_enabledread once (envCREW_ENABLED, default off in tests), crew path before the directrun_taskcall (issue_bridge.py:549), in-flight skip,CREW_MAX_PER_CYCLEcaptests/test_issue_bridge.py— newTestCrewDispatchPathclasstests/test_director.py—provided_student_outputsubstitution test
Approach: When crew_enabled:
- Skip issues with a
runningrecord indata/crew_runs.json(KTD-8 — no duplicate dispatch across overlapping cycles). - Up to
CREW_MAX_PER_CYCLEissues (default 1) go throughcrew_dispatch; the rest use the direct path this cycle (bounds wall-clock under the 30-min job timeout). done→run_task(..., provided_student_output=report_text): the crew'sreport.mdis the student deliverable; the two-judge review + scoring run unchanged on it (R9).CrewUnavailableError(spawn fail),blocked(grace expired), or non-done status (timeout/failed) → plainrun_tasksame cycle (issue_bridge.py:549) = direct-Orca fallback; recordfallback_reason.- If the fallback itself fails → existing retry-once semantics carry (
RETRY_FILE,RETRY_LIMIT=2). When disabled (test default): byte-for-byte today's path — the existing 30+ bridge tests that patchdirector.run_taskstay green unchanged.
Patterns to follow: VERIFY_GATE_STRICT env-read pattern
(issue_bridge.py:392); existing @patch("director.run_task") hermetic tests.
Test scenarios:
- Flag off:
crew_dispatchnever called;run_taskcalled (existing suite). - Flag on + crew done:
run_taskcalled withprovided_student_output== report text; result carries crew fields; review runs on the report. provided_student_outputsubstitution (director):run_task(..., provided_student_output=X)skips the studentcall_model; the output passed to_run_two_judge_reviewis X.- In-flight skip: issue present in
crew_runs.jsonwithrunning→ not re-dispatched this cycle. - Per-cycle cap: with
CREW_MAX_PER_CYCLE=1, the second crew-eligible issue uses the direct path. - Flag on + spawn failure (
CrewUnavailableError): plainrun_taskfallback same cycle; resultfallback_reason == spawn_failure. - Flag on + poll timeout: falls back direct;
fallback_reason == timeout. - Flag on +
blocked(grace expired): falls back direct;fallback_reason == blocked. - Flag on + crew
failed:status: falls back direct;fallback_reason == crew_failed. - Flag on + fallback also fails:
run_taskraises → attempt recorded in retry file (attempt 1 → retry next cycle), not marked school-failed. - Flag parsing:
CREW_ENABLED=0/absent → off;1→ on; invalid value → off + WARN.
Verification: Full tests/test_issue_bridge.py + tests/test_director.py
green (existing + new); no behavior change with the flag off.
U9. Crew surfacing + docs truth — R9, R10
Goal: Make crew execution visible (result, last_run.json, board/cycle
log) and correct the claims that still overstate wiring, so an operator can
see when an issue ran via crew vs fallback and why.
Dependencies: U8 (surfacing reads the crew result shape; docs half lands with U8).
Files:
issue_bridge.py— crew summary fields on the per-issue result +last_run.jsonentrycampus.md— FirstMate row (:231) flips ⚠️ Partial → ✅ behind flagREADME.md— crew row/file-tree entries.github/workflows/school-loop.yml—CREW_ENABLED: "1"+CREW_MAX_PER_CYCLE: "1"env on the execute job,concurrency: group: school-loop(queue,cancel-in-progress: false) so overlapping 5-min runs don't double-fetch GitHub/AgentMail, comment
Approach: Add a compact crew block to the result dict (crew_id,
status, fallback_reason, teardown_ok) mirroring the verify/entire
surfacing already shipped in U3/U6; it rides last_run.json and the board
comment. The workflow sets the flag on (KTD-4 default) and the concurrency
group (F1) prevents overlapping runs from duplicating GitHub/AgentMail polling;
campus/README describe flag-off fallback semantics and the in-flight
registry. The sweep is owned by U7 (KTD-8), not this unit.
Test scenarios:
last_run.jsonentry carries thecrewblock when the crew path is used; absent when direct.- Board/comment text includes a crew summary line when used.
campus.mdFirstMate row no longer claims un-wired dispatch (grep check).- Workflow YAML parses; execute job sets
CREW_ENABLEDandCREW_MAX_PER_CYCLE;concurrency.grouppresent.
Verification: Updated bridge suite green; campus.md/README.md row
greps clean; workflow YAML parses.
U5. campus.md correction — R10
campus.md: correct the FirstMate, verify-gate, and Layer 3 rows to match the wiring above (the Entire row already reads true once U6 lands). Docs-only; lands after U1–U4.
U6. Entire pre-merge review in the issue path — R11, R12, R13
src/qodo_pre_merge.py: rename module/function toentire_(keep the bookbag-compatible return shape); fix_get_entire_pathto fall back to~/.local/bin/entireexplicitly whenshutil.whichmisses it in worktree shells.issue_bridge.py(sync path): invoke the Entire sensor before_run_two_judge_review; non-blocking — findings appended to the review dict and surfaced on the board/comment + cycle log (WARN when absent).conductor.py(:341-359): update import + call to the renamed module.- Ops (not code):
entire enablein school-core — verified 2026-08-11 (auto-installs claude-code hooks + git-refs checkpoint backend;.entire/gitignored).entire agent add hermesis rejected by CLI 0.9.0 (unknown agent; supported: claude-code, codex, copilot-cli, cursor, factoryai-droid, gemini, opencode, pi, vogon) — tracking is repo-wide via the git hooks, so no hermes-specific entry is needed. - Tests:
_get_entire_pathfinds the binary via the explicit fallback; skip path returns gracefully with a WARN; findings parse fromentire review --format text; existing bridge/conductor tests stay green with the CLI absent.
Acceptance Examples
Verify-gate behavior (R4/R6):
| Toolchain present | VERIFY_GATE_STRICT | Direct/reusable gate behavior | Scheduled school-loop behavior |
|---|---|---|---|
| yes | any | gate runs hermetically via flake | execute proceeds |
| no | unset | visible soft-skip; no fake compile failure | execute preflight fails as infrastructure error; hosted board still publishes |
| no | 1 | strict escalation; issue cannot pass unverified | execute preflight fails before issue processing |
Nix present but verifyShell invalid | any | gate cannot run; soft-skip or strict escalation | execute preflight fails clearly |
FirstMate dispatch failure modes (R8):
| Situation | Behavior |
|---|---|
fm-spawn fails | fall back to direct-Orca same cycle |
agent never writes done: (poll timeout, 15 min) | fall back to direct-Orca same cycle |
agent writes blocked:/needs-decision: (grace ~60s expires) | fall back to direct-Orca same cycle; fallback_reason=blocked |
agent writes paused: (declared external wait) | keep polling to the 15-min timeout — clears on its own; only timeout falls back |
| overlapping cycle already has the issue in-flight | skip dispatch this cycle; next cycle collects the crew result |
| fallback also fails | existing retry-once semantics carry the issue |
| teardown fails after report read (known orca bug) | log + continue; U7's next-spawn sweep reclaims the worktree |
Entire pre-merge sensor (R11/R12):
| Situation | Behavior |
|---|---|
CLI discoverable + .entire/ enabled | entire review runs; findings appended to the review dict and surfaced |
| CLI not discoverable (worktree PATH gap) | explicit ~/.local/bin fallback finds it |
| genuinely absent | non-blocking skip + visible WARN; two-judge review proceeds |
Risks & Dependencies
- FirstMate teardown bug — CONFIRMED worse than initially documented (2026-08-11) — orca worktree ids are
<repoId>::<path>(live sample verified), andfm_backend_endpoint_atom_valid(only[A-Za-z0-9._@%+-]) gates the orca branch offm_backend_validate_task_endpoint(fm-teardown.sh:431), sofm-teardown.shrefuses EVERY orca task, not just edge ids. Mitigation:crew_dispatchnever callsfm-teardown.shfor orca; it callsorca worktree rm --worktree "id:<id>" --forcedirectly (the backend adapter's own primitive) for both immediate best-effort cleanup and the next-spawn sweep; upstream report pending. - Determinate Nix needs sudo on the self-hosted runner. If that can't be granted, the researched uv fallback (
astral-sh/setup-uv+uv run pytest) keeps the gate meaningful. Tracked as a fallback, not a blocker. - Trajectory growth in git. Mitigation: history cap (last N cycles or per-cycle summaries) enforced by the checkpoint step.
- Crew dispatch adds wall-clock per issue (spawn + agent + report vs direct call). Bounded by
CREW_MAX_PER_CYCLE(default 1) under the 30-min job timeout; the fallback bounds the rest. - Overlapping cycles at the 5-min cadence (deepened 2026-08-11) — a 15-min crew spans multiple 5-min cycles. Mitigation:
concurrency: groupin the workflow (queue, no cancel) so runs don't double-fetch GitHub/AgentMail, and thedata/crew_runs.jsonin-flight registry (KTD-8) so no issue is ever crew-dispatched twice. - U4 depends on the crew chain staying green —
scripts/fm_doctor.shis the preflight gate already wired into the execute job. - Entire's intent-awareness depends on session tracking —
entire enablemust run in school-core (creates.entire/); without it the review degrades to raw-diff only. Ops sub-task, like U3's Nix install. - CLI discovery in Orca worktree shells —
_get_entire_pathmust fall back to~/.local/bin/entireexplicitly; bareshutil.whichskips in worktrees.
Sources / Research
.scratch/wayfinder-map-pipeline-gaps.md— recon canvas with F1–F5 verdicts and delegated findings (F3: Determinate Nix / uv fallback; F4: FirstMate ship/scout contract grounded in~/.local/share/firstmate/bin/).director.py:582(session_idparam exists),director.py:714(enrich_promptcall drops it).context_orchestrator.py:78(if session_id:gate),:191(_archival_context).issue_bridge.py:475(bridge call withoutsession_id)..github/workflows/school-loop.yml:154-173(checkpoint pattern to extend in U2).verify_gate.py:160(nix develop #verifyShellsubprocess),flake.nix(verifyShell).- FirstMate contract summary (status file
done:protocol,report.md, meta keys) — in the map's F4 findings. src/qodo_pre_merge.py:133(run_qodo_improve→entire review, skip path),:40-42(_get_entire_path= bareshutil.which),conductor.py:341-359(async-path pre-merge sensor).campus.md:96(tool-table row),campus.md:124-130("Why Entire Instead of Qodo?"),README.md:107;sound-royale-ny/.entire/(reference forentire enableoutput).