=== extract: H2 section, first bash fence under Verification
pnpm --filter api test
echo second line
rc=0
FENCE_FAIL_REASON=
=== extract: H2 section with no Verification
rc=0
FENCE_FAIL_REASON=
=== extract: title naming Verification, upper-case subheading
echo upper-case heading
rc=0
FENCE_FAIL_REASON=
=== extract: H1 single-task file runs past sibling ## headings
uv run pytest tests/unit -q
rc=0
FENCE_FAIL_REASON=
=== extract: anchorless ref falls back to the file's basename
echo anchorless
rc=0
FENCE_FAIL_REASON=
=== extract: a bug titled at H1 is refused
rc=0
FENCE_FAIL_REASON=
=== extract: a bug section at H2
echo bug at h2
rc=0
FENCE_FAIL_REASON=
=== extract: missing file
rc=0
FENCE_FAIL_REASON=
=== extract: the dispatch-time snapshot wins for the task in flight
echo from the dispatch-time snapshot
rc=0
FENCE_FAIL_REASON=
=== _kill_tree: empty pid
rc=0
FENCE_FAIL_REASON=
=== _kill_tree: a parent with two children
children found: yes
alive after: 0
rc=0
FENCE_FAIL_REASON=
=== fence_compose_project: none configured
rc=0
FENCE_FAIL_REASON=
=== fence_compose_project: lower-cased
factoryosrc=0
FENCE_FAIL_REASON=
=== fence_compose_project: sanitised, leading non-alnum dropped
my-stack-v2rc=0
FENCE_FAIL_REASON=
=== classify: a table of blocks
docker compose up -d --build api                 live=yes heavy=no
docker-compose down -v                           live=yes heavy=no
bash harness/qa/suites/boot/run.sh               live=yes heavy=no
echo dockercompose                               live=no heavy=no
mydocker compose ps                              live=no heavy=no
node harness/qa/journeys/nav.mjs                 live=yes heavy=no
pnpm -r run test                                 live=no heavy=yes
pnpm --filter api test                           live=no heavy=no
pnpm --filter api --filter web test              live=no heavy=yes
pnpm --filter ...api test                        live=no heavy=yes
pnpm --filter=!api test                          live=no heavy=yes
pnpm test                                        live=no heavy=yes
cd services/api && pnpm test                     live=no heavy=no
cd services/api|pnpm test                        live=no heavy=no
cd services/api && true|pnpm test                live=no heavy=yes
npm run test --workspaces                        live=no heavy=yes
yarn workspaces run test                         live=no heavy=yes
turbo run test                                   live=no heavy=yes
pnpm turbo test                                  live=no heavy=yes
uv run pytest -q                                 live=no heavy=yes
uv run pytest tests/unit                         live=no heavy=no
pytest services/api                              live=no heavy=no
grep -r test .                                   live=no heavy=no
pnpm -r run typecheck                            live=no heavy=no
npm t                                            live=no heavy=yes
pnpm -C services/api test                        live=no heavy=no
pnpm -w test                                     live=no heavy=yes
FOO=1 pnpm test                                  live=no heavy=yes
echo hi # pnpm -r test                           live=no heavy=no
pnpm \|  -r test                                 live=no heavy=yes
npx vitest run                                   live=no heavy=no
pnpm --filter api test && docker compose up -d   live=yes heavy=no
rc=0
FENCE_FAIL_REASON=
=== classify: no drivers and no workspace roots configured
docker compose up -d                             live=no heavy=no
pnpm test                                        live=no heavy=yes
cd services/api && pnpm test                     live=no heavy=yes
uv run pytest                                    live=no heavy=yes
rc=0
FENCE_FAIL_REASON=
=== semaphores: a block needing neither
acquire rc=0 heavy=[] live=[]
after release heavy=[] live=[]
rc=0
FENCE_FAIL_REASON=
=== semaphores: heavy only
CALL sem_gate_acquire [heavy-test] [1]
acquire rc=0 heavy=[slot-heavy-test] live=[]
CALL sem_gate_release [heavy-test] slot=[slot-heavy-test]
after release heavy=[] live=[]
rc=0
FENCE_FAIL_REASON=
=== semaphores: live only
CALL sem_gate_acquire [live-qa] [1]
acquire rc=0 heavy=[] live=[slot-live-qa]
CALL sem_gate_release [live-qa] slot=[slot-live-qa]
after release heavy=[] live=[]
rc=0
FENCE_FAIL_REASON=
=== semaphores: both, in rank order
CALL sem_gate_acquire [heavy-test] [1]
CALL sem_gate_acquire [live-qa] [1]
acquire rc=0 heavy=[slot-heavy-test] live=[slot-live-qa]
CALL sem_gate_release [live-qa] slot=[slot-live-qa]
CALL sem_gate_release [heavy-test] slot=[slot-heavy-test]
after release heavy=[] live=[]
rc=0
FENCE_FAIL_REASON=
=== semaphores: heavy-test already held by the caller
CALL sem_gate_acquire [live-qa] [1]
acquire rc=0 heavy=[] live=[slot-live-qa]
CALL sem_gate_release [live-qa] slot=[slot-live-qa]
after release heavy=[] live=[]
rc=0
FENCE_FAIL_REASON=
=== semaphores: heavy-test wait expires
CALL sem_gate_acquire [heavy-test] [1]
CALL lane_defer_on_semaphore [heavy-test]
acquire rc=1 heavy=[] live=[]
after release heavy=[] live=[]
rc=0
FENCE_FAIL_REASON=
=== semaphores: live-qa expires, heavy-test given back first
CALL sem_gate_acquire [heavy-test] [1]
CALL sem_gate_acquire [live-qa] [1]
CALL sem_gate_release [heavy-test] slot=[slot-heavy-test]
CALL lane_defer_on_semaphore [live-qa]
acquire rc=1 heavy=[] live=[]
after release heavy=[] live=[]
rc=0
FENCE_FAIL_REASON=
=== semaphores: helpers missing (127) -> unguarded
CALL sem_gate_acquire [heavy-test] [1]
CALL sem_gate_acquire [live-qa] [1]
acquire rc=0 heavy=[] live=[]
after release heavy=[] live=[]
rc=0
FENCE_FAIL_REASON=
=== fence_release_semaphores: idempotent with nothing held
rc=0
FENCE_FAIL_REASON=
=== fence_log_missing_tools: anchored at bash:, sorted, unique
jq
opa
ruff-format.v2
rc=0
FENCE_FAIL_REASON=
=== fence_log_missing_tools: no log
rc=0
FENCE_FAIL_REASON=
=== fence_control_tree_probe: state dir excluded
 M README.md
?? docs/
rc=0
FENCE_FAIL_REASON=
=== fence_control_tree_probe: + the tracker excluded
 M README.md
rc=0
FENCE_FAIL_REASON=
=== fence_control_tree_probe: nothing excluded
 M README.md
?? docs/
?? harness/
rc=0
FENCE_FAIL_REASON=
=== run_fence: passes; roots and compose project withdrawn
CALL reap_orphans_under [<SB>] [T-ENV-001]
run_fence rc=0 reason=[]
--- fence log
| cpn=unset owner=unset ctl=unset lane=unset color=1/0 pwd=<SB>
rc=0
FENCE_FAIL_REASON=
=== run_fence: an operator's compose project is imposed
CALL reap_orphans_under [<SB>] [T-ENV-002]
run_fence rc=0 reason=[]
--- fence log
| cpn=factory-os owner=unset ctl=unset lane=unset color=1/0 pwd=<SB>
rc=0
FENCE_FAIL_REASON=
=== run_fence: fails fast at the failing command
CALL reap_orphans_under [<SB>] [T-FAIL-001]
run_fence rc=1 reason=[]
--- fence log
| one
| [fence] command 2/3 exited 1, the block stops here: false
rc=0
FENCE_FAIL_REASON=
=== run_fence: a missing tool voids the verdict
CALL reap_orphans_under [<SB>] [T-TOOL-001]
ERR   x T-TOOL-001: the verification fence called commands this machine does not have: nosuchtool_golden
ERR     Its exit status is not a verdict on the code — install the missing tool, or
ERR     rewrite the block to stop needing it (<SB>/logs/fence.log).
METRIC {"event":"fence_missing_tool","label":"T-TOOL-001","tools":"nosuchtool_golden","at":"2026-10-18T00:00:00+00:00"}
run_fence rc=1 reason=[]
--- fence log
| before
| bash: line 12: nosuchtool_golden: command not found
| [fence] command 2/3 exited 127, the block stops here: nosuchtool_golden --version
rc=0
FENCE_FAIL_REASON=
=== run_fence: block does not compile -> fails closed
ERR   x T-COMPILE-001: the verification block did not compile to a fail-fast script — not running it (fails closed: an empty script exits 0).
run_fence rc=1 reason=[]
--- fence log
rc=0
FENCE_FAIL_REASON=
=== run_fence: legacy fail-open runs the raw block (last command wins)
METRIC {"event":"legacy_fail_open_used","path":"verification-partial","task_id":"T-LEGACY-001","at":"2026-10-18T00:00:00+00:00"}
CALL reap_orphans_under [<SB>] [T-LEGACY-001]
run_fence rc=0 reason=[]
--- fence log
| last
rc=0
FENCE_FAIL_REASON=
=== run_fence: exceeds its bound and is killed
CALL reap_orphans_under [<SB>] [T-SLOW-001]
ERR   x T-SLOW-001: verification fence exceeded its 5s bound and was killed (<SB>/logs/fence.log).
ERR     A fence this expensive is not a usable closure contract — narrow it to the
ERR     behaviour it proves, or raise policy.verification_timeout_seconds deliberately.
METRIC {"event":"verification_timeout","label":"T-SLOW-001","timeout_s":5,"waited_s":5,"at":"2026-10-18T00:00:00+00:00"}
run_fence rc=1 reason=[]
--- fence log
rc=0
FENCE_FAIL_REASON=
=== run_fence: heavy-test wait expires -> not run
CALL sem_gate_acquire [heavy-test] [1]
CALL lane_defer_on_semaphore [heavy-test]
run_fence rc=1 reason=[]
--- fence log
rc=0
FENCE_FAIL_REASON=
=== run_fence: heavy + live taken and released around the block
CALL sem_gate_acquire [heavy-test] [1]
CALL sem_gate_acquire [live-qa] [1]
CALL reap_orphans_under [<SB>] [T-BOTH-001]
CALL sem_gate_release [live-qa] slot=[slot-live-qa]
CALL sem_gate_release [heavy-test] slot=[slot-heavy-test]
run_fence rc=0 reason=[]
--- fence log
| pnpm -r run test
| pnpm -r run test
| docker compose ps
rc=0
FENCE_FAIL_REASON=
=== run_fence: two roots, nothing touched
CALL reap_orphans_under [<SB>] [T-CTL-001]
run_fence rc=0 reason=[]
--- fence log
| quiet
rc=0
FENCE_FAIL_REASON=
=== run_fence: writes the control tree -> sandbox-escape
CALL reap_orphans_under [<SB>] [T-CTL-002]
ERR   x T-CTL-002: the verification fence MODIFIED THE CONTROL ROOT — its verdict is void.
ERR     control root: <CTL>
ERR     the working tree changed outside the paths the orchestrator writes
ERR     A fence must observe only its own workspace. Sandbox it, or pin its roots.
METRIC {"event":"fence_escaped_sandbox","label":"T-CTL-002","head_moved":false,"tree_moved":true,"at":"2026-10-18T00:00:00+00:00"}
run_fence rc=1 reason=[sandbox-escape]
--- fence log
rc=0
FENCE_FAIL_REASON=sandbox-escape
=== run_fence: writes only the control state dir -> not an escape
CALL reap_orphans_under [<SB>] [T-CTL-003]
run_fence rc=0 reason=[]
--- fence log
rc=0
FENCE_FAIL_REASON=
=== run_fence: moves the control HEAD, no journal helper -> escape
CALL reap_orphans_under [<SB>] [T-CTL-004]
ERR   x T-CTL-004: the verification fence MODIFIED THE CONTROL ROOT — its verdict is void.
ERR     control root: <CTL>
ERR     HEAD moved <SHA12> -> <SHA12>
ERR     A fence must observe only its own workspace. Sandbox it, or pin its roots.
METRIC {"event":"fence_escaped_sandbox","label":"T-CTL-004","head_moved":true,"tree_moved":false,"at":"2026-10-18T00:00:00+00:00"}
run_fence rc=1 reason=[sandbox-escape]
--- fence log
rc=0
FENCE_FAIL_REASON=sandbox-escape
=== run_fence: moves the control HEAD, not journalled -> escape
CALL reap_orphans_under [<SB>] [T-CTL-005]
CALL control_head_advance_is_ours [40] [moved]
ERR   x T-CTL-005: the verification fence MODIFIED THE CONTROL ROOT — its verdict is void.
ERR     control root: <CTL>
ERR     HEAD moved <SHA12> -> <SHA12>
ERR     A fence must observe only its own workspace. Sandbox it, or pin its roots.
METRIC {"event":"fence_escaped_sandbox","label":"T-CTL-005","head_moved":true,"tree_moved":false,"at":"2026-10-18T00:00:00+00:00"}
run_fence rc=1 reason=[sandbox-escape]
--- fence log
rc=0
FENCE_FAIL_REASON=sandbox-escape
=== run_fence: the orchestrator's own advance -> recorded, not an escape
CALL reap_orphans_under [<SB>] [T-CTL-006]
CALL control_head_advance_is_ours
METRIC {"event":"fence_control_root_advanced","label":"T-CTL-006","from":"<SHA>","to":"<SHA>","at":"2026-10-18T00:00:00+00:00"}
run_fence rc=0 reason=[]
--- fence log
rc=0
FENCE_FAIL_REASON=
=== run_task_verification: block passes
LOG   Running task Verification block (T-RV-001)
CALL reap_orphans_under [<SB>] [T-RV-001]
LOG   + Verification block passed
rc=0
FENCE_FAIL_REASON=
=== run_task_verification: block fails, last lines echoed
LOG   Running task Verification block (T-RV-002)
CALL reap_orphans_under [<SB>] [T-RV-002]
ERR   x Verification block failed (<SB>/logs/verify-20261018-000000-T-RV-002.log) — last 20 lines:
ERR     trying
ERR     [fence] command 2/2 exited 3, the block stops here: exit 3
rc=1
FENCE_FAIL_REASON=
=== run_task_verification: verification: none declared
LOG   o No Verification block found for T-RV-003 — accepted (bug closure contract / verification: none)
rc=0
FENCE_FAIL_REASON=
=== run_task_verification: bug spec without a block
LOG   o No Verification block found for STORY-007__BUG-009 — accepted (bug closure contract / verification: none)
rc=0
FENCE_FAIL_REASON=
=== run_task_verification: no block, no declaration -> fails
ERR   x No Verification block found for T-RV-004, and no 'verification: none — <reason>' declaration
rc=1
FENCE_FAIL_REASON=
=== run_task_verification: no block under legacy fail-open
METRIC {"event":"legacy_fail_open_used","path":"verification-missing","task_id":"T-RV-004","at":"2026-10-18T00:00:00+00:00"}
LOG   o No Verification block found for T-RV-004 — skipping (legacy_fail_open)
rc=0
FENCE_FAIL_REASON=
--- verify logs written
verify-20261018-000000-T-RV-001.log
verify-20261018-000000-T-RV-002.log
