Repository navigation
fix: keep no-change OMP watcher turns silent - #265
Merged
Merged
Conversation
OMP 18.10.1 re-prompts a final message whose only content is signed thinking (features.unexpectedStopDetection defaults to "mechanical"; turn-recovery.ts #handleUnexpectedAssistantStop), so a wake turn with nothing for the captain could not end silently and firstmate wrote a filler line such as "Captain, standing by." to stop the retry loop. OMP has no per-turn silent-stop API, so the primary extension now: - lets a wake-only turn end with the marker [fm:silent], which is text and therefore never retried in mechanical mode; - rewrites that marker, or a whole-message no-change line, to "…" via the assistant_message hook; OMP's chat view renders dot-only text as nothing; - only does so in an episode a watcher wake opened with no captain input (user message or user-attributed custom message) and no captain-facing branch merge; every other turn keeps its text. The routine branch-merge prefix moves into the shared dispatch lib so the primary can tell routine notes from captain-facing merges. Replay on the 19-20 Oct primary transcript hides 146 of 434 final text messages, all pure no-change lines.
The [fm:silent] marker streamed visibly before the assistant_message rewrite replaced it. A wake-only turn now ends with "…" directly: it is text, so OMP's mechanical unexpected-stop path never retries it, and OMP's chat view renders dot-only text as nothing in every streamed frame. The no-change backstop keeps rewriting whole-message no-change lines on wake-only episodes to the marker. In an episode the captain joined, a dot-only final text is emptied so OMP re-prompts for a visible answer, as it does for any silent stop. The real-SDK test now streams replies in delayed chunks and asserts the silent wake turn draws zero visible lines in every streamed frame.
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
Stop the primary firstmate (OMP harness) from sending "no-change" chat lines to the captain on turns that were started only by a watcher wake and found nothing for him. Captain approved building this on 20 Oct. This is firstmate shared tracked material (.omp/extensions, docs, tests), so firstmate-coding-guidelines apply.
Problem (measured): a 48 h audit found 43% of firstmate's chat texts were no-change lines ("Captain, standing by." 84x, "Nothing new needs you." ...), burying real captain asks. AGENTS.md section 8 already says waiting is silent and no-change updates are not captain-facing, but on OMP a turn that ends with no visible text triggers OMP's own recovery nudge ("You said you would continue with a tool call or action but stopped ... Give the final answer now", up to 3 attempts), so firstmate emits a filler line to stop the nudge loop.
Requirement: trace the real cause first (not a phrase filter first); find under exactly which conditions the nudge fires and whether OMP offers a supported way to end a turn deliberately silent (extension hook, turn-end API, setting, tool); prefer the supported mechanism; only if none exists, use the smallest extension-side approach (a fixed marker the Firstmate OMP extension recognises, which stops the nudge and hides the marker). A phrase filter may only be a backstop for wake-only turns and must never hide anything on a turn the captain started.
Constraints: captain-initiated turns are never suppressed. Real outcomes, decisions, PR-ready and failure reports from wake turns still show. No change to watcher or wake semantics, wake draining or acknowledgement, or turn-end supervision guards (docs/turnend-guard.md). Nothing was tested on the live primary session; everything ran in isolation.
Acceptance criteria:
Findings (put these in the PR body, per firstmate):
Decisions and tradeoffs:
What Changed
…, which OMP renders invisibly throughout streaming without triggering mechanical recovery. Add a wake-only no-change backstop, preserve substantive outcomes and captain replies, and request a visible answer when the captain receives a dot-only response.Risk Assessment
✅ Low: Captain, the change is bounded, preserves captain-facing outcomes, and the prior fix correctly resets episode state on session replacement and aborts.
Testing
Focused regressions and isolated OMP 18.10.1 sessions passed streaming visibility, recovery, captain guards, substantive reports, branch classification, session replacement, and abort checks. Captured rendered HTML, frame data, and CLI transcripts. Historical replay remains untested because the required private transcript was unavailable within the authorized boundary. No source changes remain.
Evidence: Live OMP scenario transcript
Evidence: Actual OMP rendered chat frames
Evidence: Focused regression results
~/.no-mistakes/evidence/01M5BGZB4PZNGE3E9FE5XNNJGY/streamed-frames.json)~/.no-mistakes/evidence/01M5BGZB4PZNGE3E9FE5XNNJGY/live-driver.mjs)Evidence: Cause verification and validation limits
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 1 issue found → auto-fixed ✅
.omp/extensions/fm-primary-omp.ts:261- Episode flags survive native session replacement. If a captain turn is interrupted before a text-bearing final, captainJoined remains true across /new or /resume; the next watcher-only turn has its ellipsis erased at line 284, restoring the recovery nudge this change should prevent. Both flags (lines 261–262) reset only on a text-bearing stop (lines 297–302), so wakeOpened can likewise leak into another session and incorrectly enable the backstop at line 286. Reset the episode classification on session_switch before the existing replacement handler delivers wakes (.omp/extensions/fm-primary-omp.ts:487).🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
omp --versionconfirmed 18.10.1.bun add @oh-my-pi/pi-coding-agent@18.10.1installed the matching SDK inside the disposable worktree directory.Rantest_silent_wake_turn_episode_rulesandtest_silent_wake_turn_with_real_sdkfromtests/fm-omp-primary.test.shwith workspace-local temporary directories.Ran the evidence-preservedlive-driver.mjsthrough Bun against real OMP sessions and a local delayed streaming provider.Captured every assistant update through OMP'sAssistantMessageComponent.render(80)and exported the actual rendered lines to JSON and HTML.Inspected matching OMP recovery settings, classifier, retry implementation, and extension API types to verify the documented cause and API limitation.Removed the disposable SDK, test homes, and drivers;git status --shortwas empty.✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.