fix(bin): resolve captain calls against the closed-task archive - #3053
fix(bin): resolve captain calls against the closed-task archive#3053AgardnerAU wants to merge 4 commits into
Conversation
The completion gate resolved every entry in a task's decision_keys against data/backlog.md alone. tasks-axi prune moves closed tasks out of the backlog and into data/done-archive.md, so a finished investigation whose captain calls were correctly answered failed its own gate permanently and its cleanup was refused for good. Observed on a real archived call whose answer was recorded in full. Both gates now look for each entry in the home's configured closed-task archive as well as its live backlog. Only the lookup is widened: what counts as answered is still decided by verify_hold_durable, so an archived call closed with no recorded captain answer keeps failing exactly as it did while live. An archive that exists but cannot be read refuses both gates by name, because a check that could not look must never be recorded as a check that found nothing outstanding; an archive that does not exist yet is not an error and simply carries no tasks. The archive rows are handed to tasks-axi to parse rather than read by a second parser here, so the row format keeps one owner.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Reviews (2): Last reviewed commit: "no-mistakes(document): document configur..." | Re-trigger Greptile |
archive_path matched only a double-quoted value with nothing after it, so a home configuring its archive as a TOML literal string, or with an inline comment, silently fell back to data/done-archive.md. The gate then resolved captain calls against a different file than the one tasks-axi prunes into, and a correctly answered, pruned call failed complete, verify, and non-forced teardown anyway - the same defect this lookup exists to remove, wearing a config-parsing disguise. Verified against tasks-axi 0.2.5 which form it actually honours: basic (double-quoted) strings, literal (single-quoted) strings, and an inline comment after either all select the configured archive. All four are now read. The value is matched by its own quote delimiters rather than to end-of-line, so a '#' inside the path is not mistaken for a comment. The new regression drives the real prune through every honoured form and asserts the gate and teardown both accept a call archived at the configured path. It fails on the previous parser at the single-quoted form, reporting the default path in its refusal.
|
Speaking as Kun's firstmate: Reviewed HEAD Class: corrective. Lookup-only widening of VISION (per rule):
What is not cleared:
Security: no. This is waiting on the author, not the captain: address the archive-parser P1, confirm the Merge-eligible: NO. Captain-flag NOW: NO. |
|
Speaking as Kun's firstmate: Re-read since the earlier stamp on HEAD Class: corrective (unchanged). Lookup-only widening of What changed since the stamp:
VISION (per rule): unchanged, still aligns (honest gate after prune; missing recorded answer still fails; archive lookup is scripted; obligations stay closed by durable records). What is not cleared:
This is waiting on the author, not the captain: confirm or revert the Merge-eligible: NO. |
The defect
bin/fm-captain-hold.sh'scompleteandverifyresolved every entry in a task'sdecision_keysagainstdata/backlog.mdonly.tasks-axi prunemoves closed tasks out of the backlog and intodata/done-archive.md, so a finished investigation whose captain calls were correctly answered failed its own completion gate permanently, and its cleanup was refused for good.Reproduced against a real archived entry (
agfp-triage-waves, keyissue-2550-idle-timeout-gap), staged into a fixture home:no captain-held task issue-2550-idle-timeout-gap and no legacy identity agfp-triage-waves-decision-issue-2550-idle-timeout-gap in .../data/backlog.md, exit 1verified: agfp-triage-waves captain-call inventory, exit 0That entry resolves through the legacy
<origin>-decision-<key>identity, so archive lookup covers the legacy path too.The fix
Lookup only.
task_show_durabletries the live backlog first, then the configured archive. What counts as answered is still decided solely byverify_hold_durable, so an archived call closed with no recorded captain answer keeps failing exactly as it did while live. The gate's contract, the archive format, and the captain-hold lifecycle are deliberately untouched.archive_pathreads tasks-axi's own[markdown] archivesetting rather than hardcoding the path.archived_task_showrestages the archive's rows under the## Doneheading tasks-axi parses and hands them totasks-axi show --file, so the archive row format keeps exactly one parser.require_readable_archiveguards both gate paths: an archive that exists but cannot be read refuses by name. An archive that does not exist is deliberately not an error - nothing has been pruned yet, and the lookup finds no task, which still fails the gate. Fail-closed either way.command_holdandcommand_answerdeliberately still read the live backlog only; widening those would change write semantics, outside this fix's scope.Regression cover, both directions
tests/fm-captain-hold-lifecycle.test.shgains one behavioural test driving the realpruneand asserting observable exit codes and refusal text:complete,verify, and cleanupProved by three mutations, each caught:
Verification
Local, against the committed code:
fm-captain-hold-lifecycle,fm-teardown,fm-teardown-endpoint-safety,fm-bearings-snapshot,fm-classify-decision-key- 5 suites, 0 failures.bin/fm-lint.shandbin/fm-doc-audience-check.shclean. The no-mistakes pipeline completed review, test, document, and lint.CI has not run on this pull request and must not be read as green: fork pull requests here wait on an upstream maintainer to release workflow runs.