Skip to content

feat(daemon): launch ladders → step() O8 observations (coupling-core B1)#475

Merged
proboscis merged 1 commit into
mainfrom
feat/coupling-core-launch-plane
Jun 12, 2026
Merged

feat(daemon): launch ladders → step() O8 observations (coupling-core B1)#475
proboscis merged 1 commit into
mainfrom
feat/coupling-core-launch-plane

Conversation

@proboscis

Copy link
Copy Markdown
Owner

What

Phase B1 of the coupling-core roadmap: the four launch ladders (W2 handleStartRun, W3 processStartRunCore, W4 processContinueRunCore, W5 handleContinueRun) and the failure arm (W7 failOpenCodeRunBootstrap) no longer write run status events. All 37 ladder append sites are replaced by O8 launch observations decided in the pure transition core.

ladder (imperative bootstrap, unchanged control flow)
  │  reportLaunchProgress(st, run, launchSignal)      ← launch-plane executor
  ▼
stepLaunchProgress (pure policy, step.go)
  stageRunCreated → queued      stageLaunchReady → booting
  stageWorkspaceOnly/stageAgentStarted → running
  failure → [error artifact, failed(reason=launch_<step>), log]
  │  effectSetStatus
  ▼
commitRunStatus (status_commit.go) ← THE single status-event constructor
  ▲
  └─ Daemon.updateStatus (monitor plane: +publish +auto-resolve +listeners)

Key decisions (run-state-machine.md §7 D-B1)

  • commitRunStatus extraction: updateStatus's guard/append core is now a process-neutral function, so the worker plane (which runs SocketServer without a Daemon) commits through identical guards. Status events are constructed in exactly one place.
  • Stage vocabulary in the observation, statuses in the policy — the ladders report facts; the mapping is stepLaunchProgress's.
  • Terminal absorption == old store-guard behavior: launch appends on terminal runs were already silently rejected (daemon source); now the no-write is a policy decision (L4), not a discarded error.
  • Launch failures carry launch_<step> reasons (new law L9), rendered by orch ps as failed(launch_session) etc.
  • The implicit initial queued (fold default) is no longer materialized as a redundant event.
  • Listener scope unchanged: launch transitions stay listener-invisible (widening I8 is a separate decision).

Whitelist meter

nosemgrep: run-status-write-surface: 47 → 10 (socket.go 40 → 3). Every survivor has a §6 disposition: W6/W8 (integrate v2), W9 ×4 / W10 (quarantined law boundaries), appendRunResolvedByUser (B3 verb), plus the sanctioned constructor itself.

Tests

  • O8 added to the law-sweep observation set → L4 terminality, determinism, L1a idempotent convergence, and stream fixed-point laws now cover launch observations automatically.
  • New: TestStepLaunchProgressStageMapping (stage→status + re-affirmation silence), TestStepLaunchFailureCarriesReason (artifact order, launch_<step>, launch_bootstrap fallback).
  • go build ./..., go test ./internal/daemon (19.4s ok), make lint (all semgrep fixtures pass, 0 findings), full go test ./... — only the two pre-existing tmux-environment integration failures (TestAgentClaudeCreatesMultiplexerSession, TestAgentStatePersistence), reproduced identically on main @ f39a19b.

Docs in the same change set

run-state-machine.md §1 (writer table + single-constructor note), §2 (O8), §3 (O8 matrix rows), §5 (L9 + launch_<step> reason family), §6 (W2–W5/W7 → integrated), §7 (D-B1); AGENTS.md status-write-surface; roadmap B1 + watchlist rows 1/6.

Per the routing rule this is a core change: frontier + human review — please review before merging.

🤖 Generated with Claude Code

…coupling-core B1)

The four launch ladders (handleStartRun / processStartRunCore /
processContinueRunCore / handleContinueRun) and their failure arm
(failOpenCodeRunBootstrap) no longer write run status events. Every
milestone and bootstrap failure is reported as an O8 launch observation
(launchSignal) and decided by the pure policy stepLaunchProgress:

    stageRunCreated -> queued, stageLaunchReady -> booting,
    stageWorkspaceOnly/stageAgentStarted -> running,
    failure -> failed (reason launch_<step>, error artifact first)

- commitRunStatus (new status_commit.go) extracts the guard/append core
  of updateStatus and is now the single constructor site for status
  events. updateStatus keeps the monitor-plane consequences (publish,
  auto-resolve, listeners); reportLaunchProgress is the launch-plane
  executor and also serves the worker process, which has no Daemon.
- Launch failures gain machine-readable reasons launch_<step> (new law
  L9), keeping the error-artifact-then-verdict order of the old ladders.
- Terminal absorption replaces store-guard reliance: a launch
  observation on a terminal view is absorbed by the stepRun L4 guard
  instead of dying as a silently discarded append error (same fold
  outcome as before).
- The implicit initial queued (the fold default) is no longer
  materialized as a redundant event.
- nosemgrep whitelist: 47 -> 10 annotations (socket.go 40 -> 3; every
  survivor has a recorded disposition in run-state-machine.md section 6).
- Law tests: O8 joined the law-sweep observation set, so terminality,
  determinism, idempotent convergence and stream fixed-point now cover
  it; dedicated stage-mapping and failure-reason tests added.
- Docs in the same change set: run-state-machine.md sections 1/2/3/5/6/7
  (D-B1), AGENTS.md status-write-surface, roadmap B1 + watchlist.

Verified: go build ./..., go test ./internal/daemon, make lint, full
go test ./... (only the two pre-existing tmux-environment integration
failures, identical on main at f39a19b).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@proboscis proboscis merged commit 19d4bf2 into main Jun 12, 2026
3 checks passed
@proboscis proboscis deleted the feat/coupling-core-launch-plane branch June 12, 2026 17:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant