fix(bin): treat a torn-down blocker as resolved in the fleet snapshot - #25
Merged
rub-a-dub-dub merged 1 commit intoSep 22, 2026
Merged
Conversation
rub-a-dub-dub
force-pushed
the
fm/firstmate-stale-blocker-links-hide-decisions
branch
from
September 22, 2026 16:32
8d9d5d4 to
a97253d
Compare
fm-fleet-snapshot.sh's blocked-by resolver only marked a blocker resolved when that blocker's own row was still present in backlog.md with state=done. Once a landed blocker was torn down or aged out of Done retention, its id simply vanished from the lookup and every row still naming it read as permanently unresolved, disagreeing with tasks-axi's own resolver (which correctly treats a missing blocker id as no longer blocking) and hiding the dependent captain holds behind a disclosed gate instead of surfacing them as decisions. Update the affected fixtures: several exercised the old behavior directly (asserting a nonexistent blocker id stays "blocked" forever) or used a nonexistent id as a stand-in for a genuinely still-open external dependency, which the fix now resolves too - give those a real, undone row so the scenario they're testing stays genuine.
rub-a-dub-dub
force-pushed
the
fm/firstmate-stale-blocker-links-hide-decisions
branch
from
September 22, 2026 20:58
a97253d to
d57de31
Compare
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
Four captain decisions had been hidden for two days: each is linked
blocked-bya task whose blocker has already landed, but the bearings digest buckets any hold with an unresolved blocker asblocked, keeping it out of Captain's Call.What I found
Per the assigned scope, I first verified each of the four
blocked-bylinks against reality:firstmate-retain-report-single-shotblocked-byfirstmate-lint-debt-blocking-prs- the blocker genuinely landed (PR chore: annotate pre-existing shellcheck findings that fail CI lint #10, merged and an ancestor of main; three later merges all show Lint passing clean).firstmate-unreplayable-backlog-closeblocked-byfirstmate-lint-debt-blocking-prs- same, genuinely landed.cowork-skills-directory-phone-design-forksblocked-bycowork-skills-directory-selfcontained-folder- genuinely landed inclaude-cowork-skills(PR feat: add crash and reboot resilience for firstmate kunchenguid/firstmate#51, merged, ancestor of that repo's main).firstmate-answered-arm-incomplete-cleanupblocked-byfirstmate-retain-report-single-shot- not landed; still an active, unfinished, unmerged task. Correctly still blocked - left alone.That pointed at
data/backlog.md, but that file is captain-private runtime state, not tracked in this repo, so there was nothing to ship there. Digging into why the digest still showed all three as blocked despitetasks-axiitself already resolving them correctly (blocked_by: none) found the real bug:bin/fm-fleet-snapshot.shbuilds its own independent, regex-based view ofdata/backlog.mdrather than using tasks-axi's resolver. Its$resolved_idsmap only marks a blocker resolved when that blocker's own row is still present in the file withstate == done. Once a landed blocker is torn down or ages out of the Done retention window - which is exactly what happened to both named blockers here - its id simply disappears from the map, and every row still naming it reads as permanently unresolved rather than long-since-resolved.Fix
One-line change to the
unresolved_blocker_idsfilter inbin/fm-fleet-snapshot.sh: a blocker only counts as unresolved when a record for it exists and isn't done. An absent record (already torn down) now resolves, matchingtasks-axi's own semantics, so the two readers of one backlog can no longer disagree. Updated the file's own header comment (the single documented owner of this contract) to match.Kept the fix bounded to the resolver disagreement rather than unifying
fm-fleet-snapshot.shonto tasks-axi generally - that script's raw-markdown parsing covers many other fields (title, hold reason, links, etc.) and a full unification reaches well past this defect.Tests
Several existing fixtures exercised the old behavior directly, or used a nonexistent blocker id as a stand-in for a genuinely still-open external dependency (which this fix now also resolves). Updated those to either match the corrected semantics or given the "still open" ids a real, undone row so the scenario they're testing stays genuine. Full runs of every test file touching this code path (
fm-bearings-snapshot,fm-fleet-snapshot-view,fm-captain-hold-lifecycle,fm-classify-decision-key,fm-home-summary-refresh,fm-remote-secondmate-lifecycle-e2e,fm-secondmate-reconcile,fm-remote-backlog-handoff,fm-secondmate-lifecycle-e2e,fm-session-start) pass, plus a fullCI=true bin/fm-lint.sh.Verified the actual outcome against the live backlog, not just the code: after the fix, all three genuinely-unblocked holds - including the phone-layout decision pair - resolve to
hold_bucket: live/captain_actionable: trueand appear indecisions_open, while the fourth (still genuinely blocked) correctly stays a gate.Scope notes
data/backlog.md- it's outside this worktree and captain-private; the resolved state there was already correct, nothing needed clearing.