Repository navigation
fix: restore Claude control on Herdr without clearing ambiguous text - #12
Merged
Merged
Conversation
…r remainder ownership; 30s proof wait
…rvative proof behavior
MrGTV-love
force-pushed
the
fm/fm-herdr-claude-exit
branch
from
October 5, 2026 02:22
00b484a to
c795167
Compare
… portable serial 5. The full CI log identified the generation-6 header-collision wait. Its shared await_reply_result helper checked listener ownership only once; a listener exiting after that observation stranded the wait. Moved the ownership check into the existing polling loop, covering every caller without changing production Claude/Herdr behavior or weakening capture and acknowledgement assertions. Updated the existing verification documentation. A deterministic smoke using the real process-event listener reproduced the header-collision failure before the fix and passed afterward. Verification: bash tests/fm-remote-reply.test.sh completed with ALL TESTS PASSED; bash -n tests/fm-remote-reply.test.sh passed. Temporary smoke files were removed. No pipeline-control, publication, or other validation phases were invoked
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.
Intent
"why are any new lanes launching in tmux when I have requested herdr?" Earlier: "why are not using herdr with the other lanes. Why are we using tmux? I asked for it to be in herdr so observability is better. It also has other advantages". Standing preference: fix processes, not handicap them.
Context: all 7 Vernant lanes and their Claude workers still run on tmux, although every home's config/backend is herdr. Two things block Claude on herdr. (1) The herdr server has no teamclaude proxy environment; PR #8 (TeamClaude launcher) fixes that. (2) This task: on herdr, fm-control exit/relaunch (and slash commands such as /exit, /compact, /) never reach a Claude worker, so a Claude worker cannot be stopped, relaunched or compacted through firstmate. PR 8's validation failed 3 times because its test agent stalled on exactly this during a Herdr-lab relaunch. Upstream tracks it as kunchenguid/firstmate issues 6136 ("slash-command popup hides the composer payload") and 6210, both open.
Finish Claude control without deleting ambiguous typed text -> preserve-text-proof-30s
What Changed
/compact, public exit, and same-endpoint relaunch; document the proof timeout, color policy, and updated runtime evidence.Risk Assessment
✅ Low: The changes are bounded to Claude composer proof and color handling, conform to the recorded preservation decisions, and introduce no substantiated correctness, security, or unnecessary-component findings.
Testing
After change and prerequisite inspection, targeted regressions and isolated live Claude/Herdr scenarios passed following resolution of fixture consent, TLS, and paste-probe setup issues; rendered terminal evidence and product transcripts were captured, labs and scaffolding were removed, and no full-suite, lint, formatter, static-analysis, publication, or other pipeline phase was run.
/compactfollowed byNot enough messages to compact.in both launch shapes.FMHERDRRELAUNCH35276_28994, which existed only in its instructions./gate-proofinvocation produced Claude’s replyFMHERDRSKILL35275_20455; captured in the consolidated product evidence./coto/compact; delayed-native-calls.log records one literal send and one Enter, followed by the actual handler response./ex, known send failure, and an absent exit marker; the native command trace contains no Enter or Ctrl+U on this path.keep my noteunchanged without Enter or Ctrl+U.could not be sent, retained/exit keep my note, removed its marker, and issued no Enter or Ctrl+U./compactproof encounteringompareturned send-failed, preserved the exact draft, and issued neither Enter nor Ctrl+U.[Pasted text #1] keep my note; submit returned send-failed with no Enter or Ctrl+U.pactsuffix was cleared to an empty composer and returned send-failed; an actual oversized unbracketed burst also produced an owned truncated suffix that was safely cleared without Enter…[Pasted text #1 +9 lines]; the submitted transcript preserved all rows, and Claude retrieved the private token after an endorsement that did not repeat it./compactliteral; the first was deliberately dropped, and the second produced the real handler response without clearing the command.FMHERDRPONG35276_4745andFMHERDROPPONG35276_5820.Evidence: Rendered real Claude/Herdr terminal surfaces
Source: Rendered real Claude/Herdr terminal surfaces
Evidence: Preserved drafts, refusal results, and marker postconditions
Source: Preserved drafts, refusal results, and marker postconditions
Evidence: Native product command trace for preservation probes
Source: Native product command trace for preservation probes
Evidence: Swallowed Enter and identity-loss command trace
Source: Swallowed Enter and identity-loss command trace
Evidence: Native paste delivery and endorsed token readback
Source: Native paste delivery and endorsed token readback
Evidence: Validation selectors, isolation details, and resolved fixture failures
Source: Validation selectors, isolation details, and resolved fixture failures
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 3 issues found → auto-fixed ✅
bin/backends/herdr.sh:3507- The new timeout transition conflicts with “Finish Claude control without deleting ambiguous typed text”: it returns the same clear-authorizing result as an owned suffix. Concrete sequence: an initially empty Claude composer receives /compact; during delayed rendering, the operator replaces it with a /co draft. That strict prefix remains rendering until the deadline, then send_text_submit invokes Ctrl+U and deletes it. The unreadable-capture variant also permits blind deletion: failed reads default to rendering even if the operator has entered unrelated text. Related sites: bin/backends/herdr.sh:3480 (prefix classification), :3498-3501 (failed-read fallback), :3504 (owned-suffix result), :3552-3553 (timeout routed to clear), :3525-3527 (deletion before read-back), and :3289-3291 (documented timeout clearing). Unconditional failed-proof cleanup predates this branch, but remains reachable through the new preservation logic. Distinguish an unproven timeout from proven suffix ownership at await_payload and refuse without clearing on the former. Preserve the approved 30-second wait and immediate owned-suffix cleanup; this finding asks for review of the unresolved timeout behavior, not reversal of the accepted infix policy.tests/fm-herdr-submit-confirm-live-e2e.test.sh:62- The new production relaunch at tests/fm-herdr-submit-confirm-live-e2e.test.sh:286 creates a staged launch directory that cleanup never removes. bin/fm-spawn.sh:5396-5419 derives /tmp/fm-$PROD_ID+<SHA256-of-canonical-CONTROL_HOME>, then :5428-5435 writes launch.$SPAWN_GEN.sh there. Cleanup removes only the unhashed /tmp/fm-$PROD_ID and the fixture root, so every run reaching staging leaves the private launch script behind, including failure exits. Track this fixture's exact hashed staging directory and remove it after lab teardown, before deleting the control home; do not sweep other tasks' directories.docs/herdr-backend.md:602- The retained paragraph at docs/herdr-backend.md:602-609 still says a placeholder plus any literal remainder is cleared with Ctrl+U. That contradicts the newly added preservation contract at :589-590 and the implementation: for /compact with '[Pasted text chore: ignore graft cache files #1] keep my note', bin/backends/herdr.sh:3473-3477 returns foreign and :3560-3562 refuses without clearing. Narrow the old clear instructions to the approved owned-suffix case and describe ambiguous placeholder-adjacent literals as no-clear refusals.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
/compactfollowed byNot enough messages to compact.in both launch shapes.FMHERDRRELAUNCH35276_28994, which existed only in its instructions./gate-proofinvocation produced Claude’s replyFMHERDRSKILL35275_20455; captured in the consolidated product evidence./coto/compact; delayed-native-calls.log records one literal send and one Enter, followed by the actual handler response./ex, known send failure, and an absent exit marker; the native command trace contains no Enter or Ctrl+U on this path.keep my noteunchanged without Enter or Ctrl+U.could not be sent, retained/exit keep my note, removed its marker, and issued no Enter or Ctrl+U./compactproof encounteringompareturned send-failed, preserved the exact draft, and issued neither Enter nor Ctrl+U.[Pasted text #1] keep my note; submit returned send-failed with no Enter or Ctrl+U.pactsuffix was cleared to an empty composer and returned send-failed; an actual oversized unbracketed burst also produced an owned truncated suffix that was safely cleared without Enter…[Pasted text #1 +9 lines]; the submitted transcript preserved all rows, and Claude retrieved the private token after an endorsement that did not repeat it./compactliteral; the first was deliberately dropped, and the second produced the real handler response without clearing the command.FMHERDRPONG35276_4745andFMHERDROPPONG35276_5820.git diff --stat 6bec7da0431ca70b23e36af6e113fba13ede292c 3b8843701840a847cf5cfecfb569f2f6ad6e0dbcandcommand -v herdr claude jq bash python3 tmux.Executed 15 selected behavioral regressions fromtests/fm-backend-herdr.test.shand three Herdr exit regressions fromtests/fm-control.test.sh, using disposable selector drivers; exact selectors are recorded invalidation-manifest.json.Drove actual Claude Code 2.1.289 on Herdr 0.9.1 through disposable instrumented drivers based ontests/fm-herdr-submit-confirm-live-e2e.test.sh; every Herdr operation usedbin/fm-herdr-lab.shwith a named non-default session.Injected real composer edits during payload proof: foreign text, a strict prefix at the default deadline, a strict infix, and placeholder-adjacent foreign text; checked preserved content, absent exit markers, and no product Enter or Ctrl+U.Injected unreadable transport captures after literal delivery withFM_BACKEND_HERDR_PROOF_WAIT=2; verified public exit refusal and preservation of the actual draft.Completed a real composer prefix after proof began; verified/compactreached its handler with one literal send and one Enter.Ran public relaunch and exit in production/default-color and forced-truecolor shapes; verified the replacement acknowledged its private instructions and exit preserved the endpoint.Executed a disposable/gate-proofskill, ordinary reply requests, and a U+2063 operational payload; observed actual Claude responses.Used native bracketed terminal paste to produce[Pasted text #1 +9 lines]; after explicit user endorsement, Claude returned a token present only in the prior pasted payload.Injected a swallowed first Enter and omitted identity fields from subsequent real native status responses; verified the colored command retried Enter and reached the/compacthandler.Investigated and resolved fixture provisioning, external-import consent, and TLS setup failures using real startup captures and a CLI-owned debug log; scoped certificate trust to a disposable workspace bundle without changing system trust or credentials.Rendered actual terminal captures into HTML, archived exact driver sources and invocations, completed helper teardown traps, and confirmed removal of all owned disposable drivers and transient workspace files.✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.