feat: adapt crew-dispatch path to omp v17.1.3 (Oh My Pi) - #1
Merged
Merged
Conversation
Commit ec09871 introduced 'firstmate's' inside a heredoc body nested in a command substitution; bash 3.2's lexer tracks quote state through the heredoc while scanning for the closing paren, so bash -n failed and every crew brief scaffold broke. Reword to 'the firstmate authority check'. Issue kunchenguid#166 documents this bug class.
omp (the renamed/extended Pi, 'pi --version' prints omp/17.1.3) is the pi adapter family; all facts verified live 2026-07-26 on omp v17.1.3 / herdr 0.7.1. Composer (the false-pending that broke every fm-send to an omp worker): omp draws a two-row rounded-box composer (top border ╭…╮ with model/status and a persistent auto session title, input row ╰─ <interior> ─╯) that matched none of the herdr classifier's three shapes, so the last transcript │ box row won the bottom-most scan and read pending forever. The shape now has one owner, fm_composer_omp_pair_find plus fm_composer_omp_strip_row in bin/fm-composer-lib.sh, integrated into the herdr, orca, and cmux classifiers (bottom-most pair outranks transcript boxes above it) and into the tmux cursor-row path (the input row alone identifies the composer there). The dead-shell/unknown refusal rule is untouched. Busy signatures: omp's footer is a braille spinner, a status phrase, and the literal ⟨esc⟩ (U+27E8/U+27E9); Pi 0.80.x's 'Working...' never appears. Added the ⟨esc⟩ alternative to the shared and pi-scoped busy regexes. Verified herdr's native agent get reports agent=pi but agent_status=idle through an entire active omp turn, so window_is_busy now corroborates a native idle against the pane tail exactly like crew_pane_is_busy; a human-blocked omp pane renders no footer, so corroboration cannot mask a real block. Harness detection: omp sets both OMPCODE=1 and CLAUDECODE=1 (compat shim); fm-harness.sh checked claude first and printed claude, so session start emitted the claude Stop-hook protocol inside omp sessions where those hooks never fire. OMPCODE=1 now wins and prints pi (no new adapter name). Tests that pin claude detection now scrub OMPCODE so an omp host shell cannot leak. Knowledge: harness-adapters pi section gains dated omp v17.1.3 facts (busy signature, composer shape, no trust dialog observed, /quit and turn_end verified, k3 thinking ceiling low/high/max via 'omp models', pi --list-models rejected, dual env markers, herdr identity); docs/verification records the dated commands and output.
…ot leak Upstream kunchenguid#1047's detection test predates omp-awareness: under an omp host shell the ambient OMPCODE=1 wins layer-1 detection before the fake kimi ancestry is consulted, so the ancestry case returned pi. Same leak class as the claude-pinned suites scrubbed in the omp adaptation.
…p in architecture
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
Adapt firstmate's crew-dispatch path to omp v17.1.3 (Oh My Pi, the renamed/extended Pi - 'pi --version' prints omp/17.1.3), which is the pi adapter family: the captain directed all crewmates run on harness pi with model kimi-code/k3, and firstmate's pi adapter was verified against Pi 0.80.6 which differs from omp. Fixes on this branch: (0) fix a bash 3.2 heredoc parse regression in bin/fm-brief.sh (apostrophe in a heredoc inside command substitution broke brief scaffolding entirely; issue kunchenguid#166 documents the bug class) by rewording 'firstmate's authority check' to 'the firstmate authority check'. (1) Teach the composer classifier omp's two-row rounded-box composer shape (top border ╭…╮ carrying model/status plus a persistent auto session title that is never content; input row ╰─ ─╯ whose spaces-only interior means empty): previously the last transcript │ box row won the bottom-most-match scan and read pending forever, so every fm-send to an omp worker false-reported 'Enter swallowed' though delivery succeeded. The shape has one owner (fm_composer_omp_pair_find + fm_composer_omp_strip_row in bin/fm-composer-lib.sh), integrated into herdr/orca/cmux classifiers and the tmux cursor-row path; the dead-shell/unknown refusal safety rule is deliberately preserved - per the captain's approved review decisions the herdr omp branch is identity-gated exactly like the Pi separated shape (one shared native identity read per classification; pi:idle/done/blocked accepts, working or unreadable identity refuses with unknown, a known non-pi agent keeps the generic verdict) and loses to an already-accepted lower Pi separated pair, so a stale omp box left on screen after a crash can never authorize typing into a live shell. orca/cmux have no identity primitive and their stale-box exposure equals the pre-existing bordered shape's. (2) Add omp's busy footer signature ⟨esc⟩ (literal U+27E8/U+27E9, not the locale-fragile braille spinner) to the shared and pi-scoped busy regexes; verified herdr's native agent get reports agent=pi but agent_status=idle through an entire active omp turn, so the corroborated busy observation has one shared owner (fm_busy_state_corroborate in bin/fm-tmux-lib.sh, captain-approved): native busy trusted outright, native idle and unknown fall through to the harness-scoped pane-tail signature, consumed by fm-watch.sh window_is_busy, bin/fm-pending-reply-lib.sh fm_pending_reply_backend_observation (prevents the secondmate reply-recovery clock starting mid-turn for omp workers), and bin/fm-crew-state.sh crew_pane_is_busy (a human-blocked pane renders no footer, so corroboration cannot mask a real block). (3) Harness detection: omp sets both OMPCODE=1 and CLAUDECODE=1 (compat shim) and fm-harness.sh checked CLAUDECODE first, printing claude inside omp sessions so session start emitted the claude Stop-hook supervision protocol that never fires; OMPCODE=1 now wins and prints pi (no new adapter name). Tests pinning claude or kimi ancestry detection now scrub OMPCODE so an omp host shell cannot leak into them (including one upstream kunchenguid#1047 kimi test with the same leak class). The branch is rebased onto origin/main with upstream kunchenguid#1047 (verified kimi crewmate adapter) and kunchenguid#1049 (scoped tmux busy detection) union-preserved: kimi's markerless-ancestry comment and moon-phase busy signature are kept verbatim, and the omp additions sit alongside them - do not treat the union as a mistake. Knowledge surfaces updated: harness-adapters pi section gains dated omp v17.1.3 facts (busy signature, composer shape, no trust dialog observed, /quit and turn_end verified, k3 thinking ceiling low/high/max per 'omp models', pi --list-models rejected, dual env markers, herdr identity), and docs/verification/runtime-backends.md + supervision.md record the dated commands and exact output. Deliberate scope exclusions: no AGENTS.md changes (harness-adapters skill owns the omp facts per the knowledge-placement tree), and two pre-existing baseline test failures (fm-backend-orca metadata-write case, fm-session-start concurrent-lock BASHPID case) reproduced on the clean tree and left alone as unrelated to this task. Delivery: the captain approved the fork path - push goes to origin https://github.com/kvkenyon/firstmate.git (the fork, whose GitHub parent is kunchenguid/firstmate), and the PR must be opened as a cross-fork PR targeting kunchenguid/firstmate main so the maintainer can review; do NOT open the PR against the fork's own main. This exact head (23ae4b8) already completed review/test/document/lint/push in run 01KYE8VG3XCT5RZXATD4HBWERM; only the pr step failed there because that run had cached the pre-fork target URL, now corrected.
What Changed
fm_composer_omp_pair_find/fm_composer_omp_strip_rowinbin/fm-composer-lib.sh), wired into the herdr/orca/cmux classifiers and the tmux cursor-row path, sofm-sendto an omp worker no longer false-reports "Enter swallowed"; the herdr branch is identity-gated (pi identity accepts, working/unreadable refuses withunknown) and loses to a lower Pi separated pair or lower unmatched separator, preserving the dead-shell refusal rule.⟨esc⟩busy footer to the shared and pi-scoped busy regexes and centralize corroboration infm_busy_state_corroborate(bin/fm-tmux-lib.sh) — native busy trusted, native idle/unknown falling through to the pane-tail signature — consumed byfm-watch.sh,fm-pending-reply-lib.sh, andfm-crew-state.sh.OMPCODE=1win over theCLAUDECODE=1compat shim inbin/fm-harness.shso omp sessions detect aspi, fix a bash 3.2 heredoc parse regression inbin/fm-brief.sh(apostrophe inside command substitution), scrubOMPCODEfrom claude/kimi ancestry test pins, and record the dated omp v17.1.3 findings in the harness-adapters skill plusdocs/verification/.Pipeline review flagged two issues on the omp classifier (pair ranking against lower separators, and a per-line ANSI-strip subshell on the hot path); both were auto-fixed and re-checked, with new fixtures in
tests/fm-backend-herdr.test.sh.Risk Assessment
✅ Low: Both previously reported issues are fixed narrowly and correctly — the omp pair is now ranked below every lower separator (with a regression fixture reproducing the exact failing sequence) and the per-line fork regression is collapsed to a single line-preserving strip — leaving a well-bounded, identity-gated, well-tested adapter change that matches every source-verifiable acceptance criterion.
Testing
Ran the targeted suites touched by this change (herdr backend, composer lib, crew-state, pending-reply, tmux submit/busy, brief, kimi/secondmate harness, turnend, watcher-lock, x-mode) — all pass. An initial run showed composer failures on this branch AND on the base commit; the cause was the harness shell's
LC_CTYPE=Clocale breaking multibyte glyph matching, and re-running underen_US.UTF-8made everything pass, including the two failures the intent described as pre-existing baseline breakage. For product-level evidence I drove a real tmux pane rendering an omp v17.1.3 screen and classified it with both this branch's and the base commit's libraries in the same run, capturing a before/after CLI transcript covering all four intent items: composerpending→empty(the false "Enter swallowed"), typed text stillpending, the⟨esc⟩busy footer flipping idle→busy with corroboration only when the footer is present, harness detectionclaude→piunder dual env markers, and the bash 3.2 heredoc parse offm-brief.shgoing from a syntax error to clean. No product failures found; temp copies of the base checkout were removed and the worktree is clean.Evidence: omp adapter end-to-end before/after transcript (live tmux pane)
=== 1. Live omp crewmate pane (tmux capture-pane) ====== │ captain: rebase onto origin/main and report │ │ crewmate: done, 3 commits replayed │ ╭─ kimi-code/k3 · ready · omp adapter adaptation ─────╮ ╰─ ─╯ [cursor_y=4 -> the '╰─ ... ─╯' input row] === 2. fm-send's post-Enter composer check on that same live pane ==== BEFORE (base c64ad1c): fm_tmux_composer_state -> pending AFTER (this branch): fm_tmux_composer_state -> empty ('pending' is what made every fm-send to an omp worker false-report "Enter swallowed") === 3. Typed text in the same omp composer must still read pending === ╭─ kimi-code/k3 · ready ─────╮ ╰─ report your bearings ─╯ AFTER (this branch): fm_tmux_composer_state -> pending === 4. omp busy footer during an active turn ==== ╭─ kimi-code/k3 · thinking ─────╮ ╰─ ─╯ ⟨esc⟩ to interrupt · 24s BEFORE (base c64ad1c): fm_pane_is_busy(pi) -> idle AFTER (this branch): fm_pane_is_busy(pi) -> busy corroboration owner (herdr native agent get says idle mid-turn): fm_busy_state_corroborate(native=idle, omp pane tail, pi) -> busy fm_busy_state_corroborate(native=idle, empty pane, pi) -> idle === 5. Harness detection inside an omp session (OMPCODE=1 + CLAUDECODE=1) === BEFORE (base c64ad1c): fm-harness.sh -> claude AFTER (this branch): fm-harness.sh -> pi real claude session (CLAUDECODE=1 only, unchanged): claude === 6. bash 3.2 heredoc parse of bin/fm-brief.sh (issue #166 class) == BEFORE (base c64ad1c): /bin/bash -n fm-brief.sh -> /tmp/omp-c64ad1c/bin/fm-brief.sh: line 314: unexpected EOF while looking for matching `)' /tmp/omp-c64ad1c/bin/fm-brief.sh: line 388: syntax error: unexpected end of file AFTER (this branch): /bin/bash -n fm-brief.sh -> okEvidence: New omp composer cases in the herdr suite (all ok)
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed ✅
bin/backends/herdr.sh:2014- The omp branch ranks its pair against FM_BACKEND_HERDR_PI_PAIR_LINE only. When the Pi scan found an INCOMPLETE separator below the generic match (herdr.sh:1991-1995 deliberately sets found=0 because 'a lower unmatched separator proves the generic row is stale'), FM_BACKEND_HERDR_PI_PAIR_LINE stays 0, so the guard passes trivially and a pi:idle identity flips found back to 1 using a rounded-box row that sits ABOVE that lower separator. Failing sequence: capture tail = '│ transcript │', '╭… ╮', '╰─ ─╯', then a lone >=8-char '─' rule below (a Pi composer mid-repaint, or a rule in tool output); identity reads pi:idle so the identity gate cannot catch it, and the verdict becomes 'empty' instead of 'unknown', letting fm-send submit into a pane whose bottom-most structure was judged non-injectable. This contradicts the change's own stated 'bottom-most still wins across shapes' invariant, and the new test only covers the complete-pair case. Fix: add '&& [ "$FM_COMPOSER_OMP_PAIR_LINE" -gt "$FM_BACKEND_HERDR_PI_LAST_SEPARATOR_LINE" ]' (it subsumes the PI_PAIR_LINE check, since a pair's closing row is always a separator), plus a fixture with an omp pair above a lone separator.bin/fm-composer-lib.sh:114- fm_composer_omp_pair_find forks a subshell plus a sed (fm_composer_strip_ansi) for EVERY captured line. The '╰' guard in fm_composer_omp_pair_scan is ineffective exactly where cost matters: an omp pane always renders '╰', so every composer poll pays 2 x FM_BACKEND_HERDR_COMPOSER_LINES (and the cmux/orca equivalents) processes, added on top of herdr's two existing per-line scans of the same capture — a per-poll regression on the hot classification path. Strip ANSI once over the whole capture before the loop (sed preserves line count, so row numbering is unchanged) and drop the per-line pipeline.🔧 Fix: rank omp pair below lower separators; strip ANSI once
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
bash tests/fm-backend-herdr.test.sh(includes the 7 new omp composer cases: empty-below-transcript, typed-below-empty, dark-truecolor border variants, identity gate, ranking below a live Pi separator, lone-separator → unknown)bash tests/fm-composer-lib.test.shbash tests/fm-crew-state.test.shbash tests/fm-pending-reply.test.shbash tests/fm-tmux-submit-busy.test.shbash tests/fm-brief.test.shbash tests/fm-kimi-harness.test.shbash tests/fm-secondmate-harness.test.shbash tests/fm-turnend-guard.test.sh,tests/fm-watcher-lock.test.sh,tests/fm-x-mode.test.shbash tests/fm-backend-orca.test.shandbash tests/fm-session-start.test.sh— the two failures the author flagged as pre-existing baseline failures both PASS under a UTF-8 locale; they were locale (LC_CTYPE=C) artifacts, not product failuresManual e2e: livetmuxpane rendering an omp screen, classified withfm_tmux_composer_statefrom both this branch and agit archiveof base c64ad1c side-by-side (empty composer, typed composer)Manual e2e:fm_pane_is_busy w piandfm_busy_state_corroborate idle <tail> piagainst a live pane showing the⟨esc⟩ to interruptfooter, plus the footerless negative caseManual e2e:OMPCODE=1 CLAUDECODE=1 bash bin/fm-harness.shvs base, andCLAUDECODE=1aloneManual e2e:/bin/bash -n bin/fm-brief.sh(bash 3.2.57) on this branch vs base✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.