fix(fleet): verify fails-closed on unverifiable + interactive watch
- isSendAccepted now returns 'accepted' | 'draft' | 'unverifiable' (was bool)
- Blank/empty capture => 'unverifiable' => process.exitCode=1 with distinct
"could not verify delivery (blank/no response captured)" message; previously
blank was treated as success, violating FR-5 fail-closed semantics
- Draft line ('^> ') => process.exitCode=1 with "left as unsubmitted draft"
message; distinct wording from unverifiable case
- agent watch now dispatched through injectable InteractiveRunner (stdio:inherit)
instead of the capturing CommandRunner; tmux attach requires TTY passthrough
- Default spawnInteractive implementation uses node:child_process spawn with
stdio:'inherit'; injectable via FleetCommandDeps.interactiveRunner for tests
- Removed buildSystemdIsActiveCommand (dead code — exported but unused)
- Tests: blank=>exitCode=1, draft=>exitCode=1, real response=>exitCode=0,
watch dispatched through interactiveRunner not capturing runner
- PRD: added "Known limitations" section (heuristic verify, blank fails closed,
non-pi/claude draft detection is best-effort, watch requires TTY passthrough)
- Code comment on isSendAccepted notes pi/claude-specific draft heuristic
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RMoEx7hfdFGjUiCHuN1RRi
This commit is contained in:
@@ -75,6 +75,19 @@ observability and no safe way to watch a session.
|
||||
- Situational: run against the live `mosaic-factory` fleet; capture `fleet ps` output,
|
||||
a kill-and-detect cycle, a read-only `watch`, and a `send --verify` pass/fail pair.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- **Verify heuristic is best-effort:** `agent send --verify` uses a `>` -prefix draft
|
||||
heuristic that is specific to pi/claude TUIs. Draft detection for codex and opencode
|
||||
TUIs is best-effort only; those runtimes may not use the same input-line indicator.
|
||||
- **Blank capture fails closed:** Full-screen TUIs (claude, codex, opencode, pi) render
|
||||
blank for `tmux capture-pane`. When the captured output is empty, `send --verify`
|
||||
returns non-zero with an "unverifiable" message rather than silently succeeding. This
|
||||
is an intentional fail-closed design (FR-5).
|
||||
- **`agent watch` requires TTY passthrough:** `tmux attach` is interactive and must be
|
||||
run with inherited stdio. It cannot be captured through a pipe. Tests inject a fake
|
||||
`interactiveRunner`; the real implementation spawns with `stdio: 'inherit'`.
|
||||
|
||||
## Surfaces & parity (MVP-X1)
|
||||
|
||||
CLI lands this phase. TUI surface follows in the `packages/mosaic` wizard; webUI in
|
||||
|
||||
Reference in New Issue
Block a user