Conversation
|
Speaking as Kun's firstmate: First look on HEAD Closes claim: do not close #2483. Body currently has no Contract-class: new-default. This always-on change rewrites the fleet IDLE_RE safety contract: previously a match alone did not bypass shape/ANSI de-emphasis gates (bright placeholder-like drafts stayed pending); now any matching row is furniture and is excluded from the pending vote regardless of styling. Docs now warn an overly broad override can hide real typed text. That is default-behavior change, not a pure restore — even though the motivating incident is the away-mode wedge family. VISION.md (per-rule):
CI FAIL (blocking): Attestation: MATCH ( Overlaps: Blockers for author: (1) fix or intentionally update the failing daemon pending-guard test; (2) do not claim closes on #2483 until padded case is proven; (3) expect captain review for the new-default IDLE_RE gate once otherwise green. Merge-eligible N. Firstmate-flag no (not otherwise-ready). Security FYI: looser empty proof on IDLE_RE match could inject into a composer whose bright matching text was meant to stay pending — tip only, not a captain card while CI-red. |
|
Speaking as Kun's firstmate: Re-triage on newer tip Contract-class: new-default (unchanged). Always-on rewrite of fleet VISION.md (per-rule): same as prior stamp — Authority explicit fails auto-merge (always-on looser/different empty proof); Scripts/Fleet/Scope pass; Interface/Delegation mixed (unblocks away-inject for furniture hints, changes when empty is proven). Closes: body still has no Attestation: MATCH ( Otherwise completely ready except the new-default decision → waiting-captain. Firstmate-flag YES. Do not merge / do not rebase while held. Security FYI: IDLE_RE match no longer forces pending on bright furniture — mitigated by empty_seen requirement; tip only, not the merge gate (default-behavior is). |
…utrank empty verdict
…eption to safety gates
…lassify_rows (bin/fm-composer-lib.sh) let a box with ONLY an idle-regex-matching row default to `empty` with zero corroboration, breaking the pre-existing safety test in tests/fm-daemon.test.sh (bright/styled text matching a custom FM_COMPOSER_IDLE_RE override must stay non-empty). Fixed by requiring at least one row to independently prove `empty` before the box can resolve to `empty`; furniture rows are excused from voting but never themselves count as proof, so an idle-only box now reads `unknown` (safe) instead of `empty`. Verified this preserves the round-2 hint-row-poisoning fix and the ambiguous-geometry furniture test. Updated docs/configuration.md's FM_COMPOSER_IDLE_RE entry and a test comment to match. Ran fm-daemon.test.sh, fm-composer-ghost.test.sh, fm-composer-lib.test.sh, and 6 other composer-related suites locally — all pass (exit 0, no `not ok` lines)
2fdd608 to
d8c0936
Compare
Verified Scope
This PR fixes the reproducible Claude/tmux cases in the current classifier: the U+276F + U+00A0 idle row and a bright idle-hint row poisoning an otherwise empty bordered composer. It also preserves
pendingfor real text, including drafts that extend a placeholder prefix.The issue's reported padded production capture could not be reproduced from the available evidence, so this PR intentionally does not claim full resolution.
Intent
Captain's intent: convert the incident-driven Firstmate messaging-reliability backlog into shipped fixes now. Address GitHub issue #2483 in this fork and open a PR through the normal contribution flow, with exact linkage to issue #2483.
Issue #2483 substance: with away mode active on a Claude primary (tmux backend), the sub-supervisor daemon deferred every single injection from AFK entry: 6,117
inject deferred: supervisor composer not confirmed-empty (state=pending ...)lines over ~6 days at ~15s cadence, including long stretches where the primary pane was provably idle (empty bordered composer, no queued text, between turns). The max-defer escape fired and wrote an alarm marker, but with no active alert channel configured the net effect was silent: three green PRs awaiting merge sat undelivered for ~2 days. Root cause: Claude's standard bordered composer's idle row renders as the U+276F prompt followed by U+00A0 (NBSP) rather than a literally blank line, which the shared composer classifier misreads aspendingrather thanemptyon the tmux backend. The issue notes the sibling symptom already reproduces infm-send's submit verification (delivery unconfirmed; verdict=pendingon a live idle Claude pane) and cross-references #2361 for the herdr/pi case.What Changed
_fm_composer_classify_rowsinbin/fm-composer-lib.shnow excludes rows that exactly match the idle-placeholder regex (FM_COMPOSER_IDLE_RE/default) from the pending vote as "furniture" (fixes Claude's bordered composer idle row, which renders as U+276F followed by U+00A0/NBSP, being misread aspending), but requires at least one row to independently proveemptybefore the box can resolve toempty— an idle-only box with no corroborating row now readsunknowninstead ofempty.test_claude_nbsp_idle_row_is_emptyandtest_bright_furniture_row_does_not_poison_idle_verdicttotests/fm-composer-ghost.test.sh, and updatestest_unproved_empty_geometry_fails_closed's expected verdict for a lone idle-hint row frompending-unproventounknown.docs/configuration.md'sFM_COMPOSER_IDLE_REentry and.agents/skills/afk/SKILL.mdto document the exact-match furniture exclusion and which safety gates it can and cannot bypass.Progress on #2483
Risk Assessment
✅ Low: Small, well-scoped fix to _fm_composer_classify_rows (bin/fm-composer-lib.sh:976-1008): traced every branch (single idle row, hint-row poisoning, all-furniture box, placeholder-prefix draft) against the new exact-match furniture_re and empty_seen invariant, all consistent with the added/updated regression tests and with the pre-existing fm-daemon.test.sh safety test that motivated this round; docs/SKILL.md updates match the new behavior; no source-content-only tests introduced.
Testing
Ran the two test suites that cover this change end-to-end (fm-composer-ghost.test.sh and fm-daemon.test.sh) with clean exit codes and zero failures, then independently reproduced both the original #2483 hint-row-poisoning bug and the round-2 CI regression by sourcing the real classifier at the pre-fix and target commits against fake tmux fixtures — both defects are confirmed present before the respective fixes and absent at target.
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-composer-ghost.test.sh (35 ok, 0 not ok, exit 0)bash tests/fm-daemon.test.sh (126 ok, 0 not ok, exit 0), including test_pane_input_pending_preserves_bright_placeholder_like_draftManual repro: sourced bin/fm-tmux-lib.sh against a fake tmux with a single-row box containing only 'custom idle>' matching a custom FM_COMPOSER_IDLE_RE override -> 'unknown' at target d8c0936 vs 'empty' at pre-fix f9ec7ec (proves the CI regression this commit fixes)Manual repro: same harness with the ❯+NBSP idle glyph row plus a separate bright 'Ask anything...' hint row -> 'empty' at target d8c0936 vs 'pending' at pre-hint-fix bdfe642 (proves the original #2483 hint-row-poisoning bug is fixed)✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.