fix(composer): make prompt detection locale-invariant - #4
Merged
Merged
Conversation
No-mistakes runs the suite with LC_ALL=C, where bash ${var#?} and
${var:0:1} count bytes and grep multi-byte character classes become
raw-byte sets. That misread idle placeholders after ❯/› as pending,
promoted box-drawing rows into bare composers, and classified U+2063
injections as user. Strip glyphs by exact prefix, match bare agent
prompts with case, classify inject markers by full prefix, and skip
the cd-guard shellcheck belt-check when shellcheck is absent.
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
Fix the five pre-existing Firstmate main-suite test failures that were blocking every PR at the red test gate (including the capacity branch). The failures only reproduced under no-mistakes' LC_ALL=C environment: (1) AFK inject e2e misclassified U+2063 digests as user because bash ${var:0:1} counts bytes; (2-4) composer/placeholder expectations failed because ${var#?} multi-byte glyph stripping and grep multi-byte character classes break under C locale, misreading idle placeholders after ❯/› as pending and promoting box-drawing rows into bare composers; (5) fm-cd-pretool-check shellcheck belt-check failed when shellcheck was absent. Fix the CODE for locale invariance (exact glyph prefix strip, case-based bare-agent-prompt match, full-prefix inject marker classification) and align the shellcheck test skip with the arm-pretool pattern. Keep the change strictly scoped to these five failures; do not touch capacity skill files.
What Changed
LC_ALL=C.Risk Assessment
✅ Low: Captain, the changes remain narrowly scoped to the five locale-dependent failures, and the follow-up safely resolves the prior custom Herdr regex portability risk by using a discovered UTF-8 locale or failing closed.
Testing
The supplied full-suite baseline passed; focused
LC_ALL=Ccomposer, fake-Herdr, real-tmux AFK, and shellcheck-absent checks also passed, with transcripts demonstrating correct placeholder, pending-text, box-row, sentinel, and skip behavior. The optional real-Herdr e2e skipped because Herdr is not installed, but its affected classifier path passed both the fake-Herdr suite and direct runtime verification.Evidence: Locale-invariant behavior transcript
ambient locale: LC_ALL=C LANG=C Claude idle placeholder after ❯ => empty Codex idle placeholder after › => empty Claude typed content after ❯ => pending Herdr box-drawing row => unknown U+2063 submission prefix=e281a3 classification=injectionEvidence: Focused LC_ALL=C regression tests
Evidence: Shellcheck-absent behavior
The complete cd-guard test passed with shellcheck deliberately absent from PATH, ending with: ok - shellcheck not installed, skippingPipeline
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:839- A customFM_BACKEND_HERDR_BARE_PROMPT_REno longer replaces the default matcher:❯and›are always accepted before the configured expression is consulted. This breaks the documented override contract and could authorize injection into a prompt an operator intentionally excluded. Apply the case matcher only when the configured value is the default, or confirm that the setting is now intentionally additive.bin/backends/herdr.sh:846- Custom prompt matching now depends on eitherC.UTF-8oren_US.UTF-8existing. Neither locale name is guaranteed; if both are unavailable, grep can fall back to bytewise matching with errors hidden, recreating the false-positive behavior this change fixes. Select an available UTF-8 locale or implement custom glyph matching without optional locale dependencies.🔧 Fix: Discover available UTF-8 locale for custom Herdr prompts
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"Configured full-suite baseline already passed:command -v tmux >/dev/null || { echo "tmux is required for e2e tests" >&2; exit 1; }; tmux -V; rc=0; for t in tests/*.test.sh; do echo "== $t =="; bash "$t" || rc=1; done; exit "$rc"LC_ALL=C LANG=C bash tests/fm-composer-lib.test.shLC_ALL=C LANG=C bash tests/fm-backend-herdr.test.shLC_ALL=C LANG=C bash tests/fm-afk-inject-e2e.test.shLC_ALL=C LANG=C bash tests/fm-afk-inject-herdr-e2e.test.sh(skipped: Herdr binary unavailable)PATH=<temporary PATH without shellcheck> LC_ALL=C LANG=C bash tests/fm-cd-pretool-check.test.shManualLC_ALL=Cruntime exercise offm_composer_classify_contentandfm_backend_herdr_composer_statefor❯/›placeholders, typed input, box-drawing rows, and U+2063 classificationReviewedab9cd7e...afd0644changed paths and confirmed no capacity skill files were touched.✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.