Skip to content

feat: adapt crew-dispatch path to omp v17.1.3 (Oh My Pi) - #1

Merged
kvkenyon merged 9 commits into
mainfrom
fm/omp-adapter-adapt
Jul 26, 2026
Merged

kvkenyon merged 9 commits into
mainfrom
fm/omp-adapter-adapt

Conversation

@kvkenyon

Copy link
Copy Markdown
Owner

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

  • Teach the composer classifier omp's two-row rounded-box shape via a single owner (fm_composer_omp_pair_find / fm_composer_omp_strip_row in bin/fm-composer-lib.sh), wired into the herdr/orca/cmux classifiers and the tmux cursor-row path, so fm-send to an omp worker no longer false-reports "Enter swallowed"; the herdr branch is identity-gated (pi identity accepts, working/unreadable refuses with unknown) and loses to a lower Pi separated pair or lower unmatched separator, preserving the dead-shell refusal rule.
  • Add omp's ⟨esc⟩ busy footer to the shared and pi-scoped busy regexes and centralize corroboration in fm_busy_state_corroborate (bin/fm-tmux-lib.sh) — native busy trusted, native idle/unknown falling through to the pane-tail signature — consumed by fm-watch.sh, fm-pending-reply-lib.sh, and fm-crew-state.sh.
  • Make OMPCODE=1 win over the CLAUDECODE=1 compat shim in bin/fm-harness.sh so omp sessions detect as pi, fix a bash 3.2 heredoc parse regression in bin/fm-brief.sh (apostrophe inside command substitution), scrub OMPCODE from claude/kimi ancestry test pins, and record the dated omp v17.1.3 findings in the harness-adapters skill plus docs/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=C locale breaking multibyte glyph matching, and re-running under en_US.UTF-8 made 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: composer pending→empty (the false "Enter swallowed"), typed text still pending, the ⟨esc⟩ busy footer flipping idle→busy with corroboration only when the footer is present, harness detection claude→pi under dual env markers, and the bash 3.2 heredoc parse of fm-brief.sh going 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 -> ok

=== 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 -> ok
Evidence: New omp composer cases in the herdr suite (all ok)
ok - fm_backend_herdr_composer_state: an empty omp rounded-box composer below a transcript │ box reads empty (composer wins)
ok - fm_backend_herdr_composer_state: typed text in an omp rounded-box composer below an empty transcript │ box reads pending
ok - fm_backend_herdr_composer_state: an omp composer whose dark-truecolor border drops as ghost styling still reads its real text pending
ok - fm_backend_herdr_composer_state: an empty omp composer with dark-truecolor borders reads empty
ok - fm_backend_herdr_composer_state: an omp pair never authorizes a working or unreadable target, and a non-Pi agent keeps the generic verdict
ok - fm_backend_herdr_composer_state: an omp pair above an accepted Pi separator pair keeps the separated verdict
ok - fm_backend_herdr_composer_state: an omp pair above a lone unmatched separator reads unknown, never empty

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.sh
  • bash tests/fm-crew-state.test.sh
  • bash tests/fm-pending-reply.test.sh
  • bash tests/fm-tmux-submit-busy.test.sh
  • bash tests/fm-brief.test.sh
  • bash tests/fm-kimi-harness.test.sh
  • bash tests/fm-secondmate-harness.test.sh
  • bash tests/fm-turnend-guard.test.sh, tests/fm-watcher-lock.test.sh, tests/fm-x-mode.test.sh
  • bash tests/fm-backend-orca.test.sh and bash 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 failures
  • Manual e2e: live tmux pane rendering an omp screen, classified with fm_tmux_composer_state from both this branch and a git archive of base c64ad1c side-by-side (empty composer, typed composer)
  • Manual e2e: fm_pane_is_busy w pi and fm_busy_state_corroborate idle <tail> pi against a live pane showing the ⟨esc⟩ to interrupt footer, plus the footerless negative case
  • Manual e2e: OMPCODE=1 CLAUDECODE=1 bash bin/fm-harness.sh vs base, and CLAUDECODE=1 alone
  • Manual 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.

kvkenyon added 9 commits July 25, 2026 21:47
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.
@kvkenyon
kvkenyon merged commit ee75808 into main Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant