feat(bin): confirm tmux submits from semantic lifecycle records - #1391
Open
JaredHuynhning wants to merge 8 commits into
Open
feat(bin): confirm tmux submits from semantic lifecycle records#1391JaredHuynhning wants to merge 8 commits into
JaredHuynhning wants to merge 8 commits into
Conversation
Submit confirmation on the tmux path now reads the harness's own generation-stamped busy record (bin/fm-busy-lib.sh) instead of rendered composer characters: a trusted busy record with an advanced sequence after Enter confirms the submit, and a record-proven mid-turn pane accepts the Enter as queued. Claude, OpenCode, Pi, and pi-signed are covered through the existing kunchenguid#1327 hook wiring; codex, kimi, grok, unarmed tasks, and context-free sends keep the composer scraper as an explicitly labelled composer-fallback verdict, and the away-mode daemon's context-free call keeps its exact bare verdict. During bake-in (FM_SUBMIT_SEMANTIC_COMPARE=1) both signals are evaluated in parallel and a loud SUBMIT-CONFIRM DISAGREEMENT warning fires when they differ, so a mis-wired hook reporting submits that did not happen is caught instead of trusted. fm-send passes the task's semantic context through the backend dispatcher and surfaces how confirmation was attempted in error output. The old-bin conformance shim registers fm-busy-lib.sh as a copied sibling because fm-tmux-lib.sh now sources it.
…tures fm-tmux-lib.sh now sources fm-busy-lib.sh for semantic submit confirmation, so every synthetic root that symlinks fm-tmux-lib.sh needs the new sibling reachable or teardown dies at source time.
…nfirm Independent review rejected the first cut for confirming sends from an unchanged busy record: the spawn-time seed or a stuck record from a crashed turn confirmed every send forever (B1), a rejected Enter still confirmed (B2), a turn from a previously queued message could credit a swallowed Enter (B3), concurrent sends could claim one turn (B4), a contradicted confirmation still marked pending replies delivered (B5), the shipped default contradicted the no-pane-read claim (B6), and one test encoded the defect as intended behaviour (B7). Redesign: only a record-proven idle baseline enters the semantic path, and confirmation requires a trusted busy record with an advanced sequence observed after an Enter this send actually delivered, under a per-task submit lock that fails closed when contended and breaks dead holders' stale locks. Busy, unknown, and unreadable baselines route to the labelled composer fallback, so an unchanged record can never confirm. A send whose every Enter was rejected is send-failed. During bake-in the rendered composer is read once after the verdict; a contradicted confirmation is downgraded to unknown semantic-contradicted and every disagreement is appended durably to state/<id>.submit-disagreement, which teardown now removes along with the lock. The B7 test now proves busy baselines never confirm from the record, and new tests pin the rejected-Enter, contended-lock, stale-lock, downgrade, and default-environment single-read behaviours.
…orrelation Captain re-scope after the independent recheck: the per-task submit lock half-covered the concurrency problem (busy and ineligible sends bypassed it and ran the fallback concurrently) while adding failure modes of its own: a legitimate send could block up to 60 seconds on an unstamped lock, PID reuse could lock a task out repeatedly, and an interruption between the stale-lock rename and removal leaked a stale directory. A half-covering lock that can block real sends is worse than the unserialised status quo, so it is removed along with its two tests, and teardown no longer cleans a lock artifact. The five recheck-closed fixes stay: unchanged and non-idle records never confirm and route to the labelled fallback, a rejected Enter is send-failed, a contradicted confirmation downgrades so a pending-reply delivery is never committed on a contradiction, the default pane read stays post-verdict and veto-only, and the busy-baseline test proves the record alone never confirms. Known gaps stated in code and docs and owned by the queued fm-submit-correlation follow-up: no send-to-turn correlation (an unrelated turn can be credited to a send when the composer reads empty or unknown) and no concurrent-send serialisation; correlation needs a per-submit token the harness echoes back.
… semantic verification date
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Finishes the semantic-lifecycle migration on the tmux submit path (system-review item 1): an instruction's delivery is confirmed from the harness's own lifecycle signal, with rendered-composer scraping demoted to an explicitly labelled fallback.
What changed
empty turn-opened) only when a trusted busy record with an advanced sequence is observed after an Enter keystroke the send actually delivered. An unchanged record never confirms anything: busy, unknown, malformed, and stale baselines - including the spawn-time seed and a stuck record from a crashed turn - route to the rendered-composer core, whose verdict carries an explicitcomposer-fallbacklabel.send-failed, never a confirmation.FM_SUBMIT_SEMANTIC_COMPARE=1(the bake-in default) the composer is read exactly once, after the verdict; a confirmation contradicted by a still-pending composer is downgraded tounknown semantic-contradicted, and every disagreement is recorded durably instate/<id>.submit-disagreement(cleaned by teardown, documented in AGENTS.md).fm-sendaccepts only exactempty, so a pending-reply delivery is never committed on a contradiction - closing the suppression class behind the 9.5-hour incident recorded inbin/fm-tmux-lib.sh's header.bin/fm-busy-lib.sh's trust table, so codex and kimi flip automatically when their verification gates open.FM_SUBMIT_SEMANTIC_MIN_BUDGET) defaults to a conservative 2 seconds per attempt, sized to cover the writer chain (harness event dispatch, process spawn, writer lock, atomic write) on a loaded machine.Known gaps, deliberately not addressed here
Validation
Validated through the no-mistakes pipeline: two review rounds (three findings fixed in-pipeline: the test suite registered in the runner's family map, a stale lock comment removed, and the confirm-budget rationale corrected with the raised floor), full test suite, documentation, and lint all green.
tests/fm-tmux-submit-semantic.test.shproves transition-confirmed submits with zero pane reads at the post-bake-in setting and exactly one post-verdict read at the default, the contradiction downgrade with its durable record, the rejected-Enter refusal, and that busy baselines never confirm from the record.🤖 Generated with Claude Code