wait-discipline: no retry/resume protocol for transient API errors or quota stalls #46

Open
opened 2026-08-14 13:01:52 +00:00 by jbr870 · 110 comments
Owner

PREQ: Run supervisor — out-of-run resume and liveness watch for the unattended driver

Created: 2026-08-25

History. This issue began as a retrospective finding (rank 10 of 13 in #37; promoted
watchlist RC-W2). The in-run half shipped as a meta-amend: wait-discipline §3a (bounded retry
for transient calls, scheduled wait against a stated quota reset) and phase-runner §5
(re-dispatch of a runner killed by a transient error), commit 2ceacfe. The amendment's
desk-check (comment 1393) found original AC2 — "an unattended run that hits a 529 resumes
without operator input"
— structurally unreachable from inside the session and routed the
remainder here. This PREQ is that remainder: the out-of-run supervisor.

Problem

An operator running an unattended pipeline run loses the run whenever the driver session's
own turn
is ended by a self-clearing condition. Nothing inside the session can retry a call the
session never got to make — by the time the error exists, there is no turn left to run the retry
in. The run then sits dead until a human happens to look.

Two recorded incidents, one shape:

  • Transient API error: /dev:integrate hit API Error: 529 Overloaded and stopped; 8m 47s
    of dead time until the operator typed "Try again" — recovered only because a human was watching.
  • Quota exhaustion with a stated reset: a usage-quota kill cost ~3h 17m past the stated
    reset
    because nothing was scheduled against it (verity slot5-164 / slot2-167).

Users:

  • Primary: the operator who starts an unattended run and walks away — they need the run to
    survive self-clearing stalls without them.
  • Secondary: the retrospective reader, who needs stalls and their handling to be auditable
    from the run's durable record rather than indistinguishable from slowness.

Current state: wait-discipline §3a covers every call made inside a live turn, and
phase-runner §5 re-dispatches a runner that dies. A dead driver turn is a documented
limitation: "a stop that costs whatever the operator's absence costs."

Proposed Solution

A supervisor that lives outside the driver session and watches an unattended run. Supervision
is opt-in at run launch — the operator engages the supervisor when starting an unattended
run; it is never inferred onto an attended session.

The resumability rule (definitional, settled by review). A run is resumable when there is
positive evidence that no turn is in flight and the last turn ended on a self-clearing
cause
— a transient error or a quota/rate-limit kill. An idle session whose turn died on a 529
is resumable (that is the founding incident); a session that may still be mid-turn is not, and an
operator-initiated stop is never a self-clearing cause and is never auto-resumed. "Dead"
(session gone) and "idle turn-end" both resume; "possibly mid-work" only alerts.

  • Transient cause (explicitly: HTTP 429/500/502/503/529 and harness-reported
    transient/overload errors — classified by the rule below, not an open-ended family): resume
    with bounded, backoff-spaced attempts; when the bound is exhausted, escalate naming the
    attempt count. The bound is per incident — a later, distinct incident gets a fresh bound.
  • Quota/rate-limit exhaustion with a stated reset: record the reset time and schedule the
    resume against it
    — never a guessed interval. A reset time already in the past resumes
    immediately. Classification rule: a stated reset/retry-after accompanies the error →
    scheduled path; otherwise → bounded-retry path (this settles 429's double role).
  • Stalled but not resumable (progress stopped, but no positive evidence the turn is over):
    alert-only. The supervisor surfaces the stall and never writes into the session.
  • Lifecycle: the supervisor attaches at launch, stands down when the run completes
    normally
    , and at most one supervisor watches a given run (a second attach is refused).
  • Resume lands in the existing resume discipline: a resumed driver re-verifies in-flight
    mutations before trusting the tree (wait-discipline rule 5), and when the project declares a
    post-resume claims-reconstruction step, the resume path invokes it. The semantics of
    reclaiming open claims are #65's, defined once #43's ledger lands — this feature only provides
    the hook.
  • Alerts and records: every intervention and escalation is written to the run's durable
    forge record
    (the project's declared run-traceability surface); when the project declares a
    notification channel, escalations are additionally delivered through it.
  • Tunables are declared, with suite defaults: retry bound, backoff shape, and stall
    threshold ship as stated suite defaults which a project may override in a declared
    configuration block; the values in force are the ones the acceptance criteria are judged
    against.

Scope: Full (supervisor + liveness watch, alert-only on ambiguity) — chosen over
quota-only-minimal, over notify-only (challenged by review; rejected because an unattended
overnight run has nobody reachable to receive the notification — the quota incident lost 3h 17m
for exactly that reason), and over absorb-#65 (reclaim semantics depend on #43's in-flight
ledger).

User Stories

  • As an operator, I want a driver whose turn was killed by a transient error to be resumed
    automatically with bounded retries, so that an unattended run survives a 529 without me
    watching.
  • As an operator, I want a quota-killed run to resume at the stated reset time, so that no run
    time is lost past a reset the platform already told us about.
  • As an operator, I want a stalled-but-possibly-working driver surfaced to me rather than
    nudged, so that wedged runs become visible without risking duplicate work from double-driving.
  • As a retrospective reader, I want every supervisor intervention recorded with the run, so that
    a stall and its handling are auditable and distinguishable from mere slowness.

Acceptance Criteria

  • Given a supervised unattended run whose driver turn ends on a transient error (per the
    classification rule), when the supervisor detects the run is resumable, then the run is
    resumed without operator input, with attempts bounded and backoff-spaced per the declared
    (or default) values.
  • Given the per-incident retry bound is exhausted without a successful resume, when the last
    attempt fails, then the supervisor stops retrying and escalates, naming the attempt count
    and the error.
  • Given a driver killed by quota exhaustion with a stated reset time, when the supervisor
    detects it, then the reset time is recorded and the resume is scheduled against that time
    (immediately, if the reset is already past), and the run resumes without operator input.
  • Given a quota kill with no discoverable reset time, when the supervisor detects it, then
    it follows the bounded-retry path per the classification rule, escalating on exhaustion
    with what it observed.
  • Given a driver that stops making progress without positive evidence that its turn is over,
    when the declared (or default) stall threshold passes, then the supervisor escalates and
    does not resume, nudge, or otherwise write into the session.
  • Given any resume, when the supervisor starts it, then the resumability rule held: positive
    evidence of no turn in flight, a self-clearing cause, and not an operator-initiated stop.
  • Given a supervised run that completes normally, when the driver finishes, then the
    supervisor stands down without intervening, and this is visible in the run's record.
  • Given a run that already has a supervisor attached, when a second supervisor attempts to
    attach, then the attach is refused — at most one supervisor per run.
  • Given the supervisor cannot read the driver's state or cannot trigger a resume (the
    harness surface is unavailable or refuses), when it detects this, then it escalates with
    what it observed rather than acting on ambiguity.
  • Given a project that declares a post-resume claims-reconstruction step, when the
    supervisor resumes a run, then that step is invoked before phase work continues (the
    step's own semantics are #65, out of scope here).
  • Given any supervisor intervention or escalation (detection, each retry, a scheduled
    resume, a stall alert, a stand-down), when it happens, then it is written to the run's
    durable forge record — and additionally delivered via the project's declared notification
    channel, when one is declared.

Out of Scope

  • Reclaim semantics for open claims — who may reclaim, on what evidence (#65; interfaced via
    the post-resume hook, not absorbed; depends on #43's ledger).
  • Nudging or resuming a session without positive evidence its turn is over — alert-only by
    decision; revisit only with evidence that alert-only strands wedged runs.
  • Supervisor high-availability — a crashed supervisor (or host reboot mid-run, including
    across a scheduled quota resume) is not itself supervised. The recursion stops here,
    deliberately: the supervisor is the safety net, not a guaranteed one. Its absence is visible
    in the run record (interventions stop appearing).
  • Attended/interactive sessions — the human present is the supervisor; supervision is
    opt-in at unattended launch only.
  • In-run retry behavior — shipped in wait-discipline §3a (2ceacfe).
  • Supervising phase-runner subagents — covered by phase-runner §5 re-dispatch.

Dependencies

  • wait-discipline §3a + phase-runner §5 (landed, 2ceacfe): this feature completes the
    escalation story those sections explicitly defer to "a supervisor outside the run."
  • External system of record: the harness that hosts driver sessions. The supervisor reads
    session/turn state and triggers resumes through whatever surface the harness actually offers —
    its real contract must be verified before design (/dev:technical-plan §2.2b), not assumed. This
    is the load-bearing feasibility risk for every resume AC; see Notes.
  • #65 (related, non-blocking): defines the reclaim semantics the post-resume hook will
    invoke; itself downstream of #43's claims ledger (in flight).
  • Portability baseline (CLAUDE.md): the supervisor is suite glue — POSIX-baseline shell plus
    the bash/jq helper tier; nothing stack- or project-specific baked in. The declared tunables
    block must obey the declared-block parseability rules (scalars + flat lists).

Timeline

Milestone Date Notes
Requirements complete 2026-08-25
Development complete
QA complete
UAT approved

Notes

  • Constraints: unattended runs only, opt-in at launch; resumes only under the resumability
    rule; stack-agnostic per the suite's portability baseline.
  • Open questions / known risk: the harness's session-state and resume surface is unverified
    — every resume AC presupposes it. /dev:technical-plan §2.2b must verify the real contract
    before design; if the surface cannot support positive turn-state evidence, the feature falls
    back to notify-only and this PREQ returns for re-scoping.
  • Validation note: every AC's Given requires inducing a driver death/stall; the test plan
    must state how each condition is induced or simulated — an AC only checkable by waiting for a
    real 529 is not a testable case.
  • Key decisions: scope = Full over quota-only-minimal, notify-only (panel's simpler
    alternative — rejected: unattended means nobody receives the notification for hours), and
    don't-build; #65 interfaced (hook), not absorbed; liveness = alert-only; resumable = idle
    turn-end on a self-clearing cause (settles the panel's AC1-vs-AC6 contradiction — the
    founding incident is resumable, operator stops never are); tunables declared with suite
    defaults; alerts = forge record always + declared channel when present.
# PREQ: Run supervisor — out-of-run resume and liveness watch for the unattended driver **Created:** 2026-08-25 > **History.** This issue began as a retrospective finding (rank 10 of 13 in #37; promoted > watchlist RC-W2). The in-run half shipped as a meta-amend: wait-discipline §3a (bounded retry > for transient calls, scheduled wait against a stated quota reset) and phase-runner §5 > (re-dispatch of a runner killed by a transient error), commit `2ceacfe`. The amendment's > desk-check (comment 1393) found original AC2 — *"an unattended run that hits a 529 resumes > without operator input"* — structurally unreachable from inside the session and routed the > remainder here. This PREQ is that remainder: the out-of-run supervisor. ## Problem An operator running an **unattended pipeline run** loses the run whenever the **driver session's own turn** is ended by a self-clearing condition. Nothing inside the session can retry a call the session never got to make — by the time the error exists, there is no turn left to run the retry in. The run then sits dead until a human happens to look. Two recorded incidents, one shape: - **Transient API error:** `/dev:integrate` hit `API Error: 529 Overloaded` and stopped; 8m 47s of dead time until the operator typed "Try again" — recovered only because a human was watching. - **Quota exhaustion with a stated reset:** a usage-quota kill cost **~3h 17m past the stated reset** because nothing was scheduled against it (verity slot5-164 / slot2-167). **Users:** - **Primary:** the operator who starts an unattended run and walks away — they need the run to survive self-clearing stalls without them. - **Secondary:** the retrospective reader, who needs stalls and their handling to be auditable from the run's durable record rather than indistinguishable from slowness. **Current state:** wait-discipline §3a covers every call made *inside* a live turn, and phase-runner §5 re-dispatches a *runner* that dies. A dead **driver** turn is a documented limitation: "a stop that costs whatever the operator's absence costs." ## Proposed Solution A **supervisor that lives outside the driver session** and watches an unattended run. Supervision is **opt-in at run launch** — the operator engages the supervisor when starting an unattended run; it is never inferred onto an attended session. **The resumability rule (definitional, settled by review).** A run is *resumable* when there is **positive evidence that no turn is in flight** and the last turn **ended on a self-clearing cause** — a transient error or a quota/rate-limit kill. An idle session whose turn died on a 529 is resumable (that is the founding incident); a session that may still be mid-turn is not, and an **operator-initiated stop is never a self-clearing cause and is never auto-resumed**. "Dead" (session gone) and "idle turn-end" both resume; "possibly mid-work" only alerts. - **Transient cause** (explicitly: HTTP 429/500/502/503/529 and harness-reported transient/overload errors — classified by the rule below, not an open-ended family): resume with **bounded, backoff-spaced attempts**; when the bound is exhausted, escalate naming the attempt count. The bound is **per incident** — a later, distinct incident gets a fresh bound. - **Quota/rate-limit exhaustion with a stated reset:** record the reset time and **schedule the resume against it** — never a guessed interval. A reset time already in the past resumes immediately. **Classification rule:** a stated reset/retry-after accompanies the error → scheduled path; otherwise → bounded-retry path (this settles 429's double role). - **Stalled but not resumable** (progress stopped, but no positive evidence the turn is over): **alert-only.** The supervisor surfaces the stall and never writes into the session. - **Lifecycle:** the supervisor attaches at launch, **stands down when the run completes normally**, and **at most one supervisor watches a given run** (a second attach is refused). - **Resume lands in the existing resume discipline:** a resumed driver re-verifies in-flight mutations before trusting the tree (wait-discipline rule 5), and when the project declares a post-resume claims-reconstruction step, the resume path invokes it. The *semantics* of reclaiming open claims are #65's, defined once #43's ledger lands — this feature only provides the hook. - **Alerts and records:** every intervention and escalation is **written to the run's durable forge record** (the project's declared run-traceability surface); when the project declares a notification channel, escalations are additionally delivered through it. - **Tunables are declared, with suite defaults:** retry bound, backoff shape, and stall threshold ship as stated suite defaults which a project may override in a declared configuration block; the values in force are the ones the acceptance criteria are judged against. **Scope:** Full (supervisor + liveness watch, alert-only on ambiguity) — chosen over quota-only-minimal, over notify-only (challenged by review; rejected because an unattended overnight run has nobody reachable to receive the notification — the quota incident lost 3h 17m for exactly that reason), and over absorb-#65 (reclaim semantics depend on #43's in-flight ledger). ## User Stories - As an operator, I want a driver whose turn was killed by a transient error to be resumed automatically with bounded retries, so that an unattended run survives a 529 without me watching. - As an operator, I want a quota-killed run to resume at the stated reset time, so that no run time is lost past a reset the platform already told us about. - As an operator, I want a stalled-but-possibly-working driver surfaced to me rather than nudged, so that wedged runs become visible without risking duplicate work from double-driving. - As a retrospective reader, I want every supervisor intervention recorded with the run, so that a stall and its handling are auditable and distinguishable from mere slowness. ## Acceptance Criteria - [ ] Given a supervised unattended run whose driver turn ends on a transient error (per the classification rule), when the supervisor detects the run is resumable, then the run is resumed without operator input, with attempts bounded and backoff-spaced per the declared (or default) values. - [ ] Given the per-incident retry bound is exhausted without a successful resume, when the last attempt fails, then the supervisor stops retrying and escalates, naming the attempt count and the error. - [ ] Given a driver killed by quota exhaustion with a stated reset time, when the supervisor detects it, then the reset time is recorded and the resume is scheduled against that time (immediately, if the reset is already past), and the run resumes without operator input. - [ ] Given a quota kill with no discoverable reset time, when the supervisor detects it, then it follows the bounded-retry path per the classification rule, escalating on exhaustion with what it observed. - [ ] Given a driver that stops making progress without positive evidence that its turn is over, when the declared (or default) stall threshold passes, then the supervisor escalates and does **not** resume, nudge, or otherwise write into the session. - [ ] Given any resume, when the supervisor starts it, then the resumability rule held: positive evidence of no turn in flight, a self-clearing cause, and not an operator-initiated stop. - [ ] Given a supervised run that completes normally, when the driver finishes, then the supervisor stands down without intervening, and this is visible in the run's record. - [ ] Given a run that already has a supervisor attached, when a second supervisor attempts to attach, then the attach is refused — at most one supervisor per run. - [ ] Given the supervisor cannot read the driver's state or cannot trigger a resume (the harness surface is unavailable or refuses), when it detects this, then it escalates with what it observed rather than acting on ambiguity. - [ ] Given a project that declares a post-resume claims-reconstruction step, when the supervisor resumes a run, then that step is invoked before phase work continues (the step's own semantics are #65, out of scope here). - [ ] Given any supervisor intervention or escalation (detection, each retry, a scheduled resume, a stall alert, a stand-down), when it happens, then it is written to the run's durable forge record — and additionally delivered via the project's declared notification channel, when one is declared. ## Out of Scope - **Reclaim semantics for open claims** — who may reclaim, on what evidence (#65; interfaced via the post-resume hook, not absorbed; depends on #43's ledger). - **Nudging or resuming a session without positive evidence its turn is over** — alert-only by decision; revisit only with evidence that alert-only strands wedged runs. - **Supervisor high-availability** — a crashed supervisor (or host reboot mid-run, including across a scheduled quota resume) is not itself supervised. The recursion stops here, deliberately: the supervisor is the safety net, not a guaranteed one. Its absence is visible in the run record (interventions stop appearing). - **Attended/interactive sessions** — the human present *is* the supervisor; supervision is opt-in at unattended launch only. - **In-run retry behavior** — shipped in wait-discipline §3a (2ceacfe). - **Supervising phase-runner subagents** — covered by phase-runner §5 re-dispatch. ## Dependencies - **wait-discipline §3a + phase-runner §5 (landed, `2ceacfe`):** this feature completes the escalation story those sections explicitly defer to "a supervisor outside the run." - **External system of record: the harness that hosts driver sessions.** The supervisor reads session/turn state and triggers resumes through whatever surface the harness actually offers — its real contract must be verified before design (/dev:technical-plan §2.2b), not assumed. This is the load-bearing feasibility risk for every resume AC; see Notes. - **#65 (related, non-blocking):** defines the reclaim semantics the post-resume hook will invoke; itself downstream of #43's claims ledger (in flight). - **Portability baseline (CLAUDE.md):** the supervisor is suite glue — POSIX-baseline shell plus the bash/jq helper tier; nothing stack- or project-specific baked in. The declared tunables block must obey the declared-block parseability rules (scalars + flat lists). ## Timeline | Milestone | Date | Notes | |-----------|------|-------| | Requirements complete | 2026-08-25 | | | Development complete | | | | QA complete | | | | UAT approved | | | ## Notes - **Constraints:** unattended runs only, opt-in at launch; resumes only under the resumability rule; stack-agnostic per the suite's portability baseline. - **Open questions / known risk:** the harness's session-state and resume surface is unverified — every resume AC presupposes it. /dev:technical-plan §2.2b must verify the real contract before design; if the surface cannot support positive turn-state evidence, the feature falls back to notify-only and this PREQ returns for re-scoping. - **Validation note:** every AC's Given requires inducing a driver death/stall; the test plan must state how each condition is induced or simulated — an AC only checkable by waiting for a real 529 is not a testable case. - **Key decisions:** scope = Full over quota-only-minimal, notify-only (panel's simpler alternative — rejected: unattended means nobody receives the notification for hours), and don't-build; #65 interfaced (hook), not absorbed; liveness = alert-only; resumable = idle turn-end on a self-clearing cause (settles the panel's AC1-vs-AC6 contradiction — the founding incident is resumable, operator stops never are); tunables declared with suite defaults; alerts = forge record always + declared channel when present.
Author
Owner

/meta-amend outcome — protocol written; issue stays OPEN on AC2

Commit 2ceacfe on main. AC1 and AC3 met; AC2 partly met and honestly not reachable from skill text — see the last section.

Verified at HEAD (3b82a77)

The gap held. wait-discipline.md rule 3 ("A stall is a decision point, not an exit") enumerated three dispositions — act, escalate, or report-and-stop on a session/usage kill — all of which assume the stall needs a human or ends the run. Nothing covered "the call failed for a reason that will clear on its own." The third bullet came closest and pointed the wrong way: it says say-so-and-stop, where the right answer for a quota reset is wait-and-continue.

The amendment

New §3a — "A self-clearing stall is waited out — not escalated, and not stopped on", with the two cases distinguished as AC1 asks:

  • Transient error from a call the skill makes (the 429/500/503/529 family — forge API, registry, network): bounded retry with growing backoff, then escalate naming the attempt count. Written as a pair of failures to avoid: "One attempt is not a retry and infinite attempts are not a protocol."
  • Quota/rate-limit exhaustion with a stated reset (AC3): record the reset time when you see it and wait against that time, using rule 2's bounded loop or whatever scheduled resume the harness offers — not a guessed interval. The prior sighting is cited for why the distinction matters: ~3h 17m lost past the stated reset, with the lead about to sleep another guessed interval.
  • Either way it goes in the next report — attempts, wait duration, what cleared it. Rationale in the text: a run that silently absorbed a twenty-minute stall is indistinguishable from one that was merely slow, and neither the operator nor the next retrospective can separate them.

phase-runner.md §5 now names a transient API error as one of the causes its existing re-dispatch already covers — and makes the consequence explicit: that re-dispatch is the unattended resume for dispatched phase work. Plus two specifics: name the error in the appended line (so three transient failures are distinguishable from slowness), and wait out a stated reset rather than burning the single retry against a wall.

Gate

scripts/lint-conventions.sh — clean.

Desk-check against the originating scenario

Recorded Under the amended text
Quota kill, ~3h 17m lost after the stated reset, nothing scheduled §3a case 2: the reset time is recorded when seen and waited against with rule 2's bounded loop. Directly covered — this is AC3
A phase runner killed mid-phase by a transient error phase-runner.md §5 re-dispatches once; phases resume from the latest Phase Outcome, so the resume is unattended. Covered
A forge/helper call returning 503 §3a case 1: bounded retry, then escalate with the count. Covered
/dev:integrate stopped by a 529 on 2026-08-14, 8m 47s of dead time until the operator typed "Try again" Not covered. See below

AC2 — why this issue stays open

"An unattended run that hits a 529 resumes without operator input."

Met for phase work executed in a dispatched runner: the driver survives, sees the runner die, and re-dispatches. Not met for the case actually recorded, which is the driver's own turn being ended by the harness. Nothing inside a session can retry a call that session never got to make — by the time the error exists, there is no turn left to run the retry in. That needs a supervisor outside the run (a re-prompting wrapper, a scheduled resume, a background driver), which is a capability, not a text amendment, and outside this lane.

I have written that limitation into the procedure rather than leaving it implicit, so a reader does not infer coverage that isn't there — and paired it with the one thing text can do in that case: say so in the report, so the stall does not read as slowness.

Remaining work on this issue: decide whether the suite wants an out-of-run supervisor for the driver, and if so route it to /dev:requirements. That is a scope call, not an amendment. Everything else here is done.

What validates it next

For the covered half: the next run that hits a transient error in a helper call or a dispatched runner — the signal is an attempt count appearing in a phase report rather than a stop. For AC3 specifically, the next quota stall; the bar is that the reset time appears in the record and the wait is measured against it rather than guessed.

## /meta-amend outcome — protocol written; issue stays OPEN on AC2 Commit `2ceacfe` on `main`. **AC1 and AC3 met; AC2 partly met and honestly not reachable from skill text — see the last section.** ### Verified at HEAD (`3b82a77`) The gap held. `wait-discipline.md` rule 3 (*"A stall is a decision point, not an exit"*) enumerated three dispositions — act, escalate, or report-and-stop on a session/usage kill — all of which assume the stall needs a human or ends the run. Nothing covered *"the call failed for a reason that will clear on its own."* The third bullet came closest and pointed the wrong way: it says say-so-and-stop, where the right answer for a quota reset is wait-and-continue. ### The amendment New **§3a — "A self-clearing stall is waited out — not escalated, and not stopped on"**, with the two cases distinguished as AC1 asks: - **Transient error from a call the skill makes** (the 429/500/503/529 family — forge API, registry, network): **bounded retry with growing backoff**, then escalate *naming the attempt count*. Written as a pair of failures to avoid: *"One attempt is not a retry and infinite attempts are not a protocol."* - **Quota/rate-limit exhaustion with a stated reset** (AC3): record the reset time when you see it and wait **against that time**, using rule 2's bounded loop or whatever scheduled resume the harness offers — not a guessed interval. The prior sighting is cited for why the distinction matters: ~3h 17m lost *past the stated reset*, with the lead about to sleep another guessed interval. - **Either way it goes in the next report** — attempts, wait duration, what cleared it. Rationale in the text: a run that silently absorbed a twenty-minute stall is indistinguishable from one that was merely slow, and neither the operator nor the next retrospective can separate them. **`phase-runner.md` §5** now names a transient API error as one of the causes its existing re-dispatch already covers — and makes the consequence explicit: **that re-dispatch *is* the unattended resume** for dispatched phase work. Plus two specifics: name the error in the appended line (so three transient failures are distinguishable from slowness), and wait out a stated reset rather than burning the single retry against a wall. ### Gate `scripts/lint-conventions.sh` — clean. ### Desk-check against the originating scenario | Recorded | Under the amended text | |---|---| | Quota kill, ~3h 17m lost *after* the stated reset, nothing scheduled | §3a case 2: the reset time is recorded when seen and waited against with rule 2's bounded loop. Directly covered — this is AC3 | | A phase runner killed mid-phase by a transient error | `phase-runner.md` §5 re-dispatches once; phases resume from the latest Phase Outcome, so the resume is unattended. Covered | | A forge/helper call returning 503 | §3a case 1: bounded retry, then escalate with the count. Covered | | **`/dev:integrate` stopped by a `529` on 2026-08-14, 8m 47s of dead time until the operator typed "Try again"** | **Not covered.** See below | ### AC2 — why this issue stays open *"An unattended run that hits a 529 resumes without operator input."* Met for phase work executed in a dispatched runner: the driver survives, sees the runner die, and re-dispatches. **Not met for the case actually recorded**, which is the driver's own turn being ended by the harness. Nothing inside a session can retry a call that session never got to make — by the time the error exists, there is no turn left to run the retry in. That needs a **supervisor outside the run** (a re-prompting wrapper, a scheduled resume, a background driver), which is a capability, not a text amendment, and outside this lane. I have written that limitation into the procedure rather than leaving it implicit, so a reader does not infer coverage that isn't there — and paired it with the one thing text *can* do in that case: say so in the report, so the stall does not read as slowness. **Remaining work on this issue:** decide whether the suite wants an out-of-run supervisor for the driver, and if so route it to `/dev:requirements`. That is a scope call, not an amendment. Everything else here is done. ### What validates it next For the covered half: the next run that hits a transient error in a helper call or a dispatched runner — the signal is an attempt count appearing in a phase report rather than a stop. For AC3 specifically, the next quota stall; the bar is that the reset time appears in the record and the wait is measured against it rather than guessed.
Author
Owner

Linked: this issue is relates_to #65 (recorded by the devwork pipeline).

Linked: this issue is **relates_to** #65 (recorded by the devwork pipeline).
Author
Owner

Test Plan: run-supervisor (issue #46)

Prerequisites

The state the scenarios need (how each condition is induced/simulated is stated per scenario in
plain terms; the concrete mechanism is decided at design time — the PREQ requires only that every
condition be inducible rather than waited for):

  • A project with the pipeline configured, on which an unattended run can be started with
    supervision engaged at launch (supervision is opt-in at launch)
  • A way to end the driver's turn with a simulated transient error (429/500/502/503/529-class)
  • A way to end the driver's turn with a simulated quota kill — one variant carrying a stated
    reset time, one carrying none
  • A way to make the driver stop making progress without ending its turn (simulated stall)
  • A project declaration carrying overridden supervisor tunables (retry bound, backoff, stall
    threshold), and a second setup with no override (suite defaults in force)
  • A project declaration naming a notification channel, and a second setup with none declared
  • A project declaring a post-resume claims-reconstruction step whose invocation leaves a
    visible trace, and a second setup with no such step declared

Required Test Data

  • One supervised unattended run per scenario (scenarios are independent; each starts its own)
  • Access to the run's durable forge record, to inspect what the supervisor wrote

Test Scenarios

Scenario 1: Transient turn-death is resumed automatically

Acceptance criterion: "Given a supervised unattended run whose driver turn ends on a transient error (per the classification rule), when the supervisor detects the run is resumable, then the run is resumed without operator input, with attempts bounded and backoff-spaced per the declared (or default) values."

  1. Start a supervised unattended run; walk away (no operator input from here on)
  2. Induce a transient error that ends the driver's turn (e.g. simulated 529)
  3. Verify: the run resumes and continues its work with no operator input
  4. Verify: the run's record shows the detection and the resume, including the attempt number
  5. Verify: if more than one attempt was needed, the gaps between attempts grow, and attempt
    spacing is consistent with the values in force (defaults, in this setup)

Expected outcome: the run finishes its phase work as if the stall had been mere slowness; the record distinguishes it from slowness.

Scenario 2: Retry bound exhausted → escalation naming the count

Acceptance criterion: "Given the per-incident retry bound is exhausted without a successful resume, when the last attempt fails, then the supervisor stops retrying and escalates, naming the attempt count and the error."

  1. Start a supervised unattended run
  2. Induce a transient turn-death that keeps recurring so every resume attempt fails
  3. Verify: attempts stop after the bound in force is reached (count the recorded attempts)
  4. Verify: an escalation is recorded naming the attempt count and the error observed
  5. Verify: no further attempts appear after the escalation

Expected outcome: bounded behavior — neither a single give-up nor an infinite loop; the operator can read exactly what was tried.

Scenario 3: Quota kill with stated reset → scheduled resume

Acceptance criterion: "Given a driver killed by quota exhaustion with a stated reset time, when the supervisor detects it, then the reset time is recorded and the resume is scheduled against that time (immediately, if the reset is already past), and the run resumes without operator input."

  1. Start a supervised unattended run
  2. Induce a quota kill carrying a stated reset time a few minutes in the future
  3. Verify: the stated reset time appears in the run's record at detection time
  4. Verify: the run does not resume before the reset time
  5. Verify: the run resumes at/promptly after the reset time with no operator input

Expected outcome: the wait is measured against the platform's own reset, not guessed; zero time lost past the reset beyond ordinary latency.

Scenario 4: Quota kill with a reset already past → immediate resume

Acceptance criterion: same as Scenario 3 (the "immediately, if the reset is already past" clause).

  1. Start a supervised unattended run
  2. Induce a quota kill whose stated reset time is already in the past
  3. Verify: the recorded reset time appears in the record, and the resume happens immediately

Expected outcome: no wait against a wall that has already fallen.

Scenario 5: Quota kill with no discoverable reset → bounded-retry path

Acceptance criterion: "Given a quota kill with no discoverable reset time, when the supervisor detects it, then it follows the bounded-retry path per the classification rule, escalating on exhaustion with what it observed."

  1. Start a supervised unattended run
  2. Induce a quota kill carrying no reset time
  3. Verify: the supervisor retries per the bounded-retry path (attempts recorded, spaced, bounded)
  4. If exhausted: verify the escalation states what was observed (a quota kill, no reset found)

Expected outcome: no blind polling and no silent stop; the classification rule's else-branch is visibly taken.

Scenario 6: Stalled but possibly mid-work → alert only, no writes

Acceptance criterion: "Given a driver that stops making progress without positive evidence that its turn is over, when the declared (or default) stall threshold passes, then the supervisor escalates and does not resume, nudge, or otherwise write into the session."

  1. Start a supervised unattended run
  2. Make the driver stop progressing without ending its turn
  3. Wait past the stall threshold in force
  4. Verify: an alert is recorded (and delivered via the declared channel, if this setup has one)
  5. Verify: nothing was written into the driver session — no resume, no nudge; the session's
    state is exactly as the stall left it

Expected outcome: the wedged run becomes visible; the supervisor never risks double-driving a session that might still be working.

Scenario 7: Operator-initiated stop is never auto-resumed

Acceptance criterion: "Given any resume, when the supervisor starts it, then the resumability rule held: positive evidence of no turn in flight, a self-clearing cause, and not an operator-initiated stop."

  1. Start a supervised unattended run
  2. Stop the run deliberately, as the operator would (an intentional interrupt/stop)
  3. Wait past every threshold in force
  4. Verify: the supervisor does not resume the run
  5. Cross-check with Scenarios 1 and 3: every resume that did happen has, in the record, the
    evidence that no turn was in flight and the self-clearing cause it acted on

Expected outcome: a human's decision to stop a run is final for the supervisor; resumes happen only on recorded positive evidence.

Scenario 8: Clean completion → supervisor stands down

Acceptance criterion: "Given a supervised run that completes normally, when the driver finishes, then the supervisor stands down without intervening, and this is visible in the run's record."

  1. Start a supervised unattended run that will complete without incident
  2. Let it finish
  3. Verify: the record shows the supervisor standing down after completion
  4. Verify: no interventions were recorded during the run

Expected outcome: supervision of a healthy run is invisible except for its stand-down entry.

Scenario 9: Second attach refused

Acceptance criterion: "Given a run that already has a supervisor attached, when a second supervisor attempts to attach, then the attach is refused — at most one supervisor per run."

  1. Start a supervised unattended run
  2. Attempt to engage a second supervisor on the same run
  3. Verify: the second attach is refused with a message naming the existing supervision
  4. Verify: the run continues under exactly one supervisor (induce a transient turn-death and
    confirm exactly one resume happens)

Expected outcome: no double-resume is possible from doubled supervision.

Scenario 10: Harness surface unavailable → escalate, don't act

Acceptance criterion: "Given the supervisor cannot read the driver's state or cannot trigger a resume (the harness surface is unavailable or refuses), when it detects this, then it escalates with what it observed rather than acting on ambiguity."

  1. Start a supervised unattended run
  2. Make the driver-state surface unreadable to the supervisor (unavailable or refusing)
  3. Induce a driver turn-death while the surface is unreadable
  4. Verify: no resume is attempted
  5. Verify: an escalation is recorded stating that the state surface was unreadable and what was
    observed

Expected outcome: blindness is treated as ambiguity — surfaced loudly, never acted on.

Scenario 11: Declared post-resume reconstruction step is invoked

Acceptance criterion: "Given a project that declares a post-resume claims-reconstruction step, when the supervisor resumes a run, then that step is invoked before phase work continues."

  1. On the setup whose declaration includes a post-resume step with a visible trace, start a
    supervised unattended run
  2. Induce a transient turn-death; let the supervisor resume
  3. Verify: the declared step's trace appears, and it appears before the run's next phase work
  4. On the setup with no declared step: repeat 1–2 and verify the resume proceeds with no such
    invocation and no error about its absence

Expected outcome: the hook fires when declared, is a no-op when not, and always precedes resumed phase work.

Scenario 12: Everything is on the record; channel delivery when declared

Acceptance criterion: "Given any supervisor intervention or escalation …, when it happens, then it is written to the run's durable forge record — and additionally delivered via the project's declared notification channel, when one is declared."

  1. Re-inspect the runs from Scenarios 1, 2, 3, 6, and 8
  2. Verify: every detection, attempt, scheduled resume, alert, and stand-down those scenarios
    produced appears in the run's durable forge record, legible to a reader who was not present
  3. On the setup with a declared notification channel, induce one escalation and verify it
    arrives on that channel as well as in the record
  4. On the setup with no declared channel, induce one escalation and verify the record alone
    carries it, completely

Expected outcome: a retrospective reader can reconstruct every stall and its handling from the record; the channel is additive, never the only copy.

Scenario 13: Declared tunables are the values in force

Acceptance criterion: the "per the declared (or default) values" clauses of the retry and stall criteria.

  1. On the setup with overridden tunables (a retry bound and stall threshold different from the
    suite defaults), run Scenario 2's steps and Scenario 6's steps
  2. Verify: the attempt count at exhaustion matches the declared bound, not the default
  3. Verify: the stall alert fires against the declared threshold, not the default

Expected outcome: the declaration is honored; the acceptance criteria are judged against whichever values are in force.

Notes

  • Scenarios deliberately avoid naming how turn-death, quota kills, stalls, or an unreadable
    harness surface are induced — the PREQ requires them inducible; the mechanism is a design
    decision and will be named when lanes are annotated.
  • No browser surface exists in this suite; lane annotation at technical-plan time is expected to
    route these to non-browser lanes.
<!-- test-plan:v1 issue=46 skill=requirements --> # Test Plan: run-supervisor (issue #46) ## Prerequisites The *state* the scenarios need (how each condition is induced/simulated is stated per scenario in plain terms; the concrete mechanism is decided at design time — the PREQ requires only that every condition be inducible rather than waited for): - [ ] A project with the pipeline configured, on which an unattended run can be started with supervision engaged at launch (supervision is opt-in at launch) - [ ] A way to end the driver's turn with a simulated transient error (429/500/502/503/529-class) - [ ] A way to end the driver's turn with a simulated quota kill — one variant carrying a stated reset time, one carrying none - [ ] A way to make the driver stop making progress without ending its turn (simulated stall) - [ ] A project declaration carrying overridden supervisor tunables (retry bound, backoff, stall threshold), and a second setup with no override (suite defaults in force) - [ ] A project declaration naming a notification channel, and a second setup with none declared - [ ] A project declaring a post-resume claims-reconstruction step whose invocation leaves a visible trace, and a second setup with no such step declared ### Required Test Data - [ ] One supervised unattended run per scenario (scenarios are independent; each starts its own) - [ ] Access to the run's durable forge record, to inspect what the supervisor wrote ## Test Scenarios ### Scenario 1: Transient turn-death is resumed automatically **Acceptance criterion:** "Given a supervised unattended run whose driver turn ends on a transient error (per the classification rule), when the supervisor detects the run is resumable, then the run is resumed without operator input, with attempts bounded and backoff-spaced per the declared (or default) values." 1. Start a supervised unattended run; walk away (no operator input from here on) 2. Induce a transient error that ends the driver's turn (e.g. simulated 529) 3. Verify: the run resumes and continues its work with no operator input 4. Verify: the run's record shows the detection and the resume, including the attempt number 5. Verify: if more than one attempt was needed, the gaps between attempts grow, and attempt spacing is consistent with the values in force (defaults, in this setup) **Expected outcome:** the run finishes its phase work as if the stall had been mere slowness; the record distinguishes it from slowness. ### Scenario 2: Retry bound exhausted → escalation naming the count **Acceptance criterion:** "Given the per-incident retry bound is exhausted without a successful resume, when the last attempt fails, then the supervisor stops retrying and escalates, naming the attempt count and the error." 1. Start a supervised unattended run 2. Induce a transient turn-death that keeps recurring so every resume attempt fails 3. Verify: attempts stop after the bound in force is reached (count the recorded attempts) 4. Verify: an escalation is recorded naming the attempt count and the error observed 5. Verify: no further attempts appear after the escalation **Expected outcome:** bounded behavior — neither a single give-up nor an infinite loop; the operator can read exactly what was tried. ### Scenario 3: Quota kill with stated reset → scheduled resume **Acceptance criterion:** "Given a driver killed by quota exhaustion with a stated reset time, when the supervisor detects it, then the reset time is recorded and the resume is scheduled against that time (immediately, if the reset is already past), and the run resumes without operator input." 1. Start a supervised unattended run 2. Induce a quota kill carrying a stated reset time a few minutes in the future 3. Verify: the stated reset time appears in the run's record at detection time 4. Verify: the run does not resume before the reset time 5. Verify: the run resumes at/promptly after the reset time with no operator input **Expected outcome:** the wait is measured against the platform's own reset, not guessed; zero time lost past the reset beyond ordinary latency. ### Scenario 4: Quota kill with a reset already past → immediate resume **Acceptance criterion:** same as Scenario 3 (the "immediately, if the reset is already past" clause). 1. Start a supervised unattended run 2. Induce a quota kill whose stated reset time is already in the past 3. Verify: the recorded reset time appears in the record, and the resume happens immediately **Expected outcome:** no wait against a wall that has already fallen. ### Scenario 5: Quota kill with no discoverable reset → bounded-retry path **Acceptance criterion:** "Given a quota kill with no discoverable reset time, when the supervisor detects it, then it follows the bounded-retry path per the classification rule, escalating on exhaustion with what it observed." 1. Start a supervised unattended run 2. Induce a quota kill carrying no reset time 3. Verify: the supervisor retries per the bounded-retry path (attempts recorded, spaced, bounded) 4. If exhausted: verify the escalation states what was observed (a quota kill, no reset found) **Expected outcome:** no blind polling and no silent stop; the classification rule's else-branch is visibly taken. ### Scenario 6: Stalled but possibly mid-work → alert only, no writes **Acceptance criterion:** "Given a driver that stops making progress without positive evidence that its turn is over, when the declared (or default) stall threshold passes, then the supervisor escalates and does not resume, nudge, or otherwise write into the session." 1. Start a supervised unattended run 2. Make the driver stop progressing without ending its turn 3. Wait past the stall threshold in force 4. Verify: an alert is recorded (and delivered via the declared channel, if this setup has one) 5. Verify: nothing was written into the driver session — no resume, no nudge; the session's state is exactly as the stall left it **Expected outcome:** the wedged run becomes visible; the supervisor never risks double-driving a session that might still be working. ### Scenario 7: Operator-initiated stop is never auto-resumed **Acceptance criterion:** "Given any resume, when the supervisor starts it, then the resumability rule held: positive evidence of no turn in flight, a self-clearing cause, and not an operator-initiated stop." 1. Start a supervised unattended run 2. Stop the run deliberately, as the operator would (an intentional interrupt/stop) 3. Wait past every threshold in force 4. Verify: the supervisor does not resume the run 5. Cross-check with Scenarios 1 and 3: every resume that did happen has, in the record, the evidence that no turn was in flight and the self-clearing cause it acted on **Expected outcome:** a human's decision to stop a run is final for the supervisor; resumes happen only on recorded positive evidence. ### Scenario 8: Clean completion → supervisor stands down **Acceptance criterion:** "Given a supervised run that completes normally, when the driver finishes, then the supervisor stands down without intervening, and this is visible in the run's record." 1. Start a supervised unattended run that will complete without incident 2. Let it finish 3. Verify: the record shows the supervisor standing down after completion 4. Verify: no interventions were recorded during the run **Expected outcome:** supervision of a healthy run is invisible except for its stand-down entry. ### Scenario 9: Second attach refused **Acceptance criterion:** "Given a run that already has a supervisor attached, when a second supervisor attempts to attach, then the attach is refused — at most one supervisor per run." 1. Start a supervised unattended run 2. Attempt to engage a second supervisor on the same run 3. Verify: the second attach is refused with a message naming the existing supervision 4. Verify: the run continues under exactly one supervisor (induce a transient turn-death and confirm exactly one resume happens) **Expected outcome:** no double-resume is possible from doubled supervision. ### Scenario 10: Harness surface unavailable → escalate, don't act **Acceptance criterion:** "Given the supervisor cannot read the driver's state or cannot trigger a resume (the harness surface is unavailable or refuses), when it detects this, then it escalates with what it observed rather than acting on ambiguity." 1. Start a supervised unattended run 2. Make the driver-state surface unreadable to the supervisor (unavailable or refusing) 3. Induce a driver turn-death while the surface is unreadable 4. Verify: no resume is attempted 5. Verify: an escalation is recorded stating that the state surface was unreadable and what was observed **Expected outcome:** blindness is treated as ambiguity — surfaced loudly, never acted on. ### Scenario 11: Declared post-resume reconstruction step is invoked **Acceptance criterion:** "Given a project that declares a post-resume claims-reconstruction step, when the supervisor resumes a run, then that step is invoked before phase work continues." 1. On the setup whose declaration includes a post-resume step with a visible trace, start a supervised unattended run 2. Induce a transient turn-death; let the supervisor resume 3. Verify: the declared step's trace appears, and it appears before the run's next phase work 4. On the setup with no declared step: repeat 1–2 and verify the resume proceeds with no such invocation and no error about its absence **Expected outcome:** the hook fires when declared, is a no-op when not, and always precedes resumed phase work. ### Scenario 12: Everything is on the record; channel delivery when declared **Acceptance criterion:** "Given any supervisor intervention or escalation …, when it happens, then it is written to the run's durable forge record — and additionally delivered via the project's declared notification channel, when one is declared." 1. Re-inspect the runs from Scenarios 1, 2, 3, 6, and 8 2. Verify: every detection, attempt, scheduled resume, alert, and stand-down those scenarios produced appears in the run's durable forge record, legible to a reader who was not present 3. On the setup with a declared notification channel, induce one escalation and verify it arrives on that channel as well as in the record 4. On the setup with no declared channel, induce one escalation and verify the record alone carries it, completely **Expected outcome:** a retrospective reader can reconstruct every stall and its handling from the record; the channel is additive, never the only copy. ### Scenario 13: Declared tunables are the values in force **Acceptance criterion:** the "per the declared (or default) values" clauses of the retry and stall criteria. 1. On the setup with overridden tunables (a retry bound and stall threshold different from the suite defaults), run Scenario 2's steps and Scenario 6's steps 2. Verify: the attempt count at exhaustion matches the declared bound, not the default 3. Verify: the stall alert fires against the declared threshold, not the default **Expected outcome:** the declaration is honored; the acceptance criteria are judged against whichever values are in force. ## Notes - Scenarios deliberately avoid naming how turn-death, quota kills, stalls, or an unreadable harness surface are induced — the PREQ requires them inducible; the mechanism is a design decision and will be named when lanes are annotated. - No browser surface exists in this suite; lane annotation at technical-plan time is expected to route these to non-browser lanes.
Author
Owner
{
  "next_state": "planning",
  "produced": [
    {
      "kind": "preq",
      "ref": "issue-body",
      "summary": "PREQ: run supervisor — out-of-run resume and liveness watch for the unattended driver (Full scope; resumability rule settled by Tier-3 panel)"
    },
    {
      "kind": "test-plan",
      "ref": "comment:1490",
      "summary": "13 validation cases covering 11/11 acceptance criteria"
    }
  ],
  "findings": [
    {
      "category": "out-of-scope",
      "summary": "Reclaim semantics for open claims after driver death (who may reclaim, on what evidence)",
      "reasoning": "Interfaced via the post-resume hook, not absorbed — #65 (linked relates_to) owns the semantics and depends on #43's in-flight claims ledger",
      "id": "F-PO-46-1-1"
    },
    {
      "category": "out-of-scope",
      "summary": "Nudging or resuming a session without positive evidence its turn is over",
      "reasoning": "Alert-only by decision (positive-death-check rule) — a nudge mid-turn risks double-driving; revisit only with evidence alert-only strands wedged runs",
      "id": "F-PO-46-1-2"
    },
    {
      "category": "out-of-scope",
      "summary": "Supervisor high-availability (crashed supervisor / host reboot mid-run is itself unsupervised)",
      "reasoning": "The who-watches-the-watcher recursion stops here deliberately; supervisor absence is visible in the run record because interventions stop appearing",
      "id": "F-PO-46-1-3"
    },
    {
      "category": "out-of-scope",
      "summary": "Supervision of attended/interactive sessions",
      "reasoning": "The human present is the supervisor; supervision is opt-in at unattended launch only",
      "id": "F-PO-46-1-4"
    }
  ],
  "pending_decisions": [],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-1 skill=requirements --> ```json { "next_state": "planning", "produced": [ { "kind": "preq", "ref": "issue-body", "summary": "PREQ: run supervisor — out-of-run resume and liveness watch for the unattended driver (Full scope; resumability rule settled by Tier-3 panel)" }, { "kind": "test-plan", "ref": "comment:1490", "summary": "13 validation cases covering 11/11 acceptance criteria" } ], "findings": [ { "category": "out-of-scope", "summary": "Reclaim semantics for open claims after driver death (who may reclaim, on what evidence)", "reasoning": "Interfaced via the post-resume hook, not absorbed — #65 (linked relates_to) owns the semantics and depends on #43's in-flight claims ledger", "id": "F-PO-46-1-1" }, { "category": "out-of-scope", "summary": "Nudging or resuming a session without positive evidence its turn is over", "reasoning": "Alert-only by decision (positive-death-check rule) — a nudge mid-turn risks double-driving; revisit only with evidence alert-only strands wedged runs", "id": "F-PO-46-1-2" }, { "category": "out-of-scope", "summary": "Supervisor high-availability (crashed supervisor / host reboot mid-run is itself unsupervised)", "reasoning": "The who-watches-the-watcher recursion stops here deliberately; supervisor absence is visible in the run record because interventions stop appearing", "id": "F-PO-46-1-3" }, { "category": "out-of-scope", "summary": "Supervision of attended/interactive sessions", "reasoning": "The human present is the supervisor; supervision is opt-in at unattended launch only", "id": "F-PO-46-1-4" } ], "pending_decisions": [], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner

Software Requirements: run-supervisor

Context

An operator who starts an unattended pipeline run (one Claude Code driver session driven by
run-template.md) loses the run whenever the driver's own turn is ended by a self-clearing
condition — a transient API error (the recorded 8m47s dead 529) or a usage-quota kill with a
stated reset (the recorded ~3h17m lost past the reset). Nothing inside the session can retry a
call the session never made. This feature is the supervisor outside the run that wait-discipline
§3a explicitly defers to: opt-in at unattended launch, resuming only under the PREQ's
resumability rule, alert-only on ambiguity, everything on the durable forge record.

Approaches Considered

Approach A: Deterministic shell supervisor daemon

Summary: A helper-tier bash daemon, spawned detached at attach, that polls the driver
session's transcript, classifies turn state mechanically, and resumes via the harness CLI — no
model in the watch loop.
Pros: Classification is fully deterministic given the verified transcript contract
(structured apiErrorStatus, isApiErrorMessage, stop_reason); zero quota consumed while
watching (model calls only for actual resumes); fits the portability baseline (bash ≥ 3.2 + jq);
wholly auditable — every branch is a recorded rule, not a judgement.
Cons: A daemon lifecycle to manage (lock, stale-lock recovery, detach); clock-time parsing
for quota resets needs a probed date capability.
Effort: Medium

Approach B: Supervisor as a second Claude session

Summary: A /dev:supervise session (or scheduled agent) watches the driver with model
judgement, using harness watch tools.
Pros: Judgement available for ambiguous states; no bespoke daemon code.
Cons: Shares the exact failure domain it guards — a quota kill takes out watcher and watched
together (the founding quota incident would have killed both); burns quota continuously;
judgement is unnecessary — the classification inputs are structured fields; harder to make
auditable ("the model decided" vs a recorded rule).
Effort: Medium

Approach C: Scheduler-hosted stateless checks (cron / systemd user timer)

Summary: No long-lived process; a check script re-run every N minutes by the host scheduler,
with all state externalized.
Pros: Partially survives host reboot; no daemon liveness question.
Cons: Platform-specific installation surface (cron vs systemd vs launchd) against a
stack-agnostic suite; attach/stand-down become install/uninstall of scheduler entries (messy,
easy to leak); sub-minute stall responsiveness gone; and the reboot-survival benefit buys little
— supervisor HA is explicitly out of scope in the PREQ.
Effort: Medium-High

Decision

Selected: Approach A — deterministic shell supervisor daemon.
Rationale: The watch decision needs no model: the harness records carry structured
discriminators (verified at plan time), and a watcher that consumes quota or dies of the same
quota kill it guards against fails exactly when needed. A single detached daemon with an atomic
lock and probed capabilities matches the suite's existing helper-tier engineering and keeps the
whole behavior testable with a stub harness.

Architecture

Component Overview

  • plugin/skills/supervise/SKILL.md — the /dev:supervise skill: engagement at unattended
    launch, status, detach, the supervisor: declared-block schema, and the typed
    supervisor-event:v1 record convention.
  • plugin/skills/supervise/bin/supervisor-attach.sh — preflight (transcript readable; claude
    CLI present; jq; probe-by-doing for clock-time parsing), atomic lock acquisition, state
    init, daemon spawn (detached, setsid), synchronous engage verification (waits bounded
    for the daemon's first heartbeat, exits non-zero without it), attach record posted.
  • plugin/skills/supervise/bin/supervisor-watch.sh — the daemon loop (poll default 30 s):
    read transcript tail + mtime, classify, act, heartbeat.
  • plugin/skills/supervise/bin/supervisor-status.sh — one-screen answer: engaged? last
    heartbeat (stale = loud)? interventions so far? next scheduled action?
  • plugin/skills/supervise/bin/supervisor-detach.sh — stand-down: kill by recorded PID/pgid
    (never pattern-kill), release lock, post stand-down record; handles an already-dead daemon
    (stale state cleanup, recorded).
  • State dir: $DEVWORK_ROOT/supervisor/{session-id}/ (mode 0700) — lock/ (atomic mkdir),
    state.json (issue, cwd, tunables in force, incident/attempt counters, scheduled resume,
    alerted-condition dedup keys, daemon PID + start time; written atomically via temp + mv),
    daemon.log.
  • Consumed suite surfaces: post-comment.sh (adapter-dispatched forge writes),
    phase-outcome-read-latest.sh (run-terminal-state check), run-template.md (gains the
    opt-in engage line), wait-discipline.md §3a (limitation paragraph now points here).

Data Flow

  1. Engage (opt-in): the run template's step 0 has the driver itself run
    supervisor-attach.sh --session "$CLAUDE_CODE_SESSION_ID" --issue N (the env var is
    verified present in driver shells). Attach refuses a second supervisor (lock held + live
    PID/start-time match), reclaims a stale lock loudly, and only reports "supervision engaged"
    after observing the daemon's first heartbeat.
  2. Watch: each poll reads the transcript's last records and mtime. Classification (below)
    yields: healthy / resumable-transient / resumable-quota / not-self-clearing /
    run-complete / ambiguous-stall / operator-stop.
  3. Resume: cd {recorded cwd} (validated: exists, matches attach-time record) →
    claude -p --resume {session-id} --output-format json "<fixed resume prompt>". The prompt
    opens with a visible marker line ([run-supervisor resume — incident I, attempt A/B]),
    instructs re-verification of in-flight mutations (wait-discipline rule 5), invokes the
    project-declared post_resume_command first when declared (hook failure ⇒ escalate, do not
    continue silently), then continues driving. While the resume child runs, the daemon is in a
    resume-in-flight state: no classification of its own resume as stall or new incident;
    outcome judged on child rc + envelope is_error, then transcript progression.
  4. Record: every event (attach, detection, each attempt, scheduled resume, alert,
    operator-stop acknowledgment, stand-down, notify-channel failure) is posted to the feature
    issue via post-comment.sh as a typed supervisor-event:v1 body: {event, cause, evidence: {tail_uuid, apiErrorStatus, error_text}, attempt, bound, next_action, next_eta} — the
    synthetic error line and classification metadata only, never other transcript content.
    The declared notify_command, when present, is additionally invoked; its failure is itself
    recorded (the record is always the primary copy).
  5. Stand down: on run-complete evidence (latest Phase Outcome next_state
    {uat, accepted, deployed} — checked only when the tail shows a clean turn end), on operator
    stop (acknowledged visibly: "operator stop observed — standing down"), or on explicit
    detach. Lock released, stand-down record posted.

Classification rule (from the verified contract)

The last assistant record decides the base class — never the literal last line, because
harness bookkeeping records (last-prompt, mode) legitimately follow it and are ignored.
Non-bookkeeping records after the last assistant record override it: an operator interrupt
appends a plain user record ([Request interrupted by user]) after the error record, and that
override is a hard operator-stop. Classification lives in one seam — a single
classify-transcript helper function/file, the only code coupled to the un-versioned harness
record schema (schema drift lands in one place, and the seam is unit-testable in the shell
harness; same for the isolated clock-time parser):

Tail evidence (verified shapes) Class Action
Any interrupt record after the last assistant record operator-stop Acknowledge + stand down. Never resume.
Last assistant isApiErrorMessage:true, text matches quota-reset pattern (resets <clock> (<TZ>)) resumable-quota Parse clock+TZ → next occurrence; if that lands ≥ ~23 h out, the stated reset just passed → resume immediately. Record reset at detection; sleep till reset; resume. Unparseable time, or no probed parse capability ⇒ bounded-retry path (fail closed, per the PREQ classification rule), recorded. A failing scheduled resume falls into the bounded-retry incident path — no unbounded resume loop.
Last assistant isApiErrorMessage:true, apiErrorStatus ∈ {429, 500, 502, 503, 529} or connection-closed text resumable-transient Bounded backoff retries (per-incident), escalate on exhaustion naming count + error.
Last assistant isApiErrorMessage:true, anything else (401, …) not-self-clearing Escalate. Whitelist, never an open-ended family.
Last assistant stop_reason == "end_turn", run at terminal PO state run-complete Stand down, visibly.
Last assistant stop_reason == "end_turn", run not terminal ambiguous Alert-only (per wait-discipline, a driver never ends its turn silently mid-run — this is an on-record escalation or a defect; both are the operator's).
mtime stalled past threshold, tail non-terminal possibly-mid-work Alert-only. Never write into the session.
Transcript missing/unreadable/unparseable, or claude CLI refuses surface-unavailable Escalate with what was observed; never act on ambiguity.

Immediately before each resume attempt the transcript is re-classified in full — not
merely diffed — because detection and action can be hours apart (a quota sleep): if the tail
changed or the class is no longer resumable (operator returned, another writer, new records),
the resume is aborted and the observation recorded — closing the check-to-act race at the
moment that matters. Alerts are deduplicated per condition
(keyed on tail uuid / stall-onset): one alert per distinct condition, re-alert only on state
change.

External Data Contracts

Boundary / source Operation Real shape (verified) Provenance
Claude Code harness / session transcript store read ~/.claude/projects/{cwd-slug}/{session-id}.jsonl tail + mtime JSONL; clean end = assistant stop_reason:"end_turn"; turn-death = isApiErrorMessage:true + apiErrorStatus (int) + error + human text; quota text carries clock-time reset + TZ; interrupt = plain user record; see external-contracts/harness-session-transcript.sample.json recordedexternal-contracts/harness-session-transcript.provenance.json
Claude Code harness / headless resume CLI claude -p --resume {sid} --output-format json live-probed: resumes with context, same session id, envelope {session_id, result, is_error, subtype}; interactive-created sessions also resume headless recordedexternal-contracts/harness-resume-cli.provenance.json

Both boundaries verified by real reads/probes at plan time — no preconditions. The transcript
record schema is un-versioned harness internals; drift is a Technical Risk below, mitigated by
classifying on the minimal stable core and the surface-unavailable escape (AC-9).

Key Decisions

Decision Choice Rationale
Watch mechanism Deterministic daemon, no model in loop Structured discriminators verified; watcher must not share the quota failure domain it guards
Resume surface claude -p --resume headless, driver's own cwd Live-probed; -p gives one full agentic turn; no TTY needed
Resume permissions Inherit the driver session's own configured mode; the supervisor never passes permission-widening flags An unattended resume must not silently escalate what the operator launched
Declared-command invocation notify_command / post_resume_command exec'd with event data as argv/env only — never string-interpolated into shell Transcript-derived text is untrusted input; injection-proof by construction (mechanical AC-13)
Check-to-act race Tail re-read + compare immediately before resume; abort on change The operator may have returned between classify and act
Lock Atomic mkdir + PID/start-time liveness; stale lock reclaimed loudly Second attach refused (AC-8) without a crashed daemon blocking re-attach forever
Clock-time reset parsing Probe-by-doing at attach (behavioral, like local-fs probe_pin); fail closed to bounded-retry GNU date -d is not in the baseline; capability is behavioral, never provenance
Incident identity New incident = distinct tail record uuid after a successful resume Gives the PREQ's per-incident fresh bound a mechanical definition
Record shape Typed supervisor-event:v1 comment; metadata + synthetic error line only Retrospective-reader legibility; no transcript content (secrets) in forge records
Operator stop Acknowledge visibly and stand down Attended-again means the human is the supervisor; silence is indistinguishable from broken
Suite defaults poll 30 s; retry_bound 5; backoff 60 s × 2ⁿ; stall threshold 30 min Founding incidents: 529 cleared in minutes (bound reaches ~31 min of spaced attempts); 30 min stall ≈ the observed operator-absence cost

Technical Risks

Risk Likelihood Impact Mitigation
Transcript record schema drifts with harness updates (un-versioned internals) Med Med Classify on minimal stable core (isApiErrorMessage, stop_reason, apiErrorStatus); attach preflight re-validates readability; unparseable ⇒ surface-unavailable escalation (AC-9), never a guess
-p resume gives one agentic turn; a driver ending that turn awaiting a cross-turn harness notification exits and the run parks Med Med Falls into the ambiguous clean-end class → alert-only, consistent with the resumability rule; resume prompt instructs bounded in-turn waits per wait-discipline rule 2; dogfood run at UAT observes the real behavior
Quota-reset text variants without a reset clause, or novel phrasing Med Low Classification-rule else-branch: bounded-retry path, recorded with the observed text
Clock-time parse capability absent on some boxes Low Low Probed at attach; degraded mode (bounded-retry for quota kills) declared in the attach record
Daemon dies mid-run (host reboot, OOM) Low Med Out of scope per PREQ (HA); visibility is in scope: heartbeat in state + supervisor-status.sh reports staleness loudly; absence of interventions visible in the run record

Expert Review

Reviewers

  • Security Specialist: blocking — command injection via declared commands; check-to-act (TOCTOU) race before resume; unpinned resume permission mode. All absorbed (Key Decisions).
  • Backend Developer: blocking — interrupt-after-error misclassification (tail window, not last-assistant); stale-lock recovery; resume-in-flight self-classification; GNU date -d not in baseline. All absorbed (classification rule + Key Decisions).
  • UX Expert: blocking — attach must verify engagement positively; supervisor liveness must be visible (heartbeat + status); alert dedup to protect channel trust. All absorbed (Architecture).
  • Solution Architect: blocking — stale-lock recovery seam (concurs with Security/Backend);
    pre-resume re-classification after long quota sleeps; last-assistant-record (not
    literal-last-line) classification, since bookkeeping records follow it. All absorbed.

Changes Made

  • Classification window extended past the last assistant record so operator interrupts are a
    hard operator-stop state (Backend), with visible acknowledgment + stand-down (UX); and
    anchored on the last assistant record with bookkeeping records ignored (Architect).
  • Classification and clock parsing isolated into single testable seams — the only code coupled
    to un-versioned harness internals (Architect).
  • Pre-resume check strengthened from tail-diff to full re-classification, covering the
    hours-long quota-sleep gap (Architect); daemon death detectable at next attach is recorded
    on the forge issue during stale-lock reclaim (Architect).
  • Declared commands take event data via argv/env only; mechanical AC added (Security).
  • Pre-resume tail re-read added, aborting on any change (Security).
  • Resume inherits the driver's permission mode; no widening flags (Security).
  • Lock gained PID/start-time liveness + loud stale reclaim (Security, Backend).
  • Attach became synchronously verified (first-heartbeat wait, non-zero exit on failure) (UX).
  • Heartbeat + one-screen supervisor-status.sh; alert dedup once-per-condition (UX).
  • Clock parse: probe-by-doing at attach, fail-closed to bounded-retry; next-occurrence + ~23 h
    already-past rule (Backend, Security).
  • resume-in-flight daemon state so the loop never classifies its own resume (Backend).
  • Records carry metadata + synthetic error line only; state dir 0700; atomic state writes;
    partial-JSONL-line tolerance; detach by recorded PID; cwd validated before cd;
    transcript checked to be a regular file owned by the invoking user before automated action;
    notify_command failure itself recorded; resume prompt carries a visible marker line
    (Security, Backend, UX).
  • post_resume_command failure semantics fixed: escalate, never proceed silently (Backend).

Noted (not actioned)

  • Configurable re-alert cadence for long-lived alert conditions (UX): once-per-condition dedup
    ships; a declared re-alert interval is deliberately not added until evidence shows
    single-shot alerts get missed. Rejected for this slice on simplicity grounds.
  • Supervisor self-death detection beyond passive visibility (UX): heartbeat + status staleness
    ship; active watching-the-watcher is the PREQ's explicit HA out-of-scope. Already covered by
    out-of-scope finding and the heartbeat visibility that did ship.

Acceptance Criteria

Verification suite: plugin/skills/supervise/test/supervisor-flow.sh (+ fixtures) — a shell
integration suite authored by this feature (TDD, red-first per red-markers.md resolution
order), running the daemon against synthetic transcripts built from the recorded real shapes
(provenance-tagged, never hand-guessed), a stub claude on PATH, the local-fs adapter as the
forge target, and a stub notify_command. Executor confirmed runnable here: bash + jq + the
existing _shared/procedures/test / adapter-test/ harness conventions.

ID Criterion (from PREQ) Verification approach
AC-1 Transient turn-death resumed without operator input; attempts bounded, backoff-spaced per values in force Integration (suite above): stub-529 tail → resume invoked; attempt spacing asserted against tunables
AC-2 Bound exhausted → stop + escalate naming attempt count and error Integration: always-failing stub resume; attempts counted; escalation record asserted
AC-3 Quota kill with stated reset → reset recorded, resume scheduled against it (immediate if past), no operator input Integration: stub quota tail (real text shape); scheduled epoch asserted; already-past variant resumes immediately
AC-4 Quota kill, no discoverable reset → bounded-retry path, escalate with observations Integration: reset-less quota tail; bounded-retry branch + escalation content asserted
AC-5 Stall without positive turn-over evidence → escalate only; no resume/nudge/write into session Integration: stalled mtime, non-terminal tail; alert record asserted; transcript byte-identical after
AC-6 Every resume satisfied the resumability rule (evidence, self-clearing cause, not operator stop) Integration: each resume's supervisor-event:v1 carries tail-uuid evidence + cause; interrupt fixture never resumes
AC-7 Clean completion → stand down without intervening, visible in record Integration: end_turn tail + terminal PO (local-fs); stand-down record, zero interventions
AC-8 Second attach refused; at most one supervisor Integration: double attach; refusal names holder; single resume on induced death
AC-9 Surface unreadable / resume refused → escalate with observations, never act Integration: unreadable transcript + refusing stub CLI; no resume; escalation content asserted
AC-10 Declared post-resume step invoked before phase work continues; absent declaration = clean no-op Integration: hook stub leaves trace; ordering asserted; no-declaration variant asserted
AC-11 Every intervention/escalation on the durable forge record; declared channel additionally Integration: record completeness swept across AC-1/2/3/5/7 fixtures (local-fs); stub channel receives escalations; channel-less variant complete on record alone
AC-12 Tunables in force are the declared ones (bound, backoff, stall threshold), suite defaults otherwise Integration: declared-override variant of AC-2/AC-5 asserts declared values; default variant asserts defaults
AC-13 No transcript-derived text is string-interpolated into a shell command; declared commands receive event data as argv/env only Mechanical: grep over supervise/bin/* — no eval, no sh -c with substituted event fields; suite fixture with hostile error text executes nothing
AC-14 All supervise helpers pass the repo's helper-tier gate Mechanical: bash scripts/lint-conventions.sh (existing gate, extended to the new bin/)

No temporary scaffolding is introduced (no flags, aliases, or dual paths). The project's
observability mode is none; the supervisor's forge records are the feature's own function,
already first-class as AC-11 — no separate Observability & Audit subsection applies.

Implementation Scope

Areas

Area Files / directories involved Nature of change
Supervise skill plugin/skills/supervise/SKILL.md new — engagement/status/detach flows, supervisor: block schema (flat scalars: retry_bound, backoff_base_seconds, backoff_multiplier, stall_threshold_minutes, poll_interval_seconds, notify_command, post_resume_command), supervisor-event:v1 record convention
Supervisor helpers plugin/skills/supervise/bin/{supervisor-attach,supervisor-watch,supervisor-status,supervisor-detach}.sh new — helper tier (bash ≥ 3.2 + jq), own shebang
Test suite plugin/skills/supervise/test/ (suite + provenance-tagged fixtures + stub claude + stub notify/hook) new
Run template plugin/skills/_shared/run-template.md extend — v5: opt-in step-0 engage line using $CLAUDE_CODE_SESSION_ID
Wait discipline plugin/skills/_shared/procedures/wait-discipline.md §3a extend — the "until one exists" limitation paragraph now points to /dev:supervise
Lint gate scripts/lint-conventions.sh extend — cover the new bin/ (repo-local, mechanical only)
Plugin manifest .claude-plugin/ marketplace/plugin listing if skills are enumerated extend if required by validate

File Boundaries

The supervise skill (SKILL.md + bin/ + test/) is one coherent unit — single writer. The
run-template and wait-discipline edits are one-paragraph touches, independent of the helpers and
of each other. Lint-gate extension is independent. No shared-file contention with in-flight
siblings expected (#43 owns claims-ledger surfaces; #61 owns devcontainer) — but _shared/
edits are the known collision class: coordinate merge timing at a phase boundary.

Dependencies & Sequencing

Helpers and their test suite co-evolve (TDD). SKILL.md documents what the helpers do — draft
alongside, finalize after helper behavior settles. Template/procedure pointer edits can land
any time after the skill name is fixed. Everything else is parallel-safe.

Constraints & Non-Goals

Constraints:

  • Helper tier: bash ≥ 3.2 + jq + git, own shebang; no mapfile/declare -A; POSIX-only glue in
    anything the skill emits into an operator shell; no python/node.
  • All forge mutations via _shared/procedures/bin/* + active adapter — never inline forge CLI.
  • Capability checks are probe-by-doing (clock parse), never provenance/shape checks.
  • The supervisor: declared block obeys the declared-block parseability rules: flat scalars
    only, schema stated in the skill.
  • Gates: output to file, exit code from the command (both in helpers and in the test suite).
  • Declared commands (notify_command, post_resume_command) are the project's stack — read
    from CLAUDE.md, never defaulted to any concrete tool.

Non-goals (do NOT build):

  • Reclaim semantics for open claims (#65 — only the post_resume_command hook here).
  • Nudging or resuming without positive turn-over evidence (alert-only by decision).
  • Supervisor high-availability (crashed supervisor/host reboot is unsupervised; visibility only).
  • Supervision of attended/interactive sessions.
  • In-run retry behavior (shipped: wait-discipline §3a) and phase-runner re-dispatch (§5).
<!-- sreq:v1 issue=46 skill=technical-plan --> # Software Requirements: run-supervisor ## Context An operator who starts an unattended pipeline run (one Claude Code driver session driven by `run-template.md`) loses the run whenever the driver's own turn is ended by a self-clearing condition — a transient API error (the recorded 8m47s dead 529) or a usage-quota kill with a stated reset (the recorded ~3h17m lost past the reset). Nothing inside the session can retry a call the session never made. This feature is the supervisor outside the run that wait-discipline §3a explicitly defers to: opt-in at unattended launch, resuming only under the PREQ's resumability rule, alert-only on ambiguity, everything on the durable forge record. ## Approaches Considered ### Approach A: Deterministic shell supervisor daemon **Summary:** A helper-tier bash daemon, spawned detached at attach, that polls the driver session's transcript, classifies turn state mechanically, and resumes via the harness CLI — no model in the watch loop. **Pros:** Classification is fully deterministic given the verified transcript contract (structured `apiErrorStatus`, `isApiErrorMessage`, `stop_reason`); zero quota consumed while watching (model calls only for actual resumes); fits the portability baseline (bash ≥ 3.2 + jq); wholly auditable — every branch is a recorded rule, not a judgement. **Cons:** A daemon lifecycle to manage (lock, stale-lock recovery, detach); clock-time parsing for quota resets needs a probed `date` capability. **Effort:** Medium ### Approach B: Supervisor as a second Claude session **Summary:** A `/dev:supervise` session (or scheduled agent) watches the driver with model judgement, using harness watch tools. **Pros:** Judgement available for ambiguous states; no bespoke daemon code. **Cons:** Shares the exact failure domain it guards — a quota kill takes out watcher and watched together (the founding quota incident would have killed both); burns quota continuously; judgement is unnecessary — the classification inputs are structured fields; harder to make auditable ("the model decided" vs a recorded rule). **Effort:** Medium ### Approach C: Scheduler-hosted stateless checks (cron / systemd user timer) **Summary:** No long-lived process; a check script re-run every N minutes by the host scheduler, with all state externalized. **Pros:** Partially survives host reboot; no daemon liveness question. **Cons:** Platform-specific installation surface (cron vs systemd vs launchd) against a stack-agnostic suite; attach/stand-down become install/uninstall of scheduler entries (messy, easy to leak); sub-minute stall responsiveness gone; and the reboot-survival benefit buys little — supervisor HA is explicitly out of scope in the PREQ. **Effort:** Medium-High ## Decision **Selected:** Approach A — deterministic shell supervisor daemon. **Rationale:** The watch decision needs no model: the harness records carry structured discriminators (verified at plan time), and a watcher that consumes quota or dies of the same quota kill it guards against fails exactly when needed. A single detached daemon with an atomic lock and probed capabilities matches the suite's existing helper-tier engineering and keeps the whole behavior testable with a stub harness. ## Architecture ### Component Overview - `plugin/skills/supervise/SKILL.md` — the `/dev:supervise` skill: engagement at unattended launch, status, detach, the `supervisor:` declared-block schema, and the typed `supervisor-event:v1` record convention. - `plugin/skills/supervise/bin/supervisor-attach.sh` — preflight (transcript readable; `claude` CLI present; jq; probe-by-doing for clock-time parsing), atomic lock acquisition, state init, daemon spawn (detached, `setsid`), **synchronous engage verification** (waits bounded for the daemon's first heartbeat, exits non-zero without it), attach record posted. - `plugin/skills/supervise/bin/supervisor-watch.sh` — the daemon loop (poll default 30 s): read transcript tail + mtime, classify, act, heartbeat. - `plugin/skills/supervise/bin/supervisor-status.sh` — one-screen answer: engaged? last heartbeat (stale = loud)? interventions so far? next scheduled action? - `plugin/skills/supervise/bin/supervisor-detach.sh` — stand-down: kill by recorded PID/pgid (never pattern-kill), release lock, post stand-down record; handles an already-dead daemon (stale state cleanup, recorded). - State dir: `$DEVWORK_ROOT/supervisor/{session-id}/` (mode 0700) — `lock/` (atomic `mkdir`), `state.json` (issue, cwd, tunables in force, incident/attempt counters, scheduled resume, alerted-condition dedup keys, daemon PID + start time; written atomically via temp + `mv`), `daemon.log`. - Consumed suite surfaces: `post-comment.sh` (adapter-dispatched forge writes), `phase-outcome-read-latest.sh` (run-terminal-state check), `run-template.md` (gains the opt-in engage line), `wait-discipline.md` §3a (limitation paragraph now points here). ### Data Flow 1. **Engage (opt-in):** the run template's step 0 has the driver itself run `supervisor-attach.sh --session "$CLAUDE_CODE_SESSION_ID" --issue N` (the env var is verified present in driver shells). Attach refuses a second supervisor (lock held + live PID/start-time match), reclaims a stale lock loudly, and only reports "supervision engaged" after observing the daemon's first heartbeat. 2. **Watch:** each poll reads the transcript's last records and mtime. Classification (below) yields: healthy / resumable-transient / resumable-quota / not-self-clearing / run-complete / ambiguous-stall / operator-stop. 3. **Resume:** `cd {recorded cwd}` (validated: exists, matches attach-time record) → `claude -p --resume {session-id} --output-format json "<fixed resume prompt>"`. The prompt opens with a visible marker line (`[run-supervisor resume — incident I, attempt A/B]`), instructs re-verification of in-flight mutations (wait-discipline rule 5), invokes the project-declared `post_resume_command` first when declared (hook failure ⇒ escalate, do not continue silently), then continues driving. While the resume child runs, the daemon is in a `resume-in-flight` state: no classification of its own resume as stall or new incident; outcome judged on child rc + envelope `is_error`, then transcript progression. 4. **Record:** every event (attach, detection, each attempt, scheduled resume, alert, operator-stop acknowledgment, stand-down, notify-channel failure) is posted to the feature issue via `post-comment.sh` as a typed `supervisor-event:v1` body: `{event, cause, evidence: {tail_uuid, apiErrorStatus, error_text}, attempt, bound, next_action, next_eta}` — the synthetic error line and classification metadata only, never other transcript content. The declared `notify_command`, when present, is additionally invoked; its failure is itself recorded (the record is always the primary copy). 5. **Stand down:** on run-complete evidence (latest Phase Outcome `next_state` ∈ {uat, accepted, deployed} — checked only when the tail shows a clean turn end), on operator stop (acknowledged visibly: "operator stop observed — standing down"), or on explicit detach. Lock released, stand-down record posted. ### Classification rule (from the verified contract) The **last assistant record** decides the base class — never the literal last line, because harness bookkeeping records (`last-prompt`, `mode`) legitimately follow it and are ignored. Non-bookkeeping records *after* the last assistant record override it: an operator interrupt appends a plain user record (`[Request interrupted by user]`) after the error record, and that override is a hard operator-stop. Classification lives in **one seam** — a single `classify-transcript` helper function/file, the only code coupled to the un-versioned harness record schema (schema drift lands in one place, and the seam is unit-testable in the shell harness; same for the isolated clock-time parser): | Tail evidence (verified shapes) | Class | Action | | --- | --- | --- | | Any interrupt record after the last assistant record | operator-stop | Acknowledge + stand down. Never resume. | | Last assistant `isApiErrorMessage:true`, text matches quota-reset pattern (`resets <clock> (<TZ>)`) | resumable-quota | Parse clock+TZ → next occurrence; if that lands ≥ ~23 h out, the stated reset just passed → resume immediately. Record reset at detection; sleep till reset; resume. Unparseable time, or no probed parse capability ⇒ bounded-retry path (fail closed, per the PREQ classification rule), recorded. A failing scheduled resume falls into the bounded-retry incident path — no unbounded resume loop. | | Last assistant `isApiErrorMessage:true`, `apiErrorStatus` ∈ {429, 500, 502, 503, 529} or connection-closed text | resumable-transient | Bounded backoff retries (per-incident), escalate on exhaustion naming count + error. | | Last assistant `isApiErrorMessage:true`, anything else (401, …) | not-self-clearing | Escalate. Whitelist, never an open-ended family. | | Last assistant `stop_reason == "end_turn"`, run at terminal PO state | run-complete | Stand down, visibly. | | Last assistant `stop_reason == "end_turn"`, run **not** terminal | ambiguous | Alert-only (per wait-discipline, a driver never ends its turn silently mid-run — this is an on-record escalation or a defect; both are the operator's). | | mtime stalled past threshold, tail non-terminal | possibly-mid-work | Alert-only. Never write into the session. | | Transcript missing/unreadable/unparseable, or `claude` CLI refuses | surface-unavailable | Escalate with what was observed; never act on ambiguity. | Immediately before **each** resume attempt the transcript is **re-classified in full** — not merely diffed — because detection and action can be hours apart (a quota sleep): if the tail changed or the class is no longer resumable (operator returned, another writer, new records), the resume is **aborted** and the observation recorded — closing the check-to-act race at the moment that matters. Alerts are deduplicated per condition (keyed on tail uuid / stall-onset): one alert per distinct condition, re-alert only on state change. ### External Data Contracts | Boundary / source | Operation | Real shape (verified) | Provenance | | ----------------- | --------- | --------------------- | ---------- | | Claude Code harness / session transcript store | read `~/.claude/projects/{cwd-slug}/{session-id}.jsonl` tail + mtime | JSONL; clean end = assistant `stop_reason:"end_turn"`; turn-death = `isApiErrorMessage:true` + `apiErrorStatus` (int) + `error` + human text; quota text carries clock-time reset + TZ; interrupt = plain user record; see `external-contracts/harness-session-transcript.sample.json` | `recorded` → `external-contracts/harness-session-transcript.provenance.json` | | Claude Code harness / headless resume CLI | `claude -p --resume {sid} --output-format json` | live-probed: resumes with context, same session id, envelope `{session_id, result, is_error, subtype}`; interactive-created sessions also resume headless | `recorded` → `external-contracts/harness-resume-cli.provenance.json` | Both boundaries verified by real reads/probes at plan time — no preconditions. The transcript record schema is un-versioned harness internals; drift is a Technical Risk below, mitigated by classifying on the minimal stable core and the surface-unavailable escape (AC-9). ### Key Decisions | Decision | Choice | Rationale | | --- | --- | --- | | Watch mechanism | Deterministic daemon, no model in loop | Structured discriminators verified; watcher must not share the quota failure domain it guards | | Resume surface | `claude -p --resume` headless, driver's own cwd | Live-probed; `-p` gives one full agentic turn; no TTY needed | | Resume permissions | Inherit the driver session's own configured mode; the supervisor never passes permission-widening flags | An unattended resume must not silently escalate what the operator launched | | Declared-command invocation | `notify_command` / `post_resume_command` exec'd with event data as argv/env only — never string-interpolated into shell | Transcript-derived text is untrusted input; injection-proof by construction (mechanical AC-13) | | Check-to-act race | Tail re-read + compare immediately before resume; abort on change | The operator may have returned between classify and act | | Lock | Atomic `mkdir` + PID/start-time liveness; stale lock reclaimed loudly | Second attach refused (AC-8) without a crashed daemon blocking re-attach forever | | Clock-time reset parsing | Probe-by-doing at attach (behavioral, like local-fs `probe_pin`); fail closed to bounded-retry | GNU `date -d` is not in the baseline; capability is behavioral, never provenance | | Incident identity | New incident = distinct tail record uuid after a successful resume | Gives the PREQ's per-incident fresh bound a mechanical definition | | Record shape | Typed `supervisor-event:v1` comment; metadata + synthetic error line only | Retrospective-reader legibility; no transcript content (secrets) in forge records | | Operator stop | Acknowledge visibly and stand down | Attended-again means the human is the supervisor; silence is indistinguishable from broken | | Suite defaults | poll 30 s; retry_bound 5; backoff 60 s × 2ⁿ; stall threshold 30 min | Founding incidents: 529 cleared in minutes (bound reaches ~31 min of spaced attempts); 30 min stall ≈ the observed operator-absence cost | ## Technical Risks | Risk | Likelihood | Impact | Mitigation | | ---- | ---------- | ------ | ---------- | | Transcript record schema drifts with harness updates (un-versioned internals) | Med | Med | Classify on minimal stable core (`isApiErrorMessage`, `stop_reason`, `apiErrorStatus`); attach preflight re-validates readability; unparseable ⇒ surface-unavailable escalation (AC-9), never a guess | | `-p` resume gives one agentic turn; a driver ending that turn awaiting a cross-turn harness notification exits and the run parks | Med | Med | Falls into the ambiguous clean-end class → alert-only, consistent with the resumability rule; resume prompt instructs bounded in-turn waits per wait-discipline rule 2; dogfood run at UAT observes the real behavior | | Quota-reset text variants without a reset clause, or novel phrasing | Med | Low | Classification-rule else-branch: bounded-retry path, recorded with the observed text | | Clock-time parse capability absent on some boxes | Low | Low | Probed at attach; degraded mode (bounded-retry for quota kills) declared in the attach record | | Daemon dies mid-run (host reboot, OOM) | Low | Med | Out of scope per PREQ (HA); visibility is in scope: heartbeat in state + `supervisor-status.sh` reports staleness loudly; absence of interventions visible in the run record | ## Expert Review ### Reviewers - Security Specialist: blocking — command injection via declared commands; check-to-act (TOCTOU) race before resume; unpinned resume permission mode. All absorbed (Key Decisions). - Backend Developer: blocking — interrupt-after-error misclassification (tail window, not last-assistant); stale-lock recovery; resume-in-flight self-classification; GNU `date -d` not in baseline. All absorbed (classification rule + Key Decisions). - UX Expert: blocking — attach must verify engagement positively; supervisor liveness must be visible (heartbeat + status); alert dedup to protect channel trust. All absorbed (Architecture). - Solution Architect: blocking — stale-lock recovery seam (concurs with Security/Backend); pre-resume re-classification after long quota sleeps; last-assistant-record (not literal-last-line) classification, since bookkeeping records follow it. All absorbed. ### Changes Made - Classification window extended past the last assistant record so operator interrupts are a hard operator-stop state (Backend), with visible acknowledgment + stand-down (UX); and anchored on the last assistant record with bookkeeping records ignored (Architect). - Classification and clock parsing isolated into single testable seams — the only code coupled to un-versioned harness internals (Architect). - Pre-resume check strengthened from tail-diff to full re-classification, covering the hours-long quota-sleep gap (Architect); daemon death detectable at next attach is recorded on the forge issue during stale-lock reclaim (Architect). - Declared commands take event data via argv/env only; mechanical AC added (Security). - Pre-resume tail re-read added, aborting on any change (Security). - Resume inherits the driver's permission mode; no widening flags (Security). - Lock gained PID/start-time liveness + loud stale reclaim (Security, Backend). - Attach became synchronously verified (first-heartbeat wait, non-zero exit on failure) (UX). - Heartbeat + one-screen `supervisor-status.sh`; alert dedup once-per-condition (UX). - Clock parse: probe-by-doing at attach, fail-closed to bounded-retry; next-occurrence + ~23 h already-past rule (Backend, Security). - `resume-in-flight` daemon state so the loop never classifies its own resume (Backend). - Records carry metadata + synthetic error line only; state dir 0700; atomic state writes; partial-JSONL-line tolerance; detach by recorded PID; cwd validated before `cd`; transcript checked to be a regular file owned by the invoking user before automated action; `notify_command` failure itself recorded; resume prompt carries a visible marker line (Security, Backend, UX). - `post_resume_command` failure semantics fixed: escalate, never proceed silently (Backend). ### Noted (not actioned) - Configurable re-alert cadence for long-lived alert conditions (UX): once-per-condition dedup ships; a declared re-alert interval is deliberately not added until evidence shows single-shot alerts get missed. Rejected for this slice on simplicity grounds. - Supervisor self-death detection beyond passive visibility (UX): heartbeat + status staleness ship; active watching-the-watcher is the PREQ's explicit HA out-of-scope. Already covered by out-of-scope finding and the heartbeat visibility that did ship. ## Acceptance Criteria Verification suite: `plugin/skills/supervise/test/supervisor-flow.sh` (+ fixtures) — a shell integration suite authored by this feature (TDD, red-first per `red-markers.md` resolution order), running the daemon against synthetic transcripts built **from the recorded real shapes** (provenance-tagged, never hand-guessed), a stub `claude` on PATH, the `local-fs` adapter as the forge target, and a stub `notify_command`. Executor confirmed runnable here: bash + jq + the existing `_shared/procedures/test` / adapter-`test/` harness conventions. | ID | Criterion (from PREQ) | Verification approach | | --- | --- | --- | | AC-1 | Transient turn-death resumed without operator input; attempts bounded, backoff-spaced per values in force | Integration (suite above): stub-529 tail → resume invoked; attempt spacing asserted against tunables | | AC-2 | Bound exhausted → stop + escalate naming attempt count and error | Integration: always-failing stub resume; attempts counted; escalation record asserted | | AC-3 | Quota kill with stated reset → reset recorded, resume scheduled against it (immediate if past), no operator input | Integration: stub quota tail (real text shape); scheduled epoch asserted; already-past variant resumes immediately | | AC-4 | Quota kill, no discoverable reset → bounded-retry path, escalate with observations | Integration: reset-less quota tail; bounded-retry branch + escalation content asserted | | AC-5 | Stall without positive turn-over evidence → escalate only; no resume/nudge/write into session | Integration: stalled mtime, non-terminal tail; alert record asserted; transcript byte-identical after | | AC-6 | Every resume satisfied the resumability rule (evidence, self-clearing cause, not operator stop) | Integration: each resume's `supervisor-event:v1` carries tail-uuid evidence + cause; interrupt fixture never resumes | | AC-7 | Clean completion → stand down without intervening, visible in record | Integration: end_turn tail + terminal PO (local-fs); stand-down record, zero interventions | | AC-8 | Second attach refused; at most one supervisor | Integration: double attach; refusal names holder; single resume on induced death | | AC-9 | Surface unreadable / resume refused → escalate with observations, never act | Integration: unreadable transcript + refusing stub CLI; no resume; escalation content asserted | | AC-10 | Declared post-resume step invoked before phase work continues; absent declaration = clean no-op | Integration: hook stub leaves trace; ordering asserted; no-declaration variant asserted | | AC-11 | Every intervention/escalation on the durable forge record; declared channel additionally | Integration: record completeness swept across AC-1/2/3/5/7 fixtures (local-fs); stub channel receives escalations; channel-less variant complete on record alone | | AC-12 | Tunables in force are the declared ones (bound, backoff, stall threshold), suite defaults otherwise | Integration: declared-override variant of AC-2/AC-5 asserts declared values; default variant asserts defaults | | AC-13 | No transcript-derived text is string-interpolated into a shell command; declared commands receive event data as argv/env only | Mechanical: grep over `supervise/bin/*` — no `eval`, no `sh -c` with substituted event fields; suite fixture with hostile error text executes nothing | | AC-14 | All supervise helpers pass the repo's helper-tier gate | Mechanical: `bash scripts/lint-conventions.sh` (existing gate, extended to the new bin/) | No temporary scaffolding is introduced (no flags, aliases, or dual paths). The project's observability mode is `none`; the supervisor's forge records are the feature's own function, already first-class as AC-11 — no separate Observability & Audit subsection applies. ## Implementation Scope ### Areas | Area | Files / directories involved | Nature of change | | --- | --- | --- | | Supervise skill | `plugin/skills/supervise/SKILL.md` | new — engagement/status/detach flows, `supervisor:` block schema (flat scalars: retry_bound, backoff_base_seconds, backoff_multiplier, stall_threshold_minutes, poll_interval_seconds, notify_command, post_resume_command), `supervisor-event:v1` record convention | | Supervisor helpers | `plugin/skills/supervise/bin/{supervisor-attach,supervisor-watch,supervisor-status,supervisor-detach}.sh` | new — helper tier (bash ≥ 3.2 + jq), own shebang | | Test suite | `plugin/skills/supervise/test/` (suite + provenance-tagged fixtures + stub `claude` + stub notify/hook) | new | | Run template | `plugin/skills/_shared/run-template.md` | extend — v5: opt-in step-0 engage line using `$CLAUDE_CODE_SESSION_ID` | | Wait discipline | `plugin/skills/_shared/procedures/wait-discipline.md` §3a | extend — the "until one exists" limitation paragraph now points to `/dev:supervise` | | Lint gate | `scripts/lint-conventions.sh` | extend — cover the new bin/ (repo-local, mechanical only) | | Plugin manifest | `.claude-plugin/` marketplace/plugin listing if skills are enumerated | extend if required by validate | ### File Boundaries The supervise skill (SKILL.md + bin/ + test/) is one coherent unit — single writer. The run-template and wait-discipline edits are one-paragraph touches, independent of the helpers and of each other. Lint-gate extension is independent. No shared-file contention with in-flight siblings expected (#43 owns claims-ledger surfaces; #61 owns devcontainer) — but `_shared/` edits are the known collision class: coordinate merge timing at a phase boundary. ### Dependencies & Sequencing Helpers and their test suite co-evolve (TDD). SKILL.md documents what the helpers do — draft alongside, finalize after helper behavior settles. Template/procedure pointer edits can land any time after the skill name is fixed. Everything else is parallel-safe. ## Constraints & Non-Goals **Constraints:** - Helper tier: bash ≥ 3.2 + jq + git, own shebang; no `mapfile`/`declare -A`; POSIX-only glue in anything the skill emits into an operator shell; no python/node. - All forge mutations via `_shared/procedures/bin/*` + active adapter — never inline forge CLI. - Capability checks are probe-by-doing (clock parse), never provenance/shape checks. - The `supervisor:` declared block obeys the declared-block parseability rules: flat scalars only, schema stated in the skill. - Gates: output to file, exit code from the command (both in helpers and in the test suite). - Declared commands (`notify_command`, `post_resume_command`) are the project's stack — read from CLAUDE.md, never defaulted to any concrete tool. **Non-goals (do NOT build):** - Reclaim semantics for open claims (#65 — only the `post_resume_command` hook here). - Nudging or resuming without positive turn-over evidence (alert-only by decision). - Supervisor high-availability (crashed supervisor/host reboot is unsupervised; visibility only). - Supervision of attended/interactive sessions. - In-run retry behavior (shipped: wait-discipline §3a) and phase-runner re-dispatch (§5).
Author
Owner

Test Plan: run-supervisor (issue #46)

Prerequisites

The state the scenarios need (how each condition is induced/simulated is stated per scenario in
plain terms; the concrete mechanism is decided at design time — the PREQ requires only that every
condition be inducible rather than waited for):

  • A project with the pipeline configured, on which an unattended run can be started with
    supervision engaged at launch (supervision is opt-in at launch)
  • A way to end the driver's turn with a simulated transient error (429/500/502/503/529-class)
  • A way to end the driver's turn with a simulated quota kill — one variant carrying a stated
    reset time, one carrying none
  • A way to make the driver stop making progress without ending its turn (simulated stall)
  • A project declaration carrying overridden supervisor tunables (retry bound, backoff, stall
    threshold), and a second setup with no override (suite defaults in force)
  • A project declaration naming a notification channel, and a second setup with none declared
  • A project declaring a post-resume claims-reconstruction step whose invocation leaves a
    visible trace, and a second setup with no such step declared

Required Test Data

  • One supervised unattended run per scenario (scenarios are independent; each starts its own)
  • Access to the run's durable forge record, to inspect what the supervisor wrote

Test Scenarios

Scenario 1: Transient turn-death is resumed automatically

Acceptance criterion: "Given a supervised unattended run whose driver turn ends on a transient error (per the classification rule), when the supervisor detects the run is resumable, then the run is resumed without operator input, with attempts bounded and backoff-spaced per the declared (or default) values."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Start a supervised unattended run; walk away (no operator input from here on)
  2. Induce a transient error that ends the driver's turn (e.g. simulated 529)
  3. Verify: the run resumes and continues its work with no operator input
  4. Verify: the run's record shows the detection and the resume, including the attempt number
  5. Verify: if more than one attempt was needed, the gaps between attempts grow, and attempt
    spacing is consistent with the values in force (defaults, in this setup)

Expected outcome: the run finishes its phase work as if the stall had been mere slowness; the record distinguishes it from slowness.

Scenario 2: Retry bound exhausted → escalation naming the count

Acceptance criterion: "Given the per-incident retry bound is exhausted without a successful resume, when the last attempt fails, then the supervisor stops retrying and escalates, naming the attempt count and the error."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Start a supervised unattended run
  2. Induce a transient turn-death that keeps recurring so every resume attempt fails
  3. Verify: attempts stop after the bound in force is reached (count the recorded attempts)
  4. Verify: an escalation is recorded naming the attempt count and the error observed
  5. Verify: no further attempts appear after the escalation

Expected outcome: bounded behavior — neither a single give-up nor an infinite loop; the operator can read exactly what was tried.

Scenario 3: Quota kill with stated reset → scheduled resume

Acceptance criterion: "Given a driver killed by quota exhaustion with a stated reset time, when the supervisor detects it, then the reset time is recorded and the resume is scheduled against that time (immediately, if the reset is already past), and the run resumes without operator input."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Start a supervised unattended run
  2. Induce a quota kill carrying a stated reset time a few minutes in the future
  3. Verify: the stated reset time appears in the run's record at detection time
  4. Verify: the run does not resume before the reset time
  5. Verify: the run resumes at/promptly after the reset time with no operator input

Expected outcome: the wait is measured against the platform's own reset, not guessed; zero time lost past the reset beyond ordinary latency.

Scenario 4: Quota kill with a reset already past → immediate resume

Acceptance criterion: same as Scenario 3 (the "immediately, if the reset is already past" clause).
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Start a supervised unattended run
  2. Induce a quota kill whose stated reset time is already in the past
  3. Verify: the recorded reset time appears in the record, and the resume happens immediately

Expected outcome: no wait against a wall that has already fallen.

Scenario 5: Quota kill with no discoverable reset → bounded-retry path

Acceptance criterion: "Given a quota kill with no discoverable reset time, when the supervisor detects it, then it follows the bounded-retry path per the classification rule, escalating on exhaustion with what it observed."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Start a supervised unattended run
  2. Induce a quota kill carrying no reset time
  3. Verify: the supervisor retries per the bounded-retry path (attempts recorded, spaced, bounded)
  4. If exhausted: verify the escalation states what was observed (a quota kill, no reset found)

Expected outcome: no blind polling and no silent stop; the classification rule's else-branch is visibly taken.

Scenario 6: Stalled but possibly mid-work → alert only, no writes

Acceptance criterion: "Given a driver that stops making progress without positive evidence that its turn is over, when the declared (or default) stall threshold passes, then the supervisor escalates and does not resume, nudge, or otherwise write into the session."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Start a supervised unattended run
  2. Make the driver stop progressing without ending its turn
  3. Wait past the stall threshold in force
  4. Verify: an alert is recorded (and delivered via the declared channel, if this setup has one)
  5. Verify: nothing was written into the driver session — no resume, no nudge; the session's
    state is exactly as the stall left it

Expected outcome: the wedged run becomes visible; the supervisor never risks double-driving a session that might still be working.

Scenario 7: Operator-initiated stop is never auto-resumed

Acceptance criterion: "Given any resume, when the supervisor starts it, then the resumability rule held: positive evidence of no turn in flight, a self-clearing cause, and not an operator-initiated stop."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Start a supervised unattended run
  2. Stop the run deliberately, as the operator would (an intentional interrupt/stop)
  3. Wait past every threshold in force
  4. Verify: the supervisor does not resume the run
  5. Cross-check with Scenarios 1 and 3: every resume that did happen has, in the record, the
    evidence that no turn was in flight and the self-clearing cause it acted on

Expected outcome: a human's decision to stop a run is final for the supervisor; resumes happen only on recorded positive evidence.

Scenario 8: Clean completion → supervisor stands down

Acceptance criterion: "Given a supervised run that completes normally, when the driver finishes, then the supervisor stands down without intervening, and this is visible in the run's record."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Start a supervised unattended run that will complete without incident
  2. Let it finish
  3. Verify: the record shows the supervisor standing down after completion
  4. Verify: no interventions were recorded during the run

Expected outcome: supervision of a healthy run is invisible except for its stand-down entry.

Scenario 9: Second attach refused

Acceptance criterion: "Given a run that already has a supervisor attached, when a second supervisor attempts to attach, then the attach is refused — at most one supervisor per run."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Start a supervised unattended run
  2. Attempt to engage a second supervisor on the same run
  3. Verify: the second attach is refused with a message naming the existing supervision
  4. Verify: the run continues under exactly one supervisor (induce a transient turn-death and
    confirm exactly one resume happens)

Expected outcome: no double-resume is possible from doubled supervision.

Scenario 10: Harness surface unavailable → escalate, don't act

Acceptance criterion: "Given the supervisor cannot read the driver's state or cannot trigger a resume (the harness surface is unavailable or refuses), when it detects this, then it escalates with what it observed rather than acting on ambiguity."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Start a supervised unattended run
  2. Make the driver-state surface unreadable to the supervisor (unavailable or refusing)
  3. Induce a driver turn-death while the surface is unreadable
  4. Verify: no resume is attempted
  5. Verify: an escalation is recorded stating that the state surface was unreadable and what was
    observed

Expected outcome: blindness is treated as ambiguity — surfaced loudly, never acted on.

Scenario 11: Declared post-resume reconstruction step is invoked

Acceptance criterion: "Given a project that declares a post-resume claims-reconstruction step, when the supervisor resumes a run, then that step is invoked before phase work continues."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. On the setup whose declaration includes a post-resume step with a visible trace, start a
    supervised unattended run
  2. Induce a transient turn-death; let the supervisor resume
  3. Verify: the declared step's trace appears, and it appears before the run's next phase work
  4. On the setup with no declared step: repeat 1–2 and verify the resume proceeds with no such
    invocation and no error about its absence

Expected outcome: the hook fires when declared, is a no-op when not, and always precedes resumed phase work.

Scenario 12: Everything is on the record; channel delivery when declared

Acceptance criterion: "Given any supervisor intervention or escalation …, when it happens, then it is written to the run's durable forge record — and additionally delivered via the project's declared notification channel, when one is declared."
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. Re-inspect the runs from Scenarios 1, 2, 3, 6, and 8
  2. Verify: every detection, attempt, scheduled resume, alert, and stand-down those scenarios
    produced appears in the run's durable forge record, legible to a reader who was not present
  3. On the setup with a declared notification channel, induce one escalation and verify it
    arrives on that channel as well as in the record
  4. On the setup with no declared channel, induce one escalation and verify the record alone
    carries it, completely

Expected outcome: a retrospective reader can reconstruct every stall and its handling from the record; the channel is additive, never the only copy.

Scenario 13: Declared tunables are the values in force

Acceptance criterion: the "per the declared (or default) values" clauses of the retry and stall criteria.
Lane: integration-covered — plugin/skills/supervise/test/supervisor-flow.sh

  1. On the setup with overridden tunables (a retry bound and stall threshold different from the
    suite defaults), run Scenario 2's steps and Scenario 6's steps
  2. Verify: the attempt count at exhaustion matches the declared bound, not the default
  3. Verify: the stall alert fires against the declared threshold, not the default

Expected outcome: the declaration is honored; the acceptance criteria are judged against whichever values are in force.

Notes

  • Scenarios deliberately avoid naming how turn-death, quota kills, stalls, or an unreadable
    harness surface are induced — the PREQ requires them inducible; the mechanism is a design
    decision and will be named when lanes are annotated.
  • No browser surface exists in this suite; lane annotation at technical-plan time is expected to
    route these to non-browser lanes.

Lane annotation (added by /dev:technical-plan, 2026-08-25)

  • All 13 scenarios: integration-coveredplugin/skills/supervise/test/supervisor-flow.sh,
    the shell integration suite this feature itself authors (TDD red-first in /dev:develop; each
    scenario is bound to it by the SREQ Acceptance Criteria table). The executor is confirmed
    runnable in this environment: bash + jq (suite preflight green), same harness conventions as
    the existing _shared/procedures/test/ and adapter test/ suites. The suite drives the
    supervisor daemon against synthetic transcripts built from the plan-time recorded harness
    record shapes (external-contracts/ provenance), a stub claude on PATH, the local-fs
    adapter as forge target, and stub notify/post-resume commands — so every "induce/simulate"
    prerequisite in this plan is satisfied without waiting for a real 529.
  • No scenario is routed to e2e-browser, config-variant, or standalone human-uat: this
    project declares no browser surface (qa_domains.not_applicable: e2e/a11y/security-browser),
    tunable variants run as per-invocation suite inputs (no server or restart exists), and no
    scenario requires live-external writes. Human judgement enters at the UAT gate as declared
    (uat.url_source: dogfood a supervised run against a real project), which is the run-level
    overlay on top of these lanes, not a replacement for any one scenario.
<!-- test-plan:v1 issue=46 skill=technical-plan --> # Test Plan: run-supervisor (issue #46) ## Prerequisites The *state* the scenarios need (how each condition is induced/simulated is stated per scenario in plain terms; the concrete mechanism is decided at design time — the PREQ requires only that every condition be inducible rather than waited for): - [ ] A project with the pipeline configured, on which an unattended run can be started with supervision engaged at launch (supervision is opt-in at launch) - [ ] A way to end the driver's turn with a simulated transient error (429/500/502/503/529-class) - [ ] A way to end the driver's turn with a simulated quota kill — one variant carrying a stated reset time, one carrying none - [ ] A way to make the driver stop making progress without ending its turn (simulated stall) - [ ] A project declaration carrying overridden supervisor tunables (retry bound, backoff, stall threshold), and a second setup with no override (suite defaults in force) - [ ] A project declaration naming a notification channel, and a second setup with none declared - [ ] A project declaring a post-resume claims-reconstruction step whose invocation leaves a visible trace, and a second setup with no such step declared ### Required Test Data - [ ] One supervised unattended run per scenario (scenarios are independent; each starts its own) - [ ] Access to the run's durable forge record, to inspect what the supervisor wrote ## Test Scenarios ### Scenario 1: Transient turn-death is resumed automatically **Acceptance criterion:** "Given a supervised unattended run whose driver turn ends on a transient error (per the classification rule), when the supervisor detects the run is resumable, then the run is resumed without operator input, with attempts bounded and backoff-spaced per the declared (or default) values." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Start a supervised unattended run; walk away (no operator input from here on) 2. Induce a transient error that ends the driver's turn (e.g. simulated 529) 3. Verify: the run resumes and continues its work with no operator input 4. Verify: the run's record shows the detection and the resume, including the attempt number 5. Verify: if more than one attempt was needed, the gaps between attempts grow, and attempt spacing is consistent with the values in force (defaults, in this setup) **Expected outcome:** the run finishes its phase work as if the stall had been mere slowness; the record distinguishes it from slowness. ### Scenario 2: Retry bound exhausted → escalation naming the count **Acceptance criterion:** "Given the per-incident retry bound is exhausted without a successful resume, when the last attempt fails, then the supervisor stops retrying and escalates, naming the attempt count and the error." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Start a supervised unattended run 2. Induce a transient turn-death that keeps recurring so every resume attempt fails 3. Verify: attempts stop after the bound in force is reached (count the recorded attempts) 4. Verify: an escalation is recorded naming the attempt count and the error observed 5. Verify: no further attempts appear after the escalation **Expected outcome:** bounded behavior — neither a single give-up nor an infinite loop; the operator can read exactly what was tried. ### Scenario 3: Quota kill with stated reset → scheduled resume **Acceptance criterion:** "Given a driver killed by quota exhaustion with a stated reset time, when the supervisor detects it, then the reset time is recorded and the resume is scheduled against that time (immediately, if the reset is already past), and the run resumes without operator input." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Start a supervised unattended run 2. Induce a quota kill carrying a stated reset time a few minutes in the future 3. Verify: the stated reset time appears in the run's record at detection time 4. Verify: the run does not resume before the reset time 5. Verify: the run resumes at/promptly after the reset time with no operator input **Expected outcome:** the wait is measured against the platform's own reset, not guessed; zero time lost past the reset beyond ordinary latency. ### Scenario 4: Quota kill with a reset already past → immediate resume **Acceptance criterion:** same as Scenario 3 (the "immediately, if the reset is already past" clause). **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Start a supervised unattended run 2. Induce a quota kill whose stated reset time is already in the past 3. Verify: the recorded reset time appears in the record, and the resume happens immediately **Expected outcome:** no wait against a wall that has already fallen. ### Scenario 5: Quota kill with no discoverable reset → bounded-retry path **Acceptance criterion:** "Given a quota kill with no discoverable reset time, when the supervisor detects it, then it follows the bounded-retry path per the classification rule, escalating on exhaustion with what it observed." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Start a supervised unattended run 2. Induce a quota kill carrying no reset time 3. Verify: the supervisor retries per the bounded-retry path (attempts recorded, spaced, bounded) 4. If exhausted: verify the escalation states what was observed (a quota kill, no reset found) **Expected outcome:** no blind polling and no silent stop; the classification rule's else-branch is visibly taken. ### Scenario 6: Stalled but possibly mid-work → alert only, no writes **Acceptance criterion:** "Given a driver that stops making progress without positive evidence that its turn is over, when the declared (or default) stall threshold passes, then the supervisor escalates and does not resume, nudge, or otherwise write into the session." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Start a supervised unattended run 2. Make the driver stop progressing without ending its turn 3. Wait past the stall threshold in force 4. Verify: an alert is recorded (and delivered via the declared channel, if this setup has one) 5. Verify: nothing was written into the driver session — no resume, no nudge; the session's state is exactly as the stall left it **Expected outcome:** the wedged run becomes visible; the supervisor never risks double-driving a session that might still be working. ### Scenario 7: Operator-initiated stop is never auto-resumed **Acceptance criterion:** "Given any resume, when the supervisor starts it, then the resumability rule held: positive evidence of no turn in flight, a self-clearing cause, and not an operator-initiated stop." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Start a supervised unattended run 2. Stop the run deliberately, as the operator would (an intentional interrupt/stop) 3. Wait past every threshold in force 4. Verify: the supervisor does not resume the run 5. Cross-check with Scenarios 1 and 3: every resume that did happen has, in the record, the evidence that no turn was in flight and the self-clearing cause it acted on **Expected outcome:** a human's decision to stop a run is final for the supervisor; resumes happen only on recorded positive evidence. ### Scenario 8: Clean completion → supervisor stands down **Acceptance criterion:** "Given a supervised run that completes normally, when the driver finishes, then the supervisor stands down without intervening, and this is visible in the run's record." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Start a supervised unattended run that will complete without incident 2. Let it finish 3. Verify: the record shows the supervisor standing down after completion 4. Verify: no interventions were recorded during the run **Expected outcome:** supervision of a healthy run is invisible except for its stand-down entry. ### Scenario 9: Second attach refused **Acceptance criterion:** "Given a run that already has a supervisor attached, when a second supervisor attempts to attach, then the attach is refused — at most one supervisor per run." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Start a supervised unattended run 2. Attempt to engage a second supervisor on the same run 3. Verify: the second attach is refused with a message naming the existing supervision 4. Verify: the run continues under exactly one supervisor (induce a transient turn-death and confirm exactly one resume happens) **Expected outcome:** no double-resume is possible from doubled supervision. ### Scenario 10: Harness surface unavailable → escalate, don't act **Acceptance criterion:** "Given the supervisor cannot read the driver's state or cannot trigger a resume (the harness surface is unavailable or refuses), when it detects this, then it escalates with what it observed rather than acting on ambiguity." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Start a supervised unattended run 2. Make the driver-state surface unreadable to the supervisor (unavailable or refusing) 3. Induce a driver turn-death while the surface is unreadable 4. Verify: no resume is attempted 5. Verify: an escalation is recorded stating that the state surface was unreadable and what was observed **Expected outcome:** blindness is treated as ambiguity — surfaced loudly, never acted on. ### Scenario 11: Declared post-resume reconstruction step is invoked **Acceptance criterion:** "Given a project that declares a post-resume claims-reconstruction step, when the supervisor resumes a run, then that step is invoked before phase work continues." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. On the setup whose declaration includes a post-resume step with a visible trace, start a supervised unattended run 2. Induce a transient turn-death; let the supervisor resume 3. Verify: the declared step's trace appears, and it appears before the run's next phase work 4. On the setup with no declared step: repeat 1–2 and verify the resume proceeds with no such invocation and no error about its absence **Expected outcome:** the hook fires when declared, is a no-op when not, and always precedes resumed phase work. ### Scenario 12: Everything is on the record; channel delivery when declared **Acceptance criterion:** "Given any supervisor intervention or escalation …, when it happens, then it is written to the run's durable forge record — and additionally delivered via the project's declared notification channel, when one is declared." **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. Re-inspect the runs from Scenarios 1, 2, 3, 6, and 8 2. Verify: every detection, attempt, scheduled resume, alert, and stand-down those scenarios produced appears in the run's durable forge record, legible to a reader who was not present 3. On the setup with a declared notification channel, induce one escalation and verify it arrives on that channel as well as in the record 4. On the setup with no declared channel, induce one escalation and verify the record alone carries it, completely **Expected outcome:** a retrospective reader can reconstruct every stall and its handling from the record; the channel is additive, never the only copy. ### Scenario 13: Declared tunables are the values in force **Acceptance criterion:** the "per the declared (or default) values" clauses of the retry and stall criteria. **Lane:** integration-covered — `plugin/skills/supervise/test/supervisor-flow.sh` 1. On the setup with overridden tunables (a retry bound and stall threshold different from the suite defaults), run Scenario 2's steps and Scenario 6's steps 2. Verify: the attempt count at exhaustion matches the declared bound, not the default 3. Verify: the stall alert fires against the declared threshold, not the default **Expected outcome:** the declaration is honored; the acceptance criteria are judged against whichever values are in force. ## Notes - Scenarios deliberately avoid naming how turn-death, quota kills, stalls, or an unreadable harness surface are induced — the PREQ requires them inducible; the mechanism is a design decision and will be named when lanes are annotated. - No browser surface exists in this suite; lane annotation at technical-plan time is expected to route these to non-browser lanes. ### Lane annotation (added by /dev:technical-plan, 2026-08-25) - All 13 scenarios: `integration-covered` — `plugin/skills/supervise/test/supervisor-flow.sh`, the shell integration suite this feature itself authors (TDD red-first in /dev:develop; each scenario is bound to it by the SREQ Acceptance Criteria table). The executor is confirmed runnable in this environment: bash + jq (suite preflight green), same harness conventions as the existing `_shared/procedures/test/` and adapter `test/` suites. The suite drives the supervisor daemon against synthetic transcripts built from the plan-time **recorded** harness record shapes (`external-contracts/` provenance), a stub `claude` on PATH, the `local-fs` adapter as forge target, and stub notify/post-resume commands — so every "induce/simulate" prerequisite in this plan is satisfied without waiting for a real 529. - No scenario is routed to `e2e-browser`, `config-variant`, or standalone `human-uat`: this project declares no browser surface (`qa_domains.not_applicable`: e2e/a11y/security-browser), tunable variants run as per-invocation suite inputs (no server or restart exists), and no scenario requires live-external writes. Human judgement enters at the UAT gate as declared (`uat.url_source`: dogfood a supervised run against a real project), which is the run-level overlay on top of these lanes, not a replacement for any one scenario.
Author
Owner
{
  "next_state": "developing",
  "produced": [
    {
      "kind": "sreq",
      "ref": "comment:1575",
      "summary": "SREQ for run-supervisor (Tier 3)"
    },
    {
      "kind": "test-plan",
      "ref": "comment:1579",
      "summary": "Test plan for run-supervisor — lanes annotated: 13/13 integration-covered (named suite authored by this feature)"
    }
  ],
  "findings": [
    {
      "category": "out-of-scope",
      "summary": "Reclaim semantics for open claims after driver death (who may reclaim, on what evidence)",
      "reasoning": "Flagged as out of scope in the approved PREQ. Interfaced via the post-resume hook (declared post_resume_command), not absorbed — #65 (linked relates_to) owns the semantics and depends on #43's in-flight claims ledger. Already tracked; no new sibling issue needed.",
      "proposed_action": "accept",
      "target": null,
      "id": "F-PO-46-2-1"
    },
    {
      "category": "out-of-scope",
      "summary": "Nudging or resuming a session without positive evidence its turn is over",
      "reasoning": "Flagged as out of scope in the approved PREQ. Alert-only by decision (positive-death-check rule) — a nudge mid-turn risks double-driving; revisit only with evidence alert-only strands wedged runs. A deliberate rejection, not deferred work.",
      "proposed_action": "accept",
      "target": null,
      "id": "F-PO-46-2-2"
    },
    {
      "category": "out-of-scope",
      "summary": "Supervisor high-availability (crashed supervisor / host reboot mid-run is itself unsupervised)",
      "reasoning": "Flagged as out of scope in the approved PREQ. The who-watches-the-watcher recursion stops here deliberately; supervisor absence is visible in the run record (interventions stop appearing) and, per the SREQ, via the heartbeat that supervisor-status.sh reports. A deliberate boundary, not deferred work.",
      "proposed_action": "accept",
      "target": null,
      "id": "F-PO-46-2-3"
    },
    {
      "category": "out-of-scope",
      "summary": "Supervision of attended/interactive sessions",
      "reasoning": "Flagged as out of scope in the approved PREQ. The human present is the supervisor; supervision is opt-in at unattended launch only. A deliberate boundary, not deferred work.",
      "proposed_action": "accept",
      "target": null,
      "id": "F-PO-46-2-4"
    },
    {
      "category": "in-scope-deferrable",
      "summary": "Configurable re-alert cadence for long-lived alert conditions (UX reviewer)",
      "reasoning": "Reviewer suggestion acknowledged but not actioned in this SREQ — see Expert Review > Noted (not actioned). Rejected on simplicity grounds for this slice: once-per-condition alert dedup ships; a declared re-alert interval is not added until evidence shows single-shot alerts get missed. No follow-up ticket warranted without that evidence.",
      "proposed_action": "accept",
      "id": "F-PO-46-2-5"
    },
    {
      "category": "in-scope-deferrable",
      "summary": "Active supervisor self-death detection beyond passive visibility (UX reviewer)",
      "reasoning": "Reviewer suggestion acknowledged but not actioned in this SREQ — see Expert Review > Noted (not actioned). Already covered in part by what shipped (heartbeat in state + supervisor-status.sh staleness reporting + daemon-death recorded at next attach); the active watching-the-watcher remainder is the PREQ's explicit high-availability out-of-scope (finding F#3).",
      "proposed_action": "accept",
      "id": "F-PO-46-2-6"
    }
  ],
  "pending_decisions": [
    {
      "id": "D-PO-46-2-1",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Out of scope: 'Reclaim semantics for open claims after driver death (who may reclaim, on what evidence)'. Spawn a sibling issue, or accept (no follow-up)?",
      "options": [
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-2-1",
      "reasoning": "Flagged as out of scope in the approved PREQ. Interfaced via the post-resume hook (declared post_resume_command), not absorbed — #65 (linked relates_to) owns the semantics and depends on #43's in-flight claims ledger. Already tracked; no new sibling issue needed."
    },
    {
      "id": "D-PO-46-2-2",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Out of scope: 'Nudging or resuming a session without positive evidence its turn is over'. Spawn a sibling issue, or accept (no follow-up)?",
      "options": [
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-2-2",
      "reasoning": "Flagged as out of scope in the approved PREQ. Alert-only by decision (positive-death-check rule) — a nudge mid-turn risks double-driving; revisit only with evidence alert-only strands wedged runs. A deliberate rejection, not deferred work."
    },
    {
      "id": "D-PO-46-2-3",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Out of scope: 'Supervisor high-availability (crashed supervisor / host reboot mid-run is itself unsupervised)'. Spawn a sibling issue, or accept (no follow-up)?",
      "options": [
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-2-3",
      "reasoning": "Flagged as out of scope in the approved PREQ. The who-watches-the-watcher recursion stops here deliberately; supervisor absence is visible in the run record (interventions stop appearing) and, per the SREQ, via the heartbeat that supervisor-status.sh reports. A deliberate boundary, not deferred work."
    },
    {
      "id": "D-PO-46-2-4",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Out of scope: 'Supervision of attended/interactive sessions'. Spawn a sibling issue, or accept (no follow-up)?",
      "options": [
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-2-4",
      "reasoning": "Flagged as out of scope in the approved PREQ. The human present is the supervisor; supervision is opt-in at unattended launch only. A deliberate boundary, not deferred work."
    },
    {
      "id": "D-PO-46-2-5",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Expert-review note (not actioned): 'Configurable re-alert cadence for long-lived alert conditions (UX reviewer)'. Spawn a sibling issue, or accept the disposition?",
      "options": [
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-2-5",
      "reasoning": "Reviewer suggestion acknowledged but not actioned in this SREQ — see Expert Review > Noted (not actioned). Rejected on simplicity grounds for this slice: once-per-condition alert dedup ships; a declared re-alert interval is not added until evidence shows single-shot alerts get missed. No follow-up ticket warranted without that evidence."
    },
    {
      "id": "D-PO-46-2-6",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Expert-review note (not actioned): 'Active supervisor self-death detection beyond passive visibility (UX reviewer)'. Spawn a sibling issue, or accept the disposition?",
      "options": [
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-2-6",
      "reasoning": "Reviewer suggestion acknowledged but not actioned in this SREQ — see Expert Review > Noted (not actioned). Already covered in part by what shipped (heartbeat in state + supervisor-status.sh staleness reporting + daemon-death recorded at next attach); the active watching-the-watcher remainder is the PREQ's explicit high-availability out-of-scope (finding F#3)."
    }
  ],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-2 skill=technical-plan --> ```json { "next_state": "developing", "produced": [ { "kind": "sreq", "ref": "comment:1575", "summary": "SREQ for run-supervisor (Tier 3)" }, { "kind": "test-plan", "ref": "comment:1579", "summary": "Test plan for run-supervisor — lanes annotated: 13/13 integration-covered (named suite authored by this feature)" } ], "findings": [ { "category": "out-of-scope", "summary": "Reclaim semantics for open claims after driver death (who may reclaim, on what evidence)", "reasoning": "Flagged as out of scope in the approved PREQ. Interfaced via the post-resume hook (declared post_resume_command), not absorbed — #65 (linked relates_to) owns the semantics and depends on #43's in-flight claims ledger. Already tracked; no new sibling issue needed.", "proposed_action": "accept", "target": null, "id": "F-PO-46-2-1" }, { "category": "out-of-scope", "summary": "Nudging or resuming a session without positive evidence its turn is over", "reasoning": "Flagged as out of scope in the approved PREQ. Alert-only by decision (positive-death-check rule) — a nudge mid-turn risks double-driving; revisit only with evidence alert-only strands wedged runs. A deliberate rejection, not deferred work.", "proposed_action": "accept", "target": null, "id": "F-PO-46-2-2" }, { "category": "out-of-scope", "summary": "Supervisor high-availability (crashed supervisor / host reboot mid-run is itself unsupervised)", "reasoning": "Flagged as out of scope in the approved PREQ. The who-watches-the-watcher recursion stops here deliberately; supervisor absence is visible in the run record (interventions stop appearing) and, per the SREQ, via the heartbeat that supervisor-status.sh reports. A deliberate boundary, not deferred work.", "proposed_action": "accept", "target": null, "id": "F-PO-46-2-3" }, { "category": "out-of-scope", "summary": "Supervision of attended/interactive sessions", "reasoning": "Flagged as out of scope in the approved PREQ. The human present is the supervisor; supervision is opt-in at unattended launch only. A deliberate boundary, not deferred work.", "proposed_action": "accept", "target": null, "id": "F-PO-46-2-4" }, { "category": "in-scope-deferrable", "summary": "Configurable re-alert cadence for long-lived alert conditions (UX reviewer)", "reasoning": "Reviewer suggestion acknowledged but not actioned in this SREQ — see Expert Review > Noted (not actioned). Rejected on simplicity grounds for this slice: once-per-condition alert dedup ships; a declared re-alert interval is not added until evidence shows single-shot alerts get missed. No follow-up ticket warranted without that evidence.", "proposed_action": "accept", "id": "F-PO-46-2-5" }, { "category": "in-scope-deferrable", "summary": "Active supervisor self-death detection beyond passive visibility (UX reviewer)", "reasoning": "Reviewer suggestion acknowledged but not actioned in this SREQ — see Expert Review > Noted (not actioned). Already covered in part by what shipped (heartbeat in state + supervisor-status.sh staleness reporting + daemon-death recorded at next attach); the active watching-the-watcher remainder is the PREQ's explicit high-availability out-of-scope (finding F#3).", "proposed_action": "accept", "id": "F-PO-46-2-6" } ], "pending_decisions": [ { "id": "D-PO-46-2-1", "type": "scope-disposition", "blocking": false, "question": "Out of scope: 'Reclaim semantics for open claims after driver death (who may reclaim, on what evidence)'. Spawn a sibling issue, or accept (no follow-up)?", "options": [ "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-2-1", "reasoning": "Flagged as out of scope in the approved PREQ. Interfaced via the post-resume hook (declared post_resume_command), not absorbed — #65 (linked relates_to) owns the semantics and depends on #43's in-flight claims ledger. Already tracked; no new sibling issue needed." }, { "id": "D-PO-46-2-2", "type": "scope-disposition", "blocking": false, "question": "Out of scope: 'Nudging or resuming a session without positive evidence its turn is over'. Spawn a sibling issue, or accept (no follow-up)?", "options": [ "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-2-2", "reasoning": "Flagged as out of scope in the approved PREQ. Alert-only by decision (positive-death-check rule) — a nudge mid-turn risks double-driving; revisit only with evidence alert-only strands wedged runs. A deliberate rejection, not deferred work." }, { "id": "D-PO-46-2-3", "type": "scope-disposition", "blocking": false, "question": "Out of scope: 'Supervisor high-availability (crashed supervisor / host reboot mid-run is itself unsupervised)'. Spawn a sibling issue, or accept (no follow-up)?", "options": [ "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-2-3", "reasoning": "Flagged as out of scope in the approved PREQ. The who-watches-the-watcher recursion stops here deliberately; supervisor absence is visible in the run record (interventions stop appearing) and, per the SREQ, via the heartbeat that supervisor-status.sh reports. A deliberate boundary, not deferred work." }, { "id": "D-PO-46-2-4", "type": "scope-disposition", "blocking": false, "question": "Out of scope: 'Supervision of attended/interactive sessions'. Spawn a sibling issue, or accept (no follow-up)?", "options": [ "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-2-4", "reasoning": "Flagged as out of scope in the approved PREQ. The human present is the supervisor; supervision is opt-in at unattended launch only. A deliberate boundary, not deferred work." }, { "id": "D-PO-46-2-5", "type": "scope-disposition", "blocking": false, "question": "Expert-review note (not actioned): 'Configurable re-alert cadence for long-lived alert conditions (UX reviewer)'. Spawn a sibling issue, or accept the disposition?", "options": [ "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-2-5", "reasoning": "Reviewer suggestion acknowledged but not actioned in this SREQ — see Expert Review > Noted (not actioned). Rejected on simplicity grounds for this slice: once-per-condition alert dedup ships; a declared re-alert interval is not added until evidence shows single-shot alerts get missed. No follow-up ticket warranted without that evidence." }, { "id": "D-PO-46-2-6", "type": "scope-disposition", "blocking": false, "question": "Expert-review note (not actioned): 'Active supervisor self-death detection beyond passive visibility (UX reviewer)'. Spawn a sibling issue, or accept the disposition?", "options": [ "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-2-6", "reasoning": "Reviewer suggestion acknowledged but not actioned in this SREQ — see Expert Review > Noted (not actioned). Already covered in part by what shipped (heartbeat in state + supervisor-status.sh staleness reporting + daemon-death recorded at next attach); the active watching-the-watcher remainder is the PREQ's explicit high-availability out-of-scope (finding F#3)." } ], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Already tracked: #65 (linked relates_to) owns reclaim semantics and depends on #43's in-flight claims ledger; this slice ships only the post_resume_command hook, so a new sibling would duplicate #65. Resolved accept on the operator's instruction (2026-08-25). Rejected alternative: defer-to-issue — would spawn a duplicate of #65."
}
<!-- decision-resolution:v1 ref=D-PO-46-2-1 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Already tracked: #65 (linked relates_to) owns reclaim semantics and depends on #43's in-flight claims ledger; this slice ships only the post_resume_command hook, so a new sibling would duplicate #65. Resolved accept on the operator's instruction (2026-08-25). Rejected alternative: defer-to-issue — would spawn a duplicate of #65." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Deliberate rejection, not deferred work: the PREQ's positive-death-check rule makes alert-only the decision — a nudge mid-turn risks double-driving. Revisit only with evidence that alert-only strands wedged runs; until then there is nothing to track. Resolved accept on the operator's instruction (2026-08-25)."
}
<!-- decision-resolution:v1 ref=D-PO-46-2-2 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Deliberate rejection, not deferred work: the PREQ's positive-death-check rule makes alert-only the decision — a nudge mid-turn risks double-driving. Revisit only with evidence that alert-only strands wedged runs; until then there is nothing to track. Resolved accept on the operator's instruction (2026-08-25)." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Deliberate boundary per the PREQ: the who-watches-the-watcher recursion stops at the supervisor. Its absence stays visible (interventions stop appearing in the run record; heartbeat + supervisor-status.sh staleness shipped in the SREQ), so no follow-up ticket is warranted. Resolved accept on the operator's instruction (2026-08-25)."
}
<!-- decision-resolution:v1 ref=D-PO-46-2-3 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Deliberate boundary per the PREQ: the who-watches-the-watcher recursion stops at the supervisor. Its absence stays visible (interventions stop appearing in the run record; heartbeat + supervisor-status.sh staleness shipped in the SREQ), so no follow-up ticket is warranted. Resolved accept on the operator's instruction (2026-08-25)." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Deliberate boundary per the PREQ: an attended session's human IS the supervisor; supervision is opt-in at unattended launch only. Nothing to build or track. Resolved accept on the operator's instruction (2026-08-25)."
}
<!-- decision-resolution:v1 ref=D-PO-46-2-4 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Deliberate boundary per the PREQ: an attended session's human IS the supervisor; supervision is opt-in at unattended launch only. Nothing to build or track. Resolved accept on the operator's instruction (2026-08-25)." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Once-per-condition alert dedup ships in this slice; a declared re-alert interval is deliberately withheld until evidence shows single-shot alerts get missed (no such evidence exists — the incidents were missed resumes, not missed alerts). Resolved accept on the operator's instruction (2026-08-25). Rejected alternative: defer-to-issue — a ticket without evidence would be speculative backlog."
}
<!-- decision-resolution:v1 ref=D-PO-46-2-5 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Once-per-condition alert dedup ships in this slice; a declared re-alert interval is deliberately withheld until evidence shows single-shot alerts get missed (no such evidence exists — the incidents were missed resumes, not missed alerts). Resolved accept on the operator's instruction (2026-08-25). Rejected alternative: defer-to-issue — a ticket without evidence would be speculative backlog." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Partially shipped (heartbeat in state, supervisor-status.sh staleness reporting, daemon death recorded at next attach); the active watching-the-watcher remainder is the PREQ's explicit HA out-of-scope, already dispositioned as finding F-PO-46-2-3. Resolved accept on the operator's instruction (2026-08-25)."
}
<!-- decision-resolution:v1 ref=D-PO-46-2-6 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Partially shipped (heartbeat in state, supervisor-status.sh staleness reporting, daemon death recorded at next attach); the active watching-the-watcher remainder is the PREQ's explicit HA out-of-scope, already dispositioned as finding F-PO-46-2-3. Resolved accept on the operator's instruction (2026-08-25)." } ```
Author
Owner
{
  "waves": [
    {
      "wave": 1,
      "work_units": [
        {
          "id": "WU-46-3-1",
          "title": "Supervise skill: SKILL.md + four bin helpers + shell integration test suite",
          "files": [
            "plugin/skills/supervise/SKILL.md",
            "plugin/skills/supervise/bin/supervisor-attach.sh",
            "plugin/skills/supervise/bin/supervisor-watch.sh",
            "plugin/skills/supervise/bin/supervisor-status.sh",
            "plugin/skills/supervise/bin/supervisor-detach.sh",
            "plugin/skills/supervise/test/"
          ],
          "acceptance_criteria": [
            {"id": "AC-1"}, {"id": "AC-2"}, {"id": "AC-3"}, {"id": "AC-4"},
            {"id": "AC-5"}, {"id": "AC-6"}, {"id": "AC-7"}, {"id": "AC-8"},
            {"id": "AC-9"}, {"id": "AC-10"}, {"id": "AC-11"}, {"id": "AC-12"},
            {"id": "AC-13"},
            {"id": "AC-14", "scope": "helpers pass the existing gate; no gate edit needed — lint-conventions.sh's find already covers any new plugin/skills/*/bin/"}
          ]
        }
      ]
    },
    {
      "wave": 2,
      "work_units": [
        {
          "id": "WU-46-3-2",
          "title": "Suite integration touches: run-template v5 opt-in engage line + wait-discipline §3a pointer",
          "files": [
            "plugin/skills/_shared/run-template.md",
            "plugin/skills/_shared/procedures/wait-discipline.md"
          ],
          "acceptance_criteria": []
        }
      ]
    }
  ]
}

Decomposition notes: WU-1 is the SREQ's single-writer coherent unit (skill doc, helper tier,
TDD suite with provenance-tagged fixtures from the feature folder's external-contracts/). WU-2
is artifact-shape (two one-paragraph pointer edits in _shared/) — Test Writer skipped per the
artifact-shape exception; it runs in wave 2 so its engage line documents the flags WU-1's
attach helper actually ships. Two SREQ scope areas need no change at all, verified against the
tree: scripts/lint-conventions.sh (its find glob already scans any plugin/skills//bin/.sh)
and the plugin manifests (skills are not enumerated). Single shared worktree: execution is
sequential (Test Writer → Implementer per WU, WU-1 before WU-2).

<!-- wu-plan:v1 po=PO-46-3 skill=develop --> ```json { "waves": [ { "wave": 1, "work_units": [ { "id": "WU-46-3-1", "title": "Supervise skill: SKILL.md + four bin helpers + shell integration test suite", "files": [ "plugin/skills/supervise/SKILL.md", "plugin/skills/supervise/bin/supervisor-attach.sh", "plugin/skills/supervise/bin/supervisor-watch.sh", "plugin/skills/supervise/bin/supervisor-status.sh", "plugin/skills/supervise/bin/supervisor-detach.sh", "plugin/skills/supervise/test/" ], "acceptance_criteria": [ {"id": "AC-1"}, {"id": "AC-2"}, {"id": "AC-3"}, {"id": "AC-4"}, {"id": "AC-5"}, {"id": "AC-6"}, {"id": "AC-7"}, {"id": "AC-8"}, {"id": "AC-9"}, {"id": "AC-10"}, {"id": "AC-11"}, {"id": "AC-12"}, {"id": "AC-13"}, {"id": "AC-14", "scope": "helpers pass the existing gate; no gate edit needed — lint-conventions.sh's find already covers any new plugin/skills/*/bin/"} ] } ] }, { "wave": 2, "work_units": [ { "id": "WU-46-3-2", "title": "Suite integration touches: run-template v5 opt-in engage line + wait-discipline §3a pointer", "files": [ "plugin/skills/_shared/run-template.md", "plugin/skills/_shared/procedures/wait-discipline.md" ], "acceptance_criteria": [] } ] } ] } ``` Decomposition notes: WU-1 is the SREQ's single-writer coherent unit (skill doc, helper tier, TDD suite with provenance-tagged fixtures from the feature folder's external-contracts/). WU-2 is artifact-shape (two one-paragraph pointer edits in _shared/) — Test Writer skipped per the artifact-shape exception; it runs in wave 2 so its engage line documents the flags WU-1's attach helper actually ships. Two SREQ scope areas need no change at all, verified against the tree: scripts/lint-conventions.sh (its find glob already scans any plugin/skills/*/bin/*.sh) and the plugin manifests (skills are not enumerated). Single shared worktree: execution is sequential (Test Writer → Implementer per WU, WU-1 before WU-2).
Author
Owner

Development Journal — WU-46-3-1 (supervise skill unit)

2026-08-25T17:45 DISCOVERY: the lint gate refuses /dev:supervise until a sibling WU widens it

type: discovery
timestamp: 2026-08-25T17:45
where: scripts/lint-conventions.sh
tags: [product-finding, lint, cross-wu-dependency]

Context: planning plugin/skills/supervise/SKILL.md, whose natural spelling of the skill's own
invocation is /dev:supervise.

Pattern (PRODUCT FINDING — for the lead's finding pipeline): scripts/lint-conventions.sh
hardcodes the 14 shipped skills in SHIPPED_SKILLS and reports every /dev:<name> outside that
list as a violation ("unknown /dev: skill reference"). supervise is the 15th, and the lint file is
owned by a sibling WU, which I am told not to touch. My own AC-14 requires
bash scripts/lint-conventions.sh to exit 0, so this WU cannot write the token /dev:supervise
into any shipped markdown until the sibling adds supervise to SHIPPED_SKILLS.

Why it matters: the constraint is invisible from the SREQ — it only shows up as a red AC-14 the
first time a new skill names itself. Two consequences the lead must route: (a) the sibling WU that
extends the lint gate must add supervise to SHIPPED_SKILLS (otherwise run-template.md and
wait-discipline.md, which are supposed to point at /dev:supervise, cannot land either); and
(b) more generally, adding a skill to the suite has an undocumented second step in the meta lane.
Until (a) lands I refer to the skill by its bare name in SKILL.md prose.

2026-08-25T18:05 DISCOVERY: the pre-resume abort must test "still resumable", not "same cause"

type: discovery
timestamp: 2026-08-25T18:05
where: plugin/skills/supervise/bin/supervisor-watch.sh
tags: [classification, bound, race]

Context: implementing the SREQ's "full re-classification immediately before every resume
attempt — abort on change". The obvious reading is "abort if the class differs from the class
that opened the incident".

Pattern: that reading is wrong, and AC-4 is the case that proves it. A quota kill whose
resume fails comes back as a 529, so the cause legitimately shifts
resumable-quota -> resumable-transient between attempts of the same incident. Aborting on
that shift caps the incident at one attempt and the declared bound never applies. The correct
abort test is two separate questions: is the class still in the resumable family (if not,
the run moved on — close the incident), and has the tail record moved out from under the
schedule
(if so, somebody else wrote — re-aim, but keep the attempt count).

Why it matters: keeping the attempt count on a moved tail is the load-bearing half. Resetting
it there turns "another writer is appending" into an unbounded resume loop, which is exactly the
failure the bound exists to prevent. The incident — and therefore the bound — is identified by
the incident being open, never by the cause staying constant.

2026-08-25T18:10 DISCOVERY: attach must heartbeat before it classifies, and the pre-resume re-check is what makes AC-9a deterministic

type: discovery
timestamp: 2026-08-25T18:10
where: plugin/skills/supervise/bin/supervisor-watch.sh
tags: [daemon, race, engage-verification]

Context: AC-9a chmods the transcript unreadable immediately after attach returns and asserts
no resume ever fires. Whether the daemon has already classified and scheduled by then is a race
the test cannot control.

Pattern: two things make it deterministic rather than lucky. (1) The daemon writes its first
heartbeat before its first classification, so attach's synchronous engage check means "this
process is alive and owns the session", not "it has already decided something". (2) The SREQ's
pre-resume full re-classification catches the surface going away between scheduling and
firing — so even when the daemon did schedule a resume before the chmod, the resume aborts and
escalates instead of firing. The security requirement and the test's determinism are the same
mechanism; neither was added for the other.

<!-- dev-journal:v1 wu=WU-46-3-1 skill=develop --> # Development Journal — WU-46-3-1 (supervise skill unit) ## 2026-08-25T17:45 DISCOVERY: the lint gate refuses `/dev:supervise` until a sibling WU widens it ```yaml type: discovery timestamp: 2026-08-25T17:45 where: scripts/lint-conventions.sh tags: [product-finding, lint, cross-wu-dependency] ``` **Context:** planning `plugin/skills/supervise/SKILL.md`, whose natural spelling of the skill's own invocation is `/dev:supervise`. **Pattern (PRODUCT FINDING — for the lead's finding pipeline):** `scripts/lint-conventions.sh` hardcodes the 14 shipped skills in `SHIPPED_SKILLS` and reports every `/dev:<name>` outside that list as a violation ("unknown /dev: skill reference"). `supervise` is the 15th, and the lint file is owned by a sibling WU, which I am told not to touch. My own AC-14 requires `bash scripts/lint-conventions.sh` to exit 0, so this WU cannot write the token `/dev:supervise` into any shipped markdown until the sibling adds `supervise` to `SHIPPED_SKILLS`. **Why it matters:** the constraint is invisible from the SREQ — it only shows up as a red AC-14 the first time a new skill names itself. Two consequences the lead must route: (a) the sibling WU that extends the lint gate must add `supervise` to `SHIPPED_SKILLS` (otherwise `run-template.md` and `wait-discipline.md`, which are supposed to point at `/dev:supervise`, cannot land either); and (b) more generally, adding a skill to the suite has an undocumented second step in the meta lane. Until (a) lands I refer to the skill by its bare name in SKILL.md prose. ## 2026-08-25T18:05 DISCOVERY: the pre-resume abort must test "still resumable", not "same cause" ```yaml type: discovery timestamp: 2026-08-25T18:05 where: plugin/skills/supervise/bin/supervisor-watch.sh tags: [classification, bound, race] ``` **Context:** implementing the SREQ's "full re-classification immediately before every resume attempt — abort on change". The obvious reading is "abort if the class differs from the class that opened the incident". **Pattern:** that reading is wrong, and AC-4 is the case that proves it. A quota kill whose resume fails comes back as a **529**, so the cause legitimately shifts `resumable-quota -> resumable-transient` *between attempts of the same incident*. Aborting on that shift caps the incident at one attempt and the declared bound never applies. The correct abort test is two separate questions: **is the class still in the resumable family** (if not, the run moved on — close the incident), and **has the tail record moved out from under the schedule** (if so, somebody else wrote — re-aim, but *keep* the attempt count). **Why it matters:** keeping the attempt count on a moved tail is the load-bearing half. Resetting it there turns "another writer is appending" into an unbounded resume loop, which is exactly the failure the bound exists to prevent. The incident — and therefore the bound — is identified by the incident being open, never by the cause staying constant. ## 2026-08-25T18:10 DISCOVERY: attach must heartbeat before it classifies, and the pre-resume re-check is what makes AC-9a deterministic ```yaml type: discovery timestamp: 2026-08-25T18:10 where: plugin/skills/supervise/bin/supervisor-watch.sh tags: [daemon, race, engage-verification] ``` **Context:** AC-9a chmods the transcript unreadable immediately after attach returns and asserts no resume ever fires. Whether the daemon has already classified and scheduled by then is a race the test cannot control. **Pattern:** two things make it deterministic rather than lucky. (1) The daemon writes its first heartbeat **before** its first classification, so attach's synchronous engage check means "this process is alive and owns the session", not "it has already decided something". (2) The SREQ's pre-resume full re-classification catches the surface going away *between* scheduling and firing — so even when the daemon did schedule a resume before the chmod, the resume aborts and escalates instead of firing. The security requirement and the test's determinism are the same mechanism; neither was added for the other.
Author
Owner
{
  "outcome": "complete",
  "summary": "Supervise skill unit: SKILL.md + four bin helpers (attach/watch/status/detach) + shared lib with the two isolated seams (classify, clock parse), driven green against the 14-AC TDD shell suite (98 checks, rc 0 across four runs); lint gate rc 0. SKILL.md deliberately avoids the /dev:supervise spelling until the lint gate's SHIPPED_SKILLS list is widened (handed to WU-46-3-2).",
  "commit_refs": ["678cec1", "415e1e5"],
  "journal_ref": "1694",
  "dependencies_satisfied": [],
  "dependencies_violated": []
}
<!-- work-unit-outcome:v1 id=WU-46-3-1 skill=develop --> ```json { "outcome": "complete", "summary": "Supervise skill unit: SKILL.md + four bin helpers (attach/watch/status/detach) + shared lib with the two isolated seams (classify, clock parse), driven green against the 14-AC TDD shell suite (98 checks, rc 0 across four runs); lint gate rc 0. SKILL.md deliberately avoids the /dev:supervise spelling until the lint gate's SHIPPED_SKILLS list is widened (handed to WU-46-3-2).", "commit_refs": ["678cec1", "415e1e5"], "journal_ref": "1694", "dependencies_satisfied": [], "dependencies_violated": [] } ```
Author
Owner

Dev journal — WU-46-3-2 (wire the run supervisor into the suite surfaces)

2026-08-25T18:05 DISCOVERY: test/supervisor-flow.sh AC-9a is timing-flaky

type: discovery
timestamp: 2026-08-25T18:05
where: plugin/skills/supervise/test/supervisor-flow.sh:757
tags: [flaky-test, wu-46-3-1, race]

Context: Running the WU-1 suite as this WU's third verification gate. It failed on run 1
(FAIL - AC-9a no resume attempted once the transcript is unreadable: expected [0] got [1]),
passed on run 2, failed again on run 3 — same assertion each time, no other failure.

Pattern: Not caused by this WU. The suite reads no markdown at all (grep -n 'SKILL.md' plugin/skills/supervise/test/supervisor-flow.sh finds nothing), and the only non-markdown file
this WU touches is scripts/lint-conventions.sh, which the suite does exercise — AC-14 runs it
and reports ok on every run, including the failing ones.

The race is in the scenario itself: scenario_ac9_unreadable seeds a transient 529 on the
transcript, attaches with poll_interval_seconds=1 / backoff_base_seconds=1, and only then
runs chmod 000 on the transcript. Attach returns after the daemon's first heartbeat, so the
daemon is already polling a readable transcript carrying a resumable cause. Whether it fires a
resume before the chmod lands is a sub-second coin flip. The assertion wants "no resume once
unreadable", but it counts all resumes, including a legitimate one issued while the transcript
was still readable.

Why it matters: It is a false red on a gate other WUs must judge themselves by, and it is in
WU-46-3-1's territory (test/* is off-limits to this WU), so it is reported up rather than fixed
here.

2026-08-25T18:20 COMPLETE

type: complete
variant: development
timestamp: 2026-08-25T18:20
iterations: 1

Hardest part: Deciding how far the "(v4)" → "(v5)" rename should reach in run-template.md
the execution-model paragraph names the current version twice while also narrating v3 history, so
only the two current-version mentions moved and every historical mention (and every version-log
row) stayed put.

If I did this again: Run the WU-1 suite once before making any edit, to have a pre-edit
baseline for a flake like AC-9a instead of having to reason backwards from what the suite reads.

<!-- dev-journal:v1 wu=WU-46-3-2 skill=develop --> # Dev journal — WU-46-3-2 (wire the run supervisor into the suite surfaces) ## 2026-08-25T18:05 DISCOVERY: `test/supervisor-flow.sh` AC-9a is timing-flaky ```yaml type: discovery timestamp: 2026-08-25T18:05 where: plugin/skills/supervise/test/supervisor-flow.sh:757 tags: [flaky-test, wu-46-3-1, race] ``` **Context:** Running the WU-1 suite as this WU's third verification gate. It failed on run 1 (`FAIL - AC-9a no resume attempted once the transcript is unreadable: expected [0] got [1]`), passed on run 2, failed again on run 3 — same assertion each time, no other failure. **Pattern:** Not caused by this WU. The suite reads no markdown at all (`grep -n 'SKILL.md' plugin/skills/supervise/test/supervisor-flow.sh` finds nothing), and the only non-markdown file this WU touches is `scripts/lint-conventions.sh`, which the suite *does* exercise — AC-14 runs it and reports `ok` on every run, including the failing ones. The race is in the scenario itself: `scenario_ac9_unreadable` seeds a transient `529` on the transcript, attaches with `poll_interval_seconds=1` / `backoff_base_seconds=1`, and only *then* runs `chmod 000` on the transcript. Attach returns after the daemon's first heartbeat, so the daemon is already polling a readable transcript carrying a resumable cause. Whether it fires a resume before the `chmod` lands is a sub-second coin flip. The assertion wants "no resume once unreadable", but it counts *all* resumes, including a legitimate one issued while the transcript was still readable. **Why it matters:** It is a false red on a gate other WUs must judge themselves by, and it is in WU-46-3-1's territory (`test/*` is off-limits to this WU), so it is reported up rather than fixed here. ## 2026-08-25T18:20 COMPLETE ```yaml type: complete variant: development timestamp: 2026-08-25T18:20 iterations: 1 ``` **Hardest part:** Deciding how far the "(v4)" → "(v5)" rename should reach in `run-template.md` — the execution-model paragraph names the current version twice while also narrating v3 history, so only the two current-version mentions moved and every historical mention (and every version-log row) stayed put. **If I did this again:** Run the WU-1 suite once before making any edit, to have a pre-edit baseline for a flake like AC-9a instead of having to reason backwards from what the suite reads.
Author
Owner
{
  "outcome": "complete",
  "summary": "Suite wiring for the run supervisor: SHIPPED_SKILLS widened to include supervise (lint gate), run-template bumped to v5 with the opt-in step-0 engage line ($CLAUDE_CODE_SESSION_ID, non-zero attach = not engaged), wait-discipline §3a now points at /dev:supervise, SKILL.md prose switched to the /dev:supervise spelling. Artifact-shape WU; ACs verified by mechanical gates (lint rc 0, supervisor-flow rc 0, bash -n rc 0) + diff inspection — no behavioral tests, Test Writer skipped per the artifact-shape exception. Surfaced a pre-existing timing flake in WU-46-3-1's AC-9a scenario (routed to the cross-unit fix step).",
  "commit_refs": ["9691545"],
  "journal_ref": "1696",
  "dependencies_satisfied": ["WU-46-3-1"],
  "dependencies_violated": []
}
<!-- work-unit-outcome:v1 id=WU-46-3-2 skill=develop --> ```json { "outcome": "complete", "summary": "Suite wiring for the run supervisor: SHIPPED_SKILLS widened to include supervise (lint gate), run-template bumped to v5 with the opt-in step-0 engage line ($CLAUDE_CODE_SESSION_ID, non-zero attach = not engaged), wait-discipline §3a now points at /dev:supervise, SKILL.md prose switched to the /dev:supervise spelling. Artifact-shape WU; ACs verified by mechanical gates (lint rc 0, supervisor-flow rc 0, bash -n rc 0) + diff inspection — no behavioral tests, Test Writer skipped per the artifact-shape exception. Surfaced a pre-existing timing flake in WU-46-3-1's AC-9a scenario (routed to the cross-unit fix step).", "commit_refs": ["9691545"], "journal_ref": "1696", "dependencies_satisfied": ["WU-46-3-1"], "dependencies_violated": [] } ```
Author
Owner
{
  "phase": "develop",
  "learnings": [
    {
      "id": "L-1",
      "scope": "project",
      "status": "applied",
      "summary": "A new shipped skill must also be added to SHIPPED_SKILLS in scripts/lint-conventions.sh, or every /dev:<name> mention in shipped markdown fails the gate — an invisible-from-the-SREQ second step of adding a skill.",
      "evidence": "WU-46-3-1 DISCOVERY (SKILL.md had to avoid the /dev:supervise spelling until WU-46-3-2 widened the list)",
      "source_ref": "comment:1694",
      "applied_to": "CLAUDE.md"
    },
    {
      "id": "L-2",
      "scope": "devwork",
      "status": "unhomed",
      "summary": "A WU whose verification gate includes a sibling WU's test suite should run that suite once BEFORE its own edits, so a latent flake has a pre-edit baseline instead of requiring backwards reasoning mid-WU.",
      "evidence": "WU-46-3-2 DISCOVERY + COMPLETE (AC-9a flake surfaced during WU-2's gate runs and had to be attributed by code reading)",
      "source_ref": "comment:1696",
      "applied_to": null
    }
  ]
}
<!-- learning:v1 issue=46 skill=develop po=PO-46-3 --> ```json { "phase": "develop", "learnings": [ { "id": "L-1", "scope": "project", "status": "applied", "summary": "A new shipped skill must also be added to SHIPPED_SKILLS in scripts/lint-conventions.sh, or every /dev:<name> mention in shipped markdown fails the gate — an invisible-from-the-SREQ second step of adding a skill.", "evidence": "WU-46-3-1 DISCOVERY (SKILL.md had to avoid the /dev:supervise spelling until WU-46-3-2 widened the list)", "source_ref": "comment:1694", "applied_to": "CLAUDE.md" }, { "id": "L-2", "scope": "devwork", "status": "unhomed", "summary": "A WU whose verification gate includes a sibling WU's test suite should run that suite once BEFORE its own edits, so a latent flake has a pre-edit baseline instead of requiring backwards reasoning mid-WU.", "evidence": "WU-46-3-2 DISCOVERY + COMPLETE (AC-9a flake surfaced during WU-2's gate runs and had to be attributed by code reading)", "source_ref": "comment:1696", "applied_to": null } ] } ```
Author
Owner
{
  "next_state": "qa",
  "produced": [
    {
      "kind": "wu-plan",
      "ref": "1590",
      "summary": "2 waves / 2 WUs: supervise skill unit; _shared wiring (artifact-shape)"
    },
    {
      "kind": "work-unit-outcome",
      "ref": "1695",
      "summary": "WU-46-3-1: supervise skill — SKILL.md, 4 helpers + shared lib, 14-AC TDD suite green (98 checks)"
    },
    {
      "kind": "work-unit-outcome",
      "ref": "1697",
      "summary": "WU-46-3-2: SHIPPED_SKILLS widened, run-template v5 opt-in engage step, wait-discipline §3a pointer, /dev:supervise spelling"
    },
    {
      "kind": "dev-journal",
      "ref": "1694",
      "summary": "WU-46-3-1 development journal (3 discoveries incl. the SHIPPED_SKILLS product finding)"
    },
    {
      "kind": "dev-journal",
      "ref": "1696",
      "summary": "WU-46-3-2 development journal (AC-9a flake discovery)"
    },
    {
      "kind": "learning",
      "ref": "comment:1698",
      "summary": "2 learnings (1 applied to CLAUDE.md, 1 unhomed)"
    }
  ],
  "findings": [
    {
      "category": "in-scope-deferrable",
      "severity": "info",
      "summary": "The SREQ's pre-resume 'abort on change' rule was implemented as two separate tests, not the literal 'abort if the class changed': (a) class left the resumable family -> close the incident; (b) tail record moved -> re-aim the resume but KEEP the attempt count.",
      "reasoning": "The literal reading is wrong for AC-4: a quota resume that fails returns as a 529, so the cause legitimately shifts resumable-quota -> resumable-transient within one incident — aborting on that shift caps every quota incident at one attempt and the declared bound never applies. Keeping the attempt count on a moved tail is load-bearing the other way: resetting it would turn another writer appending records into an unbounded resume loop. Developer-decidable implementation interpretation, already verified by the suite (AC-2/AC-4); carried forward so the QA code-domain review scrutinizes the classification seam (supervisor-watch.sh + _supervisor-lib.sh sup_classify) knowing this deviation from the SREQ sentence is deliberate.",
      "proposed_action": "accept",
      "feature_value": "core",
      "requires_product_decision": false,
      "applied_disposition": "accept",
      "id": "F-PO-46-3-1"
    }
  ],
  "pending_decisions": [],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-3 skill=develop --> ```json { "next_state": "qa", "produced": [ { "kind": "wu-plan", "ref": "1590", "summary": "2 waves / 2 WUs: supervise skill unit; _shared wiring (artifact-shape)" }, { "kind": "work-unit-outcome", "ref": "1695", "summary": "WU-46-3-1: supervise skill — SKILL.md, 4 helpers + shared lib, 14-AC TDD suite green (98 checks)" }, { "kind": "work-unit-outcome", "ref": "1697", "summary": "WU-46-3-2: SHIPPED_SKILLS widened, run-template v5 opt-in engage step, wait-discipline §3a pointer, /dev:supervise spelling" }, { "kind": "dev-journal", "ref": "1694", "summary": "WU-46-3-1 development journal (3 discoveries incl. the SHIPPED_SKILLS product finding)" }, { "kind": "dev-journal", "ref": "1696", "summary": "WU-46-3-2 development journal (AC-9a flake discovery)" }, { "kind": "learning", "ref": "comment:1698", "summary": "2 learnings (1 applied to CLAUDE.md, 1 unhomed)" } ], "findings": [ { "category": "in-scope-deferrable", "severity": "info", "summary": "The SREQ's pre-resume 'abort on change' rule was implemented as two separate tests, not the literal 'abort if the class changed': (a) class left the resumable family -> close the incident; (b) tail record moved -> re-aim the resume but KEEP the attempt count.", "reasoning": "The literal reading is wrong for AC-4: a quota resume that fails returns as a 529, so the cause legitimately shifts resumable-quota -> resumable-transient within one incident — aborting on that shift caps every quota incident at one attempt and the declared bound never applies. Keeping the attempt count on a moved tail is load-bearing the other way: resetting it would turn another writer appending records into an unbounded resume loop. Developer-decidable implementation interpretation, already verified by the suite (AC-2/AC-4); carried forward so the QA code-domain review scrutinizes the classification seam (supervisor-watch.sh + _supervisor-lib.sh sup_classify) knowing this deviation from the SREQ sentence is deliberate.", "proposed_action": "accept", "feature_value": "core", "requires_product_decision": false, "applied_disposition": "accept", "id": "F-PO-46-3-1" } ], "pending_decisions": [], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner
{
  "outcome": "skipped",
  "summary": "e2e does not apply: markdown+shell skill suite, no application or browser surface",
  "findings": [],
  "not_applicable_reason": "markdown+shell skill suite — no application or browser surface to drive end-to-end; validation is the shell test harness plus dogfooding (project qa_domains declaration)"
}
<!-- qa-report:v1 issue=46 skill=qa domain=e2e phase=validate --> ```json { "outcome": "skipped", "summary": "e2e does not apply: markdown+shell skill suite, no application or browser surface", "findings": [], "not_applicable_reason": "markdown+shell skill suite — no application or browser surface to drive end-to-end; validation is the shell test harness plus dogfooding (project qa_domains declaration)" } ```
Author
Owner
{
  "outcome": "skipped",
  "summary": "a11y does not apply: no rendered UI",
  "findings": [],
  "not_applicable_reason": "no rendered UI — the deliverables are markdown skill text and shell helpers (project qa_domains declaration)"
}
<!-- qa-report:v1 issue=46 skill=qa domain=a11y phase=validate --> ```json { "outcome": "skipped", "summary": "a11y does not apply: no rendered UI", "findings": [], "not_applicable_reason": "no rendered UI — the deliverables are markdown skill text and shell helpers (project qa_domains declaration)" } ```
Author
Owner
{
  "outcome": "skipped",
  "summary": "security-browser does not apply: no browser surface",
  "findings": [],
  "not_applicable_reason": "no browser surface — nothing is served or rendered (project qa_domains declaration)"
}
<!-- qa-report:v1 issue=46 skill=qa domain=security-browser phase=validate --> ```json { "outcome": "skipped", "summary": "security-browser does not apply: no browser surface", "findings": [], "not_applicable_reason": "no browser surface — nothing is served or rendered (project qa_domains declaration)" } ```
Author
Owner
{
  "outcome": "skipped",
  "summary": "api does not apply: api_invocation mode none",
  "findings": [],
  "not_applicable_reason": "project declares api_invocation: { mode: none } — no API; markdown+shell skill suite"
}
<!-- qa-report:v1 issue=46 skill=qa domain=api phase=validate --> ```json { "outcome": "skipped", "summary": "api does not apply: api_invocation mode none", "findings": [], "not_applicable_reason": "project declares api_invocation: { mode: none } — no API; markdown+shell skill suite" } ```
Author
Owner
{
  "outcome": "skipped",
  "summary": "security-api does not apply: api_invocation mode none",
  "findings": [],
  "not_applicable_reason": "project declares api_invocation: { mode: none } — no API surface to attack; markdown+shell skill suite"
}
<!-- qa-report:v1 issue=46 skill=qa domain=security-api phase=validate --> ```json { "outcome": "skipped", "summary": "security-api does not apply: api_invocation mode none", "findings": [], "not_applicable_reason": "project declares api_invocation: { mode: none } — no API surface to attack; markdown+shell skill suite" } ```
Author
Owner
{
  "outcome": "issues-found",
  "summary": "33 verified findings: 2 in-scope-blocking (pre-resume guard blind to non-assistant writers; AC-10a ordering assertion vacuous), 20 fix-now, 3 defer-to-issue, 8 accept (incl. 1 pre-existing). Spec Checker: Compliant. Dependencies: all verified.",
  "findings": [
    {
      "id": "CR-1",
      "category": "in-scope-blocking",
      "severity": "high",
      "summary": "Pre-resume re-classification is blind to non-assistant writers: a plain user record (operator returns and types a prompt, or resumes by hand) after the error tail changes neither the class nor the assistant tail_uuid, so the guard in supervisor-watch.sh:259-283 passes and `claude -p --resume` fires into a session that may be mid-turn. Only the literal 'Request interrupted by user' text is recognized (_supervisor-lib.sh classify jq, interrupt filter).",
      "reasoning": "SREQ pre-resume rule names 'new records' and 'the operator may have come back' as abort causes; the implementation compares only the last assistant record's uuid, which does not move until the model replies. Violates the AC-6 resumability rule's positive-evidence requirement. Fix: surface a tail signal that covers ANY record after the last assistant record (e.g. total parsed record count or last-record uuid in the classify output) and abort/re-evaluate when it moved; a non-interrupt user record after an error record is at minimum abort-resume evidence."
    },
    {
      "id": "CR-2",
      "category": "in-scope-blocking",
      "severity": "high",
      "summary": "AC-10a's ordering assertion cannot fail: test/supervisor-flow.sh:834 passes the literal string \"true\" to check_true, so 'hook ran before the downstream event' passes unconditionally — hook_ts and first_event_ts are computed and never compared. The suite's green on AC-10's ordering clause (hook before resumed phase work) proves nothing.",
      "reasoning": "Confirmed independently by the Bug Hunter and the test-quality audit, and by direct read. The implementation ordering is correct (hook runs before do_resume, supervisor-watch.sh:286-297) but unverified. Fix: assert a real ordering — compare the hook trace timestamp against the stub claude invocation timestamp (both fixtures can record %s.%N traces) — or always take the honest 'not asserted' branch; prefer the real comparison."
    },
    {
      "id": "CR-3",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "A stated quota reset is parsed only when an incident OPENS: the re-aim path (supervisor-watch.sh:272-273) and post-attempt rescheduling (:314-317) use plain backoff, so a transient->quota class shift mid-incident (or a second quota kill on a moved tail) ignores its stated reset and burns the bound firing into a still-active quota window.",
      "reasoning": "Safe (bounded, escalates) but deviates from the SREQ quota path exactly on the F-PO-46-3-1 seam: the two-test decomposition dropped cause-specific rescheduling from the keep-the-incident path. Fix is localized: when the re-aimed/next cause is resumable-quota, attempt sup_parse_reset before falling back to backoff.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "core"
    },
    {
      "id": "CR-4",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "A flag passed without a value as the last argument sends all four entry scripts into a 100% CPU infinite loop: `shift 2` with $#==1 shifts nothing under the lib's set +e, so `while (( $# ))` never terminates (supervisor-attach.sh:18-25, supervisor-watch.sh:18-26, supervisor-detach.sh:18-25, supervisor-status.sh:14-21). Verified by execution: `supervisor-status.sh --session` hangs until killed.",
      "reasoning": "Operator-typo surface on every helper; the intended usage error never fires. Trivial fix: `shift 2 2>/dev/null || { usage; exit $SUP_EXIT_USAGE; }` or validate ${2+set} before shifting.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "CR-5",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "$ALERTED is expanded unquoted (supervisor-watch.sh:66 `printf '%s\\n' $ALERTED`, :84 `for k in $ALERTED`) while its keys embed tail_uuid read from the un-versioned transcript schema: a uuid containing whitespace breaks dedup (the ambiguous/stall alert re-posts every poll — unbounded forge spam) and a glob character pathname-expands against the daemon cwd, leaking filenames into persisted state.json.",
      "reasoning": "No code-execution path (the value never reaches command position), but it is exactly the unquoted-expansion-of-untrusted-data class, flagged independently by the Bug Hunter and Static Security. Fix: newline-delimited ALERTED with quoted while-read (or printf '%s' \"$ALERTED\"), no bare-word step.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "CR-6",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "SKILL.md hardcodes this feature's own tracker issue in its command examples: `--issue 46` at plugin/skills/supervise/SKILL.md:38, 70 and 81. A model following the skill on another project can copy it verbatim and post supervisor-event records onto that tracker's unrelated issue #46; run-template.md step 0 correctly uses a placeholder.",
      "reasoning": "Documentation defect with real cross-project misfire potential; trivial placeholder substitution.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "CR-7",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "retry_bound=0 still fires one resume on the immediate-ETA path: the bound is checked only at loop top with an OPEN incident (supervisor-watch.sh:213-216), but open-and-fire happen in one iteration when INC_ETA=now (quota 'just passed' clamp, or backoff_base_seconds=0), so attempt 0 vs bound 0 is never compared before firing.",
      "reasoning": "Degenerate declared bound, but 'bound 0 = never resume' is unambiguous operator intent. Fix: check INC_ATTEMPT >= SUP_RETRY_BOUND immediately before firing as well.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": true,
      "feature_value": "core"
    },
    {
      "id": "CR-8",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "possibly-mid-work does not close an open incident (supervisor-watch.sh:197-204), unlike healthy and ambiguous: after a daemon-blind window (host suspend) a stall alert leaves the old incident open with a stale ETA and attempt count, which a later genuinely-new fault inherits via the re-aim path — premature escalation naming the old incident's counts.",
      "reasoning": "Transcript activity that produced the stall is positive evidence the old incident ended; closing the incident there matches F-PO-46-3-1 half (a). Fix sits in the same dispatch block as CR-1's fix.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "core"
    },
    {
      "id": "CR-9",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "sup_parse_reset's TZ validation (_supervisor-lib.sh:368) rejects dots but admits a leading '/', so a transcript-planted zone like (/tmp/zone) reaches TZ= as an absolute tzfile path; separately GNU date treats an UNKNOWN zone name as UTC with exit 0, so a garbled zone silently yields a wrong epoch (a mis-scheduled resume) instead of the fail-closed bounded-retry path.",
      "reasoning": "No execution or exfiltration path found; impact is a shifted schedule, still bounded. Fix: require a leading alpha character (reject '/' prefix) and cross-check the zone round-trips (e.g. TZ=zone date +%Z differs from the literal for known zones is not reliable — minimally reject leading '/' and keep fail-closed on parse doubt).",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "CR-10",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-watch.sh:40-46 reads state tunables with bare jq -r and no // defaults: a missing/null field yields the string 'null' — SUP_RETRY_BOUND=null evaluates as 0 in arithmetic (instant bound-exhausted escalation) and SUP_NOTIFY_COMMAND='null' execs a program named null on every alert.",
      "reasoning": "Reachable only via hand-edited or version-skewed state.json, but the degradation is misleading rather than loud. Fix: `// defaults` in each jq read plus a sanity check that refuses to start on non-numeric tunables.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    },
    {
      "id": "CR-11",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "scripts/lint-conventions.sh:236 and 239 still say 'the 14' shipped skills — made stale by this feature's own SHIPPED_SKILLS widening to 15 (the change updated two other count sites but not the class-3 comment and its user-facing report message).",
      "reasoning": "Stale user-facing message introduced by this feature's edit. Trivial: say 15, or drop the number so the next widening cannot re-stale it.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    },
    {
      "id": "CR-12",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-attach.sh:64-65 runs mkdir -p before chmod 700, so under a permissive umask the state directory is briefly more open than intended before the tightening lands.",
      "reasoning": "Not exploitable under typical umasks; cheap to close with `umask 077` before the mkdir (subshell or save/restore).",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    },
    {
      "id": "CR-13",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "--issue with leading zeros (046) passes attach's digit check but --argjson later rejects it as invalid JSON, producing a confusing exit-5 after state was already overwritten; supervisor-detach.sh never digit-validates --issue at all.",
      "reasoning": "Input-validation gap at the entry seam; trivial to normalize (strip leading zeros / reject) and to copy attach's check into detach.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    },
    {
      "id": "CR-14",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "--session is never charset-validated: the sid is interpolated into a pathname glob (_supervisor-lib.sh:470-476, first match wins) and becomes a state-dir path component unchecked (:162-164) — `--session '*'` silently supervises an arbitrary transcript, and a sid containing '/' or '..' relocates the 0700 state dir.",
      "reasoning": "Operator/harness-supplied (session ids are UUIDs), so not hostile in practice, but a quoting slip currently produces silent wrong-session supervision instead of a loud refusal. Trivial: validate sid against [A-Za-z0-9-]+.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "CR-15",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "The AC-5 'mid-work' transcript record (test/supervisor-flow.sh:618-629) is authored from scratch — harness-session-transcript.sample.json and its provenance cover only clean_turn_end, turn_death and quota shapes; no in-progress/tool_use record was ever captured, breaking the provenance convention the other four record builders follow.",
      "reasoning": "Currently inconsequential — the classifier's in-progress branch keys only on provenance-backed discriminators (assistant role, stop_reason, isApiErrorMessage) — but it is exactly the drift risk the provenance convention exists to catch. Fix: capture a real in-progress record from a live transcript on this box into the sample + provenance files and rebuild the fixture from it.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "core"
    },
    {
      "id": "CR-16",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "AC-5 depends on GNU-style `touch -d '-30 minutes'` (test/supervisor-flow.sh:631) but the suite's capability guard (:72-75) probes only `date -d @epoch`: on a BSD-date-capable-but-BSD-touch box the mtime stays fresh, no stall fires, and AC-5 hard-FAILs instead of the guard's promised skip.",
      "reasoning": "Test-infra portability; the guard's own comment promises the skip. Fix: probe touch's relative -d form (or pin mtime via `touch -d @epoch`, which the local-fs probe pattern already models).",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": true,
      "feature_value": "incidental"
    },
    {
      "id": "CR-17",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "The quota fixtures claim to carry the recorded middle-dot separator but '\\xc2\\xb7' inside a plain double-quoted bash string is six literal characters (test/supervisor-flow.sh:520, 558; clock_str_utc's claim at :231) — the fixture bytes do not match the recorded real shape.",
      "reasoning": "Tests pass because neither classifier nor parser keys on the separator, but a future change that does would be green-lit against wrong bytes. Trivial: use $'\\xc2\\xb7' or printf.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": true,
      "feature_value": "incidental"
    },
    {
      "id": "CR-18",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "AC-8's assertions race the first daemon's own resume (test/supervisor-flow.sh:689-736): with 1s backoff/poll the first daemon can fire before kill_daemon_hard lands, so 'the reclaimed daemon resumed' can pass on the first daemon's resume (the reclaim path unproven), and a stub invocation surviving the kill -9 can intermittently fail 'exactly one resume total'.",
      "reasoning": "Same class as the AC-9a race already fixed on this branch. Fix: give the first attach a long backoff (the test owns the fixture CLAUDE.md and can rewrite tunables between attaches) so it cannot fire pre-kill, then a short-backoff reclaim attach.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "incidental"
    },
    {
      "id": "CR-19",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-status.sh:56-71 declares 'STALE — treat this supervisor as dead' during a long in-flight resume — the loop legitimately blocks in `claude -p` for the whole resumed turn, so the heartbeat stalls while state.status says resume-in-flight; it also reports 'the recorded supervisor (pid unknown) is gone' during attach's startup window when pid is still null.",
      "reasoning": "Operator-facing misinformation in exactly the states where trust matters. Fix: branch on state.status — resume-in-flight explains the stale heartbeat; status 'starting' explains a null pid.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    },
    {
      "id": "CR-20",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "sup_state_merge (_supervisor-lib.sh:176-184) has no callers — dead code.",
      "reasoning": "Hygiene while the file is already under edit; delete it.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    },
    {
      "id": "CR-21",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "The per-incident retry bound does not survive a daemon crash: supervisor-watch.sh:53-55 hard-initializes INC_ATTEMPT/INCIDENT_N/ALERTED and supervisor-attach.sh always writes incident{attempt:0}, so a re-attach against the same still-resumable tail (same uuid — by the SREQ's own incident identity, the SAME incident) restarts the bound at 0 and duplicates alert dedup state.",
      "reasoning": "Requires an operator- or template-initiated re-attach after a daemon death, so each extra window is deliberate and bounded per attach; but the state file already persists the counters precisely so they could be restored, and the SREQ's incident-identity rule says this is the same incident. Deserves its own slice: restore-from-state on reclaim plus a crash-resume test scenario.",
      "proposed_action": "defer-to-issue",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "CR-22",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "Stale-lock reclaim is a TOCTOU (supervisor-attach.sh:67-83): two concurrent attaches can both observe the dead holder; B's release (rm -rf) then deletes A's FRESH lock and both spawn daemons — two supervisors on one session, violating AC-8's invariant. No check that the lock being deleted still belongs to the stale holder.",
      "reasoning": "Mechanism verified, likelihood low (requires concurrent attaches racing a dead holder). Fix needs holder-identity-aware reclaim (e.g. write holder pid into the lock dir and verify-before-remove, or rename-based reclaim) — its own considered change with a test.",
      "proposed_action": "defer-to-issue",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "CR-23",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "The abort/re-aim path posts a resume-aborted record every backoff interval with no bound or dedup (supervisor-watch.sh:264-280): a tail that keeps moving right after each ETA (repeatedly dying driver, another writer) generates forge records indefinitely — the retry bound counts only fired resumes and alert dedup does not cover aborts.",
      "reasoning": "Rare (requires the tail to move between every schedule and fire) and each abort is individually informative, but unbounded record spam is a real forge-hygiene risk. A dedup/bound for aborts fits naturally beside CR-1's tail-signal fix.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "incidental"
    },
    {
      "id": "CR-24",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "Stall detection has structural blind spots: (a) if the last 400 transcript lines contain no assistant record, class is 'healthy' regardless of mtime (an error buried past the window is never seen); (b) a zero-byte (rotated/truncated) transcript is 'healthy' forever — the stall clock runs only for the in-progress class (_supervisor-lib.sh:285, 307-315).",
      "reasoning": "Depends on real harness record batching (the window case needs 400+ non-assistant lines after an error — not observed in recorded shapes); the empty-file case is real but requires external truncation. Both deserve a designed answer (window sizing, stall clock for no-assistant/empty states) rather than a point patch.",
      "proposed_action": "defer-to-issue",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "CR-25",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "kill -9 between do_resume and the resume-attempted post (supervisor-watch.sh:299-320) leaves a resume that reached the session with no per-attempt forge record — 'everything on the record' holds only crash-free.",
      "reasoning": "The 'detected' record already carries intent, cause and ETA, so a retrospective reader sees the incident and the schedule; supervisor crash-consistency beyond that is the PREQ's explicit HA non-goal. No incremental value over the existing record given the out-of-scope boundary.",
      "proposed_action": "accept",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "CR-26",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "On the nohup fallback (no setsid; supervisor-attach.sh:120-126), detach's TERM is deferred by bash until an in-flight `claude -p` resume returns; after the 5s escalation to SIGKILL the claude child survives orphaned and its resume lands after the detach record claims supervision stood down.",
      "reasoning": "setsid is present on effectively every Linux box this suite targets (the fallback exists for exotic environments); the failure needs no-setsid AND detach-during-in-flight-resume. The stand-down record already prints loudly. No practical value in hardening the fallback's kill semantics.",
      "proposed_action": "accept",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "CR-27",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "sup_proc_alive degrades to pid-only identity when no start token is obtainable (_supervisor-lib.sh:198-205), contradicting the lib's own 'a pid alone is not identity' — on boxes lacking ps lstart and /proc, a reused pid can block re-attach or receive detach's TERM.",
      "reasoning": "Deliberate graceful degradation: refusing outright on such boxes would break attach entirely, and the conservative direction (refuse attach) is the safe one. The exposure window requires an exotic box plus pid reuse landing on the recorded pid.",
      "proposed_action": "accept",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "CR-28",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Declared numeric tunables are unbounded in magnitude: a 20+-digit backoff_base_seconds wraps mod 2^64 in bash arithmetic (_supervisor-lib.sh:149-157; the 86400 cap applies only after a multiplication), potentially yielding a negative ETA and poll-cadence retries — still bounded by retry_bound.",
      "reasoning": "Requires a nonsense declaration; non-numeric values already warn-and-default; the retry bound contains the blast radius. No practical value.",
      "proposed_action": "accept",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "CR-29",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "'weekly limit' texts classify resumable-quota but the dateless clock parser schedules at most ~24h out, so a weekly quota kill resumes into a still-closed window, burns the bound, then escalates — safe terminal state, wasted attempts.",
      "reasoning": "The SREQ risk table already covers quota-text variants with exactly this mitigation (bounded-retry, escalate); the terminal state is safe and loud. Improving weekly handling has no defined correct schedule to aim at (the text names no day).",
      "proposed_action": "accept",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "CR-30",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Minor test-assertion weaknesses: backoff-spacing check vacuous with <2 resume lines (:417-427, covered indirectly by the count check); `grep -q \"$holder_pid\"` substring-matches (:711); dead discarded statement in all_events_json (:355); the AC-13a mechanical grep misses eval\"$x\"/single-quote-adjacent sh -c variants (:999-1002) — the dynamic canary test is the real guard.",
      "reasoning": "Each is real but the operative guards (resume count check, AC-13b canary) already cover the outcomes; none can green-light a product defect on its own.",
      "proposed_action": "accept",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "CR-31",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "The driver cwd is taken from the transcript with only an existence check (-n/-d) and never compared against the attach-time project root — a defense-in-depth gap flagged by Static Security for the resume and declared-command working directory.",
      "reasoning": "SREQ-compliant as written ('validated: exists, matches attach-time record'): the value is captured ONCE at attach — an operator-present moment, invoked by the driver itself — and never re-read from the transcript during watch, so exploiting it requires poisoning the transcript before engagement. A prefix check against project root risks false refusals on legitimate worktree layouts.",
      "proposed_action": "accept",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "CR-32",
      "category": "pre-existing",
      "severity": "low",
      "summary": "sup_top_scalar/sup_block_scalar (_supervisor-lib.sh:84-103) are not fence-aware: a project CLAUDE.md quoting the supervisor: yaml example inside a fence above the real declaration gets the example matched first — silent wrong tunables.",
      "reasoning": "Identical to the house pattern: _shared/procedures/bin/_lib.sh's _read_forge_adapter parses the forge: block with the same non-fence-aware awk, and the repo's fence-aware rule is scoped to repo tools that scan skill markdown, not declared-block readers. The declared-block schema rules place the parseability burden on the declaration. A suite-wide fence-aware declared-block reader would be its own change touching every adapter.",
      "proposed_action": "accept",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "CR-33",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Fractional `sleep 0.2`/`0.25` (supervisor-attach.sh:139, supervisor-detach.sh:61) is not POSIX-guaranteed — fine on GNU/BSD/macOS, bites only busybox-class boxes.",
      "reasoning": "The helper tier's bash>=3.2 prerequisite already excludes busybox-class boxes in practice (they lack bash too), and every targeted platform's sleep accepts fractions.",
      "proposed_action": "accept",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    }
  ],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=validate --> ```json { "outcome": "issues-found", "summary": "33 verified findings: 2 in-scope-blocking (pre-resume guard blind to non-assistant writers; AC-10a ordering assertion vacuous), 20 fix-now, 3 defer-to-issue, 8 accept (incl. 1 pre-existing). Spec Checker: Compliant. Dependencies: all verified.", "findings": [ { "id": "CR-1", "category": "in-scope-blocking", "severity": "high", "summary": "Pre-resume re-classification is blind to non-assistant writers: a plain user record (operator returns and types a prompt, or resumes by hand) after the error tail changes neither the class nor the assistant tail_uuid, so the guard in supervisor-watch.sh:259-283 passes and `claude -p --resume` fires into a session that may be mid-turn. Only the literal 'Request interrupted by user' text is recognized (_supervisor-lib.sh classify jq, interrupt filter).", "reasoning": "SREQ pre-resume rule names 'new records' and 'the operator may have come back' as abort causes; the implementation compares only the last assistant record's uuid, which does not move until the model replies. Violates the AC-6 resumability rule's positive-evidence requirement. Fix: surface a tail signal that covers ANY record after the last assistant record (e.g. total parsed record count or last-record uuid in the classify output) and abort/re-evaluate when it moved; a non-interrupt user record after an error record is at minimum abort-resume evidence." }, { "id": "CR-2", "category": "in-scope-blocking", "severity": "high", "summary": "AC-10a's ordering assertion cannot fail: test/supervisor-flow.sh:834 passes the literal string \"true\" to check_true, so 'hook ran before the downstream event' passes unconditionally — hook_ts and first_event_ts are computed and never compared. The suite's green on AC-10's ordering clause (hook before resumed phase work) proves nothing.", "reasoning": "Confirmed independently by the Bug Hunter and the test-quality audit, and by direct read. The implementation ordering is correct (hook runs before do_resume, supervisor-watch.sh:286-297) but unverified. Fix: assert a real ordering — compare the hook trace timestamp against the stub claude invocation timestamp (both fixtures can record %s.%N traces) — or always take the honest 'not asserted' branch; prefer the real comparison." }, { "id": "CR-3", "category": "in-scope-deferrable", "severity": "medium", "summary": "A stated quota reset is parsed only when an incident OPENS: the re-aim path (supervisor-watch.sh:272-273) and post-attempt rescheduling (:314-317) use plain backoff, so a transient->quota class shift mid-incident (or a second quota kill on a moved tail) ignores its stated reset and burns the bound firing into a still-active quota window.", "reasoning": "Safe (bounded, escalates) but deviates from the SREQ quota path exactly on the F-PO-46-3-1 seam: the two-test decomposition dropped cause-specific rescheduling from the keep-the-incident path. Fix is localized: when the re-aimed/next cause is resumable-quota, attempt sup_parse_reset before falling back to backoff.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "core" }, { "id": "CR-4", "category": "in-scope-deferrable", "severity": "medium", "summary": "A flag passed without a value as the last argument sends all four entry scripts into a 100% CPU infinite loop: `shift 2` with $#==1 shifts nothing under the lib's set +e, so `while (( $# ))` never terminates (supervisor-attach.sh:18-25, supervisor-watch.sh:18-26, supervisor-detach.sh:18-25, supervisor-status.sh:14-21). Verified by execution: `supervisor-status.sh --session` hangs until killed.", "reasoning": "Operator-typo surface on every helper; the intended usage error never fires. Trivial fix: `shift 2 2>/dev/null || { usage; exit $SUP_EXIT_USAGE; }` or validate ${2+set} before shifting.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "CR-5", "category": "in-scope-deferrable", "severity": "medium", "summary": "$ALERTED is expanded unquoted (supervisor-watch.sh:66 `printf '%s\\n' $ALERTED`, :84 `for k in $ALERTED`) while its keys embed tail_uuid read from the un-versioned transcript schema: a uuid containing whitespace breaks dedup (the ambiguous/stall alert re-posts every poll — unbounded forge spam) and a glob character pathname-expands against the daemon cwd, leaking filenames into persisted state.json.", "reasoning": "No code-execution path (the value never reaches command position), but it is exactly the unquoted-expansion-of-untrusted-data class, flagged independently by the Bug Hunter and Static Security. Fix: newline-delimited ALERTED with quoted while-read (or printf '%s' \"$ALERTED\"), no bare-word step.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "CR-6", "category": "in-scope-deferrable", "severity": "medium", "summary": "SKILL.md hardcodes this feature's own tracker issue in its command examples: `--issue 46` at plugin/skills/supervise/SKILL.md:38, 70 and 81. A model following the skill on another project can copy it verbatim and post supervisor-event records onto that tracker's unrelated issue #46; run-template.md step 0 correctly uses a placeholder.", "reasoning": "Documentation defect with real cross-project misfire potential; trivial placeholder substitution.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "CR-7", "category": "in-scope-deferrable", "severity": "low", "summary": "retry_bound=0 still fires one resume on the immediate-ETA path: the bound is checked only at loop top with an OPEN incident (supervisor-watch.sh:213-216), but open-and-fire happen in one iteration when INC_ETA=now (quota 'just passed' clamp, or backoff_base_seconds=0), so attempt 0 vs bound 0 is never compared before firing.", "reasoning": "Degenerate declared bound, but 'bound 0 = never resume' is unambiguous operator intent. Fix: check INC_ATTEMPT >= SUP_RETRY_BOUND immediately before firing as well.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": true, "feature_value": "core" }, { "id": "CR-8", "category": "in-scope-deferrable", "severity": "medium", "summary": "possibly-mid-work does not close an open incident (supervisor-watch.sh:197-204), unlike healthy and ambiguous: after a daemon-blind window (host suspend) a stall alert leaves the old incident open with a stale ETA and attempt count, which a later genuinely-new fault inherits via the re-aim path — premature escalation naming the old incident's counts.", "reasoning": "Transcript activity that produced the stall is positive evidence the old incident ended; closing the incident there matches F-PO-46-3-1 half (a). Fix sits in the same dispatch block as CR-1's fix.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "core" }, { "id": "CR-9", "category": "in-scope-deferrable", "severity": "low", "summary": "sup_parse_reset's TZ validation (_supervisor-lib.sh:368) rejects dots but admits a leading '/', so a transcript-planted zone like (/tmp/zone) reaches TZ= as an absolute tzfile path; separately GNU date treats an UNKNOWN zone name as UTC with exit 0, so a garbled zone silently yields a wrong epoch (a mis-scheduled resume) instead of the fail-closed bounded-retry path.", "reasoning": "No execution or exfiltration path found; impact is a shifted schedule, still bounded. Fix: require a leading alpha character (reject '/' prefix) and cross-check the zone round-trips (e.g. TZ=zone date +%Z differs from the literal for known zones is not reliable — minimally reject leading '/' and keep fail-closed on parse doubt).", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "CR-10", "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-watch.sh:40-46 reads state tunables with bare jq -r and no // defaults: a missing/null field yields the string 'null' — SUP_RETRY_BOUND=null evaluates as 0 in arithmetic (instant bound-exhausted escalation) and SUP_NOTIFY_COMMAND='null' execs a program named null on every alert.", "reasoning": "Reachable only via hand-edited or version-skewed state.json, but the degradation is misleading rather than loud. Fix: `// defaults` in each jq read plus a sanity check that refuses to start on non-numeric tunables.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" }, { "id": "CR-11", "category": "in-scope-deferrable", "severity": "low", "summary": "scripts/lint-conventions.sh:236 and 239 still say 'the 14' shipped skills — made stale by this feature's own SHIPPED_SKILLS widening to 15 (the change updated two other count sites but not the class-3 comment and its user-facing report message).", "reasoning": "Stale user-facing message introduced by this feature's edit. Trivial: say 15, or drop the number so the next widening cannot re-stale it.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" }, { "id": "CR-12", "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-attach.sh:64-65 runs mkdir -p before chmod 700, so under a permissive umask the state directory is briefly more open than intended before the tightening lands.", "reasoning": "Not exploitable under typical umasks; cheap to close with `umask 077` before the mkdir (subshell or save/restore).", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" }, { "id": "CR-13", "category": "in-scope-deferrable", "severity": "low", "summary": "--issue with leading zeros (046) passes attach's digit check but --argjson later rejects it as invalid JSON, producing a confusing exit-5 after state was already overwritten; supervisor-detach.sh never digit-validates --issue at all.", "reasoning": "Input-validation gap at the entry seam; trivial to normalize (strip leading zeros / reject) and to copy attach's check into detach.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" }, { "id": "CR-14", "category": "in-scope-deferrable", "severity": "low", "summary": "--session is never charset-validated: the sid is interpolated into a pathname glob (_supervisor-lib.sh:470-476, first match wins) and becomes a state-dir path component unchecked (:162-164) — `--session '*'` silently supervises an arbitrary transcript, and a sid containing '/' or '..' relocates the 0700 state dir.", "reasoning": "Operator/harness-supplied (session ids are UUIDs), so not hostile in practice, but a quoting slip currently produces silent wrong-session supervision instead of a loud refusal. Trivial: validate sid against [A-Za-z0-9-]+.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "CR-15", "category": "in-scope-deferrable", "severity": "medium", "summary": "The AC-5 'mid-work' transcript record (test/supervisor-flow.sh:618-629) is authored from scratch — harness-session-transcript.sample.json and its provenance cover only clean_turn_end, turn_death and quota shapes; no in-progress/tool_use record was ever captured, breaking the provenance convention the other four record builders follow.", "reasoning": "Currently inconsequential — the classifier's in-progress branch keys only on provenance-backed discriminators (assistant role, stop_reason, isApiErrorMessage) — but it is exactly the drift risk the provenance convention exists to catch. Fix: capture a real in-progress record from a live transcript on this box into the sample + provenance files and rebuild the fixture from it.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "core" }, { "id": "CR-16", "category": "in-scope-deferrable", "severity": "low", "summary": "AC-5 depends on GNU-style `touch -d '-30 minutes'` (test/supervisor-flow.sh:631) but the suite's capability guard (:72-75) probes only `date -d @epoch`: on a BSD-date-capable-but-BSD-touch box the mtime stays fresh, no stall fires, and AC-5 hard-FAILs instead of the guard's promised skip.", "reasoning": "Test-infra portability; the guard's own comment promises the skip. Fix: probe touch's relative -d form (or pin mtime via `touch -d @epoch`, which the local-fs probe pattern already models).", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": true, "feature_value": "incidental" }, { "id": "CR-17", "category": "in-scope-deferrable", "severity": "low", "summary": "The quota fixtures claim to carry the recorded middle-dot separator but '\\xc2\\xb7' inside a plain double-quoted bash string is six literal characters (test/supervisor-flow.sh:520, 558; clock_str_utc's claim at :231) — the fixture bytes do not match the recorded real shape.", "reasoning": "Tests pass because neither classifier nor parser keys on the separator, but a future change that does would be green-lit against wrong bytes. Trivial: use $'\\xc2\\xb7' or printf.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": true, "feature_value": "incidental" }, { "id": "CR-18", "category": "in-scope-deferrable", "severity": "low", "summary": "AC-8's assertions race the first daemon's own resume (test/supervisor-flow.sh:689-736): with 1s backoff/poll the first daemon can fire before kill_daemon_hard lands, so 'the reclaimed daemon resumed' can pass on the first daemon's resume (the reclaim path unproven), and a stub invocation surviving the kill -9 can intermittently fail 'exactly one resume total'.", "reasoning": "Same class as the AC-9a race already fixed on this branch. Fix: give the first attach a long backoff (the test owns the fixture CLAUDE.md and can rewrite tunables between attaches) so it cannot fire pre-kill, then a short-backoff reclaim attach.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "incidental" }, { "id": "CR-19", "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-status.sh:56-71 declares 'STALE — treat this supervisor as dead' during a long in-flight resume — the loop legitimately blocks in `claude -p` for the whole resumed turn, so the heartbeat stalls while state.status says resume-in-flight; it also reports 'the recorded supervisor (pid unknown) is gone' during attach's startup window when pid is still null.", "reasoning": "Operator-facing misinformation in exactly the states where trust matters. Fix: branch on state.status — resume-in-flight explains the stale heartbeat; status 'starting' explains a null pid.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "incidental" }, { "id": "CR-20", "category": "in-scope-deferrable", "severity": "low", "summary": "sup_state_merge (_supervisor-lib.sh:176-184) has no callers — dead code.", "reasoning": "Hygiene while the file is already under edit; delete it.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" }, { "id": "CR-21", "category": "in-scope-deferrable", "severity": "medium", "summary": "The per-incident retry bound does not survive a daemon crash: supervisor-watch.sh:53-55 hard-initializes INC_ATTEMPT/INCIDENT_N/ALERTED and supervisor-attach.sh always writes incident{attempt:0}, so a re-attach against the same still-resumable tail (same uuid — by the SREQ's own incident identity, the SAME incident) restarts the bound at 0 and duplicates alert dedup state.", "reasoning": "Requires an operator- or template-initiated re-attach after a daemon death, so each extra window is deliberate and bounded per attach; but the state file already persists the counters precisely so they could be restored, and the SREQ's incident-identity rule says this is the same incident. Deserves its own slice: restore-from-state on reclaim plus a crash-resume test scenario.", "proposed_action": "defer-to-issue", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "CR-22", "category": "in-scope-deferrable", "severity": "medium", "summary": "Stale-lock reclaim is a TOCTOU (supervisor-attach.sh:67-83): two concurrent attaches can both observe the dead holder; B's release (rm -rf) then deletes A's FRESH lock and both spawn daemons — two supervisors on one session, violating AC-8's invariant. No check that the lock being deleted still belongs to the stale holder.", "reasoning": "Mechanism verified, likelihood low (requires concurrent attaches racing a dead holder). Fix needs holder-identity-aware reclaim (e.g. write holder pid into the lock dir and verify-before-remove, or rename-based reclaim) — its own considered change with a test.", "proposed_action": "defer-to-issue", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "CR-23", "category": "in-scope-deferrable", "severity": "low", "summary": "The abort/re-aim path posts a resume-aborted record every backoff interval with no bound or dedup (supervisor-watch.sh:264-280): a tail that keeps moving right after each ETA (repeatedly dying driver, another writer) generates forge records indefinitely — the retry bound counts only fired resumes and alert dedup does not cover aborts.", "reasoning": "Rare (requires the tail to move between every schedule and fire) and each abort is individually informative, but unbounded record spam is a real forge-hygiene risk. A dedup/bound for aborts fits naturally beside CR-1's tail-signal fix.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "incidental" }, { "id": "CR-24", "category": "in-scope-deferrable", "severity": "medium", "summary": "Stall detection has structural blind spots: (a) if the last 400 transcript lines contain no assistant record, class is 'healthy' regardless of mtime (an error buried past the window is never seen); (b) a zero-byte (rotated/truncated) transcript is 'healthy' forever — the stall clock runs only for the in-progress class (_supervisor-lib.sh:285, 307-315).", "reasoning": "Depends on real harness record batching (the window case needs 400+ non-assistant lines after an error — not observed in recorded shapes); the empty-file case is real but requires external truncation. Both deserve a designed answer (window sizing, stall clock for no-assistant/empty states) rather than a point patch.", "proposed_action": "defer-to-issue", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "CR-25", "category": "in-scope-deferrable", "severity": "low", "summary": "kill -9 between do_resume and the resume-attempted post (supervisor-watch.sh:299-320) leaves a resume that reached the session with no per-attempt forge record — 'everything on the record' holds only crash-free.", "reasoning": "The 'detected' record already carries intent, cause and ETA, so a retrospective reader sees the incident and the schedule; supervisor crash-consistency beyond that is the PREQ's explicit HA non-goal. No incremental value over the existing record given the out-of-scope boundary.", "proposed_action": "accept", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "CR-26", "category": "in-scope-deferrable", "severity": "low", "summary": "On the nohup fallback (no setsid; supervisor-attach.sh:120-126), detach's TERM is deferred by bash until an in-flight `claude -p` resume returns; after the 5s escalation to SIGKILL the claude child survives orphaned and its resume lands after the detach record claims supervision stood down.", "reasoning": "setsid is present on effectively every Linux box this suite targets (the fallback exists for exotic environments); the failure needs no-setsid AND detach-during-in-flight-resume. The stand-down record already prints loudly. No practical value in hardening the fallback's kill semantics.", "proposed_action": "accept", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "CR-27", "category": "in-scope-deferrable", "severity": "low", "summary": "sup_proc_alive degrades to pid-only identity when no start token is obtainable (_supervisor-lib.sh:198-205), contradicting the lib's own 'a pid alone is not identity' — on boxes lacking ps lstart and /proc, a reused pid can block re-attach or receive detach's TERM.", "reasoning": "Deliberate graceful degradation: refusing outright on such boxes would break attach entirely, and the conservative direction (refuse attach) is the safe one. The exposure window requires an exotic box plus pid reuse landing on the recorded pid.", "proposed_action": "accept", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "CR-28", "category": "in-scope-deferrable", "severity": "low", "summary": "Declared numeric tunables are unbounded in magnitude: a 20+-digit backoff_base_seconds wraps mod 2^64 in bash arithmetic (_supervisor-lib.sh:149-157; the 86400 cap applies only after a multiplication), potentially yielding a negative ETA and poll-cadence retries — still bounded by retry_bound.", "reasoning": "Requires a nonsense declaration; non-numeric values already warn-and-default; the retry bound contains the blast radius. No practical value.", "proposed_action": "accept", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "CR-29", "category": "in-scope-deferrable", "severity": "low", "summary": "'weekly limit' texts classify resumable-quota but the dateless clock parser schedules at most ~24h out, so a weekly quota kill resumes into a still-closed window, burns the bound, then escalates — safe terminal state, wasted attempts.", "reasoning": "The SREQ risk table already covers quota-text variants with exactly this mitigation (bounded-retry, escalate); the terminal state is safe and loud. Improving weekly handling has no defined correct schedule to aim at (the text names no day).", "proposed_action": "accept", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "CR-30", "category": "in-scope-deferrable", "severity": "low", "summary": "Minor test-assertion weaknesses: backoff-spacing check vacuous with <2 resume lines (:417-427, covered indirectly by the count check); `grep -q \"$holder_pid\"` substring-matches (:711); dead discarded statement in all_events_json (:355); the AC-13a mechanical grep misses eval\"$x\"/single-quote-adjacent sh -c variants (:999-1002) — the dynamic canary test is the real guard.", "reasoning": "Each is real but the operative guards (resume count check, AC-13b canary) already cover the outcomes; none can green-light a product defect on its own.", "proposed_action": "accept", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "CR-31", "category": "in-scope-deferrable", "severity": "low", "summary": "The driver cwd is taken from the transcript with only an existence check (-n/-d) and never compared against the attach-time project root — a defense-in-depth gap flagged by Static Security for the resume and declared-command working directory.", "reasoning": "SREQ-compliant as written ('validated: exists, matches attach-time record'): the value is captured ONCE at attach — an operator-present moment, invoked by the driver itself — and never re-read from the transcript during watch, so exploiting it requires poisoning the transcript before engagement. A prefix check against project root risks false refusals on legitimate worktree layouts.", "proposed_action": "accept", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "CR-32", "category": "pre-existing", "severity": "low", "summary": "sup_top_scalar/sup_block_scalar (_supervisor-lib.sh:84-103) are not fence-aware: a project CLAUDE.md quoting the supervisor: yaml example inside a fence above the real declaration gets the example matched first — silent wrong tunables.", "reasoning": "Identical to the house pattern: _shared/procedures/bin/_lib.sh's _read_forge_adapter parses the forge: block with the same non-fence-aware awk, and the repo's fence-aware rule is scoped to repo tools that scan skill markdown, not declared-block readers. The declared-block schema rules place the parseability burden on the declaration. A suite-wide fence-aware declared-block reader would be its own change touching every adapter.", "proposed_action": "accept", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "CR-33", "category": "in-scope-deferrable", "severity": "low", "summary": "Fractional `sleep 0.2`/`0.25` (supervisor-attach.sh:139, supervisor-detach.sh:61) is not POSIX-guaranteed — fine on GNU/BSD/macOS, bites only busybox-class boxes.", "reasoning": "The helper tier's bash>=3.2 prerequisite already excludes busybox-class boxes in practice (they lack bash too), and every targeted platform's sleep accepts fractions.", "proposed_action": "accept", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "none" } ], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "next_state": "qa",
  "produced": [
    {
      "kind": "qa-report",
      "ref": "1766",
      "summary": "code domain validate: 33 verified findings (2 blocking, 20 fix-now, 3 defer-to-issue, 8 accept)"
    },
    {
      "kind": "qa-report",
      "ref": "1731",
      "summary": "e2e skipped (declared: no browser surface)"
    },
    {
      "kind": "qa-report",
      "ref": "1732",
      "summary": "a11y skipped (declared: no rendered UI)"
    },
    {
      "kind": "qa-report",
      "ref": "1733",
      "summary": "security-browser skipped (declared: no browser surface)"
    },
    {
      "kind": "qa-report",
      "ref": "1734",
      "summary": "api skipped (api_invocation mode none)"
    },
    {
      "kind": "qa-report",
      "ref": "1735",
      "summary": "security-api skipped (api_invocation mode none)"
    }
  ],
  "findings": [
    {
      "category": "in-scope-blocking",
      "severity": "high",
      "summary": "Pre-resume re-classification is blind to non-assistant writers: a plain user record (operator returns and types a prompt, or resumes by hand) after the error tail changes neither the class nor the assistant tail_uuid, so the guard in supervisor-watch.sh:259-283 passes and `claude -p --resume` fires into a session that may be mid-turn. Only the literal 'Request interrupted by user' text is recognized (_supervisor-lib.sh classify jq, interrupt filter).",
      "reasoning": "SREQ pre-resume rule names 'new records' and 'the operator may have come back' as abort causes; the implementation compares only the last assistant record's uuid, which does not move until the model replies. Violates the AC-6 resumability rule's positive-evidence requirement. Fix: surface a tail signal that covers ANY record after the last assistant record (e.g. total parsed record count or last-record uuid in the classify output) and abort/re-evaluate when it moved; a non-interrupt user record after an error record is at minimum abort-resume evidence.",
      "id": "F-PO-46-4-1"
    },
    {
      "category": "in-scope-blocking",
      "severity": "high",
      "summary": "AC-10a's ordering assertion cannot fail: test/supervisor-flow.sh:834 passes the literal string \"true\" to check_true, so 'hook ran before the downstream event' passes unconditionally — hook_ts and first_event_ts are computed and never compared. The suite's green on AC-10's ordering clause (hook before resumed phase work) proves nothing.",
      "reasoning": "Confirmed independently by the Bug Hunter and the test-quality audit, and by direct read. The implementation ordering is correct (hook runs before do_resume, supervisor-watch.sh:286-297) but unverified. Fix: assert a real ordering — compare the hook trace timestamp against the stub claude invocation timestamp (both fixtures can record %s.%N traces) — or always take the honest 'not asserted' branch; prefer the real comparison.",
      "id": "F-PO-46-4-2"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "A stated quota reset is parsed only when an incident OPENS: the re-aim path (supervisor-watch.sh:272-273) and post-attempt rescheduling (:314-317) use plain backoff, so a transient->quota class shift mid-incident (or a second quota kill on a moved tail) ignores its stated reset and burns the bound firing into a still-active quota window.",
      "reasoning": "Safe (bounded, escalates) but deviates from the SREQ quota path exactly on the F-PO-46-3-1 seam: the two-test decomposition dropped cause-specific rescheduling from the keep-the-incident path. Fix is localized: when the re-aimed/next cause is resumable-quota, attempt sup_parse_reset before falling back to backoff.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "core",
      "id": "F-PO-46-4-3"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "A flag passed without a value as the last argument sends all four entry scripts into a 100% CPU infinite loop: `shift 2` with $#==1 shifts nothing under the lib's set +e, so `while (( $# ))` never terminates (supervisor-attach.sh:18-25, supervisor-watch.sh:18-26, supervisor-detach.sh:18-25, supervisor-status.sh:14-21). Verified by execution: `supervisor-status.sh --session` hangs until killed.",
      "reasoning": "Operator-typo surface on every helper; the intended usage error never fires. Trivial fix: `shift 2 2>/dev/null || { usage; exit $SUP_EXIT_USAGE; }` or validate ${2+set} before shifting.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-4-4"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "$ALERTED is expanded unquoted (supervisor-watch.sh:66 `printf '%s\\n' $ALERTED`, :84 `for k in $ALERTED`) while its keys embed tail_uuid read from the un-versioned transcript schema: a uuid containing whitespace breaks dedup (the ambiguous/stall alert re-posts every poll — unbounded forge spam) and a glob character pathname-expands against the daemon cwd, leaking filenames into persisted state.json.",
      "reasoning": "No code-execution path (the value never reaches command position), but it is exactly the unquoted-expansion-of-untrusted-data class, flagged independently by the Bug Hunter and Static Security. Fix: newline-delimited ALERTED with quoted while-read (or printf '%s' \"$ALERTED\"), no bare-word step.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-4-5"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "SKILL.md hardcodes this feature's own tracker issue in its command examples: `--issue 46` at plugin/skills/supervise/SKILL.md:38, 70 and 81. A model following the skill on another project can copy it verbatim and post supervisor-event records onto that tracker's unrelated issue #46; run-template.md step 0 correctly uses a placeholder.",
      "reasoning": "Documentation defect with real cross-project misfire potential; trivial placeholder substitution.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-4-6"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "retry_bound=0 still fires one resume on the immediate-ETA path: the bound is checked only at loop top with an OPEN incident (supervisor-watch.sh:213-216), but open-and-fire happen in one iteration when INC_ETA=now (quota 'just passed' clamp, or backoff_base_seconds=0), so attempt 0 vs bound 0 is never compared before firing.",
      "reasoning": "Degenerate declared bound, but 'bound 0 = never resume' is unambiguous operator intent. Fix: check INC_ATTEMPT >= SUP_RETRY_BOUND immediately before firing as well.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": true,
      "feature_value": "core",
      "id": "F-PO-46-4-7"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "possibly-mid-work does not close an open incident (supervisor-watch.sh:197-204), unlike healthy and ambiguous: after a daemon-blind window (host suspend) a stall alert leaves the old incident open with a stale ETA and attempt count, which a later genuinely-new fault inherits via the re-aim path — premature escalation naming the old incident's counts.",
      "reasoning": "Transcript activity that produced the stall is positive evidence the old incident ended; closing the incident there matches F-PO-46-3-1 half (a). Fix sits in the same dispatch block as CR-1's fix.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "core",
      "id": "F-PO-46-4-8"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "sup_parse_reset's TZ validation (_supervisor-lib.sh:368) rejects dots but admits a leading '/', so a transcript-planted zone like (/tmp/zone) reaches TZ= as an absolute tzfile path; separately GNU date treats an UNKNOWN zone name as UTC with exit 0, so a garbled zone silently yields a wrong epoch (a mis-scheduled resume) instead of the fail-closed bounded-retry path.",
      "reasoning": "No execution or exfiltration path found; impact is a shifted schedule, still bounded. Fix: require a leading alpha character (reject '/' prefix) and cross-check the zone round-trips (e.g. TZ=zone date +%Z differs from the literal for known zones is not reliable — minimally reject leading '/' and keep fail-closed on parse doubt).",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-4-9"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-watch.sh:40-46 reads state tunables with bare jq -r and no // defaults: a missing/null field yields the string 'null' — SUP_RETRY_BOUND=null evaluates as 0 in arithmetic (instant bound-exhausted escalation) and SUP_NOTIFY_COMMAND='null' execs a program named null on every alert.",
      "reasoning": "Reachable only via hand-edited or version-skewed state.json, but the degradation is misleading rather than loud. Fix: `// defaults` in each jq read plus a sanity check that refuses to start on non-numeric tunables.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-4-10"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "scripts/lint-conventions.sh:236 and 239 still say 'the 14' shipped skills — made stale by this feature's own SHIPPED_SKILLS widening to 15 (the change updated two other count sites but not the class-3 comment and its user-facing report message).",
      "reasoning": "Stale user-facing message introduced by this feature's edit. Trivial: say 15, or drop the number so the next widening cannot re-stale it.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-4-11"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-attach.sh:64-65 runs mkdir -p before chmod 700, so under a permissive umask the state directory is briefly more open than intended before the tightening lands.",
      "reasoning": "Not exploitable under typical umasks; cheap to close with `umask 077` before the mkdir (subshell or save/restore).",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-4-12"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "--issue with leading zeros (046) passes attach's digit check but --argjson later rejects it as invalid JSON, producing a confusing exit-5 after state was already overwritten; supervisor-detach.sh never digit-validates --issue at all.",
      "reasoning": "Input-validation gap at the entry seam; trivial to normalize (strip leading zeros / reject) and to copy attach's check into detach.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-4-13"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "--session is never charset-validated: the sid is interpolated into a pathname glob (_supervisor-lib.sh:470-476, first match wins) and becomes a state-dir path component unchecked (:162-164) — `--session '*'` silently supervises an arbitrary transcript, and a sid containing '/' or '..' relocates the 0700 state dir.",
      "reasoning": "Operator/harness-supplied (session ids are UUIDs), so not hostile in practice, but a quoting slip currently produces silent wrong-session supervision instead of a loud refusal. Trivial: validate sid against [A-Za-z0-9-]+.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-4-14"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "The AC-5 'mid-work' transcript record (test/supervisor-flow.sh:618-629) is authored from scratch — harness-session-transcript.sample.json and its provenance cover only clean_turn_end, turn_death and quota shapes; no in-progress/tool_use record was ever captured, breaking the provenance convention the other four record builders follow.",
      "reasoning": "Currently inconsequential — the classifier's in-progress branch keys only on provenance-backed discriminators (assistant role, stop_reason, isApiErrorMessage) — but it is exactly the drift risk the provenance convention exists to catch. Fix: capture a real in-progress record from a live transcript on this box into the sample + provenance files and rebuild the fixture from it.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "core",
      "id": "F-PO-46-4-15"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "AC-5 depends on GNU-style `touch -d '-30 minutes'` (test/supervisor-flow.sh:631) but the suite's capability guard (:72-75) probes only `date -d @epoch`: on a BSD-date-capable-but-BSD-touch box the mtime stays fresh, no stall fires, and AC-5 hard-FAILs instead of the guard's promised skip.",
      "reasoning": "Test-infra portability; the guard's own comment promises the skip. Fix: probe touch's relative -d form (or pin mtime via `touch -d @epoch`, which the local-fs probe pattern already models).",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": true,
      "feature_value": "incidental",
      "id": "F-PO-46-4-16"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "The quota fixtures claim to carry the recorded middle-dot separator but '\\xc2\\xb7' inside a plain double-quoted bash string is six literal characters (test/supervisor-flow.sh:520, 558; clock_str_utc's claim at :231) — the fixture bytes do not match the recorded real shape.",
      "reasoning": "Tests pass because neither classifier nor parser keys on the separator, but a future change that does would be green-lit against wrong bytes. Trivial: use $'\\xc2\\xb7' or printf.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": true,
      "feature_value": "incidental",
      "id": "F-PO-46-4-17"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "AC-8's assertions race the first daemon's own resume (test/supervisor-flow.sh:689-736): with 1s backoff/poll the first daemon can fire before kill_daemon_hard lands, so 'the reclaimed daemon resumed' can pass on the first daemon's resume (the reclaim path unproven), and a stub invocation surviving the kill -9 can intermittently fail 'exactly one resume total'.",
      "reasoning": "Same class as the AC-9a race already fixed on this branch. Fix: give the first attach a long backoff (the test owns the fixture CLAUDE.md and can rewrite tunables between attaches) so it cannot fire pre-kill, then a short-backoff reclaim attach.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "incidental",
      "id": "F-PO-46-4-18"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-status.sh:56-71 declares 'STALE — treat this supervisor as dead' during a long in-flight resume — the loop legitimately blocks in `claude -p` for the whole resumed turn, so the heartbeat stalls while state.status says resume-in-flight; it also reports 'the recorded supervisor (pid unknown) is gone' during attach's startup window when pid is still null.",
      "reasoning": "Operator-facing misinformation in exactly the states where trust matters. Fix: branch on state.status — resume-in-flight explains the stale heartbeat; status 'starting' explains a null pid.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-4-19"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "sup_state_merge (_supervisor-lib.sh:176-184) has no callers — dead code.",
      "reasoning": "Hygiene while the file is already under edit; delete it.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-4-20"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "The per-incident retry bound does not survive a daemon crash: supervisor-watch.sh:53-55 hard-initializes INC_ATTEMPT/INCIDENT_N/ALERTED and supervisor-attach.sh always writes incident{attempt:0}, so a re-attach against the same still-resumable tail (same uuid — by the SREQ's own incident identity, the SAME incident) restarts the bound at 0 and duplicates alert dedup state.",
      "reasoning": "Requires an operator- or template-initiated re-attach after a daemon death, so each extra window is deliberate and bounded per attach; but the state file already persists the counters precisely so they could be restored, and the SREQ's incident-identity rule says this is the same incident. Deserves its own slice: restore-from-state on reclaim plus a crash-resume test scenario.",
      "proposed_action": "defer-to-issue",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-4-21"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "Stale-lock reclaim is a TOCTOU (supervisor-attach.sh:67-83): two concurrent attaches can both observe the dead holder; B's release (rm -rf) then deletes A's FRESH lock and both spawn daemons — two supervisors on one session, violating AC-8's invariant. No check that the lock being deleted still belongs to the stale holder.",
      "reasoning": "Mechanism verified, likelihood low (requires concurrent attaches racing a dead holder). Fix needs holder-identity-aware reclaim (e.g. write holder pid into the lock dir and verify-before-remove, or rename-based reclaim) — its own considered change with a test.",
      "proposed_action": "defer-to-issue",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-4-22"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "The abort/re-aim path posts a resume-aborted record every backoff interval with no bound or dedup (supervisor-watch.sh:264-280): a tail that keeps moving right after each ETA (repeatedly dying driver, another writer) generates forge records indefinitely — the retry bound counts only fired resumes and alert dedup does not cover aborts.",
      "reasoning": "Rare (requires the tail to move between every schedule and fire) and each abort is individually informative, but unbounded record spam is a real forge-hygiene risk. A dedup/bound for aborts fits naturally beside CR-1's tail-signal fix.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "incidental",
      "id": "F-PO-46-4-23"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "Stall detection has structural blind spots: (a) if the last 400 transcript lines contain no assistant record, class is 'healthy' regardless of mtime (an error buried past the window is never seen); (b) a zero-byte (rotated/truncated) transcript is 'healthy' forever — the stall clock runs only for the in-progress class (_supervisor-lib.sh:285, 307-315).",
      "reasoning": "Depends on real harness record batching (the window case needs 400+ non-assistant lines after an error — not observed in recorded shapes); the empty-file case is real but requires external truncation. Both deserve a designed answer (window sizing, stall clock for no-assistant/empty states) rather than a point patch.",
      "proposed_action": "defer-to-issue",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-4-24"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "kill -9 between do_resume and the resume-attempted post (supervisor-watch.sh:299-320) leaves a resume that reached the session with no per-attempt forge record — 'everything on the record' holds only crash-free.",
      "reasoning": "The 'detected' record already carries intent, cause and ETA, so a retrospective reader sees the incident and the schedule; supervisor crash-consistency beyond that is the PREQ's explicit HA non-goal. No incremental value over the existing record given the out-of-scope boundary.",
      "proposed_action": "accept",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-4-25"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "On the nohup fallback (no setsid; supervisor-attach.sh:120-126), detach's TERM is deferred by bash until an in-flight `claude -p` resume returns; after the 5s escalation to SIGKILL the claude child survives orphaned and its resume lands after the detach record claims supervision stood down.",
      "reasoning": "setsid is present on effectively every Linux box this suite targets (the fallback exists for exotic environments); the failure needs no-setsid AND detach-during-in-flight-resume. The stand-down record already prints loudly. No practical value in hardening the fallback's kill semantics.",
      "proposed_action": "accept",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-4-26"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "sup_proc_alive degrades to pid-only identity when no start token is obtainable (_supervisor-lib.sh:198-205), contradicting the lib's own 'a pid alone is not identity' — on boxes lacking ps lstart and /proc, a reused pid can block re-attach or receive detach's TERM.",
      "reasoning": "Deliberate graceful degradation: refusing outright on such boxes would break attach entirely, and the conservative direction (refuse attach) is the safe one. The exposure window requires an exotic box plus pid reuse landing on the recorded pid.",
      "proposed_action": "accept",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-4-27"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Declared numeric tunables are unbounded in magnitude: a 20+-digit backoff_base_seconds wraps mod 2^64 in bash arithmetic (_supervisor-lib.sh:149-157; the 86400 cap applies only after a multiplication), potentially yielding a negative ETA and poll-cadence retries — still bounded by retry_bound.",
      "reasoning": "Requires a nonsense declaration; non-numeric values already warn-and-default; the retry bound contains the blast radius. No practical value.",
      "proposed_action": "accept",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-4-28"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "'weekly limit' texts classify resumable-quota but the dateless clock parser schedules at most ~24h out, so a weekly quota kill resumes into a still-closed window, burns the bound, then escalates — safe terminal state, wasted attempts.",
      "reasoning": "The SREQ risk table already covers quota-text variants with exactly this mitigation (bounded-retry, escalate); the terminal state is safe and loud. Improving weekly handling has no defined correct schedule to aim at (the text names no day).",
      "proposed_action": "accept",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-4-29"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Minor test-assertion weaknesses: backoff-spacing check vacuous with <2 resume lines (:417-427, covered indirectly by the count check); `grep -q \"$holder_pid\"` substring-matches (:711); dead discarded statement in all_events_json (:355); the AC-13a mechanical grep misses eval\"$x\"/single-quote-adjacent sh -c variants (:999-1002) — the dynamic canary test is the real guard.",
      "reasoning": "Each is real but the operative guards (resume count check, AC-13b canary) already cover the outcomes; none can green-light a product defect on its own.",
      "proposed_action": "accept",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-4-30"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "The driver cwd is taken from the transcript with only an existence check (-n/-d) and never compared against the attach-time project root — a defense-in-depth gap flagged by Static Security for the resume and declared-command working directory.",
      "reasoning": "SREQ-compliant as written ('validated: exists, matches attach-time record'): the value is captured ONCE at attach — an operator-present moment, invoked by the driver itself — and never re-read from the transcript during watch, so exploiting it requires poisoning the transcript before engagement. A prefix check against project root risks false refusals on legitimate worktree layouts.",
      "proposed_action": "accept",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-4-31"
    },
    {
      "category": "pre-existing",
      "severity": "low",
      "summary": "sup_top_scalar/sup_block_scalar (_supervisor-lib.sh:84-103) are not fence-aware: a project CLAUDE.md quoting the supervisor: yaml example inside a fence above the real declaration gets the example matched first — silent wrong tunables.",
      "reasoning": "Identical to the house pattern: _shared/procedures/bin/_lib.sh's _read_forge_adapter parses the forge: block with the same non-fence-aware awk, and the repo's fence-aware rule is scoped to repo tools that scan skill markdown, not declared-block readers. The declared-block schema rules place the parseability burden on the declaration. A suite-wide fence-aware declared-block reader would be its own change touching every adapter.",
      "proposed_action": "accept",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-4-32"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Fractional `sleep 0.2`/`0.25` (supervisor-attach.sh:139, supervisor-detach.sh:61) is not POSIX-guaranteed — fine on GNU/BSD/macOS, bites only busybox-class boxes.",
      "reasoning": "The helper tier's bash>=3.2 prerequisite already excludes busybox-class boxes in practice (they lack bash too), and every targeted platform's sleep accepts fractions.",
      "proposed_action": "accept",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-4-33"
    }
  ],
  "pending_decisions": [
    {
      "id": "D-PO-46-4-1",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-3: A stated quota reset is parsed only when an incident OPENS: the re-aim path (supervisor-watch.sh:272-273) and post-attempt rescheduling (:314-317) use plain bac",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-3",
      "reasoning": "Safe (bounded, escalates) but deviates from the SREQ quota path exactly on the F-PO-46-3-1 seam: the two-test decomposition dropped cause-specific rescheduling from the keep-the-incident path. Fix is localized: when the re-aimed/next cause is resumable-quota, attempt sup_parse_reset before falling back to backoff."
    },
    {
      "id": "D-PO-46-4-2",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-4: A flag passed without a value as the last argument sends all four entry scripts into a 100% CPU infinite loop: `shift 2` with $#==1 shifts nothing under the lib",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-4",
      "reasoning": "Operator-typo surface on every helper; the intended usage error never fires. Trivial fix: `shift 2 2>/dev/null || { usage; exit $SUP_EXIT_USAGE; }` or validate ${2+set} before shifting."
    },
    {
      "id": "D-PO-46-4-3",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-5: $ALERTED is expanded unquoted (supervisor-watch.sh:66 `printf '%s\\n' $ALERTED`, :84 `for k in $ALERTED`) while its keys embed tail_uuid read from the un-version",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-5",
      "reasoning": "No code-execution path (the value never reaches command position), but it is exactly the unquoted-expansion-of-untrusted-data class, flagged independently by the Bug Hunter and Static Security. Fix: newline-delimited ALERTED with quoted while-read (or printf '%s' \"$ALERTED\"), no bare-word step."
    },
    {
      "id": "D-PO-46-4-4",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-6: SKILL.md hardcodes this feature's own tracker issue in its command examples: `--issue 46` at plugin/skills/supervise/SKILL.md:38, 70 and 81. A model following t",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-6",
      "reasoning": "Documentation defect with real cross-project misfire potential; trivial placeholder substitution."
    },
    {
      "id": "D-PO-46-4-5",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-7: retry_bound=0 still fires one resume on the immediate-ETA path: the bound is checked only at loop top with an OPEN incident (supervisor-watch.sh:213-216), but o",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-7",
      "reasoning": "Degenerate declared bound, but 'bound 0 = never resume' is unambiguous operator intent. Fix: check INC_ATTEMPT >= SUP_RETRY_BOUND immediately before firing as well."
    },
    {
      "id": "D-PO-46-4-6",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-8: possibly-mid-work does not close an open incident (supervisor-watch.sh:197-204), unlike healthy and ambiguous: after a daemon-blind window (host suspend) a stal",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-8",
      "reasoning": "Transcript activity that produced the stall is positive evidence the old incident ended; closing the incident there matches F-PO-46-3-1 half (a). Fix sits in the same dispatch block as CR-1's fix."
    },
    {
      "id": "D-PO-46-4-7",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-9: sup_parse_reset's TZ validation (_supervisor-lib.sh:368) rejects dots but admits a leading '/', so a transcript-planted zone like (/tmp/zone) reaches TZ= as an ",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-9",
      "reasoning": "No execution or exfiltration path found; impact is a shifted schedule, still bounded. Fix: require a leading alpha character (reject '/' prefix) and cross-check the zone round-trips (e.g. TZ=zone date +%Z differs from the literal for known zones is not reliable — minimally reject leading '/' and keep fail-closed on parse doubt)."
    },
    {
      "id": "D-PO-46-4-8",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-10: supervisor-watch.sh:40-46 reads state tunables with bare jq -r and no // defaults: a missing/null field yields the string 'null' — SUP_RETRY_BOUND=null evalua",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-10",
      "reasoning": "Reachable only via hand-edited or version-skewed state.json, but the degradation is misleading rather than loud. Fix: `// defaults` in each jq read plus a sanity check that refuses to start on non-numeric tunables."
    },
    {
      "id": "D-PO-46-4-9",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-11: scripts/lint-conventions.sh:236 and 239 still say 'the 14' shipped skills — made stale by this feature's own SHIPPED_SKILLS widening to 15 (the change updated",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-11",
      "reasoning": "Stale user-facing message introduced by this feature's edit. Trivial: say 15, or drop the number so the next widening cannot re-stale it."
    },
    {
      "id": "D-PO-46-4-10",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-12: supervisor-attach.sh:64-65 runs mkdir -p before chmod 700, so under a permissive umask the state directory is briefly more open than intended before the tighten",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-12",
      "reasoning": "Not exploitable under typical umasks; cheap to close with `umask 077` before the mkdir (subshell or save/restore)."
    },
    {
      "id": "D-PO-46-4-11",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-13: --issue with leading zeros (046) passes attach's digit check but --argjson later rejects it as invalid JSON, producing a confusing exit-5 after state was alread",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-13",
      "reasoning": "Input-validation gap at the entry seam; trivial to normalize (strip leading zeros / reject) and to copy attach's check into detach."
    },
    {
      "id": "D-PO-46-4-12",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-14: --session is never charset-validated: the sid is interpolated into a pathname glob (_supervisor-lib.sh:470-476, first match wins) and becomes a state-dir path c",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-14",
      "reasoning": "Operator/harness-supplied (session ids are UUIDs), so not hostile in practice, but a quoting slip currently produces silent wrong-session supervision instead of a loud refusal. Trivial: validate sid against [A-Za-z0-9-]+."
    },
    {
      "id": "D-PO-46-4-13",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-15: The AC-5 'mid-work' transcript record (test/supervisor-flow.sh:618-629) is authored from scratch — harness-session-transcript.sample.json and its provenance c",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-15",
      "reasoning": "Currently inconsequential — the classifier's in-progress branch keys only on provenance-backed discriminators (assistant role, stop_reason, isApiErrorMessage) — but it is exactly the drift risk the provenance convention exists to catch. Fix: capture a real in-progress record from a live transcript on this box into the sample + provenance files and rebuild the fixture from it."
    },
    {
      "id": "D-PO-46-4-14",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-16: AC-5 depends on GNU-style `touch -d '-30 minutes'` (test/supervisor-flow.sh:631) but the suite's capability guard (:72-75) probes only `date -d @epoch`: on a BS",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-16",
      "reasoning": "Test-infra portability; the guard's own comment promises the skip. Fix: probe touch's relative -d form (or pin mtime via `touch -d @epoch`, which the local-fs probe pattern already models)."
    },
    {
      "id": "D-PO-46-4-15",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-17: The quota fixtures claim to carry the recorded middle-dot separator but '\\xc2\\xb7' inside a plain double-quoted bash string is six literal characters (test/supe",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-17",
      "reasoning": "Tests pass because neither classifier nor parser keys on the separator, but a future change that does would be green-lit against wrong bytes. Trivial: use $'\\xc2\\xb7' or printf."
    },
    {
      "id": "D-PO-46-4-16",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-18: AC-8's assertions race the first daemon's own resume (test/supervisor-flow.sh:689-736): with 1s backoff/poll the first daemon can fire before kill_daemon_hard l",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-18",
      "reasoning": "Same class as the AC-9a race already fixed on this branch. Fix: give the first attach a long backoff (the test owns the fixture CLAUDE.md and can rewrite tunables between attaches) so it cannot fire pre-kill, then a short-backoff reclaim attach."
    },
    {
      "id": "D-PO-46-4-17",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-19: supervisor-status.sh:56-71 declares 'STALE — treat this supervisor as dead' during a long in-flight resume — the loop legitimately blocks in `claude -p` for",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-19",
      "reasoning": "Operator-facing misinformation in exactly the states where trust matters. Fix: branch on state.status — resume-in-flight explains the stale heartbeat; status 'starting' explains a null pid."
    },
    {
      "id": "D-PO-46-4-18",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-20: sup_state_merge (_supervisor-lib.sh:176-184) has no callers — dead code.",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-20",
      "reasoning": "Hygiene while the file is already under edit; delete it."
    },
    {
      "id": "D-PO-46-4-19",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-21: The per-incident retry bound does not survive a daemon crash: supervisor-watch.sh:53-55 hard-initializes INC_ATTEMPT/INCIDENT_N/ALERTED and supervisor-attach.sh",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "defer-to-issue",
      "finding_ref": "F-PO-46-4-21",
      "reasoning": "Requires an operator- or template-initiated re-attach after a daemon death, so each extra window is deliberate and bounded per attach; but the state file already persists the counters precisely so they could be restored, and the SREQ's incident-identity rule says this is the same incident. Deserves its own slice: restore-from-state on reclaim plus a crash-resume test scenario."
    },
    {
      "id": "D-PO-46-4-20",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-22: Stale-lock reclaim is a TOCTOU (supervisor-attach.sh:67-83): two concurrent attaches can both observe the dead holder; B's release (rm -rf) then deletes A's FRE",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "defer-to-issue",
      "finding_ref": "F-PO-46-4-22",
      "reasoning": "Mechanism verified, likelihood low (requires concurrent attaches racing a dead holder). Fix needs holder-identity-aware reclaim (e.g. write holder pid into the lock dir and verify-before-remove, or rename-based reclaim) — its own considered change with a test."
    },
    {
      "id": "D-PO-46-4-21",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-23: The abort/re-aim path posts a resume-aborted record every backoff interval with no bound or dedup (supervisor-watch.sh:264-280): a tail that keeps moving right ",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-4-23",
      "reasoning": "Rare (requires the tail to move between every schedule and fire) and each abort is individually informative, but unbounded record spam is a real forge-hygiene risk. A dedup/bound for aborts fits naturally beside CR-1's tail-signal fix."
    },
    {
      "id": "D-PO-46-4-22",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-24: Stall detection has structural blind spots: (a) if the last 400 transcript lines contain no assistant record, class is 'healthy' regardless of mtime (an error b",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "defer-to-issue",
      "finding_ref": "F-PO-46-4-24",
      "reasoning": "Depends on real harness record batching (the window case needs 400+ non-assistant lines after an error — not observed in recorded shapes); the empty-file case is real but requires external truncation. Both deserve a designed answer (window sizing, stall clock for no-assistant/empty states) rather than a point patch."
    },
    {
      "id": "D-PO-46-4-23",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-25: kill -9 between do_resume and the resume-attempted post (supervisor-watch.sh:299-320) leaves a resume that reached the session with no per-attempt forge record ",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-4-25",
      "reasoning": "The 'detected' record already carries intent, cause and ETA, so a retrospective reader sees the incident and the schedule; supervisor crash-consistency beyond that is the PREQ's explicit HA non-goal. No incremental value over the existing record given the out-of-scope boundary."
    },
    {
      "id": "D-PO-46-4-24",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-26: On the nohup fallback (no setsid; supervisor-attach.sh:120-126), detach's TERM is deferred by bash until an in-flight `claude -p` resume returns; after the 5s e",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-4-26",
      "reasoning": "setsid is present on effectively every Linux box this suite targets (the fallback exists for exotic environments); the failure needs no-setsid AND detach-during-in-flight-resume. The stand-down record already prints loudly. No practical value in hardening the fallback's kill semantics."
    },
    {
      "id": "D-PO-46-4-25",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-27: sup_proc_alive degrades to pid-only identity when no start token is obtainable (_supervisor-lib.sh:198-205), contradicting the lib's own 'a pid alone is not ide",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-4-27",
      "reasoning": "Deliberate graceful degradation: refusing outright on such boxes would break attach entirely, and the conservative direction (refuse attach) is the safe one. The exposure window requires an exotic box plus pid reuse landing on the recorded pid."
    },
    {
      "id": "D-PO-46-4-26",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-28: Declared numeric tunables are unbounded in magnitude: a 20+-digit backoff_base_seconds wraps mod 2^64 in bash arithmetic (_supervisor-lib.sh:149-157; the 86400 ",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-4-28",
      "reasoning": "Requires a nonsense declaration; non-numeric values already warn-and-default; the retry bound contains the blast radius. No practical value."
    },
    {
      "id": "D-PO-46-4-27",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-29: 'weekly limit' texts classify resumable-quota but the dateless clock parser schedules at most ~24h out, so a weekly quota kill resumes into a still-closed windo",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-4-29",
      "reasoning": "The SREQ risk table already covers quota-text variants with exactly this mitigation (bounded-retry, escalate); the terminal state is safe and loud. Improving weekly handling has no defined correct schedule to aim at (the text names no day)."
    },
    {
      "id": "D-PO-46-4-28",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-30: Minor test-assertion weaknesses: backoff-spacing check vacuous with <2 resume lines (:417-427, covered indirectly by the count check); `grep -q \"$holder_pid\"` s",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-4-30",
      "reasoning": "Each is real but the operative guards (resume count check, AC-13b canary) already cover the outcomes; none can green-light a product defect on its own."
    },
    {
      "id": "D-PO-46-4-29",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-31: The driver cwd is taken from the transcript with only an existence check (-n/-d) and never compared against the attach-time project root — a defense-in-depth ",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-4-31",
      "reasoning": "SREQ-compliant as written ('validated: exists, matches attach-time record'): the value is captured ONCE at attach — an operator-present moment, invoked by the driver itself — and never re-read from the transcript during watch, so exploiting it requires poisoning the transcript before engagement. A prefix check against project root risks false refusals on legitimate worktree layouts."
    },
    {
      "id": "D-PO-46-4-30",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-32: sup_top_scalar/sup_block_scalar (_supervisor-lib.sh:84-103) are not fence-aware: a project CLAUDE.md quoting the supervisor: yaml example inside a fence above t",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-4-32",
      "reasoning": "Identical to the house pattern: _shared/procedures/bin/_lib.sh's _read_forge_adapter parses the forge: block with the same non-fence-aware awk, and the repo's fence-aware rule is scoped to repo tools that scan skill markdown, not declared-block readers. The declared-block schema rules place the parseability burden on the declaration. A suite-wide fence-aware declared-block reader would be its own change touching every adapter."
    },
    {
      "id": "D-PO-46-4-31",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-33: Fractional `sleep 0.2`/`0.25` (supervisor-attach.sh:139, supervisor-detach.sh:61) is not POSIX-guaranteed — fine on GNU/BSD/macOS, bites only busybox-class bo",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-4-33",
      "reasoning": "The helper tier's bash>=3.2 prerequisite already excludes busybox-class boxes in practice (they lack bash too), and every targeted platform's sleep accepts fractions."
    }
  ],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-4 skill=qa --> ```json { "next_state": "qa", "produced": [ { "kind": "qa-report", "ref": "1766", "summary": "code domain validate: 33 verified findings (2 blocking, 20 fix-now, 3 defer-to-issue, 8 accept)" }, { "kind": "qa-report", "ref": "1731", "summary": "e2e skipped (declared: no browser surface)" }, { "kind": "qa-report", "ref": "1732", "summary": "a11y skipped (declared: no rendered UI)" }, { "kind": "qa-report", "ref": "1733", "summary": "security-browser skipped (declared: no browser surface)" }, { "kind": "qa-report", "ref": "1734", "summary": "api skipped (api_invocation mode none)" }, { "kind": "qa-report", "ref": "1735", "summary": "security-api skipped (api_invocation mode none)" } ], "findings": [ { "category": "in-scope-blocking", "severity": "high", "summary": "Pre-resume re-classification is blind to non-assistant writers: a plain user record (operator returns and types a prompt, or resumes by hand) after the error tail changes neither the class nor the assistant tail_uuid, so the guard in supervisor-watch.sh:259-283 passes and `claude -p --resume` fires into a session that may be mid-turn. Only the literal 'Request interrupted by user' text is recognized (_supervisor-lib.sh classify jq, interrupt filter).", "reasoning": "SREQ pre-resume rule names 'new records' and 'the operator may have come back' as abort causes; the implementation compares only the last assistant record's uuid, which does not move until the model replies. Violates the AC-6 resumability rule's positive-evidence requirement. Fix: surface a tail signal that covers ANY record after the last assistant record (e.g. total parsed record count or last-record uuid in the classify output) and abort/re-evaluate when it moved; a non-interrupt user record after an error record is at minimum abort-resume evidence.", "id": "F-PO-46-4-1" }, { "category": "in-scope-blocking", "severity": "high", "summary": "AC-10a's ordering assertion cannot fail: test/supervisor-flow.sh:834 passes the literal string \"true\" to check_true, so 'hook ran before the downstream event' passes unconditionally — hook_ts and first_event_ts are computed and never compared. The suite's green on AC-10's ordering clause (hook before resumed phase work) proves nothing.", "reasoning": "Confirmed independently by the Bug Hunter and the test-quality audit, and by direct read. The implementation ordering is correct (hook runs before do_resume, supervisor-watch.sh:286-297) but unverified. Fix: assert a real ordering — compare the hook trace timestamp against the stub claude invocation timestamp (both fixtures can record %s.%N traces) — or always take the honest 'not asserted' branch; prefer the real comparison.", "id": "F-PO-46-4-2" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "A stated quota reset is parsed only when an incident OPENS: the re-aim path (supervisor-watch.sh:272-273) and post-attempt rescheduling (:314-317) use plain backoff, so a transient->quota class shift mid-incident (or a second quota kill on a moved tail) ignores its stated reset and burns the bound firing into a still-active quota window.", "reasoning": "Safe (bounded, escalates) but deviates from the SREQ quota path exactly on the F-PO-46-3-1 seam: the two-test decomposition dropped cause-specific rescheduling from the keep-the-incident path. Fix is localized: when the re-aimed/next cause is resumable-quota, attempt sup_parse_reset before falling back to backoff.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "core", "id": "F-PO-46-4-3" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "A flag passed without a value as the last argument sends all four entry scripts into a 100% CPU infinite loop: `shift 2` with $#==1 shifts nothing under the lib's set +e, so `while (( $# ))` never terminates (supervisor-attach.sh:18-25, supervisor-watch.sh:18-26, supervisor-detach.sh:18-25, supervisor-status.sh:14-21). Verified by execution: `supervisor-status.sh --session` hangs until killed.", "reasoning": "Operator-typo surface on every helper; the intended usage error never fires. Trivial fix: `shift 2 2>/dev/null || { usage; exit $SUP_EXIT_USAGE; }` or validate ${2+set} before shifting.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-4-4" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "$ALERTED is expanded unquoted (supervisor-watch.sh:66 `printf '%s\\n' $ALERTED`, :84 `for k in $ALERTED`) while its keys embed tail_uuid read from the un-versioned transcript schema: a uuid containing whitespace breaks dedup (the ambiguous/stall alert re-posts every poll — unbounded forge spam) and a glob character pathname-expands against the daemon cwd, leaking filenames into persisted state.json.", "reasoning": "No code-execution path (the value never reaches command position), but it is exactly the unquoted-expansion-of-untrusted-data class, flagged independently by the Bug Hunter and Static Security. Fix: newline-delimited ALERTED with quoted while-read (or printf '%s' \"$ALERTED\"), no bare-word step.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-4-5" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "SKILL.md hardcodes this feature's own tracker issue in its command examples: `--issue 46` at plugin/skills/supervise/SKILL.md:38, 70 and 81. A model following the skill on another project can copy it verbatim and post supervisor-event records onto that tracker's unrelated issue #46; run-template.md step 0 correctly uses a placeholder.", "reasoning": "Documentation defect with real cross-project misfire potential; trivial placeholder substitution.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-4-6" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "retry_bound=0 still fires one resume on the immediate-ETA path: the bound is checked only at loop top with an OPEN incident (supervisor-watch.sh:213-216), but open-and-fire happen in one iteration when INC_ETA=now (quota 'just passed' clamp, or backoff_base_seconds=0), so attempt 0 vs bound 0 is never compared before firing.", "reasoning": "Degenerate declared bound, but 'bound 0 = never resume' is unambiguous operator intent. Fix: check INC_ATTEMPT >= SUP_RETRY_BOUND immediately before firing as well.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": true, "feature_value": "core", "id": "F-PO-46-4-7" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "possibly-mid-work does not close an open incident (supervisor-watch.sh:197-204), unlike healthy and ambiguous: after a daemon-blind window (host suspend) a stall alert leaves the old incident open with a stale ETA and attempt count, which a later genuinely-new fault inherits via the re-aim path — premature escalation naming the old incident's counts.", "reasoning": "Transcript activity that produced the stall is positive evidence the old incident ended; closing the incident there matches F-PO-46-3-1 half (a). Fix sits in the same dispatch block as CR-1's fix.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "core", "id": "F-PO-46-4-8" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "sup_parse_reset's TZ validation (_supervisor-lib.sh:368) rejects dots but admits a leading '/', so a transcript-planted zone like (/tmp/zone) reaches TZ= as an absolute tzfile path; separately GNU date treats an UNKNOWN zone name as UTC with exit 0, so a garbled zone silently yields a wrong epoch (a mis-scheduled resume) instead of the fail-closed bounded-retry path.", "reasoning": "No execution or exfiltration path found; impact is a shifted schedule, still bounded. Fix: require a leading alpha character (reject '/' prefix) and cross-check the zone round-trips (e.g. TZ=zone date +%Z differs from the literal for known zones is not reliable — minimally reject leading '/' and keep fail-closed on parse doubt).", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-4-9" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-watch.sh:40-46 reads state tunables with bare jq -r and no // defaults: a missing/null field yields the string 'null' — SUP_RETRY_BOUND=null evaluates as 0 in arithmetic (instant bound-exhausted escalation) and SUP_NOTIFY_COMMAND='null' execs a program named null on every alert.", "reasoning": "Reachable only via hand-edited or version-skewed state.json, but the degradation is misleading rather than loud. Fix: `// defaults` in each jq read plus a sanity check that refuses to start on non-numeric tunables.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-4-10" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "scripts/lint-conventions.sh:236 and 239 still say 'the 14' shipped skills — made stale by this feature's own SHIPPED_SKILLS widening to 15 (the change updated two other count sites but not the class-3 comment and its user-facing report message).", "reasoning": "Stale user-facing message introduced by this feature's edit. Trivial: say 15, or drop the number so the next widening cannot re-stale it.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-4-11" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-attach.sh:64-65 runs mkdir -p before chmod 700, so under a permissive umask the state directory is briefly more open than intended before the tightening lands.", "reasoning": "Not exploitable under typical umasks; cheap to close with `umask 077` before the mkdir (subshell or save/restore).", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-4-12" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "--issue with leading zeros (046) passes attach's digit check but --argjson later rejects it as invalid JSON, producing a confusing exit-5 after state was already overwritten; supervisor-detach.sh never digit-validates --issue at all.", "reasoning": "Input-validation gap at the entry seam; trivial to normalize (strip leading zeros / reject) and to copy attach's check into detach.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-4-13" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "--session is never charset-validated: the sid is interpolated into a pathname glob (_supervisor-lib.sh:470-476, first match wins) and becomes a state-dir path component unchecked (:162-164) — `--session '*'` silently supervises an arbitrary transcript, and a sid containing '/' or '..' relocates the 0700 state dir.", "reasoning": "Operator/harness-supplied (session ids are UUIDs), so not hostile in practice, but a quoting slip currently produces silent wrong-session supervision instead of a loud refusal. Trivial: validate sid against [A-Za-z0-9-]+.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-4-14" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "The AC-5 'mid-work' transcript record (test/supervisor-flow.sh:618-629) is authored from scratch — harness-session-transcript.sample.json and its provenance cover only clean_turn_end, turn_death and quota shapes; no in-progress/tool_use record was ever captured, breaking the provenance convention the other four record builders follow.", "reasoning": "Currently inconsequential — the classifier's in-progress branch keys only on provenance-backed discriminators (assistant role, stop_reason, isApiErrorMessage) — but it is exactly the drift risk the provenance convention exists to catch. Fix: capture a real in-progress record from a live transcript on this box into the sample + provenance files and rebuild the fixture from it.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "core", "id": "F-PO-46-4-15" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "AC-5 depends on GNU-style `touch -d '-30 minutes'` (test/supervisor-flow.sh:631) but the suite's capability guard (:72-75) probes only `date -d @epoch`: on a BSD-date-capable-but-BSD-touch box the mtime stays fresh, no stall fires, and AC-5 hard-FAILs instead of the guard's promised skip.", "reasoning": "Test-infra portability; the guard's own comment promises the skip. Fix: probe touch's relative -d form (or pin mtime via `touch -d @epoch`, which the local-fs probe pattern already models).", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": true, "feature_value": "incidental", "id": "F-PO-46-4-16" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "The quota fixtures claim to carry the recorded middle-dot separator but '\\xc2\\xb7' inside a plain double-quoted bash string is six literal characters (test/supervisor-flow.sh:520, 558; clock_str_utc's claim at :231) — the fixture bytes do not match the recorded real shape.", "reasoning": "Tests pass because neither classifier nor parser keys on the separator, but a future change that does would be green-lit against wrong bytes. Trivial: use $'\\xc2\\xb7' or printf.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": true, "feature_value": "incidental", "id": "F-PO-46-4-17" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "AC-8's assertions race the first daemon's own resume (test/supervisor-flow.sh:689-736): with 1s backoff/poll the first daemon can fire before kill_daemon_hard lands, so 'the reclaimed daemon resumed' can pass on the first daemon's resume (the reclaim path unproven), and a stub invocation surviving the kill -9 can intermittently fail 'exactly one resume total'.", "reasoning": "Same class as the AC-9a race already fixed on this branch. Fix: give the first attach a long backoff (the test owns the fixture CLAUDE.md and can rewrite tunables between attaches) so it cannot fire pre-kill, then a short-backoff reclaim attach.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "incidental", "id": "F-PO-46-4-18" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-status.sh:56-71 declares 'STALE — treat this supervisor as dead' during a long in-flight resume — the loop legitimately blocks in `claude -p` for the whole resumed turn, so the heartbeat stalls while state.status says resume-in-flight; it also reports 'the recorded supervisor (pid unknown) is gone' during attach's startup window when pid is still null.", "reasoning": "Operator-facing misinformation in exactly the states where trust matters. Fix: branch on state.status — resume-in-flight explains the stale heartbeat; status 'starting' explains a null pid.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-4-19" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "sup_state_merge (_supervisor-lib.sh:176-184) has no callers — dead code.", "reasoning": "Hygiene while the file is already under edit; delete it.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-4-20" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "The per-incident retry bound does not survive a daemon crash: supervisor-watch.sh:53-55 hard-initializes INC_ATTEMPT/INCIDENT_N/ALERTED and supervisor-attach.sh always writes incident{attempt:0}, so a re-attach against the same still-resumable tail (same uuid — by the SREQ's own incident identity, the SAME incident) restarts the bound at 0 and duplicates alert dedup state.", "reasoning": "Requires an operator- or template-initiated re-attach after a daemon death, so each extra window is deliberate and bounded per attach; but the state file already persists the counters precisely so they could be restored, and the SREQ's incident-identity rule says this is the same incident. Deserves its own slice: restore-from-state on reclaim plus a crash-resume test scenario.", "proposed_action": "defer-to-issue", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-4-21" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "Stale-lock reclaim is a TOCTOU (supervisor-attach.sh:67-83): two concurrent attaches can both observe the dead holder; B's release (rm -rf) then deletes A's FRESH lock and both spawn daemons — two supervisors on one session, violating AC-8's invariant. No check that the lock being deleted still belongs to the stale holder.", "reasoning": "Mechanism verified, likelihood low (requires concurrent attaches racing a dead holder). Fix needs holder-identity-aware reclaim (e.g. write holder pid into the lock dir and verify-before-remove, or rename-based reclaim) — its own considered change with a test.", "proposed_action": "defer-to-issue", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-4-22" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "The abort/re-aim path posts a resume-aborted record every backoff interval with no bound or dedup (supervisor-watch.sh:264-280): a tail that keeps moving right after each ETA (repeatedly dying driver, another writer) generates forge records indefinitely — the retry bound counts only fired resumes and alert dedup does not cover aborts.", "reasoning": "Rare (requires the tail to move between every schedule and fire) and each abort is individually informative, but unbounded record spam is a real forge-hygiene risk. A dedup/bound for aborts fits naturally beside CR-1's tail-signal fix.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "incidental", "id": "F-PO-46-4-23" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "Stall detection has structural blind spots: (a) if the last 400 transcript lines contain no assistant record, class is 'healthy' regardless of mtime (an error buried past the window is never seen); (b) a zero-byte (rotated/truncated) transcript is 'healthy' forever — the stall clock runs only for the in-progress class (_supervisor-lib.sh:285, 307-315).", "reasoning": "Depends on real harness record batching (the window case needs 400+ non-assistant lines after an error — not observed in recorded shapes); the empty-file case is real but requires external truncation. Both deserve a designed answer (window sizing, stall clock for no-assistant/empty states) rather than a point patch.", "proposed_action": "defer-to-issue", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-4-24" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "kill -9 between do_resume and the resume-attempted post (supervisor-watch.sh:299-320) leaves a resume that reached the session with no per-attempt forge record — 'everything on the record' holds only crash-free.", "reasoning": "The 'detected' record already carries intent, cause and ETA, so a retrospective reader sees the incident and the schedule; supervisor crash-consistency beyond that is the PREQ's explicit HA non-goal. No incremental value over the existing record given the out-of-scope boundary.", "proposed_action": "accept", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-4-25" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "On the nohup fallback (no setsid; supervisor-attach.sh:120-126), detach's TERM is deferred by bash until an in-flight `claude -p` resume returns; after the 5s escalation to SIGKILL the claude child survives orphaned and its resume lands after the detach record claims supervision stood down.", "reasoning": "setsid is present on effectively every Linux box this suite targets (the fallback exists for exotic environments); the failure needs no-setsid AND detach-during-in-flight-resume. The stand-down record already prints loudly. No practical value in hardening the fallback's kill semantics.", "proposed_action": "accept", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-4-26" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "sup_proc_alive degrades to pid-only identity when no start token is obtainable (_supervisor-lib.sh:198-205), contradicting the lib's own 'a pid alone is not identity' — on boxes lacking ps lstart and /proc, a reused pid can block re-attach or receive detach's TERM.", "reasoning": "Deliberate graceful degradation: refusing outright on such boxes would break attach entirely, and the conservative direction (refuse attach) is the safe one. The exposure window requires an exotic box plus pid reuse landing on the recorded pid.", "proposed_action": "accept", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-4-27" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "Declared numeric tunables are unbounded in magnitude: a 20+-digit backoff_base_seconds wraps mod 2^64 in bash arithmetic (_supervisor-lib.sh:149-157; the 86400 cap applies only after a multiplication), potentially yielding a negative ETA and poll-cadence retries — still bounded by retry_bound.", "reasoning": "Requires a nonsense declaration; non-numeric values already warn-and-default; the retry bound contains the blast radius. No practical value.", "proposed_action": "accept", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-4-28" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "'weekly limit' texts classify resumable-quota but the dateless clock parser schedules at most ~24h out, so a weekly quota kill resumes into a still-closed window, burns the bound, then escalates — safe terminal state, wasted attempts.", "reasoning": "The SREQ risk table already covers quota-text variants with exactly this mitigation (bounded-retry, escalate); the terminal state is safe and loud. Improving weekly handling has no defined correct schedule to aim at (the text names no day).", "proposed_action": "accept", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-4-29" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "Minor test-assertion weaknesses: backoff-spacing check vacuous with <2 resume lines (:417-427, covered indirectly by the count check); `grep -q \"$holder_pid\"` substring-matches (:711); dead discarded statement in all_events_json (:355); the AC-13a mechanical grep misses eval\"$x\"/single-quote-adjacent sh -c variants (:999-1002) — the dynamic canary test is the real guard.", "reasoning": "Each is real but the operative guards (resume count check, AC-13b canary) already cover the outcomes; none can green-light a product defect on its own.", "proposed_action": "accept", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-4-30" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "The driver cwd is taken from the transcript with only an existence check (-n/-d) and never compared against the attach-time project root — a defense-in-depth gap flagged by Static Security for the resume and declared-command working directory.", "reasoning": "SREQ-compliant as written ('validated: exists, matches attach-time record'): the value is captured ONCE at attach — an operator-present moment, invoked by the driver itself — and never re-read from the transcript during watch, so exploiting it requires poisoning the transcript before engagement. A prefix check against project root risks false refusals on legitimate worktree layouts.", "proposed_action": "accept", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-4-31" }, { "category": "pre-existing", "severity": "low", "summary": "sup_top_scalar/sup_block_scalar (_supervisor-lib.sh:84-103) are not fence-aware: a project CLAUDE.md quoting the supervisor: yaml example inside a fence above the real declaration gets the example matched first — silent wrong tunables.", "reasoning": "Identical to the house pattern: _shared/procedures/bin/_lib.sh's _read_forge_adapter parses the forge: block with the same non-fence-aware awk, and the repo's fence-aware rule is scoped to repo tools that scan skill markdown, not declared-block readers. The declared-block schema rules place the parseability burden on the declaration. A suite-wide fence-aware declared-block reader would be its own change touching every adapter.", "proposed_action": "accept", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-4-32" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "Fractional `sleep 0.2`/`0.25` (supervisor-attach.sh:139, supervisor-detach.sh:61) is not POSIX-guaranteed — fine on GNU/BSD/macOS, bites only busybox-class boxes.", "reasoning": "The helper tier's bash>=3.2 prerequisite already excludes busybox-class boxes in practice (they lack bash too), and every targeted platform's sleep accepts fractions.", "proposed_action": "accept", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-4-33" } ], "pending_decisions": [ { "id": "D-PO-46-4-1", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-3: A stated quota reset is parsed only when an incident OPENS: the re-aim path (supervisor-watch.sh:272-273) and post-attempt rescheduling (:314-317) use plain bac", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-3", "reasoning": "Safe (bounded, escalates) but deviates from the SREQ quota path exactly on the F-PO-46-3-1 seam: the two-test decomposition dropped cause-specific rescheduling from the keep-the-incident path. Fix is localized: when the re-aimed/next cause is resumable-quota, attempt sup_parse_reset before falling back to backoff." }, { "id": "D-PO-46-4-2", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-4: A flag passed without a value as the last argument sends all four entry scripts into a 100% CPU infinite loop: `shift 2` with $#==1 shifts nothing under the lib", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-4", "reasoning": "Operator-typo surface on every helper; the intended usage error never fires. Trivial fix: `shift 2 2>/dev/null || { usage; exit $SUP_EXIT_USAGE; }` or validate ${2+set} before shifting." }, { "id": "D-PO-46-4-3", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-5: $ALERTED is expanded unquoted (supervisor-watch.sh:66 `printf '%s\\n' $ALERTED`, :84 `for k in $ALERTED`) while its keys embed tail_uuid read from the un-version", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-5", "reasoning": "No code-execution path (the value never reaches command position), but it is exactly the unquoted-expansion-of-untrusted-data class, flagged independently by the Bug Hunter and Static Security. Fix: newline-delimited ALERTED with quoted while-read (or printf '%s' \"$ALERTED\"), no bare-word step." }, { "id": "D-PO-46-4-4", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-6: SKILL.md hardcodes this feature's own tracker issue in its command examples: `--issue 46` at plugin/skills/supervise/SKILL.md:38, 70 and 81. A model following t", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-6", "reasoning": "Documentation defect with real cross-project misfire potential; trivial placeholder substitution." }, { "id": "D-PO-46-4-5", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-7: retry_bound=0 still fires one resume on the immediate-ETA path: the bound is checked only at loop top with an OPEN incident (supervisor-watch.sh:213-216), but o", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-7", "reasoning": "Degenerate declared bound, but 'bound 0 = never resume' is unambiguous operator intent. Fix: check INC_ATTEMPT >= SUP_RETRY_BOUND immediately before firing as well." }, { "id": "D-PO-46-4-6", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-8: possibly-mid-work does not close an open incident (supervisor-watch.sh:197-204), unlike healthy and ambiguous: after a daemon-blind window (host suspend) a stal", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-8", "reasoning": "Transcript activity that produced the stall is positive evidence the old incident ended; closing the incident there matches F-PO-46-3-1 half (a). Fix sits in the same dispatch block as CR-1's fix." }, { "id": "D-PO-46-4-7", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-9: sup_parse_reset's TZ validation (_supervisor-lib.sh:368) rejects dots but admits a leading '/', so a transcript-planted zone like (/tmp/zone) reaches TZ= as an ", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-9", "reasoning": "No execution or exfiltration path found; impact is a shifted schedule, still bounded. Fix: require a leading alpha character (reject '/' prefix) and cross-check the zone round-trips (e.g. TZ=zone date +%Z differs from the literal for known zones is not reliable — minimally reject leading '/' and keep fail-closed on parse doubt)." }, { "id": "D-PO-46-4-8", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-10: supervisor-watch.sh:40-46 reads state tunables with bare jq -r and no // defaults: a missing/null field yields the string 'null' — SUP_RETRY_BOUND=null evalua", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-10", "reasoning": "Reachable only via hand-edited or version-skewed state.json, but the degradation is misleading rather than loud. Fix: `// defaults` in each jq read plus a sanity check that refuses to start on non-numeric tunables." }, { "id": "D-PO-46-4-9", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-11: scripts/lint-conventions.sh:236 and 239 still say 'the 14' shipped skills — made stale by this feature's own SHIPPED_SKILLS widening to 15 (the change updated", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-11", "reasoning": "Stale user-facing message introduced by this feature's edit. Trivial: say 15, or drop the number so the next widening cannot re-stale it." }, { "id": "D-PO-46-4-10", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-12: supervisor-attach.sh:64-65 runs mkdir -p before chmod 700, so under a permissive umask the state directory is briefly more open than intended before the tighten", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-12", "reasoning": "Not exploitable under typical umasks; cheap to close with `umask 077` before the mkdir (subshell or save/restore)." }, { "id": "D-PO-46-4-11", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-13: --issue with leading zeros (046) passes attach's digit check but --argjson later rejects it as invalid JSON, producing a confusing exit-5 after state was alread", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-13", "reasoning": "Input-validation gap at the entry seam; trivial to normalize (strip leading zeros / reject) and to copy attach's check into detach." }, { "id": "D-PO-46-4-12", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-14: --session is never charset-validated: the sid is interpolated into a pathname glob (_supervisor-lib.sh:470-476, first match wins) and becomes a state-dir path c", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-14", "reasoning": "Operator/harness-supplied (session ids are UUIDs), so not hostile in practice, but a quoting slip currently produces silent wrong-session supervision instead of a loud refusal. Trivial: validate sid against [A-Za-z0-9-]+." }, { "id": "D-PO-46-4-13", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-15: The AC-5 'mid-work' transcript record (test/supervisor-flow.sh:618-629) is authored from scratch — harness-session-transcript.sample.json and its provenance c", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-15", "reasoning": "Currently inconsequential — the classifier's in-progress branch keys only on provenance-backed discriminators (assistant role, stop_reason, isApiErrorMessage) — but it is exactly the drift risk the provenance convention exists to catch. Fix: capture a real in-progress record from a live transcript on this box into the sample + provenance files and rebuild the fixture from it." }, { "id": "D-PO-46-4-14", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-16: AC-5 depends on GNU-style `touch -d '-30 minutes'` (test/supervisor-flow.sh:631) but the suite's capability guard (:72-75) probes only `date -d @epoch`: on a BS", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-16", "reasoning": "Test-infra portability; the guard's own comment promises the skip. Fix: probe touch's relative -d form (or pin mtime via `touch -d @epoch`, which the local-fs probe pattern already models)." }, { "id": "D-PO-46-4-15", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-17: The quota fixtures claim to carry the recorded middle-dot separator but '\\xc2\\xb7' inside a plain double-quoted bash string is six literal characters (test/supe", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-17", "reasoning": "Tests pass because neither classifier nor parser keys on the separator, but a future change that does would be green-lit against wrong bytes. Trivial: use $'\\xc2\\xb7' or printf." }, { "id": "D-PO-46-4-16", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-18: AC-8's assertions race the first daemon's own resume (test/supervisor-flow.sh:689-736): with 1s backoff/poll the first daemon can fire before kill_daemon_hard l", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-18", "reasoning": "Same class as the AC-9a race already fixed on this branch. Fix: give the first attach a long backoff (the test owns the fixture CLAUDE.md and can rewrite tunables between attaches) so it cannot fire pre-kill, then a short-backoff reclaim attach." }, { "id": "D-PO-46-4-17", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-19: supervisor-status.sh:56-71 declares 'STALE — treat this supervisor as dead' during a long in-flight resume — the loop legitimately blocks in `claude -p` for", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-19", "reasoning": "Operator-facing misinformation in exactly the states where trust matters. Fix: branch on state.status — resume-in-flight explains the stale heartbeat; status 'starting' explains a null pid." }, { "id": "D-PO-46-4-18", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-20: sup_state_merge (_supervisor-lib.sh:176-184) has no callers — dead code.", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-20", "reasoning": "Hygiene while the file is already under edit; delete it." }, { "id": "D-PO-46-4-19", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-21: The per-incident retry bound does not survive a daemon crash: supervisor-watch.sh:53-55 hard-initializes INC_ATTEMPT/INCIDENT_N/ALERTED and supervisor-attach.sh", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "defer-to-issue", "finding_ref": "F-PO-46-4-21", "reasoning": "Requires an operator- or template-initiated re-attach after a daemon death, so each extra window is deliberate and bounded per attach; but the state file already persists the counters precisely so they could be restored, and the SREQ's incident-identity rule says this is the same incident. Deserves its own slice: restore-from-state on reclaim plus a crash-resume test scenario." }, { "id": "D-PO-46-4-20", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-22: Stale-lock reclaim is a TOCTOU (supervisor-attach.sh:67-83): two concurrent attaches can both observe the dead holder; B's release (rm -rf) then deletes A's FRE", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "defer-to-issue", "finding_ref": "F-PO-46-4-22", "reasoning": "Mechanism verified, likelihood low (requires concurrent attaches racing a dead holder). Fix needs holder-identity-aware reclaim (e.g. write holder pid into the lock dir and verify-before-remove, or rename-based reclaim) — its own considered change with a test." }, { "id": "D-PO-46-4-21", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-23: The abort/re-aim path posts a resume-aborted record every backoff interval with no bound or dedup (supervisor-watch.sh:264-280): a tail that keeps moving right ", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-4-23", "reasoning": "Rare (requires the tail to move between every schedule and fire) and each abort is individually informative, but unbounded record spam is a real forge-hygiene risk. A dedup/bound for aborts fits naturally beside CR-1's tail-signal fix." }, { "id": "D-PO-46-4-22", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-24: Stall detection has structural blind spots: (a) if the last 400 transcript lines contain no assistant record, class is 'healthy' regardless of mtime (an error b", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "defer-to-issue", "finding_ref": "F-PO-46-4-24", "reasoning": "Depends on real harness record batching (the window case needs 400+ non-assistant lines after an error — not observed in recorded shapes); the empty-file case is real but requires external truncation. Both deserve a designed answer (window sizing, stall clock for no-assistant/empty states) rather than a point patch." }, { "id": "D-PO-46-4-23", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-25: kill -9 between do_resume and the resume-attempted post (supervisor-watch.sh:299-320) leaves a resume that reached the session with no per-attempt forge record ", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-4-25", "reasoning": "The 'detected' record already carries intent, cause and ETA, so a retrospective reader sees the incident and the schedule; supervisor crash-consistency beyond that is the PREQ's explicit HA non-goal. No incremental value over the existing record given the out-of-scope boundary." }, { "id": "D-PO-46-4-24", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-26: On the nohup fallback (no setsid; supervisor-attach.sh:120-126), detach's TERM is deferred by bash until an in-flight `claude -p` resume returns; after the 5s e", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-4-26", "reasoning": "setsid is present on effectively every Linux box this suite targets (the fallback exists for exotic environments); the failure needs no-setsid AND detach-during-in-flight-resume. The stand-down record already prints loudly. No practical value in hardening the fallback's kill semantics." }, { "id": "D-PO-46-4-25", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-27: sup_proc_alive degrades to pid-only identity when no start token is obtainable (_supervisor-lib.sh:198-205), contradicting the lib's own 'a pid alone is not ide", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-4-27", "reasoning": "Deliberate graceful degradation: refusing outright on such boxes would break attach entirely, and the conservative direction (refuse attach) is the safe one. The exposure window requires an exotic box plus pid reuse landing on the recorded pid." }, { "id": "D-PO-46-4-26", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-28: Declared numeric tunables are unbounded in magnitude: a 20+-digit backoff_base_seconds wraps mod 2^64 in bash arithmetic (_supervisor-lib.sh:149-157; the 86400 ", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-4-28", "reasoning": "Requires a nonsense declaration; non-numeric values already warn-and-default; the retry bound contains the blast radius. No practical value." }, { "id": "D-PO-46-4-27", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-29: 'weekly limit' texts classify resumable-quota but the dateless clock parser schedules at most ~24h out, so a weekly quota kill resumes into a still-closed windo", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-4-29", "reasoning": "The SREQ risk table already covers quota-text variants with exactly this mitigation (bounded-retry, escalate); the terminal state is safe and loud. Improving weekly handling has no defined correct schedule to aim at (the text names no day)." }, { "id": "D-PO-46-4-28", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-30: Minor test-assertion weaknesses: backoff-spacing check vacuous with <2 resume lines (:417-427, covered indirectly by the count check); `grep -q \"$holder_pid\"` s", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-4-30", "reasoning": "Each is real but the operative guards (resume count check, AC-13b canary) already cover the outcomes; none can green-light a product defect on its own." }, { "id": "D-PO-46-4-29", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-31: The driver cwd is taken from the transcript with only an existence check (-n/-d) and never compared against the attach-time project root — a defense-in-depth ", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-4-31", "reasoning": "SREQ-compliant as written ('validated: exists, matches attach-time record'): the value is captured ONCE at attach — an operator-present moment, invoked by the driver itself — and never re-read from the transcript during watch, so exploiting it requires poisoning the transcript before engagement. A prefix check against project root risks false refusals on legitimate worktree layouts." }, { "id": "D-PO-46-4-30", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-32: sup_top_scalar/sup_block_scalar (_supervisor-lib.sh:84-103) are not fence-aware: a project CLAUDE.md quoting the supervisor: yaml example inside a fence above t", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-4-32", "reasoning": "Identical to the house pattern: _shared/procedures/bin/_lib.sh's _read_forge_adapter parses the forge: block with the same non-fence-aware awk, and the repo's fence-aware rule is scoped to repo tools that scan skill markdown, not declared-block readers. The declared-block schema rules place the parseability burden on the declaration. A suite-wide fence-aware declared-block reader would be its own change touching every adapter." }, { "id": "D-PO-46-4-31", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-33: Fractional `sleep 0.2`/`0.25` (supervisor-attach.sh:139, supervisor-detach.sh:61) is not POSIX-guaranteed — fine on GNU/BSD/macOS, bites only busybox-class bo", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-4-33", "reasoning": "The helper tier's bash>=3.2 prerequisite already excludes busybox-class boxes in practice (they lack bash too), and every targeted platform's sleep accepts fractions." } ], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Safe (bounded, escalates) but deviates from the SREQ quota path exactly on the F-PO-46-3-1 seam: the two-test decomposition dropped cause-specific rescheduling from the keep-the-incident path. Fix is localized: when the re-aimed/next cause is resumable-quota, attempt sup_parse_reset before falling back to backoff. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-1 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Safe (bounded, escalates) but deviates from the SREQ quota path exactly on the F-PO-46-3-1 seam: the two-test decomposition dropped cause-specific rescheduling from the keep-the-incident path. Fix is localized: when the re-aimed/next cause is resumable-quota, attempt sup_parse_reset before falling back to backoff. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Operator-typo surface on every helper; the intended usage error never fires. Trivial fix: `shift 2 2>/dev/null || { usage; exit $SUP_EXIT_USAGE; }` or validate ${2+set} before shifting. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-2 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Operator-typo surface on every helper; the intended usage error never fires. Trivial fix: `shift 2 2>/dev/null || { usage; exit $SUP_EXIT_USAGE; }` or validate ${2+set} before shifting. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "No code-execution path (the value never reaches command position), but it is exactly the unquoted-expansion-of-untrusted-data class, flagged independently by the Bug Hunter and Static Security. Fix: newline-delimited ALERTED with quoted while-read (or printf '%s' \"$ALERTED\"), no bare-word step. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-3 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "No code-execution path (the value never reaches command position), but it is exactly the unquoted-expansion-of-untrusted-data class, flagged independently by the Bug Hunter and Static Security. Fix: newline-delimited ALERTED with quoted while-read (or printf '%s' \"$ALERTED\"), no bare-word step. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Documentation defect with real cross-project misfire potential; trivial placeholder substitution. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-4 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Documentation defect with real cross-project misfire potential; trivial placeholder substitution. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Degenerate declared bound, but 'bound 0 = never resume' is unambiguous operator intent. Fix: check INC_ATTEMPT >= SUP_RETRY_BOUND immediately before firing as well. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-5 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Degenerate declared bound, but 'bound 0 = never resume' is unambiguous operator intent. Fix: check INC_ATTEMPT >= SUP_RETRY_BOUND immediately before firing as well. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Transcript activity that produced the stall is positive evidence the old incident ended; closing the incident there matches F-PO-46-3-1 half (a). Fix sits in the same dispatch block as CR-1's fix. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-6 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Transcript activity that produced the stall is positive evidence the old incident ended; closing the incident there matches F-PO-46-3-1 half (a). Fix sits in the same dispatch block as CR-1's fix. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "No execution or exfiltration path found; impact is a shifted schedule, still bounded. Fix: require a leading alpha character (reject '/' prefix) and cross-check the zone round-trips (e.g. TZ=zone date +%Z differs from the literal for known zones is not reliable — minimally reject leading '/' and keep fail-closed on parse doubt). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-7 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "No execution or exfiltration path found; impact is a shifted schedule, still bounded. Fix: require a leading alpha character (reject '/' prefix) and cross-check the zone round-trips (e.g. TZ=zone date +%Z differs from the literal for known zones is not reliable — minimally reject leading '/' and keep fail-closed on parse doubt). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Reachable only via hand-edited or version-skewed state.json, but the degradation is misleading rather than loud. Fix: `// defaults` in each jq read plus a sanity check that refuses to start on non-numeric tunables. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-8 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Reachable only via hand-edited or version-skewed state.json, but the degradation is misleading rather than loud. Fix: `// defaults` in each jq read plus a sanity check that refuses to start on non-numeric tunables. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Stale user-facing message introduced by this feature's edit. Trivial: say 15, or drop the number so the next widening cannot re-stale it. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-9 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Stale user-facing message introduced by this feature's edit. Trivial: say 15, or drop the number so the next widening cannot re-stale it. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Not exploitable under typical umasks; cheap to close with `umask 077` before the mkdir (subshell or save/restore). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-10 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Not exploitable under typical umasks; cheap to close with `umask 077` before the mkdir (subshell or save/restore). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Input-validation gap at the entry seam; trivial to normalize (strip leading zeros / reject) and to copy attach's check into detach. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-11 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Input-validation gap at the entry seam; trivial to normalize (strip leading zeros / reject) and to copy attach's check into detach. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Operator/harness-supplied (session ids are UUIDs), so not hostile in practice, but a quoting slip currently produces silent wrong-session supervision instead of a loud refusal. Trivial: validate sid against [A-Za-z0-9-]+. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-12 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Operator/harness-supplied (session ids are UUIDs), so not hostile in practice, but a quoting slip currently produces silent wrong-session supervision instead of a loud refusal. Trivial: validate sid against [A-Za-z0-9-]+. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Currently inconsequential — the classifier's in-progress branch keys only on provenance-backed discriminators (assistant role, stop_reason, isApiErrorMessage) — but it is exactly the drift risk the provenance convention exists to catch. Fix: capture a real in-progress record from a live transcript on this box into the sample + provenance files and rebuild the fixture from it. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-13 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Currently inconsequential — the classifier's in-progress branch keys only on provenance-backed discriminators (assistant role, stop_reason, isApiErrorMessage) — but it is exactly the drift risk the provenance convention exists to catch. Fix: capture a real in-progress record from a live transcript on this box into the sample + provenance files and rebuild the fixture from it. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Test-infra portability; the guard's own comment promises the skip. Fix: probe touch's relative -d form (or pin mtime via `touch -d @epoch`, which the local-fs probe pattern already models). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-14 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Test-infra portability; the guard's own comment promises the skip. Fix: probe touch's relative -d form (or pin mtime via `touch -d @epoch`, which the local-fs probe pattern already models). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Tests pass because neither classifier nor parser keys on the separator, but a future change that does would be green-lit against wrong bytes. Trivial: use $'\\xc2\\xb7' or printf. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-15 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Tests pass because neither classifier nor parser keys on the separator, but a future change that does would be green-lit against wrong bytes. Trivial: use $'\\xc2\\xb7' or printf. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Same class as the AC-9a race already fixed on this branch. Fix: give the first attach a long backoff (the test owns the fixture CLAUDE.md and can rewrite tunables between attaches) so it cannot fire pre-kill, then a short-backoff reclaim attach. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-16 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Same class as the AC-9a race already fixed on this branch. Fix: give the first attach a long backoff (the test owns the fixture CLAUDE.md and can rewrite tunables between attaches) so it cannot fire pre-kill, then a short-backoff reclaim attach. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Operator-facing misinformation in exactly the states where trust matters. Fix: branch on state.status — resume-in-flight explains the stale heartbeat; status 'starting' explains a null pid. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-17 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Operator-facing misinformation in exactly the states where trust matters. Fix: branch on state.status — resume-in-flight explains the stale heartbeat; status 'starting' explains a null pid. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Hygiene while the file is already under edit; delete it. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-18 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Hygiene while the file is already under edit; delete it. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Rare (requires the tail to move between every schedule and fire) and each abort is individually informative, but unbounded record spam is a real forge-hygiene risk. A dedup/bound for aborts fits naturally beside CR-1's tail-signal fix. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-21 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Rare (requires the tail to move between every schedule and fire) and each abort is individually informative, but unbounded record spam is a real forge-hygiene risk. A dedup/bound for aborts fits naturally beside CR-1's tail-signal fix. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the fix is trivial/small and (where noted) adjacent to a blocking fix already being made this round, so a separate issue would cost more ceremony than the fix itself." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "The 'detected' record already carries intent, cause and ETA, so a retrospective reader sees the incident and the schedule; supervisor crash-consistency beyond that is the PREQ's explicit HA non-goal. No incremental value over the existing record given the out-of-scope boundary. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-23 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "The 'detected' record already carries intent, cause and ETA, so a retrospective reader sees the incident and the schedule; supervisor crash-consistency beyond that is the PREQ's explicit HA non-goal. No incremental value over the existing record given the out-of-scope boundary. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "setsid is present on effectively every Linux box this suite targets (the fallback exists for exotic environments); the failure needs no-setsid AND detach-during-in-flight-resume. The stand-down record already prints loudly. No practical value in hardening the fallback's kill semantics. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-24 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "setsid is present on effectively every Linux box this suite targets (the fallback exists for exotic environments); the failure needs no-setsid AND detach-during-in-flight-resume. The stand-down record already prints loudly. No practical value in hardening the fallback's kill semantics. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Deliberate graceful degradation: refusing outright on such boxes would break attach entirely, and the conservative direction (refuse attach) is the safe one. The exposure window requires an exotic box plus pid reuse landing on the recorded pid. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-25 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Deliberate graceful degradation: refusing outright on such boxes would break attach entirely, and the conservative direction (refuse attach) is the safe one. The exposure window requires an exotic box plus pid reuse landing on the recorded pid. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Requires a nonsense declaration; non-numeric values already warn-and-default; the retry bound contains the blast radius. No practical value. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-26 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Requires a nonsense declaration; non-numeric values already warn-and-default; the retry bound contains the blast radius. No practical value. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "The SREQ risk table already covers quota-text variants with exactly this mitigation (bounded-retry, escalate); the terminal state is safe and loud. Improving weekly handling has no defined correct schedule to aim at (the text names no day). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-27 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "The SREQ risk table already covers quota-text variants with exactly this mitigation (bounded-retry, escalate); the terminal state is safe and loud. Improving weekly handling has no defined correct schedule to aim at (the text names no day). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Each is real but the operative guards (resume count check, AC-13b canary) already cover the outcomes; none can green-light a product defect on its own. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-28 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Each is real but the operative guards (resume count check, AC-13b canary) already cover the outcomes; none can green-light a product defect on its own. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "SREQ-compliant as written ('validated: exists, matches attach-time record'): the value is captured ONCE at attach — an operator-present moment, invoked by the driver itself — and never re-read from the transcript during watch, so exploiting it requires poisoning the transcript before engagement. A prefix check against project root risks false refusals on legitimate worktree layouts. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-29 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "SREQ-compliant as written ('validated: exists, matches attach-time record'): the value is captured ONCE at attach — an operator-present moment, invoked by the driver itself — and never re-read from the transcript during watch, so exploiting it requires poisoning the transcript before engagement. A prefix check against project root risks false refusals on legitimate worktree layouts. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Identical to the house pattern: _shared/procedures/bin/_lib.sh's _read_forge_adapter parses the forge: block with the same non-fence-aware awk, and the repo's fence-aware rule is scoped to repo tools that scan skill markdown, not declared-block readers. The declared-block schema rules place the parseability burden on the declaration. A suite-wide fence-aware declared-block reader would be its own change touching every adapter. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-30 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Identical to the house pattern: _shared/procedures/bin/_lib.sh's _read_forge_adapter parses the forge: block with the same non-fence-aware awk, and the repo's fence-aware rule is scoped to repo tools that scan skill markdown, not declared-block readers. The declared-block schema rules place the parseability burden on the declaration. A suite-wide fence-aware declared-block reader would be its own change touching every adapter. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "The helper tier's bash>=3.2 prerequisite already excludes busybox-class boxes in practice (they lack bash too), and every targeted platform's sleep accepts fractions. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.",
  "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-31 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "The helper tier's bash>=3.2 prerequisite already excludes busybox-class boxes in practice (they lack bash too), and every targeted platform's sleep accepts fractions. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; the choice follows the canonical recommender (finding.v1.md) computed from the finding's recorded axes, and a scope-disposition is non-blocking and latest-wins, so it is cheaply reversible.", "rejected_alternative": "defer-to-issue: rejected — the finding's feature value is none (reasoned in the disposition rationale), so a backlog issue would only accumulate noise." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "defer-to-issue",
  "rationale": "Operator-facing misinformation in exactly the states where trust matters. Fix: branch on state.status — resume-in-flight explains the stale heartbeat; status 'starting' explains a null pid. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice follows the canonical recommender over the finding's recorded axes (fix_cost substantial => defer). Fold target judged per /dev:resolve's confidence rule: no existing issue covers supervisor-daemon robustness, so CR-21 spawns the home and CR-22/CR-24 fold into it (same daemon, same component).",
  "rejected_alternative": "fix-now: rejected — the fix is substantial (state-restore contract / lock-reclaim redesign / stall-window design) and would grow this QA round past its blocking set; the risk each finding names is bounded and rare."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-19 --> ```json { "status": "resolved", "chosen_option": "defer-to-issue", "rationale": "Operator-facing misinformation in exactly the states where trust matters. Fix: branch on state.status — resume-in-flight explains the stale heartbeat; status 'starting' explains a null pid. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice follows the canonical recommender over the finding's recorded axes (fix_cost substantial => defer). Fold target judged per /dev:resolve's confidence rule: no existing issue covers supervisor-daemon robustness, so CR-21 spawns the home and CR-22/CR-24 fold into it (same daemon, same component).", "rejected_alternative": "fix-now: rejected — the fix is substantial (state-restore contract / lock-reclaim redesign / stall-window design) and would grow this QA round past its blocking set; the risk each finding names is bounded and rare." } ```
Author
Owner

Linked: this issue is sibling #255 (recorded by the devwork pipeline).

Linked: this issue is **sibling** #255 (recorded by the devwork pipeline).
Author
Owner
{
  "status": "resolved",
  "chosen_option": "defer-to-issue",
  "target_issue_ref": "255",
  "rationale": "Hygiene while the file is already under edit; delete it. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice follows the canonical recommender over the finding's recorded axes (fix_cost substantial => defer). Fold target judged per /dev:resolve's confidence rule: no existing issue covers supervisor-daemon robustness, so CR-21 spawns the home and CR-22/CR-24 fold into it (same daemon, same component).",
  "rejected_alternative": "fix-now: rejected — the fix is substantial (state-restore contract / lock-reclaim redesign / stall-window design) and would grow this QA round past its blocking set; the risk each finding names is bounded and rare."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-20 --> ```json { "status": "resolved", "chosen_option": "defer-to-issue", "target_issue_ref": "255", "rationale": "Hygiene while the file is already under edit; delete it. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice follows the canonical recommender over the finding's recorded axes (fix_cost substantial => defer). Fold target judged per /dev:resolve's confidence rule: no existing issue covers supervisor-daemon robustness, so CR-21 spawns the home and CR-22/CR-24 fold into it (same daemon, same component).", "rejected_alternative": "fix-now: rejected — the fix is substantial (state-restore contract / lock-reclaim redesign / stall-window design) and would grow this QA round past its blocking set; the risk each finding names is bounded and rare." } ```
Author
Owner

Linked: this issue is sibling #255 (recorded by the devwork pipeline).

Linked: this issue is **sibling** #255 (recorded by the devwork pipeline).
Author
Owner
{
  "status": "resolved",
  "chosen_option": "defer-to-issue",
  "target_issue_ref": "255",
  "rationale": "Mechanism verified, likelihood low (requires concurrent attaches racing a dead holder). Fix needs holder-identity-aware reclaim (e.g. write holder pid into the lock dir and verify-before-remove, or rename-based reclaim) — its own considered change with a test. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice follows the canonical recommender over the finding's recorded axes (fix_cost substantial => defer). Fold target judged per /dev:resolve's confidence rule: no existing issue covers supervisor-daemon robustness, so CR-21 spawns the home and CR-22/CR-24 fold into it (same daemon, same component).",
  "rejected_alternative": "fix-now: rejected — the fix is substantial (state-restore contract / lock-reclaim redesign / stall-window design) and would grow this QA round past its blocking set; the risk each finding names is bounded and rare."
}
<!-- decision-resolution:v1 ref=D-PO-46-4-22 --> ```json { "status": "resolved", "chosen_option": "defer-to-issue", "target_issue_ref": "255", "rationale": "Mechanism verified, likelihood low (requires concurrent attaches racing a dead holder). Fix needs holder-identity-aware reclaim (e.g. write holder pid into the lock dir and verify-before-remove, or rename-based reclaim) — its own considered change with a test. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice follows the canonical recommender over the finding's recorded axes (fix_cost substantial => defer). Fold target judged per /dev:resolve's confidence rule: no existing issue covers supervisor-daemon robustness, so CR-21 spawns the home and CR-22/CR-24 fold into it (same daemon, same component).", "rejected_alternative": "fix-now: rejected — the fix is substantial (state-restore contract / lock-reclaim redesign / stall-window design) and would grow this QA round past its blocking set; the risk each finding names is bounded and rare." } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "12 red regression scenarios added for the promoted set (CR-1,3,4,5,7,8,9,10,12,13,14,23); CR-1 and CR-4 proven able to fail against current code; CR-12 is a green guard by nature (TOCTOU window unobservable black-box — valid regression guard, cannot be red pre-fix). Suite + lint green with guards in place. Doc/test-file findings (CR-2,6,11,15,16,17,18,19,20) need no separate red test: the fix edits the test/doc artifact itself, verified by the re-validate run and mechanical gates.",
  "findings": [],
  "artifacts": {
    "test_files": [
      "plugin/skills/supervise/test/supervisor-flow.sh"
    ],
    "test_commit": "1512dc8",
    "test_marker": {
      "runner": "bespoke-shell-harness",
      "write": "first line of scenario fn: echo \"SKIP-RED - <CR-ID> unfixed (promote: delete this line)\"; return 0",
      "promote": "delete that one guard line; never touch the assertions below it"
    }
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=tests --> ```json { "outcome": "clean", "summary": "12 red regression scenarios added for the promoted set (CR-1,3,4,5,7,8,9,10,12,13,14,23); CR-1 and CR-4 proven able to fail against current code; CR-12 is a green guard by nature (TOCTOU window unobservable black-box — valid regression guard, cannot be red pre-fix). Suite + lint green with guards in place. Doc/test-file findings (CR-2,6,11,15,16,17,18,19,20) need no separate red test: the fix edits the test/doc artifact itself, verified by the re-validate run and mechanical gates.", "findings": [], "artifacts": { "test_files": [ "plugin/skills/supervise/test/supervisor-flow.sh" ], "test_commit": "1512dc8", "test_marker": { "runner": "bespoke-shell-harness", "write": "first line of scenario fn: echo \"SKIP-RED - <CR-ID> unfixed (promote: delete this line)\"; return 0", "promote": "delete that one guard line; never touch the assertions below it" } } } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "All 23 in-scope findings fixed (CR-1..CR-20, CR-23; commits d018dd7 + f1b306c). 11 red tests promoted by guard deletion; CR-8 re-armed on an event-based wait and red-proven against a reverted fix. Assertion-constraint check vs test_commit 1512dc8: inside CR scenarios only guard lines changed. Fixer deviations flagged for the sweep adversarial pass: (a) attach record cause changed to operator-attach; (b) resumes now require the tail signature unchanged twice, one poll apart; (c) a foreign write found at pre-resume re-classification stands the supervisor down (operator-stop) rather than re-aiming. Gates: supervise suite 142 ok / 0 FAIL (independently re-run by the lead), lint clean, smoke PASS.",
  "findings": [],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=fix --> ```json { "outcome": "clean", "summary": "All 23 in-scope findings fixed (CR-1..CR-20, CR-23; commits d018dd7 + f1b306c). 11 red tests promoted by guard deletion; CR-8 re-armed on an event-based wait and red-proven against a reverted fix. Assertion-constraint check vs test_commit 1512dc8: inside CR scenarios only guard lines changed. Fixer deviations flagged for the sweep adversarial pass: (a) attach record cause changed to operator-attach; (b) resumes now require the tail signature unchanged twice, one poll apart; (c) a foreign write found at pre-resume re-classification stands the supervisor down (operator-stop) rather than re-aiming. Gates: supervise suite 142 ok / 0 FAIL (independently re-run by the lead), lint clean, smoke PASS.", "findings": [], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "outcome": "issues-found",
  "summary": "Round-2 fresh-context re-validation of the round-1 fixes: all 21 prior findings independently RESOLVED; 2 new low-severity findings (CR-34 residual arg-parse gap in need_value; CR-35 SKILL.md drift on the two new daemon behaviors). The fixer round-1 deviations (operator-attach cause, two-look stability gate, foreign-write standdown) were independently assessed sound.",
  "findings": [
    {
      "id": "CR-34",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "need_value() (added by round 1 for CR-4) guards only a flag at end-of-argv: a flag followed by another flag, e.g. `supervisor-attach.sh --session --issue 46`, silently sets SESSION='--issue' (the charset check permits '-') and misparses instead of erroring.",
      "reasoning": "Residual of the CR-4 class found by the fresh-context re-validation: no hang, but a silent misparse at the same seam. Trivial: reject a value starting with '--' in need_value (no legitimate value of these flags starts with '--').",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "CR-35",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "SKILL.md's classification/behavior text does not document two behaviors round 1 added to the daemon: the pre-resume foreign-write standdown (a non-interrupt user record found at re-classification stands the supervisor down as operator-stop) and the two-consecutive-stable-observations requirement before any resume fires.",
      "reasoning": "In this suite the skill markdown IS the product; behavior the helpers have but the skill text does not describe is drift a future amendment round would misread. Small text addition to the classification section.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    }
  ],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=validate --> ```json { "outcome": "issues-found", "summary": "Round-2 fresh-context re-validation of the round-1 fixes: all 21 prior findings independently RESOLVED; 2 new low-severity findings (CR-34 residual arg-parse gap in need_value; CR-35 SKILL.md drift on the two new daemon behaviors). The fixer round-1 deviations (operator-attach cause, two-look stability gate, foreign-write standdown) were independently assessed sound.", "findings": [ { "id": "CR-34", "category": "in-scope-deferrable", "severity": "low", "summary": "need_value() (added by round 1 for CR-4) guards only a flag at end-of-argv: a flag followed by another flag, e.g. `supervisor-attach.sh --session --issue 46`, silently sets SESSION='--issue' (the charset check permits '-') and misparses instead of erroring.", "reasoning": "Residual of the CR-4 class found by the fresh-context re-validation: no hang, but a silent misparse at the same seam. Trivial: reject a value starting with '--' in need_value (no legitimate value of these flags starts with '--').", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "CR-35", "category": "in-scope-deferrable", "severity": "low", "summary": "SKILL.md's classification/behavior text does not document two behaviors round 1 added to the daemon: the pre-resume foreign-write standdown (a non-interrupt user record found at re-classification stands the supervisor down as operator-stop) and the two-consecutive-stable-observations requirement before any resume fires.", "reasoning": "In this suite the skill markdown IS the product; behavior the helpers have but the skill text does not describe is drift a future amendment round would misread. Small text addition to the classification section.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core" } ], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "outcome": "issues-found",
  "summary": "Validation run (test-plan:v1, 13 scenarios) over the declared shell integration lane — this project has no browser, so the e2e slot carries the PREQ-derived validation run. Suite fresh run: 147 ok / 0 FAIL; supervisor-event records verified legible by a real read of posted records. 8 scenarios PASS; 5 coverage gaps vs plan text recorded as V-1..V-5 (backoff growth unexercised; future-reset live fire uncovered by design; past-reset record value unasserted; AC-11 sweep mislabeled population; stall-override test lacks discriminating power). AC-13/AC-14 suite groups trace to SREQ expert-review ACs — legitimate, not scope creep.",
  "findings": [
    {
      "id": "V-1",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "Test-plan Scenario 1 step 5 (attempt gaps GROW) is unexercised: every suite scenario declares backoff_multiplier=1, so exponential backoff (base x multiplier^n, the documented default shape) is never observed anywhere in the suite.",
      "reasoning": "Validation-run finding against plan text. Fix: one scenario (or an extension of AC-2's) with backoff_multiplier=2 and short base asserting the recorded ETAs/attempt spacing grow geometrically.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "V-2",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Test-plan Scenario 3 step 5 (the run actually resumes at/promptly after a FUTURE reset time) is uncovered by design: scenario_ac3_future proves the scheduling math only and never lets the resume fire.",
      "reasoning": "The firing-at-ETA machinery is a single shared code path (next_eta + the now>=INC_ETA gate) proven live by AC-1/AC-2 at backoff ETAs and by AC-3b at an immediate quota ETA; the only untested increment is a wall-clock sleep to a minute-granularity future reset, costing 60s+ of suite runtime for a path composition already covers. Accept with this reasoning; the dogfood UAT run observes the real long-sleep behavior.",
      "proposed_action": "accept",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "V-3",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Test-plan Scenario 4 step 3 first clause: scenario_ac3_past never asserts the parsed reset value was RECORDED (only that the resume fired promptly with cause resumable-quota); AC-3a has the value assertion, the past variant does not.",
      "reasoning": "Trivial test addition: assert the detected record / state carries the parsed reset epoch in the past-variant too.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    },
    {
      "id": "V-4",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "Test-plan Scenario 12 step 2: AC-11's completeness sweep labeled 'sweep(AC-3)' actually re-inspects scenario_ac3_past's fixture (only it sets AC3_ISSUE/keep_sandbox); scenario_ac3_future is never completeness-swept, so the sweep silently covers Scenario 4 twice and Scenario 3 never.",
      "reasoning": "Validation-run finding: the sweep's population is mislabeled — a plan-text completeness claim quietly narrowed. Fix: keep the future variant's sandbox too and sweep both (or sweep future and relabel).",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "V-5",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "Test-plan Scenario 13: the stall-threshold override test cannot discriminate override from default — it ages the transcript exactly 30 minutes with stall_threshold_minutes=1 declared, but the suite DEFAULT threshold is also 30, so a supervisor ignoring the override would still alert at this boundary.",
      "reasoning": "Validation-run finding: zero discriminating power on the overridden tunable. Trivial: age the transcript ~5 minutes (over the 1-minute override, far under the 30-minute default) so an ignored override produces NO alert and the test fails.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    }
  ],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=e2e phase=validate --> ```json { "outcome": "issues-found", "summary": "Validation run (test-plan:v1, 13 scenarios) over the declared shell integration lane — this project has no browser, so the e2e slot carries the PREQ-derived validation run. Suite fresh run: 147 ok / 0 FAIL; supervisor-event records verified legible by a real read of posted records. 8 scenarios PASS; 5 coverage gaps vs plan text recorded as V-1..V-5 (backoff growth unexercised; future-reset live fire uncovered by design; past-reset record value unasserted; AC-11 sweep mislabeled population; stall-override test lacks discriminating power). AC-13/AC-14 suite groups trace to SREQ expert-review ACs — legitimate, not scope creep.", "findings": [ { "id": "V-1", "category": "in-scope-deferrable", "severity": "medium", "summary": "Test-plan Scenario 1 step 5 (attempt gaps GROW) is unexercised: every suite scenario declares backoff_multiplier=1, so exponential backoff (base x multiplier^n, the documented default shape) is never observed anywhere in the suite.", "reasoning": "Validation-run finding against plan text. Fix: one scenario (or an extension of AC-2's) with backoff_multiplier=2 and short base asserting the recorded ETAs/attempt spacing grow geometrically.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "V-2", "category": "in-scope-deferrable", "severity": "low", "summary": "Test-plan Scenario 3 step 5 (the run actually resumes at/promptly after a FUTURE reset time) is uncovered by design: scenario_ac3_future proves the scheduling math only and never lets the resume fire.", "reasoning": "The firing-at-ETA machinery is a single shared code path (next_eta + the now>=INC_ETA gate) proven live by AC-1/AC-2 at backoff ETAs and by AC-3b at an immediate quota ETA; the only untested increment is a wall-clock sleep to a minute-granularity future reset, costing 60s+ of suite runtime for a path composition already covers. Accept with this reasoning; the dogfood UAT run observes the real long-sleep behavior.", "proposed_action": "accept", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "V-3", "category": "in-scope-deferrable", "severity": "low", "summary": "Test-plan Scenario 4 step 3 first clause: scenario_ac3_past never asserts the parsed reset value was RECORDED (only that the resume fired promptly with cause resumable-quota); AC-3a has the value assertion, the past variant does not.", "reasoning": "Trivial test addition: assert the detected record / state carries the parsed reset epoch in the past-variant too.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" }, { "id": "V-4", "category": "in-scope-deferrable", "severity": "medium", "summary": "Test-plan Scenario 12 step 2: AC-11's completeness sweep labeled 'sweep(AC-3)' actually re-inspects scenario_ac3_past's fixture (only it sets AC3_ISSUE/keep_sandbox); scenario_ac3_future is never completeness-swept, so the sweep silently covers Scenario 4 twice and Scenario 3 never.", "reasoning": "Validation-run finding: the sweep's population is mislabeled — a plan-text completeness claim quietly narrowed. Fix: keep the future variant's sandbox too and sweep both (or sweep future and relabel).", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "V-5", "category": "in-scope-deferrable", "severity": "medium", "summary": "Test-plan Scenario 13: the stall-threshold override test cannot discriminate override from default — it ages the transcript exactly 30 minutes with stall_threshold_minutes=1 declared, but the suite DEFAULT threshold is also 30, so a supervisor ignoring the override would still alert at this boundary.", "reasoning": "Validation-run finding: zero discriminating power on the overridden tunable. Trivial: age the transcript ~5 minutes (over the 1-minute override, far under the 30-minute default) so an ignored override produces NO alert and the test fails.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core" } ], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "next_state": "qa",
  "produced": [
    {
      "kind": "qa-report",
      "ref": "1845",
      "summary": "code validate round 2: 21/21 round-1 findings independently resolved; 2 new low findings"
    },
    {
      "kind": "qa-report",
      "ref": "1846",
      "summary": "validation run over the shell lane: 147 ok / 0 FAIL; 5 plan-text coverage gaps (V-1..V-5)"
    }
  ],
  "findings": [
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "need_value() (added by round 1 for CR-4) guards only a flag at end-of-argv: a flag followed by another flag, e.g. `supervisor-attach.sh --session --issue 46`, silently sets SESSION='--issue' (the charset check permits '-') and misparses instead of erroring.",
      "reasoning": "Residual of the CR-4 class found by the fresh-context re-validation: no hang, but a silent misparse at the same seam. Trivial: reject a value starting with '--' in need_value (no legitimate value of these flags starts with '--').",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-5-1"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "SKILL.md's classification/behavior text does not document two behaviors round 1 added to the daemon: the pre-resume foreign-write standdown (a non-interrupt user record found at re-classification stands the supervisor down as operator-stop) and the two-consecutive-stable-observations requirement before any resume fires.",
      "reasoning": "In this suite the skill markdown IS the product; behavior the helpers have but the skill text does not describe is drift a future amendment round would misread. Small text addition to the classification section.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-5-2"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "Test-plan Scenario 1 step 5 (attempt gaps GROW) is unexercised: every suite scenario declares backoff_multiplier=1, so exponential backoff (base x multiplier^n, the documented default shape) is never observed anywhere in the suite.",
      "reasoning": "Validation-run finding against plan text. Fix: one scenario (or an extension of AC-2's) with backoff_multiplier=2 and short base asserting the recorded ETAs/attempt spacing grow geometrically.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-5-3"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Test-plan Scenario 3 step 5 (the run actually resumes at/promptly after a FUTURE reset time) is uncovered by design: scenario_ac3_future proves the scheduling math only and never lets the resume fire.",
      "reasoning": "The firing-at-ETA machinery is a single shared code path (next_eta + the now>=INC_ETA gate) proven live by AC-1/AC-2 at backoff ETAs and by AC-3b at an immediate quota ETA; the only untested increment is a wall-clock sleep to a minute-granularity future reset, costing 60s+ of suite runtime for a path composition already covers. Accept with this reasoning; the dogfood UAT run observes the real long-sleep behavior.",
      "proposed_action": "accept",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-5-4"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Test-plan Scenario 4 step 3 first clause: scenario_ac3_past never asserts the parsed reset value was RECORDED (only that the resume fired promptly with cause resumable-quota); AC-3a has the value assertion, the past variant does not.",
      "reasoning": "Trivial test addition: assert the detected record / state carries the parsed reset epoch in the past-variant too.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-5-5"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "Test-plan Scenario 12 step 2: AC-11's completeness sweep labeled 'sweep(AC-3)' actually re-inspects scenario_ac3_past's fixture (only it sets AC3_ISSUE/keep_sandbox); scenario_ac3_future is never completeness-swept, so the sweep silently covers Scenario 4 twice and Scenario 3 never.",
      "reasoning": "Validation-run finding: the sweep's population is mislabeled — a plan-text completeness claim quietly narrowed. Fix: keep the future variant's sandbox too and sweep both (or sweep future and relabel).",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-5-6"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "Test-plan Scenario 13: the stall-threshold override test cannot discriminate override from default — it ages the transcript exactly 30 minutes with stall_threshold_minutes=1 declared, but the suite DEFAULT threshold is also 30, so a supervisor ignoring the override would still alert at this boundary.",
      "reasoning": "Validation-run finding: zero discriminating power on the overridden tunable. Trivial: age the transcript ~5 minutes (over the 1-minute override, far under the 30-minute default) so an ignored override produces NO alert and the test fails.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-5-7"
    }
  ],
  "pending_decisions": [
    {
      "id": "D-PO-46-5-1",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-34: need_value() (added by round 1 for CR-4) guards only a flag at end-of-argv: a flag followed by another flag, e.g. `supervisor-attach.sh --session --issue 46`, s",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-5-1",
      "reasoning": "Residual of the CR-4 class found by the fresh-context re-validation: no hang, but a silent misparse at the same seam. Trivial: reject a value starting with '--' in need_value (no legitimate value of these flags starts with '--')."
    },
    {
      "id": "D-PO-46-5-2",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for CR-35: SKILL.md's classification/behavior text does not document two behaviors round 1 added to the daemon: the pre-resume foreign-write standdown (a non-interrupt use",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-5-2",
      "reasoning": "In this suite the skill markdown IS the product; behavior the helpers have but the skill text does not describe is drift a future amendment round would misread. Small text addition to the classification section."
    },
    {
      "id": "D-PO-46-5-3",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for V-1: Test-plan Scenario 1 step 5 (attempt gaps GROW) is unexercised: every suite scenario declares backoff_multiplier=1, so exponential backoff (base x multiplier^n,",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-5-3",
      "reasoning": "Validation-run finding against plan text. Fix: one scenario (or an extension of AC-2's) with backoff_multiplier=2 and short base asserting the recorded ETAs/attempt spacing grow geometrically."
    },
    {
      "id": "D-PO-46-5-4",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for V-2: Test-plan Scenario 3 step 5 (the run actually resumes at/promptly after a FUTURE reset time) is uncovered by design: scenario_ac3_future proves the scheduling m",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-5-4",
      "reasoning": "The firing-at-ETA machinery is a single shared code path (next_eta + the now>=INC_ETA gate) proven live by AC-1/AC-2 at backoff ETAs and by AC-3b at an immediate quota ETA; the only untested increment is a wall-clock sleep to a minute-granularity future reset, costing 60s+ of suite runtime for a path composition already covers. Accept with this reasoning; the dogfood UAT run observes the real long-sleep behavior."
    },
    {
      "id": "D-PO-46-5-5",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for V-3: Test-plan Scenario 4 step 3 first clause: scenario_ac3_past never asserts the parsed reset value was RECORDED (only that the resume fired promptly with cause re",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-5-5",
      "reasoning": "Trivial test addition: assert the detected record / state carries the parsed reset epoch in the past-variant too."
    },
    {
      "id": "D-PO-46-5-6",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for V-4: Test-plan Scenario 12 step 2: AC-11's completeness sweep labeled 'sweep(AC-3)' actually re-inspects scenario_ac3_past's fixture (only it sets AC3_ISSUE/keep_san",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-5-6",
      "reasoning": "Validation-run finding: the sweep's population is mislabeled — a plan-text completeness claim quietly narrowed. Fix: keep the future variant's sandbox too and sweep both (or sweep future and relabel)."
    },
    {
      "id": "D-PO-46-5-7",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for V-5: Test-plan Scenario 13: the stall-threshold override test cannot discriminate override from default — it ages the transcript exactly 30 minutes with stall_thre",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-5-7",
      "reasoning": "Validation-run finding: zero discriminating power on the overridden tunable. Trivial: age the transcript ~5 minutes (over the 1-minute override, far under the 30-minute default) so an ignored override produces NO alert and the test fails."
    }
  ],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-5 skill=qa --> ```json { "next_state": "qa", "produced": [ { "kind": "qa-report", "ref": "1845", "summary": "code validate round 2: 21/21 round-1 findings independently resolved; 2 new low findings" }, { "kind": "qa-report", "ref": "1846", "summary": "validation run over the shell lane: 147 ok / 0 FAIL; 5 plan-text coverage gaps (V-1..V-5)" } ], "findings": [ { "category": "in-scope-deferrable", "severity": "low", "summary": "need_value() (added by round 1 for CR-4) guards only a flag at end-of-argv: a flag followed by another flag, e.g. `supervisor-attach.sh --session --issue 46`, silently sets SESSION='--issue' (the charset check permits '-') and misparses instead of erroring.", "reasoning": "Residual of the CR-4 class found by the fresh-context re-validation: no hang, but a silent misparse at the same seam. Trivial: reject a value starting with '--' in need_value (no legitimate value of these flags starts with '--').", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-5-1" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "SKILL.md's classification/behavior text does not document two behaviors round 1 added to the daemon: the pre-resume foreign-write standdown (a non-interrupt user record found at re-classification stands the supervisor down as operator-stop) and the two-consecutive-stable-observations requirement before any resume fires.", "reasoning": "In this suite the skill markdown IS the product; behavior the helpers have but the skill text does not describe is drift a future amendment round would misread. Small text addition to the classification section.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-5-2" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "Test-plan Scenario 1 step 5 (attempt gaps GROW) is unexercised: every suite scenario declares backoff_multiplier=1, so exponential backoff (base x multiplier^n, the documented default shape) is never observed anywhere in the suite.", "reasoning": "Validation-run finding against plan text. Fix: one scenario (or an extension of AC-2's) with backoff_multiplier=2 and short base asserting the recorded ETAs/attempt spacing grow geometrically.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-5-3" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "Test-plan Scenario 3 step 5 (the run actually resumes at/promptly after a FUTURE reset time) is uncovered by design: scenario_ac3_future proves the scheduling math only and never lets the resume fire.", "reasoning": "The firing-at-ETA machinery is a single shared code path (next_eta + the now>=INC_ETA gate) proven live by AC-1/AC-2 at backoff ETAs and by AC-3b at an immediate quota ETA; the only untested increment is a wall-clock sleep to a minute-granularity future reset, costing 60s+ of suite runtime for a path composition already covers. Accept with this reasoning; the dogfood UAT run observes the real long-sleep behavior.", "proposed_action": "accept", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-5-4" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "Test-plan Scenario 4 step 3 first clause: scenario_ac3_past never asserts the parsed reset value was RECORDED (only that the resume fired promptly with cause resumable-quota); AC-3a has the value assertion, the past variant does not.", "reasoning": "Trivial test addition: assert the detected record / state carries the parsed reset epoch in the past-variant too.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-5-5" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "Test-plan Scenario 12 step 2: AC-11's completeness sweep labeled 'sweep(AC-3)' actually re-inspects scenario_ac3_past's fixture (only it sets AC3_ISSUE/keep_sandbox); scenario_ac3_future is never completeness-swept, so the sweep silently covers Scenario 4 twice and Scenario 3 never.", "reasoning": "Validation-run finding: the sweep's population is mislabeled — a plan-text completeness claim quietly narrowed. Fix: keep the future variant's sandbox too and sweep both (or sweep future and relabel).", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-5-6" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "Test-plan Scenario 13: the stall-threshold override test cannot discriminate override from default — it ages the transcript exactly 30 minutes with stall_threshold_minutes=1 declared, but the suite DEFAULT threshold is also 30, so a supervisor ignoring the override would still alert at this boundary.", "reasoning": "Validation-run finding: zero discriminating power on the overridden tunable. Trivial: age the transcript ~5 minutes (over the 1-minute override, far under the 30-minute default) so an ignored override produces NO alert and the test fails.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-5-7" } ], "pending_decisions": [ { "id": "D-PO-46-5-1", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-34: need_value() (added by round 1 for CR-4) guards only a flag at end-of-argv: a flag followed by another flag, e.g. `supervisor-attach.sh --session --issue 46`, s", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-5-1", "reasoning": "Residual of the CR-4 class found by the fresh-context re-validation: no hang, but a silent misparse at the same seam. Trivial: reject a value starting with '--' in need_value (no legitimate value of these flags starts with '--')." }, { "id": "D-PO-46-5-2", "type": "scope-disposition", "blocking": false, "question": "Disposition for CR-35: SKILL.md's classification/behavior text does not document two behaviors round 1 added to the daemon: the pre-resume foreign-write standdown (a non-interrupt use", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-5-2", "reasoning": "In this suite the skill markdown IS the product; behavior the helpers have but the skill text does not describe is drift a future amendment round would misread. Small text addition to the classification section." }, { "id": "D-PO-46-5-3", "type": "scope-disposition", "blocking": false, "question": "Disposition for V-1: Test-plan Scenario 1 step 5 (attempt gaps GROW) is unexercised: every suite scenario declares backoff_multiplier=1, so exponential backoff (base x multiplier^n,", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-5-3", "reasoning": "Validation-run finding against plan text. Fix: one scenario (or an extension of AC-2's) with backoff_multiplier=2 and short base asserting the recorded ETAs/attempt spacing grow geometrically." }, { "id": "D-PO-46-5-4", "type": "scope-disposition", "blocking": false, "question": "Disposition for V-2: Test-plan Scenario 3 step 5 (the run actually resumes at/promptly after a FUTURE reset time) is uncovered by design: scenario_ac3_future proves the scheduling m", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-5-4", "reasoning": "The firing-at-ETA machinery is a single shared code path (next_eta + the now>=INC_ETA gate) proven live by AC-1/AC-2 at backoff ETAs and by AC-3b at an immediate quota ETA; the only untested increment is a wall-clock sleep to a minute-granularity future reset, costing 60s+ of suite runtime for a path composition already covers. Accept with this reasoning; the dogfood UAT run observes the real long-sleep behavior." }, { "id": "D-PO-46-5-5", "type": "scope-disposition", "blocking": false, "question": "Disposition for V-3: Test-plan Scenario 4 step 3 first clause: scenario_ac3_past never asserts the parsed reset value was RECORDED (only that the resume fired promptly with cause re", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-5-5", "reasoning": "Trivial test addition: assert the detected record / state carries the parsed reset epoch in the past-variant too." }, { "id": "D-PO-46-5-6", "type": "scope-disposition", "blocking": false, "question": "Disposition for V-4: Test-plan Scenario 12 step 2: AC-11's completeness sweep labeled 'sweep(AC-3)' actually re-inspects scenario_ac3_past's fixture (only it sets AC3_ISSUE/keep_san", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-5-6", "reasoning": "Validation-run finding: the sweep's population is mislabeled — a plan-text completeness claim quietly narrowed. Fix: keep the future variant's sandbox too and sweep both (or sweep future and relabel)." }, { "id": "D-PO-46-5-7", "type": "scope-disposition", "blocking": false, "question": "Disposition for V-5: Test-plan Scenario 13: the stall-threshold override test cannot discriminate override from default — it ages the transcript exactly 30 minutes with stall_thre", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-5-7", "reasoning": "Validation-run finding: zero discriminating power on the overridden tunable. Trivial: age the transcript ~5 minutes (over the 1-minute override, far under the 30-minute default) so an ignored override produces NO alert and the test fails." } ], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Residual of the CR-4 class found by the fresh-context re-validation: no hang, but a silent misparse at the same seam. Trivial: reject a value starting with '--' in need_value (no legitimate value of these flags starts with '--'). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching."
}
<!-- decision-resolution:v1 ref=D-PO-46-5-1 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Residual of the CR-4 class found by the fresh-context re-validation: no hang, but a silent misparse at the same seam. Trivial: reject a value starting with '--' in need_value (no legitimate value of these flags starts with '--'). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "In this suite the skill markdown IS the product; behavior the helpers have but the skill text does not describe is drift a future amendment round would misread. Small text addition to the classification section. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching."
}
<!-- decision-resolution:v1 ref=D-PO-46-5-2 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "In this suite the skill markdown IS the product; behavior the helpers have but the skill text does not describe is drift a future amendment round would misread. Small text addition to the classification section. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Validation-run finding against plan text. Fix: one scenario (or an extension of AC-2's) with backoff_multiplier=2 and short base asserting the recorded ETAs/attempt spacing grow geometrically. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching."
}
<!-- decision-resolution:v1 ref=D-PO-46-5-3 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Validation-run finding against plan text. Fix: one scenario (or an extension of AC-2's) with backoff_multiplier=2 and short base asserting the recorded ETAs/attempt spacing grow geometrically. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "The firing-at-ETA machinery is a single shared code path (next_eta + the now>=INC_ETA gate) proven live by AC-1/AC-2 at backoff ETAs and by AC-3b at an immediate quota ETA; the only untested increment is a wall-clock sleep to a minute-granularity future reset, costing 60s+ of suite runtime for a path composition already covers. Accept with this reasoning; the dogfood UAT run observes the real long-sleep behavior. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "fix-now: rejected — a 60s+ wall-clock sleep buys coverage of a code path already proven by composition (shared ETA-fire machinery + immediate-quota variant); the dogfood UAT run observes the real behavior."
}
<!-- decision-resolution:v1 ref=D-PO-46-5-4 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "The firing-at-ETA machinery is a single shared code path (next_eta + the now>=INC_ETA gate) proven live by AC-1/AC-2 at backoff ETAs and by AC-3b at an immediate quota ETA; the only untested increment is a wall-clock sleep to a minute-granularity future reset, costing 60s+ of suite runtime for a path composition already covers. Accept with this reasoning; the dogfood UAT run observes the real long-sleep behavior. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "fix-now: rejected — a 60s+ wall-clock sleep buys coverage of a code path already proven by composition (shared ETA-fire machinery + immediate-quota variant); the dogfood UAT run observes the real behavior." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Trivial test addition: assert the detected record / state carries the parsed reset epoch in the past-variant too. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching."
}
<!-- decision-resolution:v1 ref=D-PO-46-5-5 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Trivial test addition: assert the detected record / state carries the parsed reset epoch in the past-variant too. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Validation-run finding: the sweep's population is mislabeled — a plan-text completeness claim quietly narrowed. Fix: keep the future variant's sandbox too and sweep both (or sweep future and relabel). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching."
}
<!-- decision-resolution:v1 ref=D-PO-46-5-6 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Validation-run finding: the sweep's population is mislabeled — a plan-text completeness claim quietly narrowed. Fix: keep the future variant's sandbox too and sweep both (or sweep future and relabel). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Validation-run finding: zero discriminating power on the overridden tunable. Trivial: age the transcript ~5 minutes (over the 1-minute override, far under the 30-minute default) so an ignored override produces NO alert and the test fails. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching."
}
<!-- decision-resolution:v1 ref=D-PO-46-5-7 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Validation-run finding: zero discriminating power on the overridden tunable. Trivial: age the transcript ~5 minutes (over the 1-minute override, far under the 30-minute default) so an ignored override produces NO alert and the test fails. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial/small edits in files this QA round is already touching." } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "Round 2: validation-gap coverage landed (V-1 geometric-backoff scenario; V-3 past-reset record assertion; V-4 AC-11 sweep now inspects both AC-3 variants, correctly labeled; V-5 stall-override test discriminates override from default) plus a red test for CR-34, red-proven with a live misparse reproduction (a daemon engaged under a state dir named --issue). Round-1 CR scenario assertions untouched. Suite rc=0 / 0 FAIL / 1 SKIP-RED (CR-34, pending fix); lint clean. Commit 6282755 (stacked on f1b306c).",
  "findings": [],
  "artifacts": {
    "test_files": [
      "plugin/skills/supervise/test/supervisor-flow.sh"
    ],
    "test_commit": "6282755",
    "test_marker": {
      "runner": "bespoke-shell-harness",
      "write": "first line of scenario fn: echo \"SKIP-RED - <ID> unfixed (promote: delete this line)\"; return 0",
      "promote": "delete that one guard line; never touch the assertions below it"
    }
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=tests --> ```json { "outcome": "clean", "summary": "Round 2: validation-gap coverage landed (V-1 geometric-backoff scenario; V-3 past-reset record assertion; V-4 AC-11 sweep now inspects both AC-3 variants, correctly labeled; V-5 stall-override test discriminates override from default) plus a red test for CR-34, red-proven with a live misparse reproduction (a daemon engaged under a state dir named --issue). Round-1 CR scenario assertions untouched. Suite rc=0 / 0 FAIL / 1 SKIP-RED (CR-34, pending fix); lint clean. Commit 6282755 (stacked on f1b306c).", "findings": [], "artifacts": { "test_files": [ "plugin/skills/supervise/test/supervisor-flow.sh" ], "test_commit": "6282755", "test_marker": { "runner": "bespoke-shell-harness", "write": "first line of scenario fn: echo \"SKIP-RED - <ID> unfixed (promote: delete this line)\"; return 0", "promote": "delete that one guard line; never touch the assertions below it" } } } ```
Author
Owner
{
  "outcome": "issues-found",
  "summary": "Sweep adversarial pass (fable, fresh context, over fix commits d018dd7+c423585) found 1 blocking defect in the round-1 fix itself — a foreign write already present at incident open never gates the resume (S-1, CR-1 class recurrence; round 3 is framed at the class per the convergence rule) — plus 5 fix-now hardening items (S-3 quota re-clamp burn, S-5/S-6/S-7/S-9), 1 defer (S-4 abort-re-aim livelock, folding into #255), 1 accept (S-8 theoretical sig blind spots). Wide gates all green at c423585 (8 shared suites + supervise 159 ok + lint).",
  "findings": [
    {
      "id": "S-1",
      "category": "in-scope-blocking",
      "severity": "high",
      "summary": "A foreign write already on the tail when the incident OPENS never triggers the operator-stop standdown: PRE_SIG is captured WITH the human's record (supervisor-watch.sh:320), the pre-fire guard (RE_SIG == PRE_SIG, class unchanged) passes, the abort branch that alone consults RE_FOREIGN (:361-373) is skipped, and the resume fires into a session a person wrote into. Nothing at loop-top or incident-open reads foreign_writes. SKILL.md:121-125 promises the standdown for exactly this case — the doc is right and the code is not.",
      "reasoning": "Second finding of the CR-1 class after the CR-1 fix — per the convergence rule this round is framed AT THE CLASS: foreign-write evidence gates resumes at EVERY classification of a resumable tail (the loop-top classification and the pre-fire re-classification), standing down as operator-stop whenever a non-tool-result, non-bookkeeping user record exists after the failed turn — regardless of whether the signature moved since scheduling. Verified by the lead against supervisor-watch.sh:311-373. The class framing, not a point patch at one more call site."
    },
    {
      "id": "S-3",
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "The quota 'reset just passed' clamp applies on EVERY reschedule: the post-attempt path re-parses the fresh quota text the failed resume produced, and when it parses as just-passed (clock skew; weekly-limit texts naming a time-of-day days before the real reset), each reschedule clamps to immediate — attempts fire at ~2-poll spacing and burn the whole bound inside a still-closed window.",
      "reasoning": "Bounded and loud, but contradicts both 'backoff-spaced' and 'schedule against the stated clock', and each burned attempt is a real claude -p invocation. Fix: apply the just-passed immediate clamp only at incident OPEN (initial detection); on re-aim and post-attempt reschedules a just-passed parse falls back to backoff spacing.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "core"
    },
    {
      "id": "S-4",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "A perpetually moving tail is a silent unbounded livelock: each ETA re-aims with INC_ATTEMPT unchanged, the retry bound never trips, and after the abort-record bound (3, or 1 when the pair repeats) further abort-re-aim cycles leave no record and no escalation — only supervisor-status.sh shows the incident is still churning.",
      "reasoning": "No writes and no spam, and an actively-moving tail does imply somebody/something is alive — but nothing bounds abort-re-aim cycles per incident, and silence after the record bound means an operator learns of a week-long churn only by running status. Needs a designed bound (does the incident terminate? escalate? at what count?) — same incident-lifecycle family as the #255 robustness edges.",
      "proposed_action": "defer-to-issue",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "core"
    },
    {
      "id": "S-5",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-watch.sh validates --session charset but not --issue, while the same fix round added digit + leading-zero validation to attach and detach — a hand-run daemon passes a hostile --issue straight into sup_event -> post-comment.sh.",
      "reasoning": "Mitigated by 'spawned by attach, never by hand', but the hardening is inconsistent within one round; copying the same check is trivial.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    },
    {
      "id": "S-6",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "A leading-zero numeric tunable (backoff_multiplier: 08) passes _sup_num_or_default's digits-only check, then explodes downstream: bash octal error at the (( < 1 )) guard, jq --argjson rejects 08 so STATE is empty, sup_state_write writes the empty document, the daemon exits at its no-state guard, and attach reports a misleading 'spawned but never reported a heartbeat' exit 5 after a 20s wait. st_num accepts '08' from state.json with the same octal hazard.",
      "reasoning": "The 0[0-9]* refusal added for --issue is missing from the tunable path. Trivial: reject-or-normalize leading zeros in _sup_num_or_default and st_num (warn + default, matching the existing non-numeric handling).",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    },
    {
      "id": "S-7",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "st_str's `getpath(...) // \"\" | tostring` swallows boolean false — clock_parse_capable: false reads back as \"\" not \"false\"; coincidentally correct today (only compared to \"true\") but silently corrupts any legitimately-false value a future reader pulls through it.",
      "reasoning": "Latent idiom bug in a shared accessor; trivial to express as an explicit null check instead of //.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    },
    {
      "id": "S-8",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "tail_sig blind spots: the record count saturates at the tail -n 400 window; a rewrite preserving the last record, a last record lacking both uuid and timestamp on both looks, or a non-JSON appended line is invisible to the guard; mtime is captured but never compared.",
      "reasoning": "Theoretical against an append-only harness store — every named case requires a rewriting writer the harness does not have. Recording it here is the value; hardening the signature belongs with the #255 lifecycle work if the store ever changes semantics.",
      "proposed_action": "accept",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "S-9",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-status.sh prints 'resume attempt $((attempt+1)) of $bound' — an exhausted incident awaiting its escalation poll reads 'attempt 6 of 5', and retry_bound=0 briefly reads 'attempt 1 of 0'.",
      "reasoning": "Operator-facing arithmetic cosmetic; clamp the display at the bound.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    }
  ],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=validate --> ```json { "outcome": "issues-found", "summary": "Sweep adversarial pass (fable, fresh context, over fix commits d018dd7+c423585) found 1 blocking defect in the round-1 fix itself — a foreign write already present at incident open never gates the resume (S-1, CR-1 class recurrence; round 3 is framed at the class per the convergence rule) — plus 5 fix-now hardening items (S-3 quota re-clamp burn, S-5/S-6/S-7/S-9), 1 defer (S-4 abort-re-aim livelock, folding into #255), 1 accept (S-8 theoretical sig blind spots). Wide gates all green at c423585 (8 shared suites + supervise 159 ok + lint).", "findings": [ { "id": "S-1", "category": "in-scope-blocking", "severity": "high", "summary": "A foreign write already on the tail when the incident OPENS never triggers the operator-stop standdown: PRE_SIG is captured WITH the human's record (supervisor-watch.sh:320), the pre-fire guard (RE_SIG == PRE_SIG, class unchanged) passes, the abort branch that alone consults RE_FOREIGN (:361-373) is skipped, and the resume fires into a session a person wrote into. Nothing at loop-top or incident-open reads foreign_writes. SKILL.md:121-125 promises the standdown for exactly this case — the doc is right and the code is not.", "reasoning": "Second finding of the CR-1 class after the CR-1 fix — per the convergence rule this round is framed AT THE CLASS: foreign-write evidence gates resumes at EVERY classification of a resumable tail (the loop-top classification and the pre-fire re-classification), standing down as operator-stop whenever a non-tool-result, non-bookkeeping user record exists after the failed turn — regardless of whether the signature moved since scheduling. Verified by the lead against supervisor-watch.sh:311-373. The class framing, not a point patch at one more call site." }, { "id": "S-3", "category": "in-scope-deferrable", "severity": "medium", "summary": "The quota 'reset just passed' clamp applies on EVERY reschedule: the post-attempt path re-parses the fresh quota text the failed resume produced, and when it parses as just-passed (clock skew; weekly-limit texts naming a time-of-day days before the real reset), each reschedule clamps to immediate — attempts fire at ~2-poll spacing and burn the whole bound inside a still-closed window.", "reasoning": "Bounded and loud, but contradicts both 'backoff-spaced' and 'schedule against the stated clock', and each burned attempt is a real claude -p invocation. Fix: apply the just-passed immediate clamp only at incident OPEN (initial detection); on re-aim and post-attempt reschedules a just-passed parse falls back to backoff spacing.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "core" }, { "id": "S-4", "category": "in-scope-deferrable", "severity": "low", "summary": "A perpetually moving tail is a silent unbounded livelock: each ETA re-aims with INC_ATTEMPT unchanged, the retry bound never trips, and after the abort-record bound (3, or 1 when the pair repeats) further abort-re-aim cycles leave no record and no escalation — only supervisor-status.sh shows the incident is still churning.", "reasoning": "No writes and no spam, and an actively-moving tail does imply somebody/something is alive — but nothing bounds abort-re-aim cycles per incident, and silence after the record bound means an operator learns of a week-long churn only by running status. Needs a designed bound (does the incident terminate? escalate? at what count?) — same incident-lifecycle family as the #255 robustness edges.", "proposed_action": "defer-to-issue", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "core" }, { "id": "S-5", "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-watch.sh validates --session charset but not --issue, while the same fix round added digit + leading-zero validation to attach and detach — a hand-run daemon passes a hostile --issue straight into sup_event -> post-comment.sh.", "reasoning": "Mitigated by 'spawned by attach, never by hand', but the hardening is inconsistent within one round; copying the same check is trivial.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" }, { "id": "S-6", "category": "in-scope-deferrable", "severity": "low", "summary": "A leading-zero numeric tunable (backoff_multiplier: 08) passes _sup_num_or_default's digits-only check, then explodes downstream: bash octal error at the (( < 1 )) guard, jq --argjson rejects 08 so STATE is empty, sup_state_write writes the empty document, the daemon exits at its no-state guard, and attach reports a misleading 'spawned but never reported a heartbeat' exit 5 after a 20s wait. st_num accepts '08' from state.json with the same octal hazard.", "reasoning": "The 0[0-9]* refusal added for --issue is missing from the tunable path. Trivial: reject-or-normalize leading zeros in _sup_num_or_default and st_num (warn + default, matching the existing non-numeric handling).", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" }, { "id": "S-7", "category": "in-scope-deferrable", "severity": "low", "summary": "st_str's `getpath(...) // \"\" | tostring` swallows boolean false — clock_parse_capable: false reads back as \"\" not \"false\"; coincidentally correct today (only compared to \"true\") but silently corrupts any legitimately-false value a future reader pulls through it.", "reasoning": "Latent idiom bug in a shared accessor; trivial to express as an explicit null check instead of //.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" }, { "id": "S-8", "category": "in-scope-deferrable", "severity": "low", "summary": "tail_sig blind spots: the record count saturates at the tail -n 400 window; a rewrite preserving the last record, a last record lacking both uuid and timestamp on both looks, or a non-JSON appended line is invisible to the guard; mtime is captured but never compared.", "reasoning": "Theoretical against an append-only harness store — every named case requires a rewriting writer the harness does not have. Recording it here is the value; hardening the signature belongs with the #255 lifecycle work if the store ever changes semantics.", "proposed_action": "accept", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "S-9", "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-status.sh prints 'resume attempt $((attempt+1)) of $bound' — an exhausted incident awaiting its escalation poll reads 'attempt 6 of 5', and retry_bound=0 briefly reads 'attempt 1 of 0'.", "reasoning": "Operator-facing arithmetic cosmetic; clamp the display at the bound.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" } ], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "next_state": "qa",
  "produced": [
    {
      "kind": "qa-report",
      "ref": "1856",
      "summary": "sweep adversarial pass: 1 blocking (S-1 pre-open foreign write), 5 fix-now, 1 defer, 1 accept; wide gates green at c423585"
    }
  ],
  "findings": [
    {
      "category": "in-scope-blocking",
      "severity": "high",
      "summary": "A foreign write already on the tail when the incident OPENS never triggers the operator-stop standdown: PRE_SIG is captured WITH the human's record (supervisor-watch.sh:320), the pre-fire guard (RE_SIG == PRE_SIG, class unchanged) passes, the abort branch that alone consults RE_FOREIGN (:361-373) is skipped, and the resume fires into a session a person wrote into. Nothing at loop-top or incident-open reads foreign_writes. SKILL.md:121-125 promises the standdown for exactly this case — the doc is right and the code is not.",
      "reasoning": "Second finding of the CR-1 class after the CR-1 fix — per the convergence rule this round is framed AT THE CLASS: foreign-write evidence gates resumes at EVERY classification of a resumable tail (the loop-top classification and the pre-fire re-classification), standing down as operator-stop whenever a non-tool-result, non-bookkeeping user record exists after the failed turn — regardless of whether the signature moved since scheduling. Verified by the lead against supervisor-watch.sh:311-373. The class framing, not a point patch at one more call site.",
      "id": "F-PO-46-6-1"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "medium",
      "summary": "The quota 'reset just passed' clamp applies on EVERY reschedule: the post-attempt path re-parses the fresh quota text the failed resume produced, and when it parses as just-passed (clock skew; weekly-limit texts naming a time-of-day days before the real reset), each reschedule clamps to immediate — attempts fire at ~2-poll spacing and burn the whole bound inside a still-closed window.",
      "reasoning": "Bounded and loud, but contradicts both 'backoff-spaced' and 'schedule against the stated clock', and each burned attempt is a real claude -p invocation. Fix: apply the just-passed immediate clamp only at incident OPEN (initial detection); on re-aim and post-attempt reschedules a just-passed parse falls back to backoff spacing.",
      "proposed_action": "fix-now",
      "fix_cost": "small",
      "adjacent_to_blocking": true,
      "feature_value": "core",
      "id": "F-PO-46-6-2"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "A perpetually moving tail is a silent unbounded livelock: each ETA re-aims with INC_ATTEMPT unchanged, the retry bound never trips, and after the abort-record bound (3, or 1 when the pair repeats) further abort-re-aim cycles leave no record and no escalation — only supervisor-status.sh shows the incident is still churning.",
      "reasoning": "No writes and no spam, and an actively-moving tail does imply somebody/something is alive — but nothing bounds abort-re-aim cycles per incident, and silence after the record bound means an operator learns of a week-long churn only by running status. Needs a designed bound (does the incident terminate? escalate? at what count?) — same incident-lifecycle family as the #255 robustness edges.",
      "proposed_action": "defer-to-issue",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "core",
      "id": "F-PO-46-6-3"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-watch.sh validates --session charset but not --issue, while the same fix round added digit + leading-zero validation to attach and detach — a hand-run daemon passes a hostile --issue straight into sup_event -> post-comment.sh.",
      "reasoning": "Mitigated by 'spawned by attach, never by hand', but the hardening is inconsistent within one round; copying the same check is trivial.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-6-4"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "A leading-zero numeric tunable (backoff_multiplier: 08) passes _sup_num_or_default's digits-only check, then explodes downstream: bash octal error at the (( < 1 )) guard, jq --argjson rejects 08 so STATE is empty, sup_state_write writes the empty document, the daemon exits at its no-state guard, and attach reports a misleading 'spawned but never reported a heartbeat' exit 5 after a 20s wait. st_num accepts '08' from state.json with the same octal hazard.",
      "reasoning": "The 0[0-9]* refusal added for --issue is missing from the tunable path. Trivial: reject-or-normalize leading zeros in _sup_num_or_default and st_num (warn + default, matching the existing non-numeric handling).",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-6-5"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "st_str's `getpath(...) // \"\" | tostring` swallows boolean false — clock_parse_capable: false reads back as \"\" not \"false\"; coincidentally correct today (only compared to \"true\") but silently corrupts any legitimately-false value a future reader pulls through it.",
      "reasoning": "Latent idiom bug in a shared accessor; trivial to express as an explicit null check instead of //.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-6-6"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "tail_sig blind spots: the record count saturates at the tail -n 400 window; a rewrite preserving the last record, a last record lacking both uuid and timestamp on both looks, or a non-JSON appended line is invisible to the guard; mtime is captured but never compared.",
      "reasoning": "Theoretical against an append-only harness store — every named case requires a rewriting writer the harness does not have. Recording it here is the value; hardening the signature belongs with the #255 lifecycle work if the store ever changes semantics.",
      "proposed_action": "accept",
      "fix_cost": "substantial",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-6-7"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-status.sh prints 'resume attempt $((attempt+1)) of $bound' — an exhausted incident awaiting its escalation poll reads 'attempt 6 of 5', and retry_bound=0 briefly reads 'attempt 1 of 0'.",
      "reasoning": "Operator-facing arithmetic cosmetic; clamp the display at the bound.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-6-8"
    }
  ],
  "pending_decisions": [
    {
      "id": "D-PO-46-6-1",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for S-3: The quota 'reset just passed' clamp applies on EVERY reschedule: the post-attempt path re-parses the fresh quota text the failed resume produced, and when it pa",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-6-2",
      "reasoning": "Bounded and loud, but contradicts both 'backoff-spaced' and 'schedule against the stated clock', and each burned attempt is a real claude -p invocation. Fix: apply the just-passed immediate clamp only at incident OPEN (initial detection); on re-aim and post-attempt reschedules a just-passed parse falls back to backoff spacing."
    },
    {
      "id": "D-PO-46-6-2",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for S-4: A perpetually moving tail is a silent unbounded livelock: each ETA re-aims with INC_ATTEMPT unchanged, the retry bound never trips, and after the abort-record b",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "defer-to-issue",
      "finding_ref": "F-PO-46-6-3",
      "reasoning": "No writes and no spam, and an actively-moving tail does imply somebody/something is alive — but nothing bounds abort-re-aim cycles per incident, and silence after the record bound means an operator learns of a week-long churn only by running status. Needs a designed bound (does the incident terminate? escalate? at what count?) — same incident-lifecycle family as the #255 robustness edges."
    },
    {
      "id": "D-PO-46-6-3",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for S-5: supervisor-watch.sh validates --session charset but not --issue, while the same fix round added digit + leading-zero validation to attach and detach — a hand-",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-6-4",
      "reasoning": "Mitigated by 'spawned by attach, never by hand', but the hardening is inconsistent within one round; copying the same check is trivial."
    },
    {
      "id": "D-PO-46-6-4",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for S-6: A leading-zero numeric tunable (backoff_multiplier: 08) passes _sup_num_or_default's digits-only check, then explodes downstream: bash octal error at the (( < 1",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-6-5",
      "reasoning": "The 0[0-9]* refusal added for --issue is missing from the tunable path. Trivial: reject-or-normalize leading zeros in _sup_num_or_default and st_num (warn + default, matching the existing non-numeric handling)."
    },
    {
      "id": "D-PO-46-6-5",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for S-7: st_str's `getpath(...) // \"\" | tostring` swallows boolean false — clock_parse_capable: false reads back as \"\" not \"false\"; coincidentally correct today (only ",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-6-6",
      "reasoning": "Latent idiom bug in a shared accessor; trivial to express as an explicit null check instead of //."
    },
    {
      "id": "D-PO-46-6-6",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for S-8: tail_sig blind spots: the record count saturates at the tail -n 400 window; a rewrite preserving the last record, a last record lacking both uuid and timestamp ",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-6-7",
      "reasoning": "Theoretical against an append-only harness store — every named case requires a rewriting writer the harness does not have. Recording it here is the value; hardening the signature belongs with the #255 lifecycle work if the store ever changes semantics."
    },
    {
      "id": "D-PO-46-6-7",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for S-9: supervisor-status.sh prints 'resume attempt $((attempt+1)) of $bound' — an exhausted incident awaiting its escalation poll reads 'attempt 6 of 5', and retry_b",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-6-8",
      "reasoning": "Operator-facing arithmetic cosmetic; clamp the display at the bound."
    }
  ],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-6 skill=qa --> ```json { "next_state": "qa", "produced": [ { "kind": "qa-report", "ref": "1856", "summary": "sweep adversarial pass: 1 blocking (S-1 pre-open foreign write), 5 fix-now, 1 defer, 1 accept; wide gates green at c423585" } ], "findings": [ { "category": "in-scope-blocking", "severity": "high", "summary": "A foreign write already on the tail when the incident OPENS never triggers the operator-stop standdown: PRE_SIG is captured WITH the human's record (supervisor-watch.sh:320), the pre-fire guard (RE_SIG == PRE_SIG, class unchanged) passes, the abort branch that alone consults RE_FOREIGN (:361-373) is skipped, and the resume fires into a session a person wrote into. Nothing at loop-top or incident-open reads foreign_writes. SKILL.md:121-125 promises the standdown for exactly this case — the doc is right and the code is not.", "reasoning": "Second finding of the CR-1 class after the CR-1 fix — per the convergence rule this round is framed AT THE CLASS: foreign-write evidence gates resumes at EVERY classification of a resumable tail (the loop-top classification and the pre-fire re-classification), standing down as operator-stop whenever a non-tool-result, non-bookkeeping user record exists after the failed turn — regardless of whether the signature moved since scheduling. Verified by the lead against supervisor-watch.sh:311-373. The class framing, not a point patch at one more call site.", "id": "F-PO-46-6-1" }, { "category": "in-scope-deferrable", "severity": "medium", "summary": "The quota 'reset just passed' clamp applies on EVERY reschedule: the post-attempt path re-parses the fresh quota text the failed resume produced, and when it parses as just-passed (clock skew; weekly-limit texts naming a time-of-day days before the real reset), each reschedule clamps to immediate — attempts fire at ~2-poll spacing and burn the whole bound inside a still-closed window.", "reasoning": "Bounded and loud, but contradicts both 'backoff-spaced' and 'schedule against the stated clock', and each burned attempt is a real claude -p invocation. Fix: apply the just-passed immediate clamp only at incident OPEN (initial detection); on re-aim and post-attempt reschedules a just-passed parse falls back to backoff spacing.", "proposed_action": "fix-now", "fix_cost": "small", "adjacent_to_blocking": true, "feature_value": "core", "id": "F-PO-46-6-2" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "A perpetually moving tail is a silent unbounded livelock: each ETA re-aims with INC_ATTEMPT unchanged, the retry bound never trips, and after the abort-record bound (3, or 1 when the pair repeats) further abort-re-aim cycles leave no record and no escalation — only supervisor-status.sh shows the incident is still churning.", "reasoning": "No writes and no spam, and an actively-moving tail does imply somebody/something is alive — but nothing bounds abort-re-aim cycles per incident, and silence after the record bound means an operator learns of a week-long churn only by running status. Needs a designed bound (does the incident terminate? escalate? at what count?) — same incident-lifecycle family as the #255 robustness edges.", "proposed_action": "defer-to-issue", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "core", "id": "F-PO-46-6-3" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-watch.sh validates --session charset but not --issue, while the same fix round added digit + leading-zero validation to attach and detach — a hand-run daemon passes a hostile --issue straight into sup_event -> post-comment.sh.", "reasoning": "Mitigated by 'spawned by attach, never by hand', but the hardening is inconsistent within one round; copying the same check is trivial.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-6-4" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "A leading-zero numeric tunable (backoff_multiplier: 08) passes _sup_num_or_default's digits-only check, then explodes downstream: bash octal error at the (( < 1 )) guard, jq --argjson rejects 08 so STATE is empty, sup_state_write writes the empty document, the daemon exits at its no-state guard, and attach reports a misleading 'spawned but never reported a heartbeat' exit 5 after a 20s wait. st_num accepts '08' from state.json with the same octal hazard.", "reasoning": "The 0[0-9]* refusal added for --issue is missing from the tunable path. Trivial: reject-or-normalize leading zeros in _sup_num_or_default and st_num (warn + default, matching the existing non-numeric handling).", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-6-5" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "st_str's `getpath(...) // \"\" | tostring` swallows boolean false — clock_parse_capable: false reads back as \"\" not \"false\"; coincidentally correct today (only compared to \"true\") but silently corrupts any legitimately-false value a future reader pulls through it.", "reasoning": "Latent idiom bug in a shared accessor; trivial to express as an explicit null check instead of //.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-6-6" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "tail_sig blind spots: the record count saturates at the tail -n 400 window; a rewrite preserving the last record, a last record lacking both uuid and timestamp on both looks, or a non-JSON appended line is invisible to the guard; mtime is captured but never compared.", "reasoning": "Theoretical against an append-only harness store — every named case requires a rewriting writer the harness does not have. Recording it here is the value; hardening the signature belongs with the #255 lifecycle work if the store ever changes semantics.", "proposed_action": "accept", "fix_cost": "substantial", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-6-7" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-status.sh prints 'resume attempt $((attempt+1)) of $bound' — an exhausted incident awaiting its escalation poll reads 'attempt 6 of 5', and retry_bound=0 briefly reads 'attempt 1 of 0'.", "reasoning": "Operator-facing arithmetic cosmetic; clamp the display at the bound.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-6-8" } ], "pending_decisions": [ { "id": "D-PO-46-6-1", "type": "scope-disposition", "blocking": false, "question": "Disposition for S-3: The quota 'reset just passed' clamp applies on EVERY reschedule: the post-attempt path re-parses the fresh quota text the failed resume produced, and when it pa", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-6-2", "reasoning": "Bounded and loud, but contradicts both 'backoff-spaced' and 'schedule against the stated clock', and each burned attempt is a real claude -p invocation. Fix: apply the just-passed immediate clamp only at incident OPEN (initial detection); on re-aim and post-attempt reschedules a just-passed parse falls back to backoff spacing." }, { "id": "D-PO-46-6-2", "type": "scope-disposition", "blocking": false, "question": "Disposition for S-4: A perpetually moving tail is a silent unbounded livelock: each ETA re-aims with INC_ATTEMPT unchanged, the retry bound never trips, and after the abort-record b", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "defer-to-issue", "finding_ref": "F-PO-46-6-3", "reasoning": "No writes and no spam, and an actively-moving tail does imply somebody/something is alive — but nothing bounds abort-re-aim cycles per incident, and silence after the record bound means an operator learns of a week-long churn only by running status. Needs a designed bound (does the incident terminate? escalate? at what count?) — same incident-lifecycle family as the #255 robustness edges." }, { "id": "D-PO-46-6-3", "type": "scope-disposition", "blocking": false, "question": "Disposition for S-5: supervisor-watch.sh validates --session charset but not --issue, while the same fix round added digit + leading-zero validation to attach and detach — a hand-", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-6-4", "reasoning": "Mitigated by 'spawned by attach, never by hand', but the hardening is inconsistent within one round; copying the same check is trivial." }, { "id": "D-PO-46-6-4", "type": "scope-disposition", "blocking": false, "question": "Disposition for S-6: A leading-zero numeric tunable (backoff_multiplier: 08) passes _sup_num_or_default's digits-only check, then explodes downstream: bash octal error at the (( < 1", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-6-5", "reasoning": "The 0[0-9]* refusal added for --issue is missing from the tunable path. Trivial: reject-or-normalize leading zeros in _sup_num_or_default and st_num (warn + default, matching the existing non-numeric handling)." }, { "id": "D-PO-46-6-5", "type": "scope-disposition", "blocking": false, "question": "Disposition for S-7: st_str's `getpath(...) // \"\" | tostring` swallows boolean false — clock_parse_capable: false reads back as \"\" not \"false\"; coincidentally correct today (only ", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-6-6", "reasoning": "Latent idiom bug in a shared accessor; trivial to express as an explicit null check instead of //." }, { "id": "D-PO-46-6-6", "type": "scope-disposition", "blocking": false, "question": "Disposition for S-8: tail_sig blind spots: the record count saturates at the tail -n 400 window; a rewrite preserving the last record, a last record lacking both uuid and timestamp ", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-6-7", "reasoning": "Theoretical against an append-only harness store — every named case requires a rewriting writer the harness does not have. Recording it here is the value; hardening the signature belongs with the #255 lifecycle work if the store ever changes semantics." }, { "id": "D-PO-46-6-7", "type": "scope-disposition", "blocking": false, "question": "Disposition for S-9: supervisor-status.sh prints 'resume attempt $((attempt+1)) of $bound' — an exhausted incident awaiting its escalation poll reads 'attempt 6 of 5', and retry_b", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-6-8", "reasoning": "Operator-facing arithmetic cosmetic; clamp the display at the bound." } ], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Bounded and loud, but contradicts both 'backoff-spaced' and 'schedule against the stated clock', and each burned attempt is a real claude -p invocation. Fix: apply the just-passed immediate clamp only at incident OPEN (initial detection); on re-aim and post-attempt reschedules a just-passed parse falls back to backoff spacing. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — small change adjacent to the S-1 class fix in the same scheduling helper."
}
<!-- decision-resolution:v1 ref=D-PO-46-6-1 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Bounded and loud, but contradicts both 'backoff-spaced' and 'schedule against the stated clock', and each burned attempt is a real claude -p invocation. Fix: apply the just-passed immediate clamp only at incident OPEN (initial detection); on re-aim and post-attempt reschedules a just-passed parse falls back to backoff spacing. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — small change adjacent to the S-1 class fix in the same scheduling helper." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "defer-to-issue",
  "target_issue_ref": "255",
  "rationale": "No writes and no spam, and an actively-moving tail does imply somebody/something is alive — but nothing bounds abort-re-aim cycles per incident, and silence after the record bound means an operator learns of a week-long churn only by running status. Needs a designed bound (does the incident terminate? escalate? at what count?) — same incident-lifecycle family as the #255 robustness edges. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "fix-now: rejected — the bound's semantics (terminate vs escalate, at what count) are a design choice belonging with the #255 incident-lifecycle work, not a point patch."
}
<!-- decision-resolution:v1 ref=D-PO-46-6-2 --> ```json { "status": "resolved", "chosen_option": "defer-to-issue", "target_issue_ref": "255", "rationale": "No writes and no spam, and an actively-moving tail does imply somebody/something is alive — but nothing bounds abort-re-aim cycles per incident, and silence after the record bound means an operator learns of a week-long churn only by running status. Needs a designed bound (does the incident terminate? escalate? at what count?) — same incident-lifecycle family as the #255 robustness edges. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "fix-now: rejected — the bound's semantics (terminate vs escalate, at what count) are a design choice belonging with the #255 incident-lifecycle work, not a point patch." } ```
Author
Owner

Linked: this issue is sibling #255 (recorded by the devwork pipeline).

Linked: this issue is **sibling** #255 (recorded by the devwork pipeline).
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Mitigated by 'spawned by attach, never by hand', but the hardening is inconsistent within one round; copying the same check is trivial. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial copy of an existing check."
}
<!-- decision-resolution:v1 ref=D-PO-46-6-3 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Mitigated by 'spawned by attach, never by hand', but the hardening is inconsistent within one round; copying the same check is trivial. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial copy of an existing check." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "The 0[0-9]* refusal added for --issue is missing from the tunable path. Trivial: reject-or-normalize leading zeros in _sup_num_or_default and st_num (warn + default, matching the existing non-numeric handling). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial extension of the existing numeric validation."
}
<!-- decision-resolution:v1 ref=D-PO-46-6-4 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "The 0[0-9]* refusal added for --issue is missing from the tunable path. Trivial: reject-or-normalize leading zeros in _sup_num_or_default and st_num (warn + default, matching the existing non-numeric handling). — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial extension of the existing numeric validation." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Latent idiom bug in a shared accessor; trivial to express as an explicit null check instead of //. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial accessor fix."
}
<!-- decision-resolution:v1 ref=D-PO-46-6-5 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Latent idiom bug in a shared accessor; trivial to express as an explicit null check instead of //. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial accessor fix." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Theoretical against an append-only harness store — every named case requires a rewriting writer the harness does not have. Recording it here is the value; hardening the signature belongs with the #255 lifecycle work if the store ever changes semantics. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — every named case requires a rewriting writer the append-only harness store does not have; the record of the limitation is the value."
}
<!-- decision-resolution:v1 ref=D-PO-46-6-6 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Theoretical against an append-only harness store — every named case requires a rewriting writer the harness does not have. Recording it here is the value; hardening the signature belongs with the #255 lifecycle work if the store ever changes semantics. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — every named case requires a rewriting writer the append-only harness store does not have; the record of the limitation is the value." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Operator-facing arithmetic cosmetic; clamp the display at the bound. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial display clamp."
}
<!-- decision-resolution:v1 ref=D-PO-46-6-7 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Operator-facing arithmetic cosmetic; clamp the display at the bound. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial display clamp." } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "Round 3: 4 red tests written and ALL proven red in isolation (S-1 pre-open foreign write -> 3 blind resumes, no standdown; S-3 clamp re-fires every reschedule; S-5 watch --issue hang rc=124; S-6 silent wrong multiplier 8 recorded, no branded warning — mechanism corrected for this box jq 1.8.1 lenient --argjson). Also: round-2 V-1 spacing assertion de-flaked (ratio -> absolute margin) after a real jitter flake surfaced in the full-suite run. Suite rc=0 / 0 FAIL / 4 SKIP-RED; lint clean. Commit dde93c7. S-7/S-9 are cosmetic accessor/display fixes with no dedicated red test — verified by re-validate.",
  "findings": [],
  "artifacts": {
    "test_files": [
      "plugin/skills/supervise/test/supervisor-flow.sh",
      "plugin/skills/supervise/test/fixtures/bin/claude"
    ],
    "test_commit": "dde93c7",
    "test_marker": {
      "runner": "bespoke-shell-harness",
      "write": "first line of scenario fn: echo \"SKIP-RED - <ID> unfixed (promote: delete this line)\"; return 0",
      "promote": "delete that one guard line; never touch the assertions below it"
    }
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=tests --> ```json { "outcome": "clean", "summary": "Round 3: 4 red tests written and ALL proven red in isolation (S-1 pre-open foreign write -> 3 blind resumes, no standdown; S-3 clamp re-fires every reschedule; S-5 watch --issue hang rc=124; S-6 silent wrong multiplier 8 recorded, no branded warning — mechanism corrected for this box jq 1.8.1 lenient --argjson). Also: round-2 V-1 spacing assertion de-flaked (ratio -> absolute margin) after a real jitter flake surfaced in the full-suite run. Suite rc=0 / 0 FAIL / 4 SKIP-RED; lint clean. Commit dde93c7. S-7/S-9 are cosmetic accessor/display fixes with no dedicated red test — verified by re-validate.", "findings": [], "artifacts": { "test_files": [ "plugin/skills/supervise/test/supervisor-flow.sh", "plugin/skills/supervise/test/fixtures/bin/claude" ], "test_commit": "dde93c7", "test_marker": { "runner": "bespoke-shell-harness", "write": "first line of scenario fn: echo \"SKIP-RED - <ID> unfixed (promote: delete this line)\"; return 0", "promote": "delete that one guard line; never touch the assertions below it" } } } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "Round 3 fixes landed (commit 8007611): S-1 fixed AT THE CLASS — foreign-write gating now runs at every classification of a resumable tail (loop-top + pre-fire, one shared helper), standing down as operator-stop before any incident/fire; S-3 just-passed clamp restricted to incident open via an explicit may_clamp flag; S-5 watch validates --issue; S-6 leading-zero tunables warn-and-default (state.json path refuses per CR-10 contract — deliberate asymmetry); S-7 st_str preserves false; S-9 status display clamped. All 4 guards promoted; assertion-constraint check: test diff is exactly the 4 guard deletions. Lead-verified gates: suite 174 ok / 0 FAIL / 0 SKIP-RED, lint clean, smoke PASS.",
  "findings": [],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=fix --> ```json { "outcome": "clean", "summary": "Round 3 fixes landed (commit 8007611): S-1 fixed AT THE CLASS — foreign-write gating now runs at every classification of a resumable tail (loop-top + pre-fire, one shared helper), standing down as operator-stop before any incident/fire; S-3 just-passed clamp restricted to incident open via an explicit may_clamp flag; S-5 watch validates --issue; S-6 leading-zero tunables warn-and-default (state.json path refuses per CR-10 contract — deliberate asymmetry); S-7 st_str preserves false; S-9 status display clamped. All 4 guards promoted; assertion-constraint check: test diff is exactly the 4 guard deletions. Lead-verified gates: suite 174 ok / 0 FAIL / 0 SKIP-RED, lint clean, smoke PASS.", "findings": [], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "outcome": "issues-found",
  "summary": "Second sweep adversarial pass over the round-3 fix (commit 8007611): the class fix holds at every gated site, BUT its interaction with the harness resume contract yields 1 blocking production-only defect (T-1: the supervisor own resume prompt is a plain user record — live-probed and confirmed — so an interrupted resume poisons the tail into a permanent false operator-stop on every re-attach; invisible to the suite because the stub omits the prompt record). Plus 2 trivial fix-nows (record-text accuracy T-2, status leading-zero sanitize T-4) and 1 reasoned accept (T-3 notify suppression on operator-stop). Wide gates all green at 8007611.",
  "findings": [
    {
      "id": "T-1",
      "category": "in-scope-blocking",
      "severity": "high",
      "summary": "The supervisor's own resume prompt poisons the transcript against future supervision: a real `claude -p --resume` records its prompt as a plain user record (type:user, isMeta absent — CONFIRMED by live probe 2026-08-25, session 9b8f5b36, marker line included), which is_foreign_write has no exemption for. Any resume interrupted after the prompt-record write but before an assistant record lands (detach group-kill during resume-in-flight; daemon/box crash mid-resume; CLI failing after the append) leaves a tail every later attach classifies as a foreign write -> permanent false operator-stop standdown, exit 0, supervision silently unavailable until a human manually resumes. The suite is green because the stub claude never emulates the prompt user record and the recorded resume contract covered only the result envelope.",
      "reasoning": "Found by the second sweep's adversarial pass (F-1), confirmed by the lead's live probe (probe transcript preserved). Fix: is_foreign_write exempts user records whose text begins with the supervisor's own marker prefix '[run-supervisor resume — incident' (spoofing requires transcript write access — the same person the gate exists to detect, whose standdown is then their choice); the stub gains the real prompt-record emulation; the harness-resume-cli provenance/sample gain the recorded transcript-side shapes from the probe; red tests cover both the marker-record tail (must NOT stand down, resume proceeds) and the plain-user tail (must still stand down)."
    },
    {
      "id": "T-2",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Record-text accuracy: the loop-top foreign-write standdown reuses record_abort's boilerplate claiming 'the transcript moved between scheduling this resume and acting on it (class X -> X, tail U -> U)' when the tail did not move; next_eta's non-clamp branch detail says 'the attempt just made' on a zero-attempt re-aim path.",
      "reasoning": "The forge record is the product's audit trail; a record asserting movement that did not happen misleads the retrospective reader the records exist for. Trivial text conditioning at both sites.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": true,
      "feature_value": "incidental"
    },
    {
      "id": "T-3",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "A foreign-write standdown (cause operator-stop) never fires the declared notify_command (maybe_notify only fires on escalate/alert), so an operator whose presence was inferred from a transcript write gets neither escalation nor notification.",
      "reasoning": "Designed semantic, and correct: an operator-stop standdown means a person is at the session — the forge record carries the event, and notifying the channel about the operator's own presence is noise. The compounding risk (F-1's false standdown never notifying) is removed by T-1's fix, after which every operator-stop standdown reflects a genuine human. Accept.",
      "proposed_action": "accept",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "T-4",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-status.sh's numeric sanitize misses leading zeros: a hand-corrupted state attempt '08' throws a bash octal error to stderr and prints a garbled line.",
      "reasoning": "Read-only surface and hand-edit-only trigger, but the round's own theme is leading-zero hygiene and the sanitize half-applies it; trivial to strip/reject leading zeros in the same case statement.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental"
    }
  ],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=validate --> ```json { "outcome": "issues-found", "summary": "Second sweep adversarial pass over the round-3 fix (commit 8007611): the class fix holds at every gated site, BUT its interaction with the harness resume contract yields 1 blocking production-only defect (T-1: the supervisor own resume prompt is a plain user record — live-probed and confirmed — so an interrupted resume poisons the tail into a permanent false operator-stop on every re-attach; invisible to the suite because the stub omits the prompt record). Plus 2 trivial fix-nows (record-text accuracy T-2, status leading-zero sanitize T-4) and 1 reasoned accept (T-3 notify suppression on operator-stop). Wide gates all green at 8007611.", "findings": [ { "id": "T-1", "category": "in-scope-blocking", "severity": "high", "summary": "The supervisor's own resume prompt poisons the transcript against future supervision: a real `claude -p --resume` records its prompt as a plain user record (type:user, isMeta absent — CONFIRMED by live probe 2026-08-25, session 9b8f5b36, marker line included), which is_foreign_write has no exemption for. Any resume interrupted after the prompt-record write but before an assistant record lands (detach group-kill during resume-in-flight; daemon/box crash mid-resume; CLI failing after the append) leaves a tail every later attach classifies as a foreign write -> permanent false operator-stop standdown, exit 0, supervision silently unavailable until a human manually resumes. The suite is green because the stub claude never emulates the prompt user record and the recorded resume contract covered only the result envelope.", "reasoning": "Found by the second sweep's adversarial pass (F-1), confirmed by the lead's live probe (probe transcript preserved). Fix: is_foreign_write exempts user records whose text begins with the supervisor's own marker prefix '[run-supervisor resume — incident' (spoofing requires transcript write access — the same person the gate exists to detect, whose standdown is then their choice); the stub gains the real prompt-record emulation; the harness-resume-cli provenance/sample gain the recorded transcript-side shapes from the probe; red tests cover both the marker-record tail (must NOT stand down, resume proceeds) and the plain-user tail (must still stand down)." }, { "id": "T-2", "category": "in-scope-deferrable", "severity": "low", "summary": "Record-text accuracy: the loop-top foreign-write standdown reuses record_abort's boilerplate claiming 'the transcript moved between scheduling this resume and acting on it (class X -> X, tail U -> U)' when the tail did not move; next_eta's non-clamp branch detail says 'the attempt just made' on a zero-attempt re-aim path.", "reasoning": "The forge record is the product's audit trail; a record asserting movement that did not happen misleads the retrospective reader the records exist for. Trivial text conditioning at both sites.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": true, "feature_value": "incidental" }, { "id": "T-3", "category": "in-scope-deferrable", "severity": "low", "summary": "A foreign-write standdown (cause operator-stop) never fires the declared notify_command (maybe_notify only fires on escalate/alert), so an operator whose presence was inferred from a transcript write gets neither escalation nor notification.", "reasoning": "Designed semantic, and correct: an operator-stop standdown means a person is at the session — the forge record carries the event, and notifying the channel about the operator's own presence is noise. The compounding risk (F-1's false standdown never notifying) is removed by T-1's fix, after which every operator-stop standdown reflects a genuine human. Accept.", "proposed_action": "accept", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "T-4", "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-status.sh's numeric sanitize misses leading zeros: a hand-corrupted state attempt '08' throws a bash octal error to stderr and prints a garbled line.", "reasoning": "Read-only surface and hand-edit-only trigger, but the round's own theme is leading-zero hygiene and the sanitize half-applies it; trivial to strip/reject leading zeros in the same case statement.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental" } ], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "next_state": "qa",
  "produced": [
    {
      "kind": "qa-report",
      "ref": "1870",
      "summary": "sweep 2: round-3 fix holds; 1 blocking harness-contract interaction (T-1, live-probed), 2 trivial fix-nows, 1 accept"
    }
  ],
  "findings": [
    {
      "category": "in-scope-blocking",
      "severity": "high",
      "summary": "The supervisor's own resume prompt poisons the transcript against future supervision: a real `claude -p --resume` records its prompt as a plain user record (type:user, isMeta absent — CONFIRMED by live probe 2026-08-25, session 9b8f5b36, marker line included), which is_foreign_write has no exemption for. Any resume interrupted after the prompt-record write but before an assistant record lands (detach group-kill during resume-in-flight; daemon/box crash mid-resume; CLI failing after the append) leaves a tail every later attach classifies as a foreign write -> permanent false operator-stop standdown, exit 0, supervision silently unavailable until a human manually resumes. The suite is green because the stub claude never emulates the prompt user record and the recorded resume contract covered only the result envelope.",
      "reasoning": "Found by the second sweep's adversarial pass (F-1), confirmed by the lead's live probe (probe transcript preserved). Fix: is_foreign_write exempts user records whose text begins with the supervisor's own marker prefix '[run-supervisor resume — incident' (spoofing requires transcript write access — the same person the gate exists to detect, whose standdown is then their choice); the stub gains the real prompt-record emulation; the harness-resume-cli provenance/sample gain the recorded transcript-side shapes from the probe; red tests cover both the marker-record tail (must NOT stand down, resume proceeds) and the plain-user tail (must still stand down).",
      "id": "F-PO-46-7-1"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "Record-text accuracy: the loop-top foreign-write standdown reuses record_abort's boilerplate claiming 'the transcript moved between scheduling this resume and acting on it (class X -> X, tail U -> U)' when the tail did not move; next_eta's non-clamp branch detail says 'the attempt just made' on a zero-attempt re-aim path.",
      "reasoning": "The forge record is the product's audit trail; a record asserting movement that did not happen misleads the retrospective reader the records exist for. Trivial text conditioning at both sites.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": true,
      "feature_value": "incidental",
      "id": "F-PO-46-7-2"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "A foreign-write standdown (cause operator-stop) never fires the declared notify_command (maybe_notify only fires on escalate/alert), so an operator whose presence was inferred from a transcript write gets neither escalation nor notification.",
      "reasoning": "Designed semantic, and correct: an operator-stop standdown means a person is at the session — the forge record carries the event, and notifying the channel about the operator's own presence is noise. The compounding risk (F-1's false standdown never notifying) is removed by T-1's fix, after which every operator-stop standdown reflects a genuine human. Accept.",
      "proposed_action": "accept",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-7-3"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "supervisor-status.sh's numeric sanitize misses leading zeros: a hand-corrupted state attempt '08' throws a bash octal error to stderr and prints a garbled line.",
      "reasoning": "Read-only surface and hand-edit-only trigger, but the round's own theme is leading-zero hygiene and the sanitize half-applies it; trivial to strip/reject leading zeros in the same case statement.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "incidental",
      "id": "F-PO-46-7-4"
    }
  ],
  "pending_decisions": [
    {
      "id": "D-PO-46-7-1",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for T-2: Record-text accuracy: the loop-top foreign-write standdown reuses record_abort's boilerplate claiming 'the transcript moved between scheduling this resume and a",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-7-2",
      "reasoning": "The forge record is the product's audit trail; a record asserting movement that did not happen misleads the retrospective reader the records exist for. Trivial text conditioning at both sites."
    },
    {
      "id": "D-PO-46-7-2",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for T-3: A foreign-write standdown (cause operator-stop) never fires the declared notify_command (maybe_notify only fires on escalate/alert), so an operator whose presen",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-7-3",
      "reasoning": "Designed semantic, and correct: an operator-stop standdown means a person is at the session — the forge record carries the event, and notifying the channel about the operator's own presence is noise. The compounding risk (F-1's false standdown never notifying) is removed by T-1's fix, after which every operator-stop standdown reflects a genuine human. Accept."
    },
    {
      "id": "D-PO-46-7-3",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for T-4: supervisor-status.sh's numeric sanitize misses leading zeros: a hand-corrupted state attempt '08' throws a bash octal error to stderr and prints a garbled line.",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-7-4",
      "reasoning": "Read-only surface and hand-edit-only trigger, but the round's own theme is leading-zero hygiene and the sanitize half-applies it; trivial to strip/reject leading zeros in the same case statement."
    }
  ],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-7 skill=qa --> ```json { "next_state": "qa", "produced": [ { "kind": "qa-report", "ref": "1870", "summary": "sweep 2: round-3 fix holds; 1 blocking harness-contract interaction (T-1, live-probed), 2 trivial fix-nows, 1 accept" } ], "findings": [ { "category": "in-scope-blocking", "severity": "high", "summary": "The supervisor's own resume prompt poisons the transcript against future supervision: a real `claude -p --resume` records its prompt as a plain user record (type:user, isMeta absent — CONFIRMED by live probe 2026-08-25, session 9b8f5b36, marker line included), which is_foreign_write has no exemption for. Any resume interrupted after the prompt-record write but before an assistant record lands (detach group-kill during resume-in-flight; daemon/box crash mid-resume; CLI failing after the append) leaves a tail every later attach classifies as a foreign write -> permanent false operator-stop standdown, exit 0, supervision silently unavailable until a human manually resumes. The suite is green because the stub claude never emulates the prompt user record and the recorded resume contract covered only the result envelope.", "reasoning": "Found by the second sweep's adversarial pass (F-1), confirmed by the lead's live probe (probe transcript preserved). Fix: is_foreign_write exempts user records whose text begins with the supervisor's own marker prefix '[run-supervisor resume — incident' (spoofing requires transcript write access — the same person the gate exists to detect, whose standdown is then their choice); the stub gains the real prompt-record emulation; the harness-resume-cli provenance/sample gain the recorded transcript-side shapes from the probe; red tests cover both the marker-record tail (must NOT stand down, resume proceeds) and the plain-user tail (must still stand down).", "id": "F-PO-46-7-1" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "Record-text accuracy: the loop-top foreign-write standdown reuses record_abort's boilerplate claiming 'the transcript moved between scheduling this resume and acting on it (class X -> X, tail U -> U)' when the tail did not move; next_eta's non-clamp branch detail says 'the attempt just made' on a zero-attempt re-aim path.", "reasoning": "The forge record is the product's audit trail; a record asserting movement that did not happen misleads the retrospective reader the records exist for. Trivial text conditioning at both sites.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": true, "feature_value": "incidental", "id": "F-PO-46-7-2" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "A foreign-write standdown (cause operator-stop) never fires the declared notify_command (maybe_notify only fires on escalate/alert), so an operator whose presence was inferred from a transcript write gets neither escalation nor notification.", "reasoning": "Designed semantic, and correct: an operator-stop standdown means a person is at the session — the forge record carries the event, and notifying the channel about the operator's own presence is noise. The compounding risk (F-1's false standdown never notifying) is removed by T-1's fix, after which every operator-stop standdown reflects a genuine human. Accept.", "proposed_action": "accept", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-7-3" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "supervisor-status.sh's numeric sanitize misses leading zeros: a hand-corrupted state attempt '08' throws a bash octal error to stderr and prints a garbled line.", "reasoning": "Read-only surface and hand-edit-only trigger, but the round's own theme is leading-zero hygiene and the sanitize half-applies it; trivial to strip/reject leading zeros in the same case statement.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "incidental", "id": "F-PO-46-7-4" } ], "pending_decisions": [ { "id": "D-PO-46-7-1", "type": "scope-disposition", "blocking": false, "question": "Disposition for T-2: Record-text accuracy: the loop-top foreign-write standdown reuses record_abort's boilerplate claiming 'the transcript moved between scheduling this resume and a", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-7-2", "reasoning": "The forge record is the product's audit trail; a record asserting movement that did not happen misleads the retrospective reader the records exist for. Trivial text conditioning at both sites." }, { "id": "D-PO-46-7-2", "type": "scope-disposition", "blocking": false, "question": "Disposition for T-3: A foreign-write standdown (cause operator-stop) never fires the declared notify_command (maybe_notify only fires on escalate/alert), so an operator whose presen", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-7-3", "reasoning": "Designed semantic, and correct: an operator-stop standdown means a person is at the session — the forge record carries the event, and notifying the channel about the operator's own presence is noise. The compounding risk (F-1's false standdown never notifying) is removed by T-1's fix, after which every operator-stop standdown reflects a genuine human. Accept." }, { "id": "D-PO-46-7-3", "type": "scope-disposition", "blocking": false, "question": "Disposition for T-4: supervisor-status.sh's numeric sanitize misses leading zeros: a hand-corrupted state attempt '08' throws a bash octal error to stderr and prints a garbled line.", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-7-4", "reasoning": "Read-only surface and hand-edit-only trigger, but the round's own theme is leading-zero hygiene and the sanitize half-applies it; trivial to strip/reject leading zeros in the same case statement." } ], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "The forge record is the product's audit trail; a record asserting movement that did not happen misleads the retrospective reader the records exist for. Trivial text conditioning at both sites. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial text conditioning adjacent to the T-1 fix."
}
<!-- decision-resolution:v1 ref=D-PO-46-7-1 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "The forge record is the product's audit trail; a record asserting movement that did not happen misleads the retrospective reader the records exist for. Trivial text conditioning at both sites. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial text conditioning adjacent to the T-1 fix." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Designed semantic, and correct: an operator-stop standdown means a person is at the session — the forge record carries the event, and notifying the channel about the operator's own presence is noise. The compounding risk (F-1's false standdown never notifying) is removed by T-1's fix, after which every operator-stop standdown reflects a genuine human. Accept. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "fix-now: rejected — notifying a channel about the operator's own presence is noise; the forge record carries the event, and T-1 removes the false-positive compound case."
}
<!-- decision-resolution:v1 ref=D-PO-46-7-2 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Designed semantic, and correct: an operator-stop standdown means a person is at the session — the forge record carries the event, and notifying the channel about the operator's own presence is noise. The compounding risk (F-1's false standdown never notifying) is removed by T-1's fix, after which every operator-stop standdown reflects a genuine human. Accept. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "fix-now: rejected — notifying a channel about the operator's own presence is noise; the forge record carries the event, and T-1 removes the false-positive compound case." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Read-only surface and hand-edit-only trigger, but the round's own theme is leading-zero hygiene and the sanitize half-applies it; trivial to strip/reject leading zeros in the same case statement. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — trivial sanitize extension in a file already under edit."
}
<!-- decision-resolution:v1 ref=D-PO-46-7-3 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Read-only surface and hand-edit-only trigger, but the round's own theme is leading-zero hygiene and the sanitize half-applies it; trivial to strip/reject leading zeros in the same case statement. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — trivial sanitize extension in a file already under edit." } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "Round 4: the harness resume contract now records the transcript-side prompt record (bare-string content, isMeta absent — from the live probe, session 9b8f5b36, 2026-08-25); the stub claude emulates it on every --resume (all prior scenarios still green under the more faithful stub); red test T-1a written and proven red (false operator-stop standdown on the supervisor own marker record, no resume fired); T-1b covered by the existing round-3 S-1 scenario, cross-referenced. Suite rc=0 / 0 FAIL / 1 SKIP-RED (T-1a); lint clean. Commit 799fe9f.",
  "findings": [],
  "artifacts": {
    "test_files": [
      "plugin/skills/supervise/test/supervisor-flow.sh",
      "plugin/skills/supervise/test/fixtures/bin/claude",
      "plugin/skills/supervise/test/fixtures/harness-resume-cli.sample.json",
      "plugin/skills/supervise/test/fixtures/harness-resume-cli.provenance.json"
    ],
    "test_commit": "799fe9f",
    "test_marker": {
      "runner": "bespoke-shell-harness",
      "write": "first line of scenario fn: echo \"SKIP-RED - <ID> unfixed (promote: delete this line)\"; return 0",
      "promote": "delete that one guard line; never touch the assertions below it"
    }
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=tests --> ```json { "outcome": "clean", "summary": "Round 4: the harness resume contract now records the transcript-side prompt record (bare-string content, isMeta absent — from the live probe, session 9b8f5b36, 2026-08-25); the stub claude emulates it on every --resume (all prior scenarios still green under the more faithful stub); red test T-1a written and proven red (false operator-stop standdown on the supervisor own marker record, no resume fired); T-1b covered by the existing round-3 S-1 scenario, cross-referenced. Suite rc=0 / 0 FAIL / 1 SKIP-RED (T-1a); lint clean. Commit 799fe9f.", "findings": [], "artifacts": { "test_files": [ "plugin/skills/supervise/test/supervisor-flow.sh", "plugin/skills/supervise/test/fixtures/bin/claude", "plugin/skills/supervise/test/fixtures/harness-resume-cli.sample.json", "plugin/skills/supervise/test/fixtures/harness-resume-cli.provenance.json" ], "test_commit": "799fe9f", "test_marker": { "runner": "bespoke-shell-harness", "write": "first line of scenario fn: echo \"SKIP-RED - <ID> unfixed (promote: delete this line)\"; return 0", "promote": "delete that one guard line; never touch the assertions below it" } } } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "Round 4 fixes landed (commit 3960bf5): T-1 own-resume-marker exemption in is_foreign_write — single shared SUP_RESUME_MARKER constant read by both the prompt builder and the classifier (cannot drift), matched against both recorded content shapes (bare string + typed array), spoofing tradeoff documented, SKILL.md updated; T-2 record texts now state only what actually happened at both sites; T-4 status sanitize covers leading zeros with an honest UNKNOWN on a corrupt bound. T-1a guard promoted; assertion-constraint check: test diff is exactly that one deletion. Lead-verified gates at 3960bf5: suite 178 ok / 0 FAIL / 0 SKIP-RED, lint clean. Deviation recorded: is_interrupt stays array-only (a bare-string interrupt falls through to the foreign gate -> same standdown outcome).",
  "findings": [],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=fix --> ```json { "outcome": "clean", "summary": "Round 4 fixes landed (commit 3960bf5): T-1 own-resume-marker exemption in is_foreign_write — single shared SUP_RESUME_MARKER constant read by both the prompt builder and the classifier (cannot drift), matched against both recorded content shapes (bare string + typed array), spoofing tradeoff documented, SKILL.md updated; T-2 record texts now state only what actually happened at both sites; T-4 status sanitize covers leading zeros with an honest UNKNOWN on a corrupt bound. T-1a guard promoted; assertion-constraint check: test diff is exactly that one deletion. Lead-verified gates at 3960bf5: suite 178 ok / 0 FAIL / 0 SKIP-RED, lint clean. Deviation recorded: is_interrupt stays array-only (a bare-string interrupt falls through to the foreign gate -> same standdown outcome).", "findings": [], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "outcome": "issues-found",
  "summary": "Third sweep adversarial pass over 3960bf5: the T-1 marker exemption holds under attack (anchored matching, byte-identical round trip, interrupt independence, safe stub direction) EXCEPT one regression it introduced — any_text propagates jq empty for a non-object message field, silently dropping unknown-shaped writers from foreign_writes (U-1, fail-open on the schema-drift seam; lead-verified by live jq repro; one-token fix). Plus U-3 (status sanitize incomplete, trivial fix-now) and three reasoned accepts (U-2 documented paste-quote tradeoff, U-4 pre-existing absent-bound default, U-5 cosmetic lede). Wide gates all green at 3960bf5.",
  "findings": [
    {
      "id": "U-1",
      "category": "in-scope-blocking",
      "severity": "medium",
      "summary": "any_text's binding `(.message?.content?) as $c` (_supervisor-lib.sh:255) propagates jq `empty` when a user record's message field is a NON-OBJECT (string/number/array): the whole is_foreign_write chain evaluates to empty and select() silently DROPS the record from foreign_writes — confirmed by live jq reproduction. Pre-T-1 every helper was array-wrapped and total, so such a record counted as foreign; the fix regressed the schema-drift seam from fail-closed to fail-open: a drifted/malformed user record after the failed turn is an invisible writer and a resume can fire into a session someone is driving.",
      "reasoning": "No current harness shape triggers it (message is always an object today), but the SREQ's drift principle for this exact seam is fail-closed (classify on the minimal stable core, escalate on the unparseable — never guess past it). One-token fix: bind `(.message?.content? // null) as $c` (// maps empty to null), keeping every record total through the chain. Found by the third sweep, verified by the lead."
    },
    {
      "id": "U-2",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "The marker exemption is authorship-blind: an operator whose message begins with a pasted copy of the marker at position 0 is exempt from the foreign gate (their record still moves tail_sig -> abort+re-aim, and after two quiet polls the resume fires; any later plain record stands the supervisor down).",
      "reasoning": "Exactly the tradeoff T-1's fix documented in SKILL.md and in the code comment (write access to the transcript is the presence the gate detects); the realistic trigger is an accidental paste-quote, which the next plain record corrects. Optional future hardening (conjoin the recorded promptSource/entrypoint discriminators with the marker test) is noted on the record; not required.",
      "proposed_action": "accept",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "U-3",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "T-4's sanitize is incomplete within supervisor-status.sh itself: inc_eta (:112), hb (:83) and poll (:85) still reach bash arithmetic unsanitized (a hand-corrupted next_eta '08' prints the octal error where the status line belongs), and corrupt .incident.attempt silently coerces to 0 while corrupt bound gets the loud UNKNOWN — asymmetric honesty.",
      "reasoning": "Same class as T-4, same file, trivial: run every state number the script does arithmetic on through the same leading-zero-aware sanitize, and give a corrupt attempt the same honest treatment as a corrupt bound.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": true,
      "feature_value": "incidental"
    },
    {
      "id": "U-4",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "retry_bound ABSENT from state.json defaults to 0 in status (`// 0`), printing 'retry_bound is 0, so the incident escalates' while the daemon's actual default is 5 — reachable only on non-attach-written (older/hand-edited) state.",
      "reasoning": "Pre-existing default untouched by the rounds; attach always writes the field, so the path requires a hand-built state document. The honest-UNKNOWN pattern from T-4 could cover absence too, but absence-vs-corruption semantics on a machine-written file are #255's incident-lifecycle territory; not worth its own round here.",
      "proposed_action": "accept",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    },
    {
      "id": "U-5",
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "record_abort's 'moved' lede when the uuid is unchanged but the signature moved prints \"tail 'X' -> 'X'\", which reads as no movement — truthful but confusing.",
      "reasoning": "Cosmetic record style; the appended detail sentence carries the real cause. Not worth a fix round entry.",
      "proposed_action": "accept",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "none"
    }
  ],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=validate --> ```json { "outcome": "issues-found", "summary": "Third sweep adversarial pass over 3960bf5: the T-1 marker exemption holds under attack (anchored matching, byte-identical round trip, interrupt independence, safe stub direction) EXCEPT one regression it introduced — any_text propagates jq empty for a non-object message field, silently dropping unknown-shaped writers from foreign_writes (U-1, fail-open on the schema-drift seam; lead-verified by live jq repro; one-token fix). Plus U-3 (status sanitize incomplete, trivial fix-now) and three reasoned accepts (U-2 documented paste-quote tradeoff, U-4 pre-existing absent-bound default, U-5 cosmetic lede). Wide gates all green at 3960bf5.", "findings": [ { "id": "U-1", "category": "in-scope-blocking", "severity": "medium", "summary": "any_text's binding `(.message?.content?) as $c` (_supervisor-lib.sh:255) propagates jq `empty` when a user record's message field is a NON-OBJECT (string/number/array): the whole is_foreign_write chain evaluates to empty and select() silently DROPS the record from foreign_writes — confirmed by live jq reproduction. Pre-T-1 every helper was array-wrapped and total, so such a record counted as foreign; the fix regressed the schema-drift seam from fail-closed to fail-open: a drifted/malformed user record after the failed turn is an invisible writer and a resume can fire into a session someone is driving.", "reasoning": "No current harness shape triggers it (message is always an object today), but the SREQ's drift principle for this exact seam is fail-closed (classify on the minimal stable core, escalate on the unparseable — never guess past it). One-token fix: bind `(.message?.content? // null) as $c` (// maps empty to null), keeping every record total through the chain. Found by the third sweep, verified by the lead." }, { "id": "U-2", "category": "in-scope-deferrable", "severity": "low", "summary": "The marker exemption is authorship-blind: an operator whose message begins with a pasted copy of the marker at position 0 is exempt from the foreign gate (their record still moves tail_sig -> abort+re-aim, and after two quiet polls the resume fires; any later plain record stands the supervisor down).", "reasoning": "Exactly the tradeoff T-1's fix documented in SKILL.md and in the code comment (write access to the transcript is the presence the gate detects); the realistic trigger is an accidental paste-quote, which the next plain record corrects. Optional future hardening (conjoin the recorded promptSource/entrypoint discriminators with the marker test) is noted on the record; not required.", "proposed_action": "accept", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "U-3", "category": "in-scope-deferrable", "severity": "low", "summary": "T-4's sanitize is incomplete within supervisor-status.sh itself: inc_eta (:112), hb (:83) and poll (:85) still reach bash arithmetic unsanitized (a hand-corrupted next_eta '08' prints the octal error where the status line belongs), and corrupt .incident.attempt silently coerces to 0 while corrupt bound gets the loud UNKNOWN — asymmetric honesty.", "reasoning": "Same class as T-4, same file, trivial: run every state number the script does arithmetic on through the same leading-zero-aware sanitize, and give a corrupt attempt the same honest treatment as a corrupt bound.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": true, "feature_value": "incidental" }, { "id": "U-4", "category": "in-scope-deferrable", "severity": "low", "summary": "retry_bound ABSENT from state.json defaults to 0 in status (`// 0`), printing 'retry_bound is 0, so the incident escalates' while the daemon's actual default is 5 — reachable only on non-attach-written (older/hand-edited) state.", "reasoning": "Pre-existing default untouched by the rounds; attach always writes the field, so the path requires a hand-built state document. The honest-UNKNOWN pattern from T-4 could cover absence too, but absence-vs-corruption semantics on a machine-written file are #255's incident-lifecycle territory; not worth its own round here.", "proposed_action": "accept", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "none" }, { "id": "U-5", "category": "in-scope-deferrable", "severity": "low", "summary": "record_abort's 'moved' lede when the uuid is unchanged but the signature moved prints \"tail 'X' -> 'X'\", which reads as no movement — truthful but confusing.", "reasoning": "Cosmetic record style; the appended detail sentence carries the real cause. Not worth a fix round entry.", "proposed_action": "accept", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "none" } ], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "next_state": "qa",
  "produced": [
    {
      "kind": "qa-report",
      "ref": "1877",
      "summary": "sweep 3: T-1 fix holds; 1 blocking jq-totality regression (U-1, lead-verified), 1 trivial fix-now, 3 accepts"
    }
  ],
  "findings": [
    {
      "category": "in-scope-blocking",
      "severity": "medium",
      "summary": "any_text's binding `(.message?.content?) as $c` (_supervisor-lib.sh:255) propagates jq `empty` when a user record's message field is a NON-OBJECT (string/number/array): the whole is_foreign_write chain evaluates to empty and select() silently DROPS the record from foreign_writes — confirmed by live jq reproduction. Pre-T-1 every helper was array-wrapped and total, so such a record counted as foreign; the fix regressed the schema-drift seam from fail-closed to fail-open: a drifted/malformed user record after the failed turn is an invisible writer and a resume can fire into a session someone is driving.",
      "reasoning": "No current harness shape triggers it (message is always an object today), but the SREQ's drift principle for this exact seam is fail-closed (classify on the minimal stable core, escalate on the unparseable — never guess past it). One-token fix: bind `(.message?.content? // null) as $c` (// maps empty to null), keeping every record total through the chain. Found by the third sweep, verified by the lead.",
      "id": "F-PO-46-8-1"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "The marker exemption is authorship-blind: an operator whose message begins with a pasted copy of the marker at position 0 is exempt from the foreign gate (their record still moves tail_sig -> abort+re-aim, and after two quiet polls the resume fires; any later plain record stands the supervisor down).",
      "reasoning": "Exactly the tradeoff T-1's fix documented in SKILL.md and in the code comment (write access to the transcript is the presence the gate detects); the realistic trigger is an accidental paste-quote, which the next plain record corrects. Optional future hardening (conjoin the recorded promptSource/entrypoint discriminators with the marker test) is noted on the record; not required.",
      "proposed_action": "accept",
      "fix_cost": "small",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-8-2"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "T-4's sanitize is incomplete within supervisor-status.sh itself: inc_eta (:112), hb (:83) and poll (:85) still reach bash arithmetic unsanitized (a hand-corrupted next_eta '08' prints the octal error where the status line belongs), and corrupt .incident.attempt silently coerces to 0 while corrupt bound gets the loud UNKNOWN — asymmetric honesty.",
      "reasoning": "Same class as T-4, same file, trivial: run every state number the script does arithmetic on through the same leading-zero-aware sanitize, and give a corrupt attempt the same honest treatment as a corrupt bound.",
      "proposed_action": "fix-now",
      "fix_cost": "trivial",
      "adjacent_to_blocking": true,
      "feature_value": "incidental",
      "id": "F-PO-46-8-3"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "retry_bound ABSENT from state.json defaults to 0 in status (`// 0`), printing 'retry_bound is 0, so the incident escalates' while the daemon's actual default is 5 — reachable only on non-attach-written (older/hand-edited) state.",
      "reasoning": "Pre-existing default untouched by the rounds; attach always writes the field, so the path requires a hand-built state document. The honest-UNKNOWN pattern from T-4 could cover absence too, but absence-vs-corruption semantics on a machine-written file are #255's incident-lifecycle territory; not worth its own round here.",
      "proposed_action": "accept",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-8-4"
    },
    {
      "category": "in-scope-deferrable",
      "severity": "low",
      "summary": "record_abort's 'moved' lede when the uuid is unchanged but the signature moved prints \"tail 'X' -> 'X'\", which reads as no movement — truthful but confusing.",
      "reasoning": "Cosmetic record style; the appended detail sentence carries the real cause. Not worth a fix round entry.",
      "proposed_action": "accept",
      "fix_cost": "trivial",
      "adjacent_to_blocking": false,
      "feature_value": "none",
      "id": "F-PO-46-8-5"
    }
  ],
  "pending_decisions": [
    {
      "id": "D-PO-46-8-1",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for U-2: The marker exemption is authorship-blind: an operator whose message begins with a pasted copy of the marker at position 0 is exempt from the foreign gate (their",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-8-2",
      "reasoning": "Exactly the tradeoff T-1's fix documented in SKILL.md and in the code comment (write access to the transcript is the presence the gate detects); the realistic trigger is an accidental paste-quote, which the next plain record corrects. Optional future hardening (conjoin the recorded promptSource/entrypoint discriminators with the marker test) is noted on the record; not required."
    },
    {
      "id": "D-PO-46-8-2",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for U-3: T-4's sanitize is incomplete within supervisor-status.sh itself: inc_eta (:112), hb (:83) and poll (:85) still reach bash arithmetic unsanitized (a hand-corrupt",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "fix-now",
      "finding_ref": "F-PO-46-8-3",
      "reasoning": "Same class as T-4, same file, trivial: run every state number the script does arithmetic on through the same leading-zero-aware sanitize, and give a corrupt attempt the same honest treatment as a corrupt bound."
    },
    {
      "id": "D-PO-46-8-3",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for U-4: retry_bound ABSENT from state.json defaults to 0 in status (`// 0`), printing 'retry_bound is 0, so the incident escalates' while the daemon's actual default is",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-8-4",
      "reasoning": "Pre-existing default untouched by the rounds; attach always writes the field, so the path requires a hand-built state document. The honest-UNKNOWN pattern from T-4 could cover absence too, but absence-vs-corruption semantics on a machine-written file are #255's incident-lifecycle territory; not worth its own round here."
    },
    {
      "id": "D-PO-46-8-4",
      "type": "scope-disposition",
      "blocking": false,
      "question": "Disposition for U-5: record_abort's 'moved' lede when the uuid is unchanged but the signature moved prints \"tail 'X' -> 'X'\", which reads as no movement — truthful but confusing.",
      "options": [
        "fix-now",
        "defer-to-issue",
        "accept"
      ],
      "recommended": "accept",
      "finding_ref": "F-PO-46-8-5",
      "reasoning": "Cosmetic record style; the appended detail sentence carries the real cause. Not worth a fix round entry."
    }
  ],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-8 skill=qa --> ```json { "next_state": "qa", "produced": [ { "kind": "qa-report", "ref": "1877", "summary": "sweep 3: T-1 fix holds; 1 blocking jq-totality regression (U-1, lead-verified), 1 trivial fix-now, 3 accepts" } ], "findings": [ { "category": "in-scope-blocking", "severity": "medium", "summary": "any_text's binding `(.message?.content?) as $c` (_supervisor-lib.sh:255) propagates jq `empty` when a user record's message field is a NON-OBJECT (string/number/array): the whole is_foreign_write chain evaluates to empty and select() silently DROPS the record from foreign_writes — confirmed by live jq reproduction. Pre-T-1 every helper was array-wrapped and total, so such a record counted as foreign; the fix regressed the schema-drift seam from fail-closed to fail-open: a drifted/malformed user record after the failed turn is an invisible writer and a resume can fire into a session someone is driving.", "reasoning": "No current harness shape triggers it (message is always an object today), but the SREQ's drift principle for this exact seam is fail-closed (classify on the minimal stable core, escalate on the unparseable — never guess past it). One-token fix: bind `(.message?.content? // null) as $c` (// maps empty to null), keeping every record total through the chain. Found by the third sweep, verified by the lead.", "id": "F-PO-46-8-1" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "The marker exemption is authorship-blind: an operator whose message begins with a pasted copy of the marker at position 0 is exempt from the foreign gate (their record still moves tail_sig -> abort+re-aim, and after two quiet polls the resume fires; any later plain record stands the supervisor down).", "reasoning": "Exactly the tradeoff T-1's fix documented in SKILL.md and in the code comment (write access to the transcript is the presence the gate detects); the realistic trigger is an accidental paste-quote, which the next plain record corrects. Optional future hardening (conjoin the recorded promptSource/entrypoint discriminators with the marker test) is noted on the record; not required.", "proposed_action": "accept", "fix_cost": "small", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-8-2" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "T-4's sanitize is incomplete within supervisor-status.sh itself: inc_eta (:112), hb (:83) and poll (:85) still reach bash arithmetic unsanitized (a hand-corrupted next_eta '08' prints the octal error where the status line belongs), and corrupt .incident.attempt silently coerces to 0 while corrupt bound gets the loud UNKNOWN — asymmetric honesty.", "reasoning": "Same class as T-4, same file, trivial: run every state number the script does arithmetic on through the same leading-zero-aware sanitize, and give a corrupt attempt the same honest treatment as a corrupt bound.", "proposed_action": "fix-now", "fix_cost": "trivial", "adjacent_to_blocking": true, "feature_value": "incidental", "id": "F-PO-46-8-3" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "retry_bound ABSENT from state.json defaults to 0 in status (`// 0`), printing 'retry_bound is 0, so the incident escalates' while the daemon's actual default is 5 — reachable only on non-attach-written (older/hand-edited) state.", "reasoning": "Pre-existing default untouched by the rounds; attach always writes the field, so the path requires a hand-built state document. The honest-UNKNOWN pattern from T-4 could cover absence too, but absence-vs-corruption semantics on a machine-written file are #255's incident-lifecycle territory; not worth its own round here.", "proposed_action": "accept", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-8-4" }, { "category": "in-scope-deferrable", "severity": "low", "summary": "record_abort's 'moved' lede when the uuid is unchanged but the signature moved prints \"tail 'X' -> 'X'\", which reads as no movement — truthful but confusing.", "reasoning": "Cosmetic record style; the appended detail sentence carries the real cause. Not worth a fix round entry.", "proposed_action": "accept", "fix_cost": "trivial", "adjacent_to_blocking": false, "feature_value": "none", "id": "F-PO-46-8-5" } ], "pending_decisions": [ { "id": "D-PO-46-8-1", "type": "scope-disposition", "blocking": false, "question": "Disposition for U-2: The marker exemption is authorship-blind: an operator whose message begins with a pasted copy of the marker at position 0 is exempt from the foreign gate (their", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-8-2", "reasoning": "Exactly the tradeoff T-1's fix documented in SKILL.md and in the code comment (write access to the transcript is the presence the gate detects); the realistic trigger is an accidental paste-quote, which the next plain record corrects. Optional future hardening (conjoin the recorded promptSource/entrypoint discriminators with the marker test) is noted on the record; not required." }, { "id": "D-PO-46-8-2", "type": "scope-disposition", "blocking": false, "question": "Disposition for U-3: T-4's sanitize is incomplete within supervisor-status.sh itself: inc_eta (:112), hb (:83) and poll (:85) still reach bash arithmetic unsanitized (a hand-corrupt", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "fix-now", "finding_ref": "F-PO-46-8-3", "reasoning": "Same class as T-4, same file, trivial: run every state number the script does arithmetic on through the same leading-zero-aware sanitize, and give a corrupt attempt the same honest treatment as a corrupt bound." }, { "id": "D-PO-46-8-3", "type": "scope-disposition", "blocking": false, "question": "Disposition for U-4: retry_bound ABSENT from state.json defaults to 0 in status (`// 0`), printing 'retry_bound is 0, so the incident escalates' while the daemon's actual default is", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-8-4", "reasoning": "Pre-existing default untouched by the rounds; attach always writes the field, so the path requires a hand-built state document. The honest-UNKNOWN pattern from T-4 could cover absence too, but absence-vs-corruption semantics on a machine-written file are #255's incident-lifecycle territory; not worth its own round here." }, { "id": "D-PO-46-8-4", "type": "scope-disposition", "blocking": false, "question": "Disposition for U-5: record_abort's 'moved' lede when the uuid is unchanged but the signature moved prints \"tail 'X' -> 'X'\", which reads as no movement — truthful but confusing.", "options": [ "fix-now", "defer-to-issue", "accept" ], "recommended": "accept", "finding_ref": "F-PO-46-8-5", "reasoning": "Cosmetic record style; the appended detail sentence carries the real cause. Not worth a fix round entry." } ], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Exactly the tradeoff T-1's fix documented in SKILL.md and in the code comment (write access to the transcript is the presence the gate detects); the realistic trigger is an accidental paste-quote, which the next plain record corrects. Optional future hardening (conjoin the recorded promptSource/entrypoint discriminators with the marker test) is noted on the record; not required. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "fix-now: rejected — the tradeoff is deliberate, documented in SKILL.md and the code comment; the promptSource hardening idea is recorded here for a future amendment if paste-quotes ever bite in practice."
}
<!-- decision-resolution:v1 ref=D-PO-46-8-1 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Exactly the tradeoff T-1's fix documented in SKILL.md and in the code comment (write access to the transcript is the presence the gate detects); the realistic trigger is an accidental paste-quote, which the next plain record corrects. Optional future hardening (conjoin the recorded promptSource/entrypoint discriminators with the marker test) is noted on the record; not required. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "fix-now: rejected — the tradeoff is deliberate, documented in SKILL.md and the code comment; the promptSource hardening idea is recorded here for a future amendment if paste-quotes ever bite in practice." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "fix-now",
  "rationale": "Same class as T-4, same file, trivial: run every state number the script does arithmetic on through the same leading-zero-aware sanitize, and give a corrupt attempt the same honest treatment as a corrupt bound. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "defer-to-issue: rejected — same class as T-4, same file, trivial."
}
<!-- decision-resolution:v1 ref=D-PO-46-8-2 --> ```json { "status": "resolved", "chosen_option": "fix-now", "rationale": "Same class as T-4, same file, trivial: run every state number the script does arithmetic on through the same leading-zero-aware sanitize, and give a corrupt attempt the same honest treatment as a corrupt bound. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "defer-to-issue: rejected — same class as T-4, same file, trivial." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Pre-existing default untouched by the rounds; attach always writes the field, so the path requires a hand-built state document. The honest-UNKNOWN pattern from T-4 could cover absence too, but absence-vs-corruption semantics on a machine-written file are #255's incident-lifecycle territory; not worth its own round here. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "fix-now: rejected — reachable only on hand-built state; absence-vs-corruption semantics for machine-written state belong with #255's incident-lifecycle design."
}
<!-- decision-resolution:v1 ref=D-PO-46-8-3 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Pre-existing default untouched by the rounds; attach always writes the field, so the path requires a hand-built state document. The honest-UNKNOWN pattern from T-4 could cover absence too, but absence-vs-corruption semantics on a machine-written file are #255's incident-lifecycle territory; not worth its own round here. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "fix-now: rejected — reachable only on hand-built state; absence-vs-corruption semantics for machine-written state belong with #255's incident-lifecycle design." } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "accept",
  "rationale": "Cosmetic record style; the appended detail sentence carries the real cause. Not worth a fix round entry. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.",
  "rejected_alternative": "fix-now: rejected — truthful record text; the detail sentence carries the cause."
}
<!-- decision-resolution:v1 ref=D-PO-46-8-4 --> ```json { "status": "resolved", "chosen_option": "accept", "rationale": "Cosmetic record style; the appended detail sentence carries the real cause. Not worth a fix round entry. — Resolved autonomously by the QA round driver under the operator's 'run QA for #46' delegation; choice matches the canonical recommender over the finding's recorded axes.", "rejected_alternative": "fix-now: rejected — truthful record text; the detail sentence carries the cause." } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "Round 5: red test U-1 written and proven red (drifted-shape user record — message as bare string — silently dropped from foreign_writes; resume fired 3x with no standdown). The seeded record is explicitly commented as an authored drift shape testing the fail-closed contract, deliberately not provenance-backed. Writer also hand-verified the `// null` binding restores jq totality. Suite rc=0 / 0 FAIL / 1 SKIP-RED (U-1); lint clean. Commit ddfbfc8. U-3 (status sanitize completion) is desk-checkable, no dedicated red test.",
  "findings": [],
  "artifacts": {
    "test_files": [
      "plugin/skills/supervise/test/supervisor-flow.sh"
    ],
    "test_commit": "ddfbfc8",
    "test_marker": {
      "runner": "bespoke-shell-harness",
      "write": "first line of scenario fn: echo \"SKIP-RED - <ID> unfixed (promote: delete this line)\"; return 0",
      "promote": "delete that one guard line; never touch the assertions below it"
    }
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=tests --> ```json { "outcome": "clean", "summary": "Round 5: red test U-1 written and proven red (drifted-shape user record — message as bare string — silently dropped from foreign_writes; resume fired 3x with no standdown). The seeded record is explicitly commented as an authored drift shape testing the fail-closed contract, deliberately not provenance-backed. Writer also hand-verified the `// null` binding restores jq totality. Suite rc=0 / 0 FAIL / 1 SKIP-RED (U-1); lint clean. Commit ddfbfc8. U-3 (status sanitize completion) is desk-checkable, no dedicated red test.", "findings": [], "artifacts": { "test_files": [ "plugin/skills/supervise/test/supervisor-flow.sh" ], "test_commit": "ddfbfc8", "test_marker": { "runner": "bespoke-shell-harness", "write": "first line of scenario fn: echo \"SKIP-RED - <ID> unfixed (promote: delete this line)\"; return 0", "promote": "delete that one guard line; never touch the assertions below it" } } } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "Round 5 fixes landed (commit 8de068e): U-1 total jq binding (.message?.content? // null) with a load-bearing comment, desk-checked on eight tails (three drift shapes now foreign, marker exemption and real-person cases unchanged); U-3 every status.sh arithmetic input sanitized in one place with honest per-field corruption reporting. Fixer audited ALL 14 as-bindings in the helper tier against the empty-propagation idiom — only the one bug; audit recorded in the fix report. U-1 guard promoted; assertion-constraint check: test diff exactly one deletion. Lead-verified gates at 8de068e: suite 181 ok / 0 FAIL / 0 SKIP-RED, lint clean. One process incident recorded: a quoting slip during the fix was caught by the fixer own probe-by-doing and reverted before commit (stray a.out cleaned).",
  "findings": [],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=fix --> ```json { "outcome": "clean", "summary": "Round 5 fixes landed (commit 8de068e): U-1 total jq binding (.message?.content? // null) with a load-bearing comment, desk-checked on eight tails (three drift shapes now foreign, marker exemption and real-person cases unchanged); U-3 every status.sh arithmetic input sanitized in one place with honest per-field corruption reporting. Fixer audited ALL 14 as-bindings in the helper tier against the empty-propagation idiom — only the one bug; audit recorded in the fix report. U-1 guard promoted; assertion-constraint check: test diff exactly one deletion. Lead-verified gates at 8de068e: suite 181 ok / 0 FAIL / 0 SKIP-RED, lint clean. One process incident recorded: a quoting slip during the fix was caught by the fixer own probe-by-doing and reverted before commit (stray a.out cleaned).", "findings": [], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "FINAL (sweep exit, HEAD 8de068e): five QA rounds complete. 33 round-1 findings + 7 round-2 + 8 round-3 + 4 round-4 + 5 round-5 all dispositioned; every blocking and fix-now finding fixed with a promoted red regression test (44 new suite checks; suite 181 ok / 0 FAIL / 0 SKIP-RED). Fourth adversarial sweep (fable, fresh context, probe-executed): NO ISSUES FOUND. Deferred: issue #255 (4 robustness edges). Accepted residuals: 13, each with recorded reasoning. All wide gates green at this HEAD (8 shared suites + supervise + lint + smoke).",
  "findings": [],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=code phase=validate --> ```json { "outcome": "clean", "summary": "FINAL (sweep exit, HEAD 8de068e): five QA rounds complete. 33 round-1 findings + 7 round-2 + 8 round-3 + 4 round-4 + 5 round-5 all dispositioned; every blocking and fix-now finding fixed with a promoted red regression test (44 new suite checks; suite 181 ok / 0 FAIL / 0 SKIP-RED). Fourth adversarial sweep (fable, fresh context, probe-executed): NO ISSUES FOUND. Deferred: issue #255 (4 robustness edges). Accepted residuals: 13, each with recorded reasoning. All wide gates green at this HEAD (8 shared suites + supervise + lint + smoke).", "findings": [], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "outcome": "clean",
  "summary": "FINAL validation-run verdict (the e2e slot carries the PREQ-derived validation run; no browser exists): all 13 test-plan scenarios PASS on the final tree — the five plan-text gaps found in round 2 were closed in commit 6282755 (V-1 geometric backoff scenario, V-3 past-reset record assertion, V-4 AC-11 sweep covers both AC-3 variants, V-5 discriminating stall-override) except V-2 (future-reset live fire), accepted on composition reasoning with the dogfood UAT run named as its observer. Records verified legible by a real read. Suite at final HEAD: 181 ok / 0 FAIL.",
  "findings": [],
  "artifacts": {
    "report_path": ".devwork/feature-46-run-supervisor/code-report.md"
  }
}
<!-- qa-report:v1 issue=46 skill=qa domain=e2e phase=validate --> ```json { "outcome": "clean", "summary": "FINAL validation-run verdict (the e2e slot carries the PREQ-derived validation run; no browser exists): all 13 test-plan scenarios PASS on the final tree — the five plan-text gaps found in round 2 were closed in commit 6282755 (V-1 geometric backoff scenario, V-3 past-reset record assertion, V-4 AC-11 sweep covers both AC-3 variants, V-5 discriminating stall-override) except V-2 (future-reset live fire), accepted on composition reasoning with the dogfood UAT run named as its observer. Records verified legible by a real read. Suite at final HEAD: 181 ok / 0 FAIL.", "findings": [], "artifacts": { "report_path": ".devwork/feature-46-run-supervisor/code-report.md" } } ```
Author
Owner
{
  "next_state": "integrating",
  "produced": [
    {
      "kind": "qa-report",
      "ref": "1885",
      "summary": "code domain FINAL validate: clean at sweep HEAD 8de068e; 4th adversarial sweep (probe-executed, fable, fresh context) found no issues; coverage gate green — all six domains carry a validate report"
    },
    {
      "kind": "qa-report",
      "ref": "1886",
      "summary": "validation run FINAL: 13/13 test-plan scenarios pass on the final tree; round-2 plan-text gaps closed in 6282755; V-2 accepted on composition with the dogfood UAT walk named as its observer"
    },
    {
      "kind": "uat-prerequisites",
      "ref": "local:.devwork/feature-46-run-supervisor/test-prerequisites.md",
      "summary": "UAT card verified against the final tree (local mode, no auth, no setup): dogfood-focus notes (real quota sleep; -p one-turn park), 13 accepted residuals and the 4 deferrals to #255 listed so the walk does not re-derive them"
    },
    {
      "kind": "qa-loop-summary",
      "ref": "comment:1766",
      "summary": "5 rounds, 57 findings: 5 blocking (CR-1, CR-2, S-1, T-1, U-1 — each fixed with a promoted, red-proven regression test; suite grew 98 -> 181 checks), 31 fix-now landed, 4 deferred to sibling #255, 13 accepted with recorded reasoning. Three blocking defects were found by successive sweeps attacking the previous round own fix, each strictly narrower, converging to sweep 4: no issues. Durable side-artifact: the live-probed harness resume contract (the -p prompt is a plain user record) now recorded in the fixtures provenance."
    }
  ],
  "findings": [],
  "pending_decisions": [],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-9 skill=qa --> ```json { "next_state": "integrating", "produced": [ { "kind": "qa-report", "ref": "1885", "summary": "code domain FINAL validate: clean at sweep HEAD 8de068e; 4th adversarial sweep (probe-executed, fable, fresh context) found no issues; coverage gate green — all six domains carry a validate report" }, { "kind": "qa-report", "ref": "1886", "summary": "validation run FINAL: 13/13 test-plan scenarios pass on the final tree; round-2 plan-text gaps closed in 6282755; V-2 accepted on composition with the dogfood UAT walk named as its observer" }, { "kind": "uat-prerequisites", "ref": "local:.devwork/feature-46-run-supervisor/test-prerequisites.md", "summary": "UAT card verified against the final tree (local mode, no auth, no setup): dogfood-focus notes (real quota sleep; -p one-turn park), 13 accepted residuals and the 4 deferrals to #255 listed so the walk does not re-derive them" }, { "kind": "qa-loop-summary", "ref": "comment:1766", "summary": "5 rounds, 57 findings: 5 blocking (CR-1, CR-2, S-1, T-1, U-1 — each fixed with a promoted, red-proven regression test; suite grew 98 -> 181 checks), 31 fix-now landed, 4 deferred to sibling #255, 13 accepted with recorded reasoning. Three blocking defects were found by successive sweeps attacking the previous round own fix, each strictly narrower, converging to sweep 4: no issues. Durable side-artifact: the live-probed harness resume contract (the -p prompt is a plain user record) now recorded in the fixtures provenance." } ], "findings": [], "pending_decisions": [], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner
{
  "integration_branch": "main",
  "feature_branch": "feature/46-run-supervisor",
  "repos": [
    {
      "repo": ".",
      "base_sha": "12c444a052350f4bcfb71ef42fa367f98abd6bd9",
      "tip_sha": "8de068ebafabe5e9693b6cd0c7c87929d3b852dd",
      "commit_count": 18,
      "commits": [
        {
          "sha": "8de068ebafabe5e9693b6cd0c7c87929d3b852dd",
          "subject": "fix(run-supervisor): [QA-46 round 5] U-1 total jq bindings in the classify seam; U-3 status sanitize completed"
        },
        {
          "sha": "ddfbfc84e68e747be3394ce14e8a1735930b71de",
          "subject": "test(run-supervisor): [QA-46 round 5] red test U-1 — drifted-shape user record must stay foreign (fail-closed)"
        },
        {
          "sha": "3960bf54dd7d0d78bda7e6ff7da5f71b46cc0142",
          "subject": "fix(run-supervisor): [QA-46 round 4] T-1 own-resume-marker exemption in the foreign gate; T-2 record accuracy; T-4 status sanitize"
        },
        {
          "sha": "799fe9f692e89283d79a70169f2195f3eabddc6a",
          "subject": "test(run-supervisor): [QA-46 round 4] resume-prompt record contract + red test T-1 marker exemption"
        },
        {
          "sha": "8007611e35d9f4cf29bc3b63b97fc5b927138406",
          "subject": "fix(run-supervisor): [QA-46 round 3] S-1 foreign-write gating at every classification; S-3 open-only reset clamp; S-5,S-6,S-7,S-9 hardening"
        },
        {
          "sha": "dde93c7761138b1f56ac54f310b05a9696b40aad",
          "subject": "test(run-supervisor): [QA-46 round 3] red tests S-1,S-3,S-5,S-6 — pre-open foreign write, re-clamp spacing, watch arg validation, leading-zero tunable"
        },
        {
          "sha": "c4235854590904fbae20df09d789d812a908f005",
          "subject": "fix(run-supervisor): [QA-46 round 2] CR-34 flag-as-value rejected in all entry scripts; CR-35 SKILL.md documents standdown + stability gate"
        },
        {
          "sha": "62827555e5d346be279b965946e16ca57e80d3ad",
          "subject": "test(run-supervisor): [QA-46 round 2] validation-gap coverage V-1,V-3,V-4,V-5 + red test CR-34"
        },
        {
          "sha": "f1b306cd4b249513a6bc2d7148545192e45f217d",
          "subject": "test(run-supervisor): [QA-46 round 2] re-arm CR-8 scenario on event-based wait"
        },
        {
          "sha": "d018dd7da131fa895934858edff5ed35ce295f20",
          "subject": "fix(run-supervisor): [QA-46 round 1] CR-1..CR-20,CR-23 — resume guard, arg validation, dedup, scheduling, test integrity"
        },
        {
          "sha": "1512dc8a9457f1c30b76e8407e26bc3dfb6b4958",
          "subject": "test(run-supervisor): [QA-46 round 1] red regression tests CR-1,3,4,5,7,8,9,10,12,13,14,23"
        },
        {
          "sha": "038c149ce949df22a112f5467b0afff309ee83c6",
          "subject": "docs: capture learning — new shipped skill requires SHIPPED_SKILLS widening"
        },
        {
          "sha": "61e33d7209917301a3e697036b2a8f58bd987553",
          "subject": "test(run-supervisor): fix AC-9a race — seed non-resumable tail before revoking transcript readability"
        },
        {
          "sha": "44f6a1e857c113b1edf07d3105c115399ac3f055",
          "subject": "run-template+wait-discipline: [WU-46-3-2] wire the run supervisor into the suite surfaces"
        },
        {
          "sha": "afca037b61490e609d32a85c7da8bd9397834f20",
          "subject": "feat(run-supervisor): [WU-46-3-1] supervise skill: helpers, SKILL.md"
        },
        {
          "sha": "9fd98e95f511fc7edebdfeb634cf9b201f09c709",
          "subject": "test(run-supervisor): [WU-46-3-1] failing integration suite for supervise helpers"
        },
        {
          "sha": "d5b2194e50daa69e3a614eaba9ae502b03048949",
          "subject": "docs(run-supervisor): test plan"
        },
        {
          "sha": "ca9e2a77db4f266e610c937626684dc8fe62e572",
          "subject": "docs(run-supervisor): software requirements"
        }
      ],
      "compare_url": null,
      "pushed": true,
      "remote_url": "ssh://git@forge-devwork/jbr870/devwork-skills.git"
    }
  ]
}
<!-- code-bundle:v1 issue=46 skill=integrate --> ```json { "integration_branch": "main", "feature_branch": "feature/46-run-supervisor", "repos": [ { "repo": ".", "base_sha": "12c444a052350f4bcfb71ef42fa367f98abd6bd9", "tip_sha": "8de068ebafabe5e9693b6cd0c7c87929d3b852dd", "commit_count": 18, "commits": [ { "sha": "8de068ebafabe5e9693b6cd0c7c87929d3b852dd", "subject": "fix(run-supervisor): [QA-46 round 5] U-1 total jq bindings in the classify seam; U-3 status sanitize completed" }, { "sha": "ddfbfc84e68e747be3394ce14e8a1735930b71de", "subject": "test(run-supervisor): [QA-46 round 5] red test U-1 — drifted-shape user record must stay foreign (fail-closed)" }, { "sha": "3960bf54dd7d0d78bda7e6ff7da5f71b46cc0142", "subject": "fix(run-supervisor): [QA-46 round 4] T-1 own-resume-marker exemption in the foreign gate; T-2 record accuracy; T-4 status sanitize" }, { "sha": "799fe9f692e89283d79a70169f2195f3eabddc6a", "subject": "test(run-supervisor): [QA-46 round 4] resume-prompt record contract + red test T-1 marker exemption" }, { "sha": "8007611e35d9f4cf29bc3b63b97fc5b927138406", "subject": "fix(run-supervisor): [QA-46 round 3] S-1 foreign-write gating at every classification; S-3 open-only reset clamp; S-5,S-6,S-7,S-9 hardening" }, { "sha": "dde93c7761138b1f56ac54f310b05a9696b40aad", "subject": "test(run-supervisor): [QA-46 round 3] red tests S-1,S-3,S-5,S-6 — pre-open foreign write, re-clamp spacing, watch arg validation, leading-zero tunable" }, { "sha": "c4235854590904fbae20df09d789d812a908f005", "subject": "fix(run-supervisor): [QA-46 round 2] CR-34 flag-as-value rejected in all entry scripts; CR-35 SKILL.md documents standdown + stability gate" }, { "sha": "62827555e5d346be279b965946e16ca57e80d3ad", "subject": "test(run-supervisor): [QA-46 round 2] validation-gap coverage V-1,V-3,V-4,V-5 + red test CR-34" }, { "sha": "f1b306cd4b249513a6bc2d7148545192e45f217d", "subject": "test(run-supervisor): [QA-46 round 2] re-arm CR-8 scenario on event-based wait" }, { "sha": "d018dd7da131fa895934858edff5ed35ce295f20", "subject": "fix(run-supervisor): [QA-46 round 1] CR-1..CR-20,CR-23 — resume guard, arg validation, dedup, scheduling, test integrity" }, { "sha": "1512dc8a9457f1c30b76e8407e26bc3dfb6b4958", "subject": "test(run-supervisor): [QA-46 round 1] red regression tests CR-1,3,4,5,7,8,9,10,12,13,14,23" }, { "sha": "038c149ce949df22a112f5467b0afff309ee83c6", "subject": "docs: capture learning — new shipped skill requires SHIPPED_SKILLS widening" }, { "sha": "61e33d7209917301a3e697036b2a8f58bd987553", "subject": "test(run-supervisor): fix AC-9a race — seed non-resumable tail before revoking transcript readability" }, { "sha": "44f6a1e857c113b1edf07d3105c115399ac3f055", "subject": "run-template+wait-discipline: [WU-46-3-2] wire the run supervisor into the suite surfaces" }, { "sha": "afca037b61490e609d32a85c7da8bd9397834f20", "subject": "feat(run-supervisor): [WU-46-3-1] supervise skill: helpers, SKILL.md" }, { "sha": "9fd98e95f511fc7edebdfeb634cf9b201f09c709", "subject": "test(run-supervisor): [WU-46-3-1] failing integration suite for supervise helpers" }, { "sha": "d5b2194e50daa69e3a614eaba9ae502b03048949", "subject": "docs(run-supervisor): test plan" }, { "sha": "ca9e2a77db4f266e610c937626684dc8fe62e572", "subject": "docs(run-supervisor): software requirements" } ], "compare_url": null, "pushed": true, "remote_url": "ssh://git@forge-devwork/jbr870/devwork-skills.git" } ] } ```
Author
Owner
{
  "next_state": "uat",
  "produced": [
    {
      "kind": "code-bundle",
      "ref": "comment:1890",
      "summary": "Merged 18 commit(s) to main (fast-forward 12c444a..8de068e), pushed to origin"
    }
  ],
  "findings": [],
  "pending_decisions": [
    {
      "id": "D-PO-46-10-1",
      "type": "approval",
      "blocking": true,
      "question": "UAT: does the /dev:supervise run-supervisor work, and is it what we wanted?",
      "options": [
        "approve",
        "reject"
      ],
      "recommended": "approve",
      "reasoning": "Merged to main and pushed (fast-forward 12c444a..8de068e, 18 commits); integration gates green on the merged tree (lint-conventions clean, lint self-test pass, supervisor-flow suite pass). No integration deploy exists for this repo — UAT runs locally per the UAT card (.devwork/feature-46-run-supervisor/test-prerequisites.md): pull main, dogfood a supervised run against a real project; the card lists the 13 accepted residuals and 4 deferrals to #255 so the walk does not re-derive them. approve = a second /dev:integrate run posts accepted (queued for release) — it does NOT deploy; /dev:promote ships the accepted queue on your own cadence. reject = record what is wrong as findings; the UAT return path (qa-playbook.md par.9) classifies how far back to re-enter — the feature branch is already cleaned up, so rework starts from a branch recreated off the current main tip."
    }
  ],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-10 skill=integrate --> ```json { "next_state": "uat", "produced": [ { "kind": "code-bundle", "ref": "comment:1890", "summary": "Merged 18 commit(s) to main (fast-forward 12c444a..8de068e), pushed to origin" } ], "findings": [], "pending_decisions": [ { "id": "D-PO-46-10-1", "type": "approval", "blocking": true, "question": "UAT: does the /dev:supervise run-supervisor work, and is it what we wanted?", "options": [ "approve", "reject" ], "recommended": "approve", "reasoning": "Merged to main and pushed (fast-forward 12c444a..8de068e, 18 commits); integration gates green on the merged tree (lint-conventions clean, lint self-test pass, supervisor-flow suite pass). No integration deploy exists for this repo — UAT runs locally per the UAT card (.devwork/feature-46-run-supervisor/test-prerequisites.md): pull main, dogfood a supervised run against a real project; the card lists the 13 accepted residuals and 4 deferrals to #255 so the walk does not re-derive them. approve = a second /dev:integrate run posts accepted (queued for release) — it does NOT deploy; /dev:promote ships the accepted queue on your own cadence. reject = record what is wrong as findings; the UAT return path (qa-playbook.md par.9) classifies how far back to re-enter — the feature branch is already cleaned up, so rework starts from a branch recreated off the current main tip." } ], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner
{
  "status": "resolved",
  "chosen_option": "approve",
  "rationale": "Operator cannot run a hands-on UAT walk right now; accepting on the strength of the QA record (5 rounds, 57 findings worked, clean 4th adversarial sweep at the merge HEAD 8de068e, 13/13 test-plan scenarios green) — authority: the operator's explicit instruction in this session to resolve as approve. The dogfood use of /dev:supervise on real runs will serve as the de-facto acceptance observation (the QA record already names the dogfood UAT walk as the observer for accepted residual V-2).",
  "rejected_alternative": "Leaving the approval open until a hands-on walk is possible — turned down because the operator has no near-term window, and the skill's first real use IS a supervised dogfood run, which observes the same behavior the walk would."
}
<!-- decision-resolution:v1 ref=D-PO-46-10-1 --> ```json { "status": "resolved", "chosen_option": "approve", "rationale": "Operator cannot run a hands-on UAT walk right now; accepting on the strength of the QA record (5 rounds, 57 findings worked, clean 4th adversarial sweep at the merge HEAD 8de068e, 13/13 test-plan scenarios green) — authority: the operator's explicit instruction in this session to resolve as approve. The dogfood use of /dev:supervise on real runs will serve as the de-facto acceptance observation (the QA record already names the dogfood UAT walk as the observer for accepted residual V-2).", "rejected_alternative": "Leaving the approval open until a hands-on walk is possible — turned down because the operator has no near-term window, and the skill's first real use IS a supervised dogfood run, which observes the same behavior the walk would." } ```
Author
Owner
{
  "next_state": "accepted",
  "produced": [
    {
      "kind": "code-bundle",
      "ref": "comment:1890",
      "summary": "Accepted after UAT approval D-PO-46-10-1 (resolved approve, comment 1894); cites the existing code-bundle — 18 commits fast-forwarded to main (12c444a..8de068e), merged and cleaned up on the first run"
    }
  ],
  "findings": [],
  "pending_decisions": [],
  "suite": {
    "source": "git",
    "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-11 skill=integrate --> ```json { "next_state": "accepted", "produced": [ { "kind": "code-bundle", "ref": "comment:1890", "summary": "Accepted after UAT approval D-PO-46-10-1 (resolved approve, comment 1894); cites the existing code-bundle — 18 commits fast-forwarded to main (12c444a..8de068e), merged and cleaned up on the first run" } ], "findings": [], "pending_decisions": [], "suite": { "source": "git", "sha": "2ceacfe8490eb7efb2258c1d62981eea06acb97b", "dirty": false } } ```
Author
Owner

UAT prerequisites — issue #46, run supervisor (/dev:supervise)

Where the reviewable build is

Per the project's uat.url_source, verbatim: "no deploy — review the merged skill text on main and dogfood a run against a real project". Mode local, no PR (uat.open_pr: false).

Until /dev:integrate merges, the reviewable tree is the worktree .claude/worktrees/devwork-46 at commit 8de068e (branch feature/46-run-supervisor). The skill text to read: plugin/skills/supervise/SKILL.md. The helpers: plugin/skills/supervise/bin/.

Authentication

None. Everything is local: the supervisor reads ~/.claude/projects/<cwd-slug>/<session-id>.jsonl as your own user and posts records via the project's forge adapter (this repo: tea-cli against git.wihslon.com, your existing tea login).

Scenario-specific test data

  • The integration suite fabricated everything it needed (synthetic transcripts from recorded harness shapes, a stub claude, local-fs forge sandboxes) — nothing persists for you to inspect except the suite itself: plugin/skills/supervise/test/supervisor-flow.sh (181 checks green at 8de068e).
  • For the dogfood walk you need one unattended run on a real project with supervision engaged at launch: run-template v5 step 0 now carries the opt-in engage line (supervisor-attach.sh --session "$CLAUDE_CODE_SESSION_ID" --issue <N>). The engage refuses to report success until the daemon's first heartbeat.
  • supervisor-status.sh --session <id> gives the one-screen answer (engaged, heartbeat age, interventions, next action). supervisor-detach.sh stands it down.

Setup beyond normal startup

None. Preflight is self-contained (transcript readable, claude CLI on PATH, jq, clock-parse probe); a failing preflight names what is missing and refuses loudly.

Scenario list (from test-plan:v1 — the same activity as this walk)

All 13 scenarios ran green in the integration lane; the dogfood walk is the run-level overlay, not a re-execution of each:

  1. Transient turn-death resumed automatically (bounded, backoff-spaced)
  2. Retry bound exhausted → escalation naming the count
  3. Quota kill with stated reset → scheduled resume
  4. Quota kill with reset already past → immediate resume
  5. Quota kill with no discoverable reset → bounded-retry path
  6. Stall without turn-over evidence → alert only, no session writes
  7. Operator stop never auto-resumed
  8. Clean completion → supervisor stands down
  9. Second attach refused
  10. Harness surface unavailable → escalate, don't act
  11. Declared post-resume step invoked before phase work
  12. Everything on the durable record; channel delivery when declared
  13. Declared tunables are the values in force

Suggested dogfood focus (what the suite could not observe): a real long quota sleep (the suite accepts V-2's composition argument — the live fire at a future reset is the one path only a real run exercises), and the -p resume giving one agentic turn (SREQ Technical Risk: a driver parking after a cross-turn wait lands in the alert-only ambiguous class — confirm the alert is legible when it happens).

Known accepted residuals (so the walk doesn't re-derive them)

Thirteen accepted findings across the five QA rounds, each with recorded reasoning on the issue (highlights: crash-window record gap under the HA non-goal; nohup-fallback orphan; pid-only identity on exotic boxes; weekly-limit futile-but-bounded retries; V-2 future-reset live fire covered by composition — the dogfood walk is its observer; the marker paste-quote tradeoff; the absent-bound status default). Four robustness edges deferred to issue #255 (retry bound across re-attach, lock-reclaim TOCTOU, stall blind spots, abort-re-aim churn bound).

<!-- uat-prerequisites:v1 issue=46 skill=integrate --> # UAT prerequisites — issue #46, run supervisor (`/dev:supervise`) ## Where the reviewable build is Per the project's `uat.url_source`, verbatim: **"no deploy — review the merged skill text on main and dogfood a run against a real project"**. Mode `local`, no PR (`uat.open_pr: false`). Until `/dev:integrate` merges, the reviewable tree is the worktree `.claude/worktrees/devwork-46` at commit `8de068e` (branch `feature/46-run-supervisor`). The skill text to read: `plugin/skills/supervise/SKILL.md`. The helpers: `plugin/skills/supervise/bin/`. ## Authentication None. Everything is local: the supervisor reads `~/.claude/projects/<cwd-slug>/<session-id>.jsonl` as your own user and posts records via the project's forge adapter (this repo: `tea-cli` against git.wihslon.com, your existing `tea` login). ## Scenario-specific test data - The integration suite fabricated everything it needed (synthetic transcripts from recorded harness shapes, a stub `claude`, `local-fs` forge sandboxes) — nothing persists for you to inspect except the suite itself: `plugin/skills/supervise/test/supervisor-flow.sh` (181 checks green at `8de068e`). - For the dogfood walk you need one unattended run on a real project with supervision engaged at launch: run-template v5 step 0 now carries the opt-in engage line (`supervisor-attach.sh --session "$CLAUDE_CODE_SESSION_ID" --issue <N>`). The engage refuses to report success until the daemon's first heartbeat. - `supervisor-status.sh --session <id>` gives the one-screen answer (engaged, heartbeat age, interventions, next action). `supervisor-detach.sh` stands it down. ## Setup beyond normal startup None. Preflight is self-contained (transcript readable, `claude` CLI on PATH, jq, clock-parse probe); a failing preflight names what is missing and refuses loudly. ## Scenario list (from `test-plan:v1` — the same activity as this walk) All 13 scenarios ran green in the integration lane; the dogfood walk is the run-level overlay, not a re-execution of each: 1. Transient turn-death resumed automatically (bounded, backoff-spaced) 2. Retry bound exhausted → escalation naming the count 3. Quota kill with stated reset → scheduled resume 4. Quota kill with reset already past → immediate resume 5. Quota kill with no discoverable reset → bounded-retry path 6. Stall without turn-over evidence → alert only, no session writes 7. Operator stop never auto-resumed 8. Clean completion → supervisor stands down 9. Second attach refused 10. Harness surface unavailable → escalate, don't act 11. Declared post-resume step invoked before phase work 12. Everything on the durable record; channel delivery when declared 13. Declared tunables are the values in force Suggested dogfood focus (what the suite could not observe): a real long quota sleep (the suite accepts V-2's composition argument — the live fire at a future reset is the one path only a real run exercises), and the `-p` resume giving one agentic turn (SREQ Technical Risk: a driver parking after a cross-turn wait lands in the alert-only ambiguous class — confirm the alert is legible when it happens). ## Known accepted residuals (so the walk doesn't re-derive them) Thirteen accepted findings across the five QA rounds, each with recorded reasoning on the issue (highlights: crash-window record gap under the HA non-goal; nohup-fallback orphan; pid-only identity on exotic boxes; weekly-limit futile-but-bounded retries; V-2 future-reset live fire covered by composition — the dogfood walk is its observer; the marker paste-quote tradeoff; the absent-bound status default). Four robustness edges deferred to issue #255 (retry bound across re-attach, lock-reclaim TOCTOU, stall blind spots, abort-re-aim churn bound).
Author
Owner
{
  "tag": "dev--v0.3.0",
  "status": "tag-only",
  "repos": [
    {
      "repo": "devwork-skills",
      "tag": "dev--v0.3.0",
      "target_sha": "7e9b943cde94438da1d116513c083c2bfd54c9f2"
    }
  ]
}
<!-- release-link:v1 issue=46 skill=promote tag=dev--v0.3.0 --> ```json { "tag": "dev--v0.3.0", "status": "tag-only", "repos": [ { "repo": "devwork-skills", "tag": "dev--v0.3.0", "target_sha": "7e9b943cde94438da1d116513c083c2bfd54c9f2" } ] } ```
Author
Owner
{
  "next_state": "deployed",
  "produced": [
    {
      "kind": "release-link",
      "ref": "comment:2442",
      "summary": "Shipped in dev--v0.3.0 (tag-only release, commit 7e9b943)"
    }
  ],
  "findings": [],
  "pending_decisions": [],
  "suite": {
    "source": "git",
    "sha": "d22f1e31a4e51bfd6bdea660f106b770e4160be3",
    "dirty": false
  }
}
<!-- phase-outcome:v1 id=PO-46-12 skill=promote --> ```json { "next_state": "deployed", "produced": [ { "kind": "release-link", "ref": "comment:2442", "summary": "Shipped in dev--v0.3.0 (tag-only release, commit 7e9b943)" } ], "findings": [], "pending_decisions": [], "suite": { "source": "git", "sha": "d22f1e31a4e51bfd6bdea660f106b770e4160be3", "dirty": false } } ```
Sign in to join this conversation.
No description provided.