fix(bin): refuse tasks-axi add/create --start so In flight always has a dispatch record - #5524
Conversation
…atch record Fixes kunchenguid#4753 Dispatch (bin/fm-spawn.sh) is the only path that moves a backlog row to In flight, because it creates the task record, status file, and inbox that go with the row. A row hand-placed there through the wrapper's `add --start` had none of those, and nothing later noticed, so the live-task count included work nobody was doing. The wrapper now refuses `add --start` (exit 2) and names the dispatch path; plain `add` and `start <id>` pass through unchanged, and the lifecycle transitions address tasks-axi directly so dispatch is unaffected. The issue's other half, a reconcile sweep in bin/fm-inactive-reconcile.sh that notices an In flight row with no task record, is left as is; this change closes the only path that creates such a row.
|
Speaking as Kun's firstmate: VISION.md read in full from live main Per-rule
contract-class: restore — restores the documented dispatch/record coupling for the wrapper's HEAD |
|
Speaking as Kun's firstmate: Thank you @karotkriss — merged (squash). The home-addressing wrapper now refuses |
… a dispatch record (kunchenguid#5524) * fix(bin): refuse tasks-axi add --start so In flight always has a dispatch record Fixes kunchenguid#4753 Dispatch (bin/fm-spawn.sh) is the only path that moves a backlog row to In flight, because it creates the task record, status file, and inbox that go with the row. A row hand-placed there through the wrapper's `add --start` had none of those, and nothing later noticed, so the live-task count included work nobody was doing. The wrapper now refuses `add --start` (exit 2) and names the dispatch path; plain `add` and `start <id>` pass through unchanged, and the lifecycle transitions address tasks-axi directly so dispatch is unaffected. The issue's other half, a reconcile sweep in bin/fm-inactive-reconcile.sh that notices an In flight row with no task record, is left as is; this change closes the only path that creates such a row. * no-mistakes(review): refuse create --start alias, not just add --start * no-mistakes(review): reword add --start guard docs to drop only-path overclaim * no-mistakes(review): scope add/create --start guard docs, drop universal claim
… a dispatch record (kunchenguid#5524) * fix(bin): refuse tasks-axi add --start so In flight always has a dispatch record Fixes kunchenguid#4753 Dispatch (bin/fm-spawn.sh) is the only path that moves a backlog row to In flight, because it creates the task record, status file, and inbox that go with the row. A row hand-placed there through the wrapper's `add --start` had none of those, and nothing later noticed, so the live-task count included work nobody was doing. The wrapper now refuses `add --start` (exit 2) and names the dispatch path; plain `add` and `start <id>` pass through unchanged, and the lifecycle transitions address tasks-axi directly so dispatch is unaffected. The issue's other half, a reconcile sweep in bin/fm-inactive-reconcile.sh that notices an In flight row with no task record, is left as is; this change closes the only path that creates such a row. * no-mistakes(review): refuse create --start alias, not just add --start * no-mistakes(review): reword add --start guard docs to drop only-path overclaim * no-mistakes(review): scope add/create --start guard docs, drop universal claim
… a dispatch record (kunchenguid#5524) * fix(bin): refuse tasks-axi add --start so In flight always has a dispatch record Fixes kunchenguid#4753 Dispatch (bin/fm-spawn.sh) is the only path that moves a backlog row to In flight, because it creates the task record, status file, and inbox that go with the row. A row hand-placed there through the wrapper's `add --start` had none of those, and nothing later noticed, so the live-task count included work nobody was doing. The wrapper now refuses `add --start` (exit 2) and names the dispatch path; plain `add` and `start <id>` pass through unchanged, and the lifecycle transitions address tasks-axi directly so dispatch is unaffected. The issue's other half, a reconcile sweep in bin/fm-inactive-reconcile.sh that notices an In flight row with no task record, is left as is; this change closes the only path that creates such a row. * no-mistakes(review): refuse create --start alias, not just add --start * no-mistakes(review): reword add --start guard docs to drop only-path overclaim * no-mistakes(review): scope add/create --start guard docs, drop universal claim
… a dispatch record (kunchenguid#5524) * fix(bin): refuse tasks-axi add --start so In flight always has a dispatch record Fixes kunchenguid#4753 Dispatch (bin/fm-spawn.sh) is the only path that moves a backlog row to In flight, because it creates the task record, status file, and inbox that go with the row. A row hand-placed there through the wrapper's `add --start` had none of those, and nothing later noticed, so the live-task count included work nobody was doing. The wrapper now refuses `add --start` (exit 2) and names the dispatch path; plain `add` and `start <id>` pass through unchanged, and the lifecycle transitions address tasks-axi directly so dispatch is unaffected. The issue's other half, a reconcile sweep in bin/fm-inactive-reconcile.sh that notices an In flight row with no task record, is left as is; this change closes the only path that creates such a row. * no-mistakes(review): refuse create --start alias, not just add --start * no-mistakes(review): reword add --start guard docs to drop only-path overclaim * no-mistakes(review): scope add/create --start guard docs, drop universal claim
… a dispatch record (kunchenguid#5524) * fix(bin): refuse tasks-axi add --start so In flight always has a dispatch record Fixes kunchenguid#4753 Dispatch (bin/fm-spawn.sh) is the only path that moves a backlog row to In flight, because it creates the task record, status file, and inbox that go with the row. A row hand-placed there through the wrapper's `add --start` had none of those, and nothing later noticed, so the live-task count included work nobody was doing. The wrapper now refuses `add --start` (exit 2) and names the dispatch path; plain `add` and `start <id>` pass through unchanged, and the lifecycle transitions address tasks-axi directly so dispatch is unaffected. The issue's other half, a reconcile sweep in bin/fm-inactive-reconcile.sh that notices an In flight row with no task record, is left as is; this change closes the only path that creates such a row. * no-mistakes(review): refuse create --start alias, not just add --start * no-mistakes(review): reword add --start guard docs to drop only-path overclaim * no-mistakes(review): scope add/create --start guard docs, drop universal claim
… a dispatch record (kunchenguid#5524) * fix(bin): refuse tasks-axi add --start so In flight always has a dispatch record Fixes kunchenguid#4753 Dispatch (bin/fm-spawn.sh) is the only path that moves a backlog row to In flight, because it creates the task record, status file, and inbox that go with the row. A row hand-placed there through the wrapper's `add --start` had none of those, and nothing later noticed, so the live-task count included work nobody was doing. The wrapper now refuses `add --start` (exit 2) and names the dispatch path; plain `add` and `start <id>` pass through unchanged, and the lifecycle transitions address tasks-axi directly so dispatch is unaffected. The issue's other half, a reconcile sweep in bin/fm-inactive-reconcile.sh that notices an In flight row with no task record, is left as is; this change closes the only path that creates such a row. * no-mistakes(review): refuse create --start alias, not just add --start * no-mistakes(review): reword add --start guard docs to drop only-path overclaim * no-mistakes(review): scope add/create --start guard docs, drop universal claim
… a dispatch record (kunchenguid#5524) * fix(bin): refuse tasks-axi add --start so In flight always has a dispatch record Fixes kunchenguid#4753 Dispatch (bin/fm-spawn.sh) is the only path that moves a backlog row to In flight, because it creates the task record, status file, and inbox that go with the row. A row hand-placed there through the wrapper's `add --start` had none of those, and nothing later noticed, so the live-task count included work nobody was doing. The wrapper now refuses `add --start` (exit 2) and names the dispatch path; plain `add` and `start <id>` pass through unchanged, and the lifecycle transitions address tasks-axi directly so dispatch is unaffected. The issue's other half, a reconcile sweep in bin/fm-inactive-reconcile.sh that notices an In flight row with no task record, is left as is; this change closes the only path that creates such a row. * no-mistakes(review): refuse create --start alias, not just add --start * no-mistakes(review): reword add --start guard docs to drop only-path overclaim * no-mistakes(review): scope add/create --start guard docs, drop universal claim
Intent
Fixes #4753
Running the backlog wrapper with
add ... --startputs a row In flight although no dispatch record, status file, or inbox exists for it, and nothing later notices, so the live-task count includes work nobody is doing.Make the wrapper refuse
add --start(dispatch is the only path that moves a row to In flight) so a hand-started row cannot exist without dispatch artifacts.This closes upstream issue #4753.
What Changed
bin/fm-tasks-axi.shnow rejects--startonaddand itscreatealias, exiting with code 2 and pointing the caller to add the row Queued and letbin/fm-spawn.shdispatch it;start <id>and plainadd/createstill pass through.docs/configuration.md, explaining that a hand-started row would lack the task record, status file, and inbox that dispatch creates and would otherwise count as live work nobody is running.test_wrapper_refuses_add_startcovering both spellings' refusal (exit 2, backlog unchanged, message names the dispatch path) and the still-allowedaddthenstart <id>flow.Risk Assessment
✅ Low: A small, well-bounded wrapper guard that refuses add/create --start with an order-independent check on $1, correct passthrough for start and other commands, accurate scoped docs, and a behavioral regression test that verifies refusal and passthrough.
Testing
Ran the focused suite tests/fm-tasks-axi.test.sh (all green, including the new add/create --start case) and drove a manual end-to-end transcript through the wrapper in an isolated split home.add --startandcreate --startare both refused with exit 2 and the message naming bin/fm-spawn.sh, and the backlog stays unchanged (no In flight row created). Plainaddstill writes a Queued row andstart <id>still transitions it to In flight, matching the intent's scope. An adversarial flag-firstadd --start hs-3is also refused. No UI surface exists for this CLI change; evidence is the CLI transcript.Evidence: add --start / create --start refusal CLI transcript
Source: add --start / create --start refusal CLI transcript
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 1 issue found → auto-fixed (3) ✅
bin/fm-tasks-axi.sh:102- The add --start guard only matches the literal commandadd([ "${1:-}" = add ]), buttasks-axi addhas a documented aliascreate. I verifiedtasks-axi create <id> "<title>" --startplaces the rowin_flightidentically toadd --start, sofm-tasks-axi.sh create hs-1 "x" --startpasses the guard untouched and reintroduces the exact In-flight-row-with-no-dispatch-record defecttasks-axi add --startcan mark a row In flight with no dispatch record, and nothing ever corrects it #4753 closes.createis an advertised alias on this human/agent-facing wrapper, so it is a reachable intended-usage path, not hypothetical. Earliest shared fix: match both spellings, e.g.case "${1:-}" in add|create). The new test (tests/fm-tasks-axi.test.sh:207) exercises onlyadd, so it does not cover this sibling path; extend it to assertcreate ... --startis also refused. The remedy corrects what the change already does (fully closing the only path), so it stays auto-fix.🔧 Fix applied.
2 issues (1 error, 1 warning) still open:
bin/fm-tasks-axi.sh:102- The add --start guard only matches the literal commandadd([ "${1:-}" = add ]), buttasks-axi addhas a documented aliascreate. I verifiedtasks-axi create <id> "<title>" --startplaces the rowin_flightidentically toadd --start, sofm-tasks-axi.sh create hs-1 "x" --startpasses the guard untouched and reintroduces the exact In-flight-row-with-no-dispatch-record defecttasks-axi add --startcan mark a row In flight with no dispatch record, and nothing ever corrects it #4753 closes.createis an advertised alias on this human/agent-facing wrapper, so it is a reachable intended-usage path, not hypothetical. Earliest shared fix: match both spellings, e.g.case "${1:-}" in add|create). The new test (tests/fm-tasks-axi.test.sh:207) exercises onlyadd, so it does not cover this sibling path; extend it to assertcreate ... --startis also refused. The remedy corrects what the change already does (fully closing the only path), so it stays auto-fix.bin/fm-tasks-axi.sh:101- The change's stated goal is that "dispatch is the only path that moves a row to In flight" so "a hand-started row cannot exist without dispatch artifacts". The new guard closesadd --start/create --start, buttasks-axi start <id>is a sibling command whose sole purpose is "Move a task to In flight (idempotent)" (verified viatasks-axi start --help). The wrapper passesstart <id>straight through (line 116*passthrough), sofm-tasks-axi.sh start hs-2moves a Queued row to In flight with no dispatch record, status file, or inbox - the exacttasks-axi add --startcan mark a row In flight with no dispatch record, and nothing ever corrects it #4753 condition, since those artifacts are created by bin/fm-spawn.sh's orchestration, not bytasks-axi start(dispatch calls fm_backlog_start ->tasks-axi startdirectly, bypassing this wrapper). The new test even codifies this hole as intended behavior: tests/fm-tasks-axi.test.sh:226 assertsstart hs-2passes through. So the invariant in the intent's rationale is not actually enforced. Whether the wrapper should also refusestart <id>(matching the same refusal forcase add|create, plus astartcommand guard) is a product-scope decision beyond the literal 'refuse add --start' requirement, so this needs your call - the remedy expands the change's behavior, not just corrects it. The literal required constraint (refuse add --start) is satisfied.🔧 Fix applied.
1 warning still open:
docs/configuration.md:123- Fix-round commit f7c1cad claims to 'drop only-path overclaim', but the reworded text retains an equivalent universal claim. docs/configuration.md:123 states 'So a hand-started row cannot exist without dispatch artifacts', and the header comment at bin/fm-tasks-axi.sh:39-40 says refusing add/create --start means 'this wrapper cannot place a row In flight without the dispatch artifacts bin/fm-spawn.sh creates'. Both are false:tasks-axi start <id>places a Queued row In flight with no dispatch record, status file, or inbox, and this same wrapper passesstart <id>straight through (bin/fm-tasks-axi.sh:117*passthrough; codified by tests/fm-tasks-axi.test.sh:226 assertingstart hs-2succeeds). So a hand-started row CAN exist without dispatch artifacts viastart <id>. This is the exact 'dispatch is the only path' overclaim the round-2 user instruction said to remove ('must say that add --start and create --start no longer create an In flight row without dispatch artifacts, not that dispatch is the only path'). Sibling sites to correct together: docs/configuration.md:123 (universal 'a hand-started row cannot exist without dispatch artifacts') and bin/fm-tasks-axi.sh:39-40 (universal 'this wrapper cannot place a row In flight without the dispatch artifacts'). Remedy: scope both to add --start / create --start specifically (they no longer place a row In flight without dispatch artifacts) and drop the universal wording, sincestart <id>remains a documented direct transition the wrapper passes through. Non-functional wording correction of an inaccuracy the change itself introduced, so auto-fix; it narrows, not expands, behavior claims.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
bash tests/fm-tasks-axi.test.sh(test_wrapper_refuses_add_start drives add --start, create --start, plain add, and start <id> through the real wrapper)Manual CLI transcript through bin/fm-tasks-axi.sh against real tasks-axi in an isolated split home:add --start,create --start, plainadd,start <id>, and adversarial flag-firstadd --start hs-3✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.