Redesign os-sdlc pipeline advancement around SubagentStart/SubagentStop hooks #425

Closed
opened 2026-08-18 15:44:05 +00:00 by jared · 4 comments
Owner

Context

The implement pipeline advances via a PostToolUse hook on the Agent tool,
which requires synchronous dispatch (ADR-0121). In harnesses that force
async Agent dispatch, PostToolUse fires at launch with status:
async_launched, so the guard rejects every dispatch and the pipeline stalls
— hit live in a test session 2026-08-18. Experiment verified that
SubagentStop fires at the agent's real completion time for background-
launched agents, with agent_type, agent_id, agent_transcript_path, and
last_assistant_message in the payload (vault: reference/claude-code-
subagent-hooks-fire-for-background-agents.md). This redesign moves
completion signaling to SubagentStop and supersedes ADR-0121.

Design (agreed 2026-08-18):

• Hooks are webhook-thin and data-only — they call a single runner endpoint
with payload data, never perform work themselves. Matched to ^os-sdlc:.*$ on
both SubagentStart and SubagentStop.
• SubagentStart: records the dispatch (agent metadata, relations) and
fetches the pending handoff for that agent_type as the agent's intake
context.
• SubagentStop: posts payload metadata + created handoff to the runner
endpoint; runner records, runs post-agent steps (test suite, lint on diffed
files), and sets state.
• PostToolUse on Agent becomes a state-aware ack/next-instruction query:
async launch → "dispatched, await notification"; state shows a completed
step → routing instructions.
• Orchestrator reads only runner instructions between dispatches; an escape-
hatch investigation skill (knows expected states, queries the db for
evidence) covers breakdowns.
• Data model (simplified 2026-08-18): sessions → implementations
(created_at/completed_at/abandoned_at; state DERIVED from timestamps — both
null = active, completed_at set = completed, abandoned_at set = abandoned;
current implementation = session's latest row; runner stamps abandoned_at on
the prior unfinished round when opening a new one, and stamps completed_at
when sending final instructions) → dispatches (implementation_id, agent_id,
received_handoff_id, created_handoff_id, created_at, completed_at stamped by
SubagentStop). Agents table separate from dispatches (1:1 in practice under
the fresh-dispatch rule; a revisit is a new dispatch row with the same
agent_id). Handoffs are a noun-only table; NO handoff_transfers join table —
direction lives on the two dispatch FKs. Full design: .
sdlc/tickets/425/design.md

Tasks

[ ] Superseding ADR for ADR-0121 recording the SubagentStop-based
advancement design
[ ] Runner endpoints: dispatch-record + handoff-fetch (SubagentStart),
completion intake (SubagentStop), round start (runner start), state-aware
next-instruction query (PostToolUse)
[ ] Schema: implementations/dispatches/agents/handoffs/handoff_transfers per
the model above
[ ] SubagentStart + SubagentStop hooks with ^os-sdlc:.*$ matchers,
registered in the plugin manifest
[ ] Rework PostToolUse hook into the ack/query role (drop the async_launched
rejection)
[ ] Escape-hatch investigation skill
[ ] Confirm SubagentStop fires in the async-forcing harness on the first
real run (assumed working; adjust only if it becomes a pain point)

Acceptance criteria

[ ] A ticket runs end-to-end through the implement pipeline in a harness
where every Agent call launches async
[ ] No pipeline state advances at agent launch time
[ ] Orchestrator receives next-step instructions without reading any
pipeline file other than runner output

Origin

• Trigger: /os-sdlc:implement test run in a Fable-5 harness session
(fc87bc6b), stuck at code-probe with repeated async_launched rejections
• Improvised this session: none (manual synthetic-event piping identified as
interim unstick, not applied here)
• Chain: pipeline stall ← PostToolUse-on-Agent fires at launch under async
dispatch ← sync-only advancement design — DESIGN (ADR-0121)
• Root candidate: this ticket

Spec (published 2026-08-18; supplements the capture sections above — design detail lives in .sdlc/tickets/425/design.md)

Problem Statement

When I run /os-sdlc:implement in a harness that launches every Agent call asynchronously, the pipeline stalls permanently: the PostToolUse hook fires at agent launch with status async_launched, the ADR-0121 guard rejects it, and no advancement path remains. Even in sync harnesses, advancement depends on a launch-time hook standing in for a completion signal, and the recovery machinery (resume/recover/reemit/rollback) exists mostly to escape stuck stored state.

Solution

Advance the pipeline on the agent's real completion signal (SubagentStop, verified to fire at true completion for background agents) instead of the Agent tool call return. Hooks become webhook-thin data couriers into runner CLI endpoints; the runner owns all state, post-agent steps (tests, lint), and routing; state is derived from timestamps so ambiguous in-flight state is structurally impossible; the orchestrator reads only runner instructions, with an escape-hatch skill for investigating divergence.

User Stories

  1. As a pipeline orchestrator, I want the runner to advance state when an agent actually completes, so that async-launching harnesses do not stall the pipeline.
  2. As a pipeline orchestrator, I want the same flow to work under synchronous dispatch, so that the pipeline is harness-agnostic.
  3. As a pipeline orchestrator, I want a single instruction-query endpoint that answers from current state, so that I never read pipeline internals between dispatches.
  4. As a pipeline orchestrator, I want the instruction query to be idempotent, so that re-asking after a notification never corrupts state or double-dispatches.
  5. As a pipeline agent, I want my intake handoff injected at SubagentStart, so that I start with the assignment content the previous stage produced.
  6. As a pipeline agent, I want the handoff I produce recorded at SubagentStop, so that the next stage receives it without orchestrator relay.
  7. As the runner, I want a dispatch row created at SubagentStart and completed at SubagentStop, so that every agent's lifecycle is timestamped in the database.
  8. As the runner, I want to run post-agent steps (test suite, then lint over diffed files) at completion intake, so that gate outcomes are recorded before the orchestrator asks for instructions.
  9. As the runner, I want implementation state derived purely from created_at/completed_at/abandoned_at timestamps, so that no stored state column can disagree with reality.
  10. As the runner, I want opening a new round to stamp abandoned_at on any prior unfinished implementation for the session, so that a session always has exactly one current implementation.
  11. As the user, I want the pipeline to fail loudly (ADR-0108) when an event arrives that state cannot explain, so that breakage is visible instead of silently absorbed.
  12. As the user, I want per-dispatch and per-round durations derivable from timestamps, so that timing analysis needs no extra instrumentation.
  13. As the orchestrator, I want an escape-hatch skill documenting expected state at each pipeline point with database queries, so that I can investigate divergence without improvising reads.
  14. As a hook author, I want SubagentStart/SubagentStop matched to ^os-sdlc:.*$ only, so that non-pipeline agents never trigger pipeline endpoints.
  15. As a maintainer, I want the PostToolUse hook reduced to a thin state-aware ack/query with the async_launched rejection removed, so that launch receipts acknowledge rather than reject.
  16. As a maintainer, I want the recovery cluster (resume/recover/reemit/rollback) retired where timestamps make it redundant, so that the runner is smaller and has fewer stuck-state escape hatches to maintain.
  17. As a maintainer, I want a superseding ADR for ADR-0121, so that the decision record explains why sync-only dispatch was abandoned.
  18. As a future implementer, I want agents and dispatches modeled separately, so that a re-invoked agent gets a new dispatch row without schema change.

Implementation Decisions

  • Storage stays SQLite/Sequel in the existing per-project runner database; the change is a migration adding implementations, agents, and handoffs tables and extending dispatches with received/created handoff FKs and lifecycle timestamps — not a new stack.
  • Runner endpoints are new Thor commands on the existing runner CLI, emitting one JSON object on stdout: round-start/instruction query (serves both the orchestrator pull and the PostToolUse query), SubagentStart dispatch-record + handoff-fetch, SubagentStop completion intake.
  • Hooks are webhook-thin: parse the event, call one runner endpoint, relay its output. No state logic in hooks. SubagentStart/SubagentStop registered in the plugin hooks manifest with matcher ^os-sdlc:.*$.
  • SubagentStart returns the pending handoff for the agent's type as additionalContext (its intake); SubagentStop posts the full payload plus the produced handoff; the runner then stamps dispatch completion, runs the test gate, on green runs lint over diffed files, records step results, and advances routing state.
  • The handoffs table replaces brief files as the record of inter-agent content; the existing per-state brief content-selection logic moves behind whatever renders a handoff row. Handoffs are noun-only; direction lives on the two dispatch FKs (no join table).
  • Derived state contract: implementation active when completed_at and abandoned_at are both null; the session's latest row is current; the runner stamps abandoned_at when opening a replacement round and completed_at when it sends final instructions.
  • The instruction query is split command/query: dispatch-row creation is separated from state reads so repeated queries are safe (the current advance path creates dispatch rows unconditionally).
  • Gate logic, sequencing, and retry routing remain in tested Ruby per ADR-0097 — never in prompts or skills. The implement skill's sync-dispatch mandate is rewritten to describe the new flow.
  • The recovery cluster is deleted by default; only the genuine human decision point (retry-with-guidance/skip/abort after a failed gate) survives, as routing.
  • A superseding ADR for ADR-0121 is written before implementation lands.

Testing Decisions

  • Single seam: the runner CLI. Tests invoke the Thor commands (new endpoints plus surviving ones) with arguments and synthetic payload JSON, asserting on the emitted JSON and the resulting SQLite rows — external behavior only, never internal method calls or intermediate objects.
  • Hooks are not tested directly; they are thin shells over the CLI and stay that way. If a hook grows logic worth testing, that logic moves into the CLI/engine first.
  • Prior art: the existing runner CLI argument tests and gate/engine tests in the runner test directory; the async-guard and resume/recover test cluster is retired with the code it covers.
  • Timestamp-derived state is tested through the CLI contract: sequences of endpoint calls produce the expected derived states and instruction outputs, including the loud-stall response to inexplicable events.

Out of Scope

  • Parallel pipeline agents / multiple active implementations per session.
  • Recording skill invocations or hook firings as dispatches (agents only).
  • Harness changes: the async-launching harness is taken as given; no attempt to force sync dispatch.
  • Bulk migration of historical run data into the new schema.

Further Notes

  • Open questions deferred to implementation (none blocking): whether SubagentStart/Stop re-fire on SendMessage resume; whether last_assistant_message is persisted in full; first-real-run confirmation that SubagentStop fires in the async-forcing harness; how much retry semantics survive for post-agent steps.
  • Alignment investigation (2026-08-18) estimates net −200 to −600 LOC once the recovery cluster is retired; details in the design doc's alignment section.
## Context The implement pipeline advances via a PostToolUse hook on the Agent tool, which requires synchronous dispatch (ADR-0121). In harnesses that force async Agent dispatch, PostToolUse fires at launch with status: async_launched, so the guard rejects every dispatch and the pipeline stalls — hit live in a test session 2026-08-18. Experiment verified that SubagentStop fires at the agent's real completion time for background- launched agents, with agent_type, agent_id, agent_transcript_path, and last_assistant_message in the payload (vault: reference/claude-code- subagent-hooks-fire-for-background-agents.md). This redesign moves completion signaling to SubagentStop and supersedes ADR-0121. Design (agreed 2026-08-18): • Hooks are webhook-thin and data-only — they call a single runner endpoint with payload data, never perform work themselves. Matched to ^os-sdlc:.*$ on both SubagentStart and SubagentStop. • SubagentStart: records the dispatch (agent metadata, relations) and fetches the pending handoff for that agent_type as the agent's intake context. • SubagentStop: posts payload metadata + created handoff to the runner endpoint; runner records, runs post-agent steps (test suite, lint on diffed files), and sets state. • PostToolUse on Agent becomes a state-aware ack/next-instruction query: async launch → "dispatched, await notification"; state shows a completed step → routing instructions. • Orchestrator reads only runner instructions between dispatches; an escape- hatch investigation skill (knows expected states, queries the db for evidence) covers breakdowns. • Data model (simplified 2026-08-18): sessions → implementations (created_at/completed_at/abandoned_at; state DERIVED from timestamps — both null = active, completed_at set = completed, abandoned_at set = abandoned; current implementation = session's latest row; runner stamps abandoned_at on the prior unfinished round when opening a new one, and stamps completed_at when sending final instructions) → dispatches (implementation_id, agent_id, received_handoff_id, created_handoff_id, created_at, completed_at stamped by SubagentStop). Agents table separate from dispatches (1:1 in practice under the fresh-dispatch rule; a revisit is a new dispatch row with the same agent_id). Handoffs are a noun-only table; NO handoff_transfers join table — direction lives on the two dispatch FKs. Full design: . sdlc/tickets/425/design.md ## Tasks [ ] Superseding ADR for ADR-0121 recording the SubagentStop-based advancement design [ ] Runner endpoints: dispatch-record + handoff-fetch (SubagentStart), completion intake (SubagentStop), round start (runner start), state-aware next-instruction query (PostToolUse) [ ] Schema: implementations/dispatches/agents/handoffs/handoff_transfers per the model above [ ] SubagentStart + SubagentStop hooks with ^os-sdlc:.*$ matchers, registered in the plugin manifest [ ] Rework PostToolUse hook into the ack/query role (drop the async_launched rejection) [ ] Escape-hatch investigation skill [ ] Confirm SubagentStop fires in the async-forcing harness on the first real run (assumed working; adjust only if it becomes a pain point) ## Acceptance criteria [ ] A ticket runs end-to-end through the implement pipeline in a harness where every Agent call launches async [ ] No pipeline state advances at agent launch time [ ] Orchestrator receives next-step instructions without reading any pipeline file other than runner output ## Origin • Trigger: /os-sdlc:implement test run in a Fable-5 harness session (fc87bc6b), stuck at code-probe with repeated async_launched rejections • Improvised this session: none (manual synthetic-event piping identified as interim unstick, not applied here) • Chain: pipeline stall ← PostToolUse-on-Agent fires at launch under async dispatch ← sync-only advancement design — DESIGN (ADR-0121) • Root candidate: this ticket # Spec (published 2026-08-18; supplements the capture sections above — design detail lives in .sdlc/tickets/425/design.md) ## Problem Statement When I run /os-sdlc:implement in a harness that launches every Agent call asynchronously, the pipeline stalls permanently: the PostToolUse hook fires at agent launch with status async_launched, the ADR-0121 guard rejects it, and no advancement path remains. Even in sync harnesses, advancement depends on a launch-time hook standing in for a completion signal, and the recovery machinery (resume/recover/reemit/rollback) exists mostly to escape stuck stored state. ## Solution Advance the pipeline on the agent's real completion signal (SubagentStop, verified to fire at true completion for background agents) instead of the Agent tool call return. Hooks become webhook-thin data couriers into runner CLI endpoints; the runner owns all state, post-agent steps (tests, lint), and routing; state is derived from timestamps so ambiguous in-flight state is structurally impossible; the orchestrator reads only runner instructions, with an escape-hatch skill for investigating divergence. ## User Stories 1. As a pipeline orchestrator, I want the runner to advance state when an agent actually completes, so that async-launching harnesses do not stall the pipeline. 2. As a pipeline orchestrator, I want the same flow to work under synchronous dispatch, so that the pipeline is harness-agnostic. 3. As a pipeline orchestrator, I want a single instruction-query endpoint that answers from current state, so that I never read pipeline internals between dispatches. 4. As a pipeline orchestrator, I want the instruction query to be idempotent, so that re-asking after a notification never corrupts state or double-dispatches. 5. As a pipeline agent, I want my intake handoff injected at SubagentStart, so that I start with the assignment content the previous stage produced. 6. As a pipeline agent, I want the handoff I produce recorded at SubagentStop, so that the next stage receives it without orchestrator relay. 7. As the runner, I want a dispatch row created at SubagentStart and completed at SubagentStop, so that every agent's lifecycle is timestamped in the database. 8. As the runner, I want to run post-agent steps (test suite, then lint over diffed files) at completion intake, so that gate outcomes are recorded before the orchestrator asks for instructions. 9. As the runner, I want implementation state derived purely from created_at/completed_at/abandoned_at timestamps, so that no stored state column can disagree with reality. 10. As the runner, I want opening a new round to stamp abandoned_at on any prior unfinished implementation for the session, so that a session always has exactly one current implementation. 11. As the user, I want the pipeline to fail loudly (ADR-0108) when an event arrives that state cannot explain, so that breakage is visible instead of silently absorbed. 12. As the user, I want per-dispatch and per-round durations derivable from timestamps, so that timing analysis needs no extra instrumentation. 13. As the orchestrator, I want an escape-hatch skill documenting expected state at each pipeline point with database queries, so that I can investigate divergence without improvising reads. 14. As a hook author, I want SubagentStart/SubagentStop matched to ^os-sdlc:.*$ only, so that non-pipeline agents never trigger pipeline endpoints. 15. As a maintainer, I want the PostToolUse hook reduced to a thin state-aware ack/query with the async_launched rejection removed, so that launch receipts acknowledge rather than reject. 16. As a maintainer, I want the recovery cluster (resume/recover/reemit/rollback) retired where timestamps make it redundant, so that the runner is smaller and has fewer stuck-state escape hatches to maintain. 17. As a maintainer, I want a superseding ADR for ADR-0121, so that the decision record explains why sync-only dispatch was abandoned. 18. As a future implementer, I want agents and dispatches modeled separately, so that a re-invoked agent gets a new dispatch row without schema change. ## Implementation Decisions - Storage stays SQLite/Sequel in the existing per-project runner database; the change is a migration adding implementations, agents, and handoffs tables and extending dispatches with received/created handoff FKs and lifecycle timestamps — not a new stack. - Runner endpoints are new Thor commands on the existing runner CLI, emitting one JSON object on stdout: round-start/instruction query (serves both the orchestrator pull and the PostToolUse query), SubagentStart dispatch-record + handoff-fetch, SubagentStop completion intake. - Hooks are webhook-thin: parse the event, call one runner endpoint, relay its output. No state logic in hooks. SubagentStart/SubagentStop registered in the plugin hooks manifest with matcher ^os-sdlc:.*$. - SubagentStart returns the pending handoff for the agent's type as additionalContext (its intake); SubagentStop posts the full payload plus the produced handoff; the runner then stamps dispatch completion, runs the test gate, on green runs lint over diffed files, records step results, and advances routing state. - The handoffs table replaces brief files as the record of inter-agent content; the existing per-state brief content-selection logic moves behind whatever renders a handoff row. Handoffs are noun-only; direction lives on the two dispatch FKs (no join table). - Derived state contract: implementation active when completed_at and abandoned_at are both null; the session's latest row is current; the runner stamps abandoned_at when opening a replacement round and completed_at when it sends final instructions. - The instruction query is split command/query: dispatch-row creation is separated from state reads so repeated queries are safe (the current advance path creates dispatch rows unconditionally). - Gate logic, sequencing, and retry routing remain in tested Ruby per ADR-0097 — never in prompts or skills. The implement skill's sync-dispatch mandate is rewritten to describe the new flow. - The recovery cluster is deleted by default; only the genuine human decision point (retry-with-guidance/skip/abort after a failed gate) survives, as routing. - A superseding ADR for ADR-0121 is written before implementation lands. ## Testing Decisions - Single seam: the runner CLI. Tests invoke the Thor commands (new endpoints plus surviving ones) with arguments and synthetic payload JSON, asserting on the emitted JSON and the resulting SQLite rows — external behavior only, never internal method calls or intermediate objects. - Hooks are not tested directly; they are thin shells over the CLI and stay that way. If a hook grows logic worth testing, that logic moves into the CLI/engine first. - Prior art: the existing runner CLI argument tests and gate/engine tests in the runner test directory; the async-guard and resume/recover test cluster is retired with the code it covers. - Timestamp-derived state is tested through the CLI contract: sequences of endpoint calls produce the expected derived states and instruction outputs, including the loud-stall response to inexplicable events. ## Out of Scope - Parallel pipeline agents / multiple active implementations per session. - Recording skill invocations or hook firings as dispatches (agents only). - Harness changes: the async-launching harness is taken as given; no attempt to force sync dispatch. - Bulk migration of historical run data into the new schema. ## Further Notes - Open questions deferred to implementation (none blocking): whether SubagentStart/Stop re-fire on SendMessage resume; whether last_assistant_message is persisted in full; first-real-run confirmation that SubagentStop fires in the async-forcing harness; how much retry semantics survive for post-agent steps. - Alignment investigation (2026-08-18) estimates net −200 to −600 LOC once the recovery cluster is retired; details in the design doc's alignment section.
Author
Owner

Work started 2026-08-18: design phase. Design doc drafted at .sdlc/tickets/425/design.md (SubagentStop-based advancement, webhook-thin hooks, timestamp-derived implementation state). Implementation follows after design review.

Work started 2026-08-18: design phase. Design doc drafted at .sdlc/tickets/425/design.md (SubagentStop-based advancement, webhook-thin hooks, timestamp-derived implementation state). Implementation follows after design review.
Author
Owner

Alignment investigation done 2026-08-18 (two ast-grep sweeps over plugins/os-sdlc); full findings in .sdlc/tickets/425/design.md § 'Alignment with the current implementation'. Highlights: storage is already SQLite/Sequel (runner/db.rb) so the schema is a migration, not a new stack; runner endpoints land as new Thor commands on runner/cli.rb; handoffs table replaces BriefAssembler's brief files; lint moves from the decoupled lint_changed.rb hook into a runner-owned SubagentStop step; dispatch_action needs a query/command split for an idempotent instruction endpoint. Obsoleted: the ADR-0121 async guard + advancement path in post_tool_use.rb, the run_in_background:false mandate in skills/implement/SKILL.md, tickets.state column-based in-flight logic, and most of the recovery cluster (resumer/rollback/reemit/recovery_status, ~10K over 5 files) plus ~10 test files. Net est. -200 to -600 LOC.

Alignment investigation done 2026-08-18 (two ast-grep sweeps over plugins/os-sdlc); full findings in .sdlc/tickets/425/design.md § 'Alignment with the current implementation'. Highlights: storage is already SQLite/Sequel (runner/db.rb) so the schema is a migration, not a new stack; runner endpoints land as new Thor commands on runner/cli.rb; handoffs table replaces BriefAssembler's brief files; lint moves from the decoupled lint_changed.rb hook into a runner-owned SubagentStop step; dispatch_action needs a query/command split for an idempotent instruction endpoint. Obsoleted: the ADR-0121 async guard + advancement path in post_tool_use.rb, the run_in_background:false mandate in skills/implement/SKILL.md, tickets.state column-based in-flight logic, and most of the recovery cluster (resumer/rollback/reemit/recovery_status, ~10K over 5 files) plus ~10 test files. Net est. -200 to -600 LOC.
Author
Owner

Decomposed into implementation tickets: #426–#432 (linear chain #426→#427→#428→#429→#430→#431; #432 parallel off #427).

Decomposed into implementation tickets: #426–#432 (linear chain #426→#427→#428→#429→#430→#431; #432 parallel off #427).
Author
Owner

Resolution

Done: SubagentStop-driven runner rebuild complete via child tickets #426–#433, all closed with three-part resolutions: ADR-0128 supersedes ADR-0121 (#426); schema migration + round-open/next idempotent instruction query (#427); SubagentStart endpoint + webhook-thin hook with handoff intake (#428); SubagentStop completion intake with gates, step results, advancement (#429); PostToolUse async ack + pull-instruction implement skill (#430); recovery cluster retired, −867 LOC (#431); pipeline-state-investigate skill (#432); assembly sweep, live-schema fix, and end-to-end dogfood (#433). Async-forcing harnesses no longer stall: launch receipts ack, real completion advances the pipeline via lifecycle timestamps.

Evidence: commits f8ba73e, 237d16c, 63d0fbf, ea8cdfc, 8050c83, 28384cc, 61aa3a3, 1bb6700, b9a0b99 on main; final suite 276 runs/594 assertions 0 failures; dogfood run verified all four pipeline-point states per the investigation skill's contract

Follow-ups: carried on #433's close: live-session hook observation (monitor, no ticket) and the legacy ticket-pipeline retirement question (deliberate deferral pending direction); nothing else outstanding from this map

## Resolution **Done:** SubagentStop-driven runner rebuild complete via child tickets #426–#433, all closed with three-part resolutions: ADR-0128 supersedes ADR-0121 (#426); schema migration + round-open/next idempotent instruction query (#427); SubagentStart endpoint + webhook-thin hook with handoff intake (#428); SubagentStop completion intake with gates, step results, advancement (#429); PostToolUse async ack + pull-instruction implement skill (#430); recovery cluster retired, −867 LOC (#431); pipeline-state-investigate skill (#432); assembly sweep, live-schema fix, and end-to-end dogfood (#433). Async-forcing harnesses no longer stall: launch receipts ack, real completion advances the pipeline via lifecycle timestamps. **Evidence:** commits f8ba73e, 237d16c, 63d0fbf, ea8cdfc, 8050c83, 28384cc, 61aa3a3, 1bb6700, b9a0b99 on main; final suite 276 runs/594 assertions 0 failures; dogfood run verified all four pipeline-point states per the investigation skill's contract **Follow-ups:** carried on #433's close: live-session hook observation (monitor, no ticket) and the legacy ticket-pipeline retirement question (deliberate deferral pending direction); nothing else outstanding from this map
jared closed this issue 2026-08-18 21:50:59 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#425
No description provided.