step.19.txt -- b3ubot U3.6: VERIFYING -- T0/T1 tiers wired; the gate graph as a `verification` DAG; bounded repair loop (d9) + escalation. design.md §2.5's oracle harness ("the orchestrator refuses to enter VERIFYING with an empty gate set"; "Verdicts are recorded as VerificationRecords") and §4's VERIFYING span ("--gates green--> RETRO"; "--fail--> EXECUTING (bounded repair loop; then human escalation)") -- as code. Records d9's V0 default. Stops here -- does NOT continue into U3.7 or any later P3 UoW. Step: 19 Parent: end_to_end.md §5 U3.6 bullet verbatim ("VERIFYING: T0/T1 tiers wired; the gate graph as a `verification` DAG; bounded repair loop (d9) + escalation"). design.md §2.5 (the tier table + the empty-gate-set rule + the VerificationRecords sentence), §4 (the VERIFYING edges and the two load-bearing human gates -- escalation is the SECOND), §2.13 (the `verification` kind), §5 d9 (OPEN going in). app/orchestrator/ (U3.1-U3.5) is the package this grows; executing.py's generic frontier engine + resume machinery are what the pass and the repair re-entry run through; app/tools/shell.py's scrubbed allowlisted run_shell/run_gate are what the checks execute under. UoW: U3.6 Date: 2026-07-21 Origin: Operator directive 2026-07-21 (same dispatch shape as step.14-18's): draft AND execute steps/step.19.txt for U3.6 in a single pass (the step.7/9/10/11/14-18 convention, NOT a skeleton-split), with the SAME explicit HARD scope boundary -- stop after U3.6, do not continue into U3.7 or any later UoW; the operator directs P3 one UoW at a time with strict per-UoW checkpoints. ## (0) Status EXECUTED in this pass. Not a skeleton-then-later-execute split -- app/orchestrator/verifying.py, the VerifyError/EscalationError additions, the RepairContext + REPAIR_MARKER + halt_note growth in executing.py, the drafting-template gate-marker extension, the `b3ubot verify` CLI subcommand, tests/test_orchestrator_verifying.py, the design.md (§2.5/§2.13/§5 d9) / end_to_end.md / docs/orchestrator_state_machine.md edits, and this step file were all built together, per the operator's explicit "draft AND execute (single pass)" direction. Per the operator's explicit scope boundary (Origin, above), this session STOPS after U3.6 -- U3.7 (RETRO closure/freeze) is the next UoW but is NOT started here: a verified UoW lands in RETRO and just sits there; nothing drafts the retro pair or freezes the instance. ## (1) Ground truth probed at drafting (outputs -> named writers) READ design.md §2.5 in full (the tier table; the load-bearing sentence "the orchestrator refuses to enter VERIFYING with an empty gate set"; "ledger round-trip" named IN the T0 row itself -- so it became a V0 check, not an invention), §4 (the VERIFYING edges; "a repair loop that exhausts its budget stops and reports; it never grinds silently"; the oracle_feedback paragraph the diagnostics feed-back realizes), §5 d9 (OPEN: fixed vs cost-budgeted vs oracle-signal-driven), §2.13 (the `verification` kind = "the gate graph of a VERIFYING pass"). READ app/orchestrator/ in full: executing.py (the generic run_ready_frontier this step REUSES rather than duplicating; the resume machinery whose _RUNNABLE set makes a pending-reset re-run exactly the reset nodes; the evidence-stamp pattern; _h_provider_run's context shape the repair diagnostics had to enter THROUGH, not around); state_machine.py (the actual 9 edges: VERIFYING->RETRO and VERIFYING->EXECUTING both exist with U3.6-naming rationale strings -- NO state-machine change needed, a checked finding); drafting.py (RETRY_MARKER's Q-4-B distinct-scenario precedent, mirrored as REPAIR_MARKER_TEMPLATE; _format_instructions, the template the gate-marker extension lands in); ratify.py (extract_leans' title-PREFIX + marker-line-split shape, mirrored for gate extraction; the legality-first lesson). SURVEYED the gate-naming ground truth before designing the convention: every §(3) section in this repo's own steps/step.2.txt-step.18.txt uses leading `G` tokens + free prose; U2.1's 50-file b3u corpus survey documents the same shape (one file titles the section "Oracle (gates G1-G3)" -- which is why extraction matches the title by PREFIX and an off-convention title refuses honestly); NO tier markers exist anywhere in either corpus; U3.3's template emits "named gates (G1, G2, ...), each a checkable claim". Conclusion: keep G-blocks, add ONE bracketed [T:] marker per machine gate, and extend the drafting template to say so (2.2). READ app/tools/shell.py (run_shell's allowlist matches argv[0]'s BASENAME -- so the engine's own sys.executable, basename python/python3, is the one interpreter guaranteed both present and allowlisted; run_gate; scrubbed_env; exit-as-data), trail.py + app/egress.py (the two file-based precursor patterns the VerificationRecord precursor had to choose between -- JSONL chosen, 2.5), tests/conftest.py (hermetic $B3UBOT_HOME), app/cli.py (the draft/ratify/execute sibling row + Q-8-B guards `verify` joins). CONFIRMED bin/dagModel is built and working here (step.18's check re-verified by the live suite: roundtrip_verify returns "verified" on every written instance). CONFIRMED `git log --oneline -30` for the 2-commit phrasing (step.18's precedent, ae78fe1/8a3718d). CONFIRMED baseline: full suite 481 passed / 11 skipped before any edit (matches step.18's reported final). CONFIRMED live CLI smoke before committing (scratch workspace + isolated $B3UBOT_HOME), THREE legs: (a) mock draft + ratify --yes + execute --yes then `b3ubot verify --yes` -> the EMPTY-gate-set refusal verbatim, naming the marker convention and the next action (the drafted fixture skeleton's G1 is narrative -- the refusal is the correct live outcome); (b) markers added to the skeleton's §(3) by hand (the refusal's own named next action) -> verify green: 3 gates pass, verification instance beside the skeleton, verifications.jsonl rows, ENGINE VERIFICATION RECORD in §(0), engine state RETRO, rc=0; (c) the REAL repair loop: failing toy test -> pass 1 red at the pytest gate -> VERIFYING -> EXECUTING with diagnostics fed back -> HUMAN GATE diff of the repair proposal -> apply -> pass 2 green -> RETRO (passes=2 repairs=1). ## (2) What U3.6 delivers 2.1 **app/orchestrator/verifying.py** (new; the package's per-concern peer of drafting.py/ratify.py/executing.py): `verify_uow(workspace_root, uow, *, adapter, provider, output_fn, input_fn, assume_yes=, home=, max_repair_attempts=)` -- the full arc: state legality FIRST (validate_transition(state, "RETRO") admits exactly VERIFYING -- the ratify.py indirection precedent; zero reads on an illegal move), gate extraction (refuse loudly on an EMPTY machine-runnable set -- §2.5's own rule), per pass: compile the verification DAG, write it beside the skeleton, run the tier chain, record verdicts; green -> stamp + VERIFYING -> RETRO; red verdict -> one bounded repair re-entry; budget spent -> loud escalation. Plus VerifyError + EscalationError in errors.py, all re-exported through app/orchestrator/__init__. 2.2 **The gate-naming convention (decision, grounded -- see §(1) SURVEYED):** gate blocks split on leading `G` marker lines (the extract_leans precedent; gates section found by title PREFIX "Verification gates"); a gate is MACHINE-RUNNABLE iff its block carries exactly ONE bracketed tier marker: [T0:py_compile], [T0:ledger_roundtrip], [T1:pytest], or [T2: