Skip to content

fix(bin): fail loudly for queued-unsubmitted steers - #6

Merged
sparkus merged 3 commits into
mainfrom
fm/fix-fm-send-silent-queue
Aug 3, 2026
Merged

fix(bin): fail loudly for queued-unsubmitted steers#6
sparkus merged 3 commits into
mainfrom
fm/fix-fm-send-silent-queue

Conversation

@sparkus

@sparkus sparkus commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Intent

Make bin/fm-send.sh fail loudly (or deliver) when a steer lands QUEUED-UNSUBMITTED in a parked lane, instead of exiting 0.

Bug (observed 2026-08-02/03, grok on herdr): a parked worker holds a foregrounded wait so its turn never ends. fm-send types the message into a numbered composer queue item (#N [fm-from-firstmate]...) that is never submitted, yet exits 0 with no output - firstmate believes the steer was delivered. Real cost: instructions sat undelivered for tens of minutes while reported delivered. Manual workaround was a follow-up Enter per queued item. Upstream kunchenguid#1474 describes this class of defect; ship to the fork sparkus/firstmate.

Required behavior in the submit-verification path (fm-send and backend submit primitives in fm-backend.sh / herdr.sh / fm-tmux-lib.sh as needed):

  1. After normal submit, VERIFY the message left the composer queue - a numbered pending #N [fm-from-firstmate] item still present means NOT delivered.
  2. If undelivered: retry Enter only (never retype) within the existing bounded retry budget.
  3. If still undelivered after the budget: exit NON-ZERO with a one-line diagnostic naming the queued-unsubmitted condition. Never exit 0 for a positively queued-unsubmitted message.
  4. Preserve existing behavior for the opencode busy-queued Enter exception and all documented composer-state semantics in fm-composer-lib.sh (empty/pending/unknown contract).

Acceptance: both outcomes covered by tests (retry-succeeds and retry-exhausted-fails-loud); normal idle submits stay green; opencode busy-queue still reports delivered (empty). Stay inside fm-send and the submit-verification path - do not redesign supervision, the watcher, or the composer classifier.

Implemented as: shared fm_composer_has_queued_unsubmitted detector; herdr and tmux submit cores scan after would-be empty, retry Enter, return queued-unsubmitted on exhaust; fm-send fails loud with a named diagnostic.

What Changed

  • Detect numbered [fm-from-firstmate] items that remain queued after tmux or Herdr submission, and verify the queue is readable and clear before reporting delivery.
  • Retry Enter without retyping, then return a named queued-unsubmitted failure on exhaustion while preserving the OpenCode busy-queue exception.
  • Document the submit semantics and add regression coverage for successful retries, exhausted retries, unreadable scans, normal submissions, and final-scan races.

Risk Assessment

✅ Low: Captain, the change is well-bounded and now satisfies the durable queue-verification invariant on both tmux and Herdr, including unreadable probes and final-attempt clear races, without disturbing the OpenCode exception.

Testing

At the exact target SHA, focused composer, tmux, fm-send, and Herdr tests passed; end-to-end CLI evidence confirmed Enter-only retry without retyping, non-zero named reporting after exhaustion, unchanged normal idle delivery, and preserved OpenCode busy-queue delivery. No UI artifact was applicable because this is a CLI behavior change.

Evidence: fm-send end-to-end CLI transcript

retry-succeeds: exit 0, typed once, Enter twice; retry-exhausted: exit 1 with queued-unsubmitted diagnostic, typed once, Enter twice; normal-idle: exit 0 on first Enter; opencode-busy: exit 0 after bounded Enter retries.

SCENARIO retry-succeeds
exit_code=0 typed_message_count=1 enter_count=2
result=delivered
transport: TYPE target=sess:fm-lane text=steer-the-lane
transport: ENTER target=sess:fm-lane attempt=1
transport: ENTER target=sess:fm-lane attempt=2

SCENARIO retry-exhausted
exit_code=1 typed_message_count=1 enter_count=2
diagnostic=error: text not submitted to sess:fm-lane (queued-unsubmitted: numbered pending item still in the composer queue; tried meta=/var/folders/bd/ky17fvwx45353ky4s2bg8ys80000gn/T/no-mistakes-evidence/01KZ3XASR2T6H2J63730VV7RT9/retry-exhausted/home/state/lane.meta; backend=from-meta)
transport: TYPE target=sess:fm-lane text=steer-the-lane
transport: ENTER target=sess:fm-lane attempt=1
transport: ENTER target=sess:fm-lane attempt=2

SCENARIO normal-idle
exit_code=0 typed_message_count=1 enter_count=1
result=delivered
transport: TYPE target=sess:fm-lane text=steer-the-lane
transport: ENTER target=sess:fm-lane attempt=1

SCENARIO opencode-busy
exit_code=0 typed_message_count=1 enter_count=2
result=delivered
transport: TYPE target=sess:fm-lane text=steer-the-lane
transport: ENTER target=sess:fm-lane attempt=1
transport: ENTER target=sess:fm-lane attempt=2

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 2 issues found → auto-fixed ✅
  • 🚨 bin/fm-tmux-lib.sh:407 - Required criterion 1 says “After normal submit, VERIFY the message left the composer queue,” but this helper maps a failed capture-pane to return 1—the same result as a readable pane with no marker. The new empty branch can therefore return empty after a transient verification-read failure while #N [fm-from-firstmate] remains; Herdr repeats this fail-open behavior at bin/backends/herdr.sh:2699. Make the probe tri-state (queued/clear/unknown) and permit success only after a readable clear scan.
  • 🚨 bin/backends/herdr.sh:2741 - Acceptance requires “retry-succeeds,” but on the final Enter an empty candidate whose first queue scan still sees the marker becomes pending; if the exhaustion rescan then successfully observes that the queue cleared, this else still emits pending. The tmux sibling has the same final-attempt race at lines 439–478. Preserve the candidate-empty proof and return empty when the final readable scan is clear, or classify both states from one final snapshot.

🔧 Fix: Captain, fail closed on unreadable queue verification
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • git status --short --branch and git rev-parse HEAD
  • Inspected git diff a5dd0059a97c4bf38e3843db0eb900350cac6016..5c42df5fa573c42e8e1e41c7d33de9d8f42d7c9a for the submit-verification path
  • tests/fm-composer-lib.test.sh
  • tests/fm-tmux-submit-busy.test.sh
  • tests/fm-send-strict.test.sh
  • tests/fm-backend-herdr.test.sh
  • fm-send-e2e-evidence.sh "$PWD" exercising retry success, retry exhaustion, normal idle submission, and the OpenCode busy-queue exception through the real bin/fm-send.sh entry point
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

sparkus added 3 commits August 3, 2026 07:32
Parked lanes (especially grok on herdr) can accept typed text into a
numbered composer queue without submitting it. The composer row then
reads empty, so fm-send exited 0 while the steer never landed.

After each Enter that would report delivery, scan the pane for a
numbered `#N [fm-from-firstmate]` item. Retry Enter only within the
existing budget; if the item remains, report queued-unsubmitted so
fm-send exits non-zero. Preserve the opencode busy-queue exception.
@sparkus
sparkus merged commit 4e01d7f into main Aug 3, 2026
10 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