Skip to content

fix: keep minted backlog task IDs dispatchable - #7

Merged
purple-phoenix merged 4 commits into
mainfrom
fm/fm-task-id-contract-v5
Jul 28, 2026
Merged

purple-phoenix merged 4 commits into
mainfrom
fm/fm-task-id-contract-v5

Conversation

@purple-phoenix

Copy link
Copy Markdown
Owner

Intent

Align minted Firstmate backlog task IDs with runtime validation so a freshly minted ID can never be rejected at dispatch. Keep 64 as the single authoritative creation maximum where fm_task_id_creation_valid lives. Because external tasks-axi 0.2.3 has no configurable mint maximum and an optional prefix can produce 65 characters, add a small Firstmate-owned creation wrapper that stages tasks-axi minting, safely fits only overlong minted heads while preserving the two-hex uniqueness suffix, rejects invalid explicit IDs before backlog mutation, and delegates valid creation back to tasks-axi. Cover overlong minting, the passing 64-character boundary, and a clear creation-time 65-character failure. Keep the change focused with no drive-by refactors; validate through PR and CI, with the captain retaining merge authority.

What Changed

  • Add a guarded backlog creation wrapper that validates explicit IDs before mutation and safely fits overlong minted IDs to the 64-character dispatch limit while preserving their uniqueness suffix.
  • Reuse the authoritative creation validator during dispatch and route backlog creation through the active Firstmate home.
  • Preserve deterministic captain-decision holds as the documented non-dispatchable exception without truncating their IDs.

Risk Assessment

✅ Low: Captain, the branch is focused, satisfies the task-ID creation intent, and the prior correctness and contract findings are resolved without introducing a material new risk.

Testing

The previously completed full baseline and focused task-ID/captain-hold suites passed; manual CLI verification with tasks-axi 0.2.3 demonstrated a fitted 64-character mint accepted by dispatch validation, a persisted 64-character boundary ID, and a clear creation-time 65-character rejection with no backlog mutation.

Evidence: Task ID creation and dispatch CLI transcript
$ tasks-axi --version
0.2.3

$ bin/fm-task-add.sh "Make AstroAI Admin usage focused and privacy preserving across every administrator workflow" --mint --prefix astroai-admin-privacy --json
{
  "ok": true,
  "action": "add",
  "task": {
    "id": "astroai-admin-privacy-make-astroai-admin-usage-focused-and-pr-dc",
    "title": "Make AstroAI Admin usage focused and privacy preserving across every administrator workflow",
    "state": "queued",
    "kind": null,
    "repo": null,
    "priority": null,
    "created": "2026-07-28",
    "closed": null,
    "deps": [],
    "hold": null,
    "links": [],
    "body": null,
    "blocked": false,
    "blocked_by": [],
    "held": false
  }
}
observed minted id: astroai-admin-privacy-make-astroai-admin-usage-focused-and-pr-dc
observed length: 64
observed preserved suffix: dc

$ FM_GATE_REFUSE_BYPASS=1 bin/fm-spawn.sh "$MINT_ID" <fixture-project> --backend tmux  # fixture intentionally has no brief
error: no brief at /var/folders/g0/z_4x96f92cgfpm7940cqvtt00000gn/T/no-mistakes-evidence/01KYKFQ95SRJQBHDVYNZH7BWBV/task-id-home-v3/data/astroai-admin-privacy-make-astroai-admin-usage-focused-and-pr-dc/brief.md
dispatch exit: 1 (ID accepted; execution reached the later brief check)

$ bin/fm-task-add.sh <64-character-id> "boundary passes" --json
{
  "ok": true,
  "action": "add",
  "task": {
    "id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "title": "boundary passes",
    "state": "queued",
    "kind": null,
    "repo": null,
    "priority": null,
    "created": "2026-07-28",
    "closed": null,
    "deps": [],
    "hold": null,
    "links": [],
    "body": null,
    "blocked": false,
    "blocked_by": [],
    "held": false
  }
}

$ bin/fm-task-add.sh <65-character-id> "boundary fails" --json
error: task id is 65 characters; maximum is 64
65-character creation exit: 2

$ tasks-axi show <64-character-id> --file data/backlog.md
task:
  id: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  title: boundary passes
  state: queued
  blocked: no
  blocked_by: none
  held: no
  hold_reason: "-"
  hold_kind: "-"
  hold_until: "-"
  kind: task
  repo: "-"
  priority: "-"
  created: 2026-07-28
  closed: "-"
  deps: none
  links: none
  body: ""

$ tasks-axi show <65-character-id> --file data/backlog.md
error: "Task \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" not found in this backlog"
code: NOT_FOUND
help[1]: Run `tasks-axi list --file=data/backlog.md` to see existing tasks
65-character lookup exit: 1 (item absent, proving no backlog mutation)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 3 issues found → auto-fixed (2) ✅
  • 🚨 bin/fm-task-add.sh:40 - The wrapper invokes tasks-axi from the caller’s current directory instead of the active FM_HOME. A normal absolute-path invocation after changing directories can therefore read or create the wrong backlog; resolve FM_HOME and run all target-backlog tasks-axi commands from there, while preserving explicit --file overrides.
  • 🚨 bin/fm-task-add.sh:146 - Under the supported Bash 3.2 with set -u, expanding an initialized-but-empty array raises an unbound-variable error. The documented fm-task-add.sh &#34;&lt;title&gt;&#34; --mint call has no STORE_ARGS, so it aborts here before creation; use the repository’s ${array[@]+&#34;${array[@]}&#34;} compatibility form and cover minting without optional flags.
  • 🚨 AGENTS.md:426 - The intent requires the wrapper to “reject invalid explicit IDs before backlog mutation,” and this changed contract says every backlog item is created through it, but bin/fm-decision-hold.sh:268 still calls tasks_axi add directly. Its &lt;origin&gt;-decision-&lt;key&gt; IDs can exceed 64 characters and mutate the backlog without the authoritative creation check; captain, confirm whether captain-decision items are intentionally exempt or migrate that creation call.

🔧 Fix: Fix task creation and captain-hold exemptions, captain
1 error still open:

  • 🚨 bin/fm-pr-lib.sh:46 - The captain explicitly required an “ownership/exemption note where the 64-character contract lives,” but this authoritative comment still says every creation entrypoint must enforce 64 characters while fm-decision-hold.sh intentionally creates overlong captain items. Update this contract beside fm_task_id_creation_valid to scope the maximum to dispatchable items and name the deterministic captain-item exemption; the AGENTS.md note alone does not satisfy the requested placement.

🔧 Fix: Document captain-hold task ID exemption
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"
  • Configured baseline: command -v tmux &gt;/dev/null || { echo &#34;tmux is required for e2e tests&#34; &gt;&amp;2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo &#34;== $t ==&#34;; bash &#34;$t&#34; || rc=1; done; exit &#34;$rc&#34;
  • bash tests/fm-task-add.test.sh
  • bash tests/fm-decision-hold-lifecycle.test.sh
  • Manual CLI evidence using tasks-axi 0.2.3: minted an overlong prefixed ID through bin/fm-task-add.sh, verified the fitted 64-character ID and preserved two-hex suffix, passed it into bin/fm-spawn.sh until the later brief check, persisted an explicit 64-character ID, and confirmed an explicit 65-character ID failed with exit 2 before backlog mutation
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@purple-phoenix
purple-phoenix merged commit 825fdc9 into main Jul 28, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant