feat(supervision): surface captain decisions and waits - #4
Open
ItsFlow wants to merge 8 commits into
Open
Conversation
Firstmate could stop on a decision or an external delay without the captain ever receiving a self-contained explanation of what was needed, why it mattered, or what would happen next. Work sat parked and the fleet read as permanently waiting for no understandable reason. Three separate mechanisms dropped that information. A captain decision was recorded as a one-line title plus a one-line reason, so every renderer could only truncate it - and the backlog reader truncated the reason again at its first comma. A declared external delay was excluded from the captain-relevant verb set, which correctly stops wedge-nagging an idle pane but also removed the delay from every captain-facing surface. Supervision counted state/*.meta, so a home whose only live work was an unanswered decision reported as idle and the whole guard stack went silent. Add one derived, read-only contract over state firstmate already keeps durably - the backlog and the status event logs - rather than another status surface. Every open item is a decision or a wait; a wait re-declared past a threshold without clearing becomes a decision, derived from the keyed event fold rather than from its wording. Identities carry no prose, so a delay re-reported hourly stays one item and surfaces once. Record the plain language durably: fm-decision-hold.sh hold gains briefing fields for the concrete choice, why it matters now, what waiting costs, the options, and a recommendation, stored in the hold body and cleared when the hold resolves. A hold without one renders marked as not yet written rather than dressing up a raw operational note. Surface it in one captain-facing place and in ordinary replies: fm-attention.sh renders it already translated; fm-guard.sh surfaces a changed set before any in-flight test, closing the blind spot where it used to return early; fm-turnend-guard.sh stops a turn that would end on a decision the captain has never been shown, once per distinct set and never on a routine delay; and the session-start digest and supervision block carry it. Rendering is surfacing, so an ordinary read that changes nothing is never an alarm. Every supported primary harness and runtime backend is reviewed in docs/verification/supervision.md. Each passive adapter now selects its follow-up headline from the guard's own banner, so a captain decision is no longer announced as a supervision lapse.
…sion holds Point the maintainer-architecture and decision-hold mechanism surfaces at captain-attention.md rather than restating the contract, and record the durable briefing that fm-decision-hold.sh now stores on a captain hold.
The captain inbox board that landed on main carries evidence this contract missed: selecting decisions on the snapshot's captain_actionable flag also requires the backlog item's own kind to be "captain", but the documented way to gate ordinary work on the captain is tasks-axi hold <id> --reason "<reason>" --kind captain which leaves kind as ship. The flag is therefore false for exactly the threads this contract exists for. Reproduced on the real shape of the reported case: a ship item held for the captain rendered as "0 decisions need you, 1 thing is waiting", filed under waiting on something else with "next check: when the work it is waiting on finishes" - the fleet-is-always-waiting symptom, reproduced through the new surface itself. Select on the captain hold instead, whatever the item's kind says, and keep a hold with an unresolved blocker as a wait so a future-gated hold does not nag now. captain_actionable is deliberately left alone: bearings and the secondmate summary consume it with their own meanings and tests. This is also the rule the inbox board already uses, so the two captain-facing surfaces cannot disagree about what needs the captain. Record the relationship in both directions rather than leaving them reading as rival owners: this contract owns the derived set, its plain language, and the interrupt budget; the board is where the captain answers one in a browser. Correct one rationale the parser fix in the previous commit made stale: fm-inbox-view.sh no longer needs tasks-axi because the snapshot truncates a hold reason at its first comma, but it does still need it for the length cap and for the durable briefing, which the snapshot carries no body for.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Firstmate stops on a decision or an external wait without the captain ever getting a clear, self-contained explanation of what is needed, why it matters now, what waiting costs, and what happens next, so work sits silently stuck and the fleet reads as permanently waiting. Make every open captain decision and meaningful wait visible in one captain-facing place and in ordinary replies, deduplicated, still listed until answered, and cleared when resolved - a durable mechanism, not another prose reminder.
What Changed
Risk Assessment
✅ Low: The latest change is narrowly scoped to resetting the unknown attention marker after successful derivation and preserves the accepted single-writer and turn-end gate contracts without a material source-verifiable regression.
Testing
The direct shell-test invocation hit a non-executable-file setup issue, then the focused attention, turn-end guard, and session-start suites passed via
bash; the evidence script created a demo captain-attention home and transcript showing the rendered decision/waits, guard surfacing, deduplication after rewording, continued listing while open, and all-clear after resolution, with no working-tree artifacts left behind.Evidence: captain_attention_cli_transcript
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 3 issues found → auto-fixed (3) ✅
bin/fm-attention.sh:262- Intent requires a clear, self-contained captain explanation in ordinary replies, but--briefis explicitly firstmate-facing and only prints id/headline while this path still records the surfaced digest. Because session start uses marked--briefandfm-guard.shalso marks after a brief banner,.captain-attentioncan be spent before the captain-safe explanation is relayed, letting the turn-end guard allow the same decision silently.bin/fm-attention-lib.sh:339- Status-derived identities are only<class>:<task-id>:<key>, so an unkeyedpaused:orneeds-decision:that clears and later reopens uses the samedefaultidentity. If the earlier item was surfaced and no empty set was rendered in between, the digest at.captain-attentionstill matches and the new wait/decision will not surface or block; status identities need a phase/generation component or equivalent clearing behavior.bin/fm-attention-lib.sh:263- Intent requires each decision to carry what is needed, why it matters now, what waiting costs, and what happens next, butbriefing()treats any body containingCaptain briefing v1:as fullybriefedeven if those fields are absent. A partial hold update, for example only--recommend, will render as a briefed decision while omitting the choice/stakes/cost instead of warning that the captain briefing is incomplete.🔧 Fix: Fix captain attention surfacing gaps
2 issues (1 error, 1 warning) still open:
bin/fm-turnend-guard.sh:258- Intent requires Firstmate to stop on an unsurfaced captain decision, but in Claude mode the guard exits successfully as soon as the Stop-owned auto-arm proves recovery on an unhealthy watcher path, before runningattention_would_block. When in-flight work has no healthy watcher and an unsurfaced decision is also open, thisbudget_reset; exit 0path lets the turn end without the captain-call stop or the captain-safe rendering.bin/fm-attention-lib.sh:325- If the backlog projection command fails, attention substitutes{"records":[]}and continues, so backlog-backed captain holds and waits can disappear whilefm-attention.shstill renders and marks a partial or empty set. Treat snapshot failure as unavailable instead of recording a surfaced digest for incomplete attention state.🔧 Fix: Harden captain attention surfacing
1 warning still open:
bin/fm-attention-lib.sh:519- The unknown turn-end stop is bounded by a constant digest, and successful derivations never clear or rotatestate/.captain-attention-unknown. After one projection failure has been surfaced, any later failure is treated as already surfaced even if the set was readable in between, so a fresh broken projection can end a turn without the explicit unknown stop; reset the unknown marker on successful derivation or include a generation tied to known/unknown transitions.🔧 Fix: Reset unknown attention marker after recovery
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
tests/fm-attention.test.shdirect invocation returned permission denied because the test file is not executable; reran through bash without changing file mode.bash tests/fm-attention.test.shbash tests/fm-turnend-guard.test.shbash tests/fm-session-start.test.sh/var/folders/tc/llfmckm54ls5tzxm08q758lm0000gn/T/no-mistakes-evidence/01KYNC2P9QQR5M2Y4BMNX3C2DK/captain_attention_evidence.shFinal cleanup checks:git status --shortandfind . -maxdepth 2 -type d \( -name '.pytest_cache' -o -name 'node_modules' -o -name 'dist' -o -name 'build' -o -name '__pycache__' \) -print✅ **Document** - passed
✅ No issues found.
🔧 **Lint** - 1 issue found → auto-fixed ✅
🔧 Fix: Fix attention lint warnings
✅ Re-checked - no issues remain.
✅ **Push** - passed
✅ No issues found.