This repository was archived by the owner on Aug 25, 2026. It is now read-only.
fix(herdr): adopt upstream reliability while preserving fork contracts - #77
Merged
Merged
Conversation
* feat(herdr): add optional presentation spaces * no-mistakes(review): Harden Herdr projection creation and spawn serialization * no-mistakes(review): Captain, disarm Herdr cleanup before launch submission * no-mistakes(test): Correct stale Orca metadata failure fixture * no-mistakes(document): Document Herdr presentation projection accurately
…nguid#790) * feat(herdr): order presentation worker spaces * fix(herdr): preserve focus during projected cleanup * no-mistakes(review): Serialize Herdr cleanup and protect active seeded tabs * no-mistakes(review): Serialize Herdr aborts with guarded focus regressions * no-mistakes(review): Fall back flat when Herdr serialization is unavailable * no-mistakes(test): Stabilize watcher startup and AFK handoff tests * no-mistakes(document): Correct Herdr ordering and focus documentation
…uid#821) * feat(herdr): correct all-home child presentation topology Inherit the presentation opt-in to secondmate homes, label new projected spaces with the approved corner format, insert each child under its owning parent under one session-scoped lock, and keep flat non-destructive fallback. * no-mistakes(review): Exclude secondmates from Herdr presentation projection * no-mistakes(review): Harden shared Herdr locks and ambiguous child ordering * no-mistakes(review): Use adjacency-only Herdr child ownership * no-mistakes(review): Reject foreign legacy projections safely * no-mistakes(review): Validate Herdr session sockets before projection * no-mistakes(test): Fix Herdr teardown fixture session socket metadata * fix(herdr): canonicalize presentation lock socket paths Always resolve the session socket parent directory so symlink parents such as /tmp -> /private/tmp cannot split the shared cross-home lock identity. Refuse relative socket paths. Clarify lock-unavailable warnings. * no-mistakes(test): Fix Bash-compatible GitLab merge request URL parsing * no-mistakes(document): Document all-home Herdr child topology * no-mistakes(lint): Quote fallback provenance string for ShellCheck
* feat: add required pinned Herdr CI lane Install exact Herdr 0.7.4 and Treehouse 2.0.1 with official assets and SHA-256 pins, run the real-herdr-gated family serially through fm-test-run with hard-fail on herdr-not-found, and keep portable Behavior free of claimed Herdr coverage. * no-mistakes(document): Consolidate real-Herdr CI documentation ownership * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes
…id#967) * fix(herdr): reclaim resumed task projections safely * no-mistakes(review): Enforce safe Herdr reclaim close boundaries * no-mistakes(document): docs: clarify Herdr restart projection contract
* Clean stale Herdr projections at session start * no-mistakes(document): Document stale Herdr session-start projection cleanup * no-mistakes(review): Enforce locked exact Herdr projection cleanup * no-mistakes(review): Fail closed on unverified session lock ownership * no-mistakes(review): Serialize session lock acquisition atomically * no-mistakes(document): Align session-start and Herdr cleanup documentation * no-mistakes(document): Generalize lock-refusal diagnostics * no-mistakes(lint): Avoid reserved keyword in concurrency test * no-mistakes: apply CI fixes * no-mistakes: apply CI fixes
…nchenguid#775) * fix(send): treat opencode busy-queued composer state as submitted When fm-send sends a message to a BUSY opencode crewmate on the tmux backend, opencode accepts the Enter and queues the message for the next turn, but leaves the typed text visible in the composer row. The submit-verification loop sees a pending composer, exhausts retries, and reports a false "Enter swallowed" failure while the message is actually delivered. Fix: after Enter retries are exhausted and the composer still shows pending, check fm_pane_is_busy. If the pane is busy (agent mid-turn, footer shows "esc interrupt"), the harness queued the message, so return "empty" (accepted). On an idle pane, keep returning "pending" (genuine swallow detection preserved). Regression tests cover four scenarios: - busy pane + pending composer -> empty (message queued) - idle pane + pending composer -> pending (genuine swallow) - busy pane + composer clears on first Enter -> empty - idle pane + composer clears on first Enter -> empty (existing path) * docs: document busy-queued Enter exception across backend docs and skills Add explanatory comments and backend documentation for the busy-queued Enter fix (opencode 1.18.4 accepts Enter mid-turn but keeps typed text in composer until the turn ends): - bin/fm-tmux-lib.sh: document the busy-aware fallback in the file header and above fm_tmux_submit_enter_core - .agents/skills/afk/SKILL.md: daemon-facing policy note - .agents/skills/harness-adapters/SKILL.md: harness-specific fact - docs/tmux-backend.md: submit-acknowledgement section with the busy-queue exception - docs/herdr-backend.md: record the known gap - docs/architecture.md: cross-reference in the daemon section * test(tmux): fix SC2181 and make busy-submit test executable
* fix(supervision): verb-aware captain relevance, AFK wedge, head-bound state Stop free-text tokens like "merged" from promoting nonterminal working: lines to captain-relevant, so AFK no longer permanently suppresses idle recovery. Defend wedge aging independently for nonterminal progress verbs, bind no-mistakes current-state attribution to code identity (not branch alone), and mark setup-complete as nonterminal in the ship brief scaffold. * no-mistakes(review): Enforce nonterminal suppression and head-bound run attribution * no-mistakes(document): Document current-code-bound run attribution * no-mistakes(test): Wait for stable Herdr shell readiness * no-mistakes(test): Make Herdr and watcher readiness tests deterministic * no-mistakes(test): Make tmux capture and watcher lifecycle deterministic * no-mistakes(document): Document corrected supervision contracts
…#809) * Send literal config reread after inherited config push When declared inherited config changes under an already-running secondmate, build a per-home instruction from validated destination post-write bytes and deliver it on the routed secondmate path. Unchanged config sends nothing; ABSENT represents removal; captain-shared is never inlined. Covers mid-session config-push and the locked bootstrap convergence path without hardening spawn against deliberate runtime choice. * no-mistakes(review): Fix config reread framing, partial propagation, and respawn order * no-mistakes(review): Send config rereads via durable single-line pointers * no-mistakes(review): Make failed config rereads retryable * no-mistakes(review): Make config reread retries generation-safe * no-mistakes(review): Make config rereads durable and ordered * no-mistakes(review): Drain retries, bound history, preserve detect-only read-only mode * no-mistakes(review): Retain write retries and quarantine stale respawn generations * no-mistakes(review): Preserve exact config reread retries and delivery order * no-mistakes(review): Preserve exact retry bytes and bounded quarantine pruning * no-mistakes(document): Consolidated config-reread documentation
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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
Adopt owner kunchenguid/firstmate Herdr reliability onto JTInventory/firstmate from fork/main while keeping Herdr as the backend and preserving JT readable tab labels and exact lifecycle identity. Include stale projection cleanup at session start, restart reclaim, parent grouping, optional presentation ordering and focus preservation, composer/send reliability, AFK hardening already on the path, and pinned real-Herdr CI coverage. Do not change the captain's local config/backend, dirty primary skills tree, OpenClaw or PR 475, and do not merge.
What Changed
Risk Assessment
Testing
The supplied baseline, read-only Herdr 0.7.4/protocol 16 smoke, real presentation and stale-cleanup lifecycle E2E, and full isolated behavior suite all passed; initial gate-worktree refusals were resolved using the supported test runner, no source changes or transient worktree artifacts remained, and no screenshot was produced because the end-user surface is terminal/Herdr lifecycle behavior represented by CLI transcripts.
Evidence: Herdr intent E2E summary
Concise reviewer-facing proof covering flat spawn, projection ordering, focus, restart reclaim, stale cleanup, composer/send, AFK, labels, and pinned CI.Evidence: Full behavior suite
Complete transcript from the supported isolated behavior runner, including real Herdr presentation and cleanup E2E.Evidence: Real Herdr read-only smoke
ok - real Herdr smoke: client protocol 16 and live server verified (read-only)Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 7 issues found → auto-fixed (11) ✅
.github/workflows/ci.yml:163- The required “pinned real-Herdr CI coverage” is not enforced. This lane runsreal-herdr-gatedwithout enablingFM_HERDR_E2EorFM_HERDR_SMOKE; several mapped scripts therefore exit successfully as opt-in skips, while--fail-on-gate-skip 'herdr not found'rejects only that exact skip reason. The lane can pass without exercising substantial real-Herdr coverage.tests/fm-afk-inject-herdr-e2e.test.sh:39- The AFK Herdr E2E now enters its readiness loop before provisioning the lab, sourcing the backend, or creating the pane. Variables includingPANE_ID,CONTAINER, andTARGETare consequently unset, so enabling this test causes a timeout or immediate failure. Restore the removed provisioning and task-creation setup before this loop.bin/fm-session-start.sh:274- The required “stale projection cleanup at session start” is only wired into the newfm-session-start.shwrapper, but the authoritative startup instructions still direct operators to runfm-bootstrap.shandfm-lock.shseparately, and no executable call site invokes this wrapper. Following the documented lifecycle therefore bypasses cleanup. Make the wrapper the documented entrypoint or integrate cleanup into the established locked startup path.bin/backends/herdr.sh:2133- The required “composer/send reliability” remains incomplete for the mandated Herdr backend. When the baseline composer is busy, queued OpenCode submission can intentionally leave text visible; this branch retries and then returns pending instead of recognizing the accepted queue operation. The repository's adapter documentation also labels this as a known Herdr gap.bin/fm-spawn.sh:249- The new abort trap no longer cleans up flat-Herdr panes. A pane is created before later fallible operations, but abort cleanup is armed only for Orca projections; failures such as workspace resolution leave an untracked live pane, and a retry can create a duplicate lifecycle endpoint. This contradicts the required exact lifecycle identity.bin/backends/herdr.sh:2149- Herdr kill now reports success when target preparation fails and suppresses allpane closefailures without confirming that the pane disappeared. Teardown trusts this success and can remove lifecycle state while the agent remains live. Propagate close/preparation failures and confirm absence before returning success.bin/backends/herdr.sh:1538- After a successful replacement-tab creation, missing IDs cause reclaim to return flat fallback without rolling back any known new pane or failing closed when the mutation cannot be identified. A partial Herdr response can therefore leave an extra shell/tab and block exact reclaim. Roll back known resources, and return the documented post-mutation uncertainty result when identity is unavailable.🔧 Fix: Harden Herdr lifecycle and real-CI coverage
10 issues (8 errors, 2 warnings) still open:
.github/workflows/ci.yml:167- The required “pinned real-Herdr CI coverage” is still unenforced. This passesskip:to a runner that searches forskip: $token, producing the impossible patternskip: skip:; ordinary gated skips therefore remain successful. Add explicit fail-on-any-skip behavior and use it here.tests/fm-install-herdr.test.sh:81- The portable suite includes this contract test, but it still requires the removed--fail-on-gate-skip 'herdr not found'workflow text. The portable CI job will fail deterministically. Update the assertion to the corrected any-skip contract.bin/backends/herdr.sh:2152- The required composer/send reliability is incomplete for busy slash-command submission. A first Enter can fill an autocomplete placeholder while leaving the composer pending, but every busy-baseline pending state is now reported as delivered, so the necessary second Enter is never sent. Distinguish queue acceptance from autocomplete before returning success.bin/backends/herdr.sh:2140- An Enter transport failure is suppressed. With a busy baseline, the unchanged pending composer is then treated as successful delivery, causing callers to discard or acknowledge a message that was never submitted. Returnunknownorsend-failedwhenfm_backend_herdr_send_keyfails.bin/backends/herdr.sh:2169- An already-absent pane makespane closefail, so teardown refuses to remove stale metadata and its worktree even though the requested endpoint is already gone. Confirm a dead pane as idempotent success before attempting close; continue failing closed on unknown state.bin/backends/herdr.sh:1539- The required exact lifecycle identity is violated when focus restoration fails after replacement creation. This early return runs before rollback, leaving the known new pane alive while reclaim refuses the launch. Attempt exact rollback before returning the focus error.AGENTS.md:84- The authoritative layout saysconfig/secondmate-harnessmay contain harness, model, and effort tokens, but the resolver strips all whitespace and treats the result as one harness name; section 4 instead defines a separatesecondmate-profile.json. Following line 84 therefore breaks secondmate launch. Restore the single-name format and separate profile entry..agents/skills/secondmate-provisioning/SKILL.md:73- The changed skill promises that mid-sessionfm-config-push.shpublishes and sends aCONFIG_REREADinstruction, but that script only propagates files and prints its report; it never callsfm_config_send_reread_nudge. Running secondmates keep stale configuration. Either wire the promised locked generation-and-delivery path or correct the claimed behavior..agents/skills/harness-adapters/SKILL.md:140- The mandatory adapter reference still labels busy-queued Herdr submission a known gap, while this target implements it. The AFK skill and architecture documentation repeat the stale boundary, which can lead supervising agents to make incorrect recovery decisions. Align these references with the final send contract.bin/backends/herdr.sh:210- The Herdr adapter has grown to roughly 2,700 lines and now combines projection journals, ordering/focus, reclaim, composer parsing, events, and core lifecycle operations. Extract the cohesive presentation-projection subsystem into a sourced helper to reduce cross-feature coupling without changing behavior.🔧 Fix: Harden Herdr lifecycle, delivery, and CI contracts
8 issues (5 errors, 3 warnings) still open:
bin/fm-teardown.sh:810- Projected teardown suppresses pane-close or focus-lock failure, then deletes task metadata and reports success. This can leave a live pane untracked and contradicts the required “exact lifecycle identity”; preserve state and fail teardown unless exact pane absence is confirmed.bin/backends/herdr.sh:1199- Aftertab createsucceeds, partial IDs or later husk-removal verification failures return without exposing or rolling back the new endpoint. The spawn abort trap therefore cannot remove it, contradicting required “exact lifecycle identity.”bin/backends/herdr.sh:1207- Flat restart reclaim closes restored husk tabs directly without checking whether the tab is active or restoring the prior focus. Herdr may move the captain to another tab, contradicting required “focus preservation.”bin/backends/herdr.sh:2182- Busy-queue acceptance relies on the one-time pre-loop status. After an autocomplete retry, the original turn can become idle; a swallowed later Enter that leaves the exact text visible is still reported delivered, contradicting required “composer/send reliability.” Require contemporaneous busy-state proof for each retry.bin/fm-config-inherit-lib.sh:171- The changed documentation promises guarded propagation ofdata/captain-shared.md, but this compatibility entry point explicitly performs config-only propagation. Operators are subsequently told to trim local captain preferences to pointers that may not exist; implement the promised shared-file contract or remove those instructions.bin/fm-test-run.sh:138- This isolated, credential-free real-Herdr marker/send E2E is classified aslive-harness-optin, so neither portable CI nor the required Herdr lane executes it. Move it intoreal-herdr-gatedto complete the required “pinned real-Herdr CI coverage” for this production send path.AGENTS.md:154- The authoritative inheritance instructions omitconfig/herdr-presentation-spaces, and later say config-push is only for cases where reread nudges are unnecessary even though it now sendsCONFIG_REREAD. Align these instructions with the implemented allowlist and delivery behavior.bin/fm-config-push.sh:25- CLI help says nonzero status is limited to propagation errors, but the new path also exits nonzero when CONFIG_REREAD publication or delivery fails. Update the exit-status contract so operators diagnose the correct failure.🔧 Fix: Harden Herdr lifecycle, inheritance, and CI
9 issues (7 errors, 2 warnings) still open:
bin/backends/herdr.sh:1249- Post-create rollback failures are suppressed with|| true. If close or absence confirmation fails,create_taskreturns without exposing the new IDs, so spawn cannot clean up the endpoint. This still contradicts required “exact lifecycle identity.”bin/backends/herdr.sh:1125- Restart reclaim refuses to replace a restored husk when that husk is the active tab. Since Herdr restores the previously focused tab, relaunching that task can fail until the captain manually changes focus, contradicting required “restart reclaim” and “focus preservation.”bin/backends/herdr.sh:655- Teardown ignores the focus-preserving close result and succeeds whenever the pane is dead. If close succeeds but exact focus restoration fails, the failure is silently discarded, contradicting required “focus preservation.”bin/fm-teardown.sh:763- Projected teardown returns and resets the worktree before acquiring the presentation lock or confirming pane absence. A later close refusal preserves metadata but leaves it pointing to a destroyed worktree, contradicting required “exact lifecycle identity.”bin/fm-teardown.sh:835- A presentation journal with incomplete or mismatched metadata bypasses the confirmed-close path, then suppresses generic kill failure. Metadata is subsequently deleted even if the pane survives, contradicting required “exact lifecycle identity.”bin/fm-spawn.sh:837- Secondmate launch still calls config-only propagation, although the changed operator contract says launch also convergesdata/captain-shared.md. Fresh and recovery launches can start without the authoritative shared preferences.bin/backends/herdr.sh:2224- After typing text, an unreadable native status returnsunknownbefore Enter is sent;fm-send.shtreats that verdict as success. This leaves messages unsubmitted and deterministically breaks the newly gated plain-shell marker E2E, contradicting required “composer/send reliability” and “pinned real-Herdr CI coverage.”bin/fm-config-inherit-lib.sh:266- Callers pass the active data directory as a fourth argument, but this helper ignores it and hardcodes$src_home/data. WithFM_DATA_OVERRIDE, bootstrap can propagate stale or unintendedcaptain-shared.mdcontent; accept and use the explicit source-data directory.bin/fm-test-run.sh:815---fail-on-any-gate-skiponly checks the first non-empty output line. A test that prints a diagnostic beforeskip: ...can exit successfully and leave the required lane green; scan every line beginning withskip:.🔧 Fix: Harden Herdr recovery, teardown, and inheritance contracts
5 issues (4 errors, 1 warning) still open:
bin/backends/herdr.sh:2256- An unreadable native baseline sends one Enter and immediately returnsunknown, bypassing composer inspection and retries. Becausefm-send.shtreatsunknownas success, autocomplete can consume that Enter while leaving the request unsubmitted, contradicting required “composer/send reliability.”bin/fm-spawn.sh:269- Failed focus-preserving rollback falls back to generic Herdr kill and suppresses its result. This can close the captain’s active replacement tab without restoring focus, or leave a failed-to-close pane alive with no durable identity, contradicting required “focus preservation” and “exact lifecycle identity.”bin/backends/herdr.sh:1278- Whentab createmutates successfully but returns neither ID and follow-up discovery fails or is ambiguous, abort cleanup emits no identity or uncertainty record. Spawn therefore exits while the new endpoint may remain untracked, still contradicting required “exact lifecycle identity.”bin/fm-teardown.sh:798- Flat Herdr teardown and presentation journals with incomplete endpoint metadata use generic kill without the presentation lock or focus snapshot/restore. Closing a non-active last pane can move the captain to another workspace and race presentation mutations, contradicting required “focus preservation.”bin/fm-teardown.sh:826- Journal retirement occurs after the fallible worktree return. If pane closure succeeds but worktree return fails, retry can no longer revalidate the now-dead endpoint, so it deletes metadata while retaining the journal; future same-ID projection launches then fall back flat until manual cleanup.🔧 Fix: Harden Herdr send and lifecycle uncertainty handling
3 errors still open:
bin/backends/herdr.sh:1266- Flattab createreturns immediately on any nonzero CLI result. Herdr may accept the mutation before a transport failure, but this path records neither an exact cleanup target nor durable uncertainty, so a retry can create a duplicate endpoint. This contradicts the required “exact lifecycle identity”; capture the result and persist workspace/label uncertainty whenever rollback cannot be proved.bin/backends/herdr.sh:2271- For a pending composer, contemporaneous native stateunknownfalls through and sends Enter again. If the first Enter already queued the message while leaving its text visible, retries can submit it twice. This contradicts required “composer/send reliability”; retry only explicit autocomplete and returnunknownfor pending text unless current state positively provesbusy.bin/fm-teardown.sh:821- Forced secondmate teardown ignores failures fromcleanup_firstmate_home_children; recursive cleanup at line 662 does the same. Because the script does not useset -e, it continues deleting parent state after an unconfirmed child-pane close, leaving a live child untracked. This contradicts required “exact lifecycle identity”; propagate both failures before deleting any parent home or metadata.🔧 Fix: Harden Herdr mutation and teardown failure handling
2 errors still open:
bin/backends/herdr.sh:1285- After a failedtab createreturns no response IDs, this path promotes a unique same-label tab from a later listing into rollback authority. Because readable labels are non-unique and external Herdr actions do not share this lock, Firstmate can close a foreign tab. This contradicts required “exact lifecycle identity”; use only response-derived identity and otherwise persist session/workspace/label uncertainty.bin/backends/herdr.sh:2287- The wildcard maps both currentidleand unreadable states tounknown. For a swallowed Enter, exact text remains pending and currentidleproves it was not accepted as a busy queue, butfm-send.shtreatsunknownas success and acknowledges the unsent message. This contradicts required “composer/send reliability”; returnpendingfor current idle and reserveunknownfor unreadable state.🔧 Fix: Enforce Herdr identity and truthful pending verdicts
1 error still open:
bin/backends/herdr.sh:2275- The required “composer/send reliability” is still violated. The changedidle) printf 'pending'branch sends marked Codex secondmate traffic intofm-send.sh’s final-Enter fallback, but Herdr’s dispatcher calls an undefinedfm_backend_herdr_submit_enter. Underset -eu, the send exits 127 without submitting the message. Implement the Herdr primitive with the expected verdict contract or prevent this fallback from dispatching to Herdr.🔧 Fix: Implement truthful Herdr final Enter submission
2 errors still open:
bin/backends/herdr.sh:2317- The required “composer/send reliability” is contradicted when final confirmation becomes unreadable. This helper returnsunknown, butfm-send.shrejects onlypendingandsend-failed; because this fallback starts from positively pending text, a swallowed final Enter can therefore be falsely acknowledged. Treatunknownas unconfirmed failure on this final-after-pending path.bin/backends/herdr.sh:2295- The required “composer/send reliability” is contradicted because the delayed fallback sends Enter before verifying that the composer still containsexpected_text. During the preceding settle delay, the text can be consumed or replaced, causing unrelated human input to be submitted and reported successful. Preflight exact composer ownership before Enter; handle empty, mismatched, and unreadable states without submitting foreign text.🔧 Fix: Harden Herdr final Enter ownership verification
2 errors still open:
bin/backends/herdr.sh:2296- The required “composer/send reliability” is contradicted because anemptypreflight is promoted to confirmed delivery without this helper sending Enter or observing a submit-active state. During the settle delay, a user clear or TUI reset is indistinguishable from successful submission. Returnunknownunless delivery has independent confirmation.bin/backends/herdr.sh:2302- The required “composer/send reliability” is contradicted because exact pending text still receives another Enter when the native baseline isunknown. The actual state may be a busy queue that accepted a prior attempt, so this can duplicate submission—the pending/unknown condition earlier logic deliberately refuses to retry. Send only with affirmative idle proof; otherwise returnunknownwithout transport.🔧 Fix: Require idle proof for Herdr final Enter
1 error still open:
bin/backends/herdr.sh:2294- The required “composer/send reliability” is still contradicted. The changed hunk samplesbaselinebefore capturing composer ownership, then later trusts that earlieridleresult. If the pane becomes busy while the composer is being read, another Enter is sent and can duplicate a submission accepted by the previous attempt. Capture exact pending ownership first, then obtain affirmative idle proof immediately before Enter.🔧 Fix: Order Herdr ownership before idle proof
✅ Re-checked - no issues remain.
🔧 **Test** - 1 issue found → auto-fixed ✅
bash bin/fm-run-behavior-tests.sh🔧 Fix: Restore flat Herdr spawning without presentation locks
✅ Re-checked - no issues remain.
bash bin/fm-run-behavior-tests.shPipeline-provided baseline:bash bin/fm-run-behavior-tests.sh(passed)FM_HERDR_SMOKE=1 bash tests/fm-backend-herdr-smoke.test.shInitial directtests/fm-backend-herdr-presentation-e2e.test.shattempts were safely refused because this is a gate worktree; retried successfully through the repository-supported isolated runnerenv -u TMUX -u TMUX_PANE FM_TEST_JOBS=4 TMPDIR=/tmp/no-mistakes-evidence/01KYDB8XPV3F2D278AE5W3264G bash bin/fm-run-behavior-tests.shgit status --short && git diff --name-only && git diff --cached --name-only🔧 **Document** - 1 issue found → auto-fixed ✅
tests/fm-backend-herdr.test.sh:3001- Captain, the focused Herdr suite still fails its explicit metadata-matchedfm-send --keyrouting assertion. Fixing executable behavior is outside this documentation-only task.🔧 Fix: Isolate Herdr routing test from gate refusal
✅ Re-checked - no issues remain.
🔧 **Lint** - 1 issue found → auto-fixed ✅
🔧 Fix: Remove unused Herdr lint variables
✅ Re-checked - no issues remain.
✅ **Push** - passed
✅ No issues found.