Skip to content

fix(bin): accept post-colon decision keys - #8

Merged
Bloh09 merged 2 commits into
mainfrom
fm/fm-brief-decision-key-grammar
Aug 10, 2026
Merged

fix(bin): accept post-colon decision keys#8
Bloh09 merged 2 commits into
mainfrom
fm/fm-brief-decision-key-grammar

Conversation

@Bloh09

@Bloh09 Bloh09 commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Intent

Fix the decision-key grammar mismatch between what workers naturally write and what the key parser accepts.

Observed bug (live on multiple tasks): workers write needs-decision: [key=x] ... (key AFTER the colon). _fm_decision_key in bin/fm-classify-lib.sh parsed that as key default, so fm-send --resolve-key x refused with "no open decision with that key" while wake-drain's OPEN DECISIONS section displayed the raw line as if it were keyed. The canonical grammar the parser expected is needs-decision [key=x]: ... (key BEFORE the colon), but brief scaffold rule 6 mentioned [key=<slug>] without showing placement, so workers guessed the post-colon form.

Fix with one semantic owner, robustness first:

  1. Make _fm_decision_key (bin/fm-classify-lib.sh) the single owner of key extraction and have it tolerate BOTH placements: needs-decision [key=x]: ... and needs-decision: [key=x] ... (same for blocked/paused/resolved verbs that carry keys). The first key token found in either position wins; absent key still folds to default. Mid-note [key=...] prose must not become a key. Invalid post-colon key tokens fall through to default rather than dropping the line.
  2. Update fm-brief.sh scaffold rule 6 to SHOW the exact canonical grammar with a concrete example (needs-decision [key=my-slug]: summary), so new briefs teach the preferred form.
  3. Regression tests: both placements for open and resolved lines, including that a post-colon-keyed open decision is closed by --resolve-key and by a resolved line in either form. The live failure (post-colon key parsed as default -> resolve-key refusal) must be covered by a test that fails on the old parser.
  4. OPEN DECISIONS incremental fold and fm-send's --resolve-key path both go through the shared owner so they can never disagree. Bump FM_OPEN_DECISIONS_FOLD_VERSION when fold semantics change.

Constraints: firstmate shared tracked material; shellcheck-clean; behavior tests through public interfaces. Acceptance: both key placements parse to the same key everywhere (fold, display, --resolve-key), scaffold rule 6 shows the canonical grammar with an example, regression tests cover both forms, no-mistakes pipeline green with a PR on origin (Bloh09/firstmate) against main.

Prior run failed only because the claude test agent hit a session limit after review already applied fold-version bump + invalid post-colon defaulting; local targeted suites already pass on the current head.

What Changed

  • Accept decision keys both before and immediately after the colon, using shared extraction for decision folding, display, and --resolve-key.
  • Fall back to the default key for invalid post-colon tokens and bump the incremental fold version for the new semantics.
  • Teach the canonical key-before-colon grammar in generated briefs and add regressions for open, resolved, and --resolve-key flows.

Risk Assessment

✅ Low: Captain, the change is well-bounded and satisfies the required grammar, shared-fold consistency, cursor-version migration, scaffold guidance, and behavioral regression coverage without a substantiated source defect.

Testing

Targeted classifier/fold, fm-send --resolve-key, and brief-generation behavior checks passed; manual evidence generation captured the emitted canonical rule and the end-to-end post-colon resolve regression result, and the worktree remained clean.

Evidence: Generated brief rule 6 showing canonical decision-key grammar
6. If a decision belongs to a human (product choices, destructive actions),
   append `needs-decision [key=my-slug]: {summary of options}` (key token BEFORE the colon) and stop. Firstmate will reply with the decision.
   A decision or blocker you opened stays open until a `resolved` line carrying its exact key lands; a later `done:` or `working:` line never closes it, even when the answer is what started that work.
   Firstmate's reply normally writes that closing line at answer time; when a blocker or wait clears WITHOUT a firstmate reply, append `resolved [key=my-slug]: {how it cleared}` yourself (same key placement if you opened it with one) as you resume.
7. Never stop, restart, or update the shared `no-mistakes` daemon - it is one instance serving
Evidence: Public fm-send post-colon regression result

ok - fm-send --resolve-key: post-colon worker key is closable

ok - fm-send --resolve-key: the answer send itself closes the open decision
ok - fm-send --resolve-key: post-colon worker key is closable
ok - fm-send --resolve-key: an answer that starts a workstream leaves no orphaned decision
ok - fm-send: a send without --resolve-key never closes a decision, and working/done still cannot
ok - fm-send --resolve-key: a key that is not open refuses loudly before anything is sent
ok - fm-send --resolve-key: a failed send never closes the decision
ok - fm-send --resolve-key: one answer closes each named key and only those
ok - fm-send --resolve-key: a marked local-secondmate answer closes with the plain answer text
ok - fm-send --resolve-key: a remote-secondmate answer closes the same local ledger, transport-only difference
ok - fm-send --resolve-key: a failed remote transport never closes the decision
ok - fm-send --resolve-key: --key, empty message, explicit targets, and malformed keys refuse loudly

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

✅ **Review** - passed

✅ No issues found.

✅ **Test** - passed

✅ No issues found.

  • bash tests/fm-watch-triage.test.sh — exercised shared key extraction, full/incremental decision folding, both open/resolved placements, invalid post-colon fallback, and mid-note exclusion
  • bash tests/fm-send-resolve-key.test.sh — exercised the real fm-send and wake-drain interfaces, including the original post-colon-key resolve failure
  • bash tests/fm-brief.test.sh — exercised generated ship, scout, and secondmate briefs
  • FM_HOME=&#34;$evidence_dir/brief-home&#34; bin/fm-brief.sh evidence-scout alpha --scout followed by extraction of emitted rule 6 — captured the generated user-facing grammar contract
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

_fm_decision_key now owns both placements (needs-decision [key=x]: and
needs-decision: [key=x]), so fold, OPEN DECISIONS, and fm-send --resolve-key
agree. Brief rule 6 shows the canonical pre-colon form with an example.
@Bloh09
Bloh09 merged commit 1c4612f into main Aug 10, 2026
13 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.

2 participants