=== classify 'test-fail' (no log)
--- stdout
test-fail
--- stderr
rc=0
=== classify 'post-task-tests-failed' (no log)
--- stdout
test-fail
--- stderr
rc=0
=== classify 'gate:lint' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'gate:py-test' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'gate:' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'verification-failed' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'bug-reverification-failed' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'sandbox-escape' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'arch-check-failed' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'commit-failed' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'empty-diff' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'zero-tests' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'spec-mutated' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'missing-evidence' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'missing-evidence:ac-3' (no log)
--- stdout
verification-failed
--- stderr
rc=0
=== classify 'review-rejected' (no log)
--- stdout
review-rejected
--- stderr
rc=0
=== classify 'noop-unconfirmed' (no log)
--- stdout
review-rejected
--- stderr
rc=0
=== classify 'qa-failed' (no log)
--- stdout
test-fail
--- stderr
rc=0
=== classify 'qa-error' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'review-error' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'arch-check-error' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'arch-check-escalated' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'evidence-invalid' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'budget-exceeded' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'agent-reported-blocked' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'spec-file-missing' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'blocked-dependencies' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'blocked-dependencies (deps_status=1)' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'lease-expired' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'lease-expired (ttl 900s)' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'rebase-conflict' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'merged-tree-tests-failed' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'merged-tree-tests-failed (2 suites)' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'merged-tree-check-failed' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'merged-tree-build-failed' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'merged-tree-sync-failed:pnpm' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'fast-forward-refused' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'integration-lock-timeout' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'integrator-no-base-head' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'merge-conflict' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'agent-execution-failed' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify '' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'TEST-FAIL' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'test-fail ' (no log)
--- stdout
blocked
--- stderr
rc=0
=== classify 'verification-failed-x' (no log)
--- stdout
blocked
--- stderr
rc=0
=== default branch: LAST_AGENT_EXIT=124 wins with no log
--- stdout
timeout
--- stderr
rc=0
=== default branch: LAST_AGENT_EXIT=124 outranks a valid adapter hint
--- stdout
timeout
--- stderr
rc=0
=== default branch: LAST_AGENT_EXIT=1 and a plain log, no adapter -> blocked
--- stdout
blocked
--- stderr
rc=0
=== default branch: the core timeout marker in the log
--- stdout
timeout
--- stderr
rc=0
=== default branch: a custom TIMEOUT_DIAG_MARKER
--- stdout
timeout
--- stderr
rc=0
=== default branch: the default marker is not the custom one
--- stdout
blocked
--- stderr
rc=0
=== default branch: a log path that does not exist
--- stdout
blocked
--- stderr
rc=0
=== default branch: log defaults to CURRENT_TASK_LOG
--- stdout
transient-auth
--- stderr
rc=0
=== default branch: CURRENT_TASK_LOG carrying the marker
--- stdout
timeout
--- stderr
rc=0
=== adapter: a valid class is taken
--- stdout
transient-auth
--- stderr
rc=0
=== adapter: the adapter sees the log path
--- stdout
test-fail
--- stderr
rc=0
=== adapter: only the first line, whitespace stripped
--- stdout
timeout
--- stderr
rc=0
=== adapter: padded valid class
--- stdout
review-rejected
--- stderr
rc=0
=== adapter: a class outside the taxonomy is dropped, with an error
--- stdout
blocked
--- stderr
ERROR: ! Runner adapter 'aider' returned failure class 'auth-ish', which is not one of: transient-auth timeout test-fail verification-failed review-rejected blocked. Dropped — recorded as blocked.
rc=0
=== adapter: outside the taxonomy, adapter name unknown
--- stdout
blocked
--- stderr
ERROR: ! Runner adapter 'unknown' returned failure class 'auth-ish', which is not one of: transient-auth timeout test-fail verification-failed review-rejected blocked. Dropped — recorded as blocked.
rc=0
=== adapter: outside the taxonomy, no error() defined -> silent
--- stdout
blocked
--- stderr
rc=0
=== adapter: empty answer -> blocked
--- stdout
blocked
--- stderr
rc=0
=== adapter: fails with output -> the output still counts
--- stdout
timeout
--- stderr
rc=0
=== adapter: its stderr is swallowed
--- stdout
blocked
--- stderr
rc=0
=== adapter: never consulted for a gate failure
--- stdout
verification-failed
--- stderr
rc=0
=== adapter: never consulted for a named reason
--- stdout
verification-failed
--- stderr
rc=0
=== FAILURE_CLASSES narrows what an adapter may answer
--- stdout
blocked
--- stderr
ERROR: ! Runner adapter 'unknown' returned failure class 'transient-auth', which is not one of: timeout blocked. Dropped — recorded as blocked.
rc=0
=== FAILURE_CLASSES unset: the built-in six
--- stdout
verification-failed
--- stderr
rc=0
=== set -u: no CURRENT_TASK_LOG, LAST_AGENT_EXIT or FAILURE_CLASSES
--- stdout
blocked
--- stderr
rc=0
=== set -u: no reason at all
--- stdout
--- stderr
<where>: $1: unbound variable
rc=1
=== streak: below the limit
--- stdout
rc=0 CONSECUTIVE_FAILS=1
--- stderr
rc=0
=== streak: zero fails
--- stdout
rc=0 CONSECUTIVE_FAILS=0
--- stderr
rc=0
=== streak: at the limit (noted, reset)
--- stdout
rc=0 CONSECUTIVE_FAILS=0
--- stderr
ERROR: Reached 2 consecutive failures (limit 2). Noting and continuing to the next task with satisfied dependencies (use --stop-on-failure to halt instead).
rc=0
--- metrics
{"event":"consecutive_fail_limit_reached","consecutive_fails":2,"limit":2,"action":"continue","at":"2026-10-19T00:00:00+00:00"}
=== streak: above the limit (noted, reset)
--- stdout
rc=0 CONSECUTIVE_FAILS=0
--- stderr
ERROR: Reached 5 consecutive failures (limit 2). Noting and continuing to the next task with satisfied dependencies (use --stop-on-failure to halt instead).
rc=0
--- metrics
{"event":"consecutive_fail_limit_reached","consecutive_fails":5,"limit":2,"action":"continue","at":"2026-10-19T00:00:00+00:00"}
=== streak: limit 1, one fail
--- stdout
rc=0 CONSECUTIVE_FAILS=0
--- stderr
ERROR: Reached 1 consecutive failures (limit 1). Noting and continuing to the next task with satisfied dependencies (use --stop-on-failure to halt instead).
rc=0
--- metrics
{"event":"consecutive_fail_limit_reached","consecutive_fails":1,"limit":1,"action":"continue","at":"2026-10-19T00:00:00+00:00"}
=== streak: limit 0, zero fails
--- stdout
rc=0 CONSECUTIVE_FAILS=0
--- stderr
ERROR: Reached 0 consecutive failures (limit 0). Noting and continuing to the next task with satisfied dependencies (use --stop-on-failure to halt instead).
rc=0
--- metrics
{"event":"consecutive_fail_limit_reached","consecutive_fails":0,"limit":0,"action":"continue","at":"2026-10-19T00:00:00+00:00"}
=== streak: fires once per streak of the limit
--- stdout
rc=0 CONSECUTIVE_FAILS=0
rc=0 CONSECUTIVE_FAILS=0
rc=0 CONSECUTIVE_FAILS=0
--- stderr
ERROR: Reached 2 consecutive failures (limit 2). Noting and continuing to the next task with satisfied dependencies (use --stop-on-failure to halt instead).
ERROR: Reached 2 consecutive failures (limit 2). Noting and continuing to the next task with satisfied dependencies (use --stop-on-failure to halt instead).
rc=0
--- metrics
{"event":"consecutive_fail_limit_reached","consecutive_fails":2,"limit":2,"action":"continue","at":"2026-10-19T00:00:00+00:00"}
{"event":"consecutive_fail_limit_reached","consecutive_fails":2,"limit":2,"action":"continue","at":"2026-10-19T00:00:00+00:00"}
=== streak: a non-numeric count
--- stdout
--- stderr
<where>: x: unbound variable
rc=1
=== write_blocker: a named reason
--- stdout
--- stderr
rc=0
--- metrics
{"event":"task_blocked","task_id":"T-1","reason":"test-fail","class":"test-fail","at":"2026-10-19T00:00:00+00:00"}
--- blockers.md

## 2026-10-19 00:00 · T-1

- Spec: harness/stories/S-1/tasks/T-1.md#t-1
- Failure: test-fail
- Class: test-fail
- Log: <SB>/logs/task-T-1.log
- Severity: P2
- Status: needs-investigation
=== write_blocker: a gate reason
--- stdout
--- stderr
rc=0
--- metrics
{"event":"task_blocked","task_id":"T-2","reason":"gate:lint","class":"verification-failed","at":"2026-10-19T00:00:00+00:00"}
--- blockers.md

## 2026-10-19 00:00 · T-2

- Spec: spec#t-2
- Failure: gate:lint
- Class: verification-failed
- Log: <SB>/logs/task-T-2.log
- Severity: P2
- Status: needs-investigation
=== write_blocker: extra bullets (the lease sweep's recovery answers)
--- stdout
--- stderr
rc=0
--- metrics
{"event":"task_blocked","task_id":"T-3","reason":"lease-expired (ttl 900s)","class":"blocked","at":"2026-10-19T00:00:00+00:00"}
--- blockers.md

## 2026-10-19 00:00 · T-3

- Spec: spec#t-3
- Failure: lease-expired (ttl 900s)
- Class: blocked
- Log: n/a
- Lane: 2
- Base SHA: abc
- Branch: lane/2/T-3
- PID: dead
- Severity: P2
- Status: needs-investigation
=== write_blocker: an empty extra is no line
--- stdout
--- stderr
rc=0
--- metrics
{"event":"task_blocked","task_id":"T-4","reason":"review-rejected","class":"review-rejected","at":"2026-10-19T00:00:00+00:00"}
--- blockers.md

## 2026-10-19 00:00 · T-4

- Spec: spec#t-4
- Failure: review-rejected
- Class: review-rejected
- Log: log
- Severity: P2
- Status: needs-investigation
=== write_blocker: classifies from CURRENT_TASK_LOG, not <log-path>
--- stdout
--- stderr
rc=0
--- metrics
{"event":"task_blocked","task_id":"T-5","reason":"agent-execution-failed","class":"timeout","at":"2026-10-19T00:00:00+00:00"}
--- blockers.md

## 2026-10-19 00:00 · T-5

- Spec: spec#t-5
- Failure: agent-execution-failed
- Class: timeout
- Log: /elsewhere.log
- Severity: P2
- Status: needs-investigation
=== write_blocker: LAST_AGENT_EXIT=124
--- stdout
--- stderr
rc=0
--- metrics
{"event":"task_blocked","task_id":"T-6","reason":"agent-execution-failed","class":"timeout","at":"2026-10-19T00:00:00+00:00"}
--- blockers.md

## 2026-10-19 00:00 · T-6

- Spec: spec#t-6
- Failure: agent-execution-failed
- Class: timeout
- Log: log
- Severity: P2
- Status: needs-investigation
=== write_blocker: a reason with quotes and spaces
--- stdout
--- stderr
rc=0
--- metrics
{"event":"task_blocked","task_id":"QUEUE-GUARD","reason":"foreign queue.txt write: "x" changed","class":"blocked","at":"2026-10-19T00:00:00+00:00"}
--- blockers.md

## 2026-10-19 00:00 · QUEUE-GUARD

- Spec: q.txt
- Failure: foreign queue.txt write: "x" changed
- Class: blocked
- Log: n/a
- Severity: P2
- Status: needs-investigation
=== write_blocker: appends rows to an existing ledger
--- stdout
--- stderr
rc=0
--- metrics
{"event":"task_blocked","task_id":"T-7","reason":"blocked-dependencies","class":"blocked","at":"2026-10-19T00:00:00+00:00"}
{"event":"task_blocked","task_id":"T-8","reason":"qa-failed","class":"test-fail","at":"2026-10-19T00:00:00+00:00"}
--- blockers.md
# Blockers

## 2026-10-19 00:00 · T-7

- Spec: spec#t-7
- Failure: blocked-dependencies
- Class: blocked
- Log: l1
- Severity: P2
- Status: needs-investigation

## 2026-10-19 00:00 · T-8

- Spec: spec#t-8
- Failure: qa-failed
- Class: test-fail
- Log: l2
- Severity: P2
- Status: needs-investigation
=== write_blocker: an unwritable ledger
--- stdout
--- stderr
<where>: <SB>/no/such/dir/blockers.md: No such file or directory
rc=0
--- metrics
{"event":"task_blocked","task_id":"T-9","reason":"test-fail","class":"test-fail","at":"2026-10-19T00:00:00+00:00"}
=== write_blocker: missing positional args under set -u
--- stdout
--- stderr
<where>: $3: unbound variable
rc=1
=== write_blocker: a lane child journals the row instead
--- stdout
CALL lane_journal_record [blocker] [T-11] [spec#t-11] [test-fail] [l] [- Lane: 2]
CALL lane_journal_record [blocker] [T-12] [spec#t-12] [gate:lint] [l] []
--- stderr
rc=0
