Repository navigation
VC-807: confirm a minted harness launch before it moves the resume seed; skip announce for --version/--help/housekeeping and nested runs - #921
Merged
hussainph merged 3 commits intoOct 19, 2026
Conversation
The wrapper announced and minted for every invocation, so 'claude --version', 'claude mcp list' or 'codex --help' repointed the running harness and overwrote the resume seed, and Resume session ran a phantom id or the wrong binary. - Wrapper: skip the announce/mint for adapter-declared non-session argv (--version/--help and housekeeping subcommands), and run a harness nested inside a running one of its kind (its own session markers set) exactly as outside Volli. - Host: hold a minted id as pending; the harness and its seed move together only when that harness's startup hook, or a hook naming the id, arrives. - Host: an announce that changes harness without a mint clears the foreign seed, so resume falls back to the new harness's latest.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…-resume-runs-the-wrong-harness-or-a-phan
…-resume-runs-the-wrong-harness-or-a-phan
This was referenced Oct 18, 2026
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.
Defect
The generated harness wrapper called
volli session harness <id>(with--mintfor argv-id harnesses: claude-code, cursor) on every invocation inside a Volli terminal, whatever the arguments. The host treated each call as a launch:harnessSessionIdwith a fresh uuid at once ("Overwrites, always"), and repointedactiveHarnessId;activeHarnessIdand kept the previous harness's id.Resume reads the two fields together (
pty/scope.ts), so after ordinary housekeeping commands:claude --version/claude mcp list/claude doctor/claude updatewith seed A → Resume session ranclaude --resume '<phantom>'(no conversation found);codex --help(or a real codex closed before its first turn) after a claude session →codex resume '<a claude uuid>';claude -p/claude mcp listrun by a live claude's Bash tool inheritedPATH+VOLLI_SESSION, minted over the parent's seed, and (with-p) reported its own turns as the parent's.I checked the cited lines on current
origin/main(wrapper.tsannounce/mint,harness-verbs.tsrecordHarnessLaunch/activeHarnessId/ "Overwrites, always",pty/scope.tsresume build) before changing anything.Fix
Wrapper (
packages/shared/src/harness/wrapper.ts)nonSessionArgv: { flags, subcommands }. A declared flag in any position (--version,--help, …), or a declared subcommand as the first word, skips the announce/mint. Nothing else about the invocation changes. The lists come from the installed CLIs'--helpoutput: claude, codex (-Vis its version flag, not-v), opencode, cursor-agent.sessionMarkersis set, e.g.CLAUDECODE) execs the real binary exactly as outside Volli: no announce, no mint, no injected hooks. Volli already scrubs these markers from every terminal it spawns (scrubInheritedSessionEnv), so here they can only have come from a running harness above this process. A marker that is not a valid shell name is skipped, so the wrapper can't fail to parse.Host (
packages/host-core/src/agent-dispatch/harness-verbs.ts)session.started, or a hook naming the minted id. If the event reports an id, that id wins. When the record moves, a secondsession-harnessnotice withchanged: truerepoints the renderer caches; the mint's own notice now sayschanged: false.harnessSessionId, so resume falls back to the new harness'slatestline instead of pairing a foreign id with the new binary.recordHarnessLaunchcount on every announce/mint. The resume argv/semantics in VC-401: per-harness resume reference table, rendered from the resume builder #882's table are unchanged.E2E fixtures
fake-harness.mjs: in interactive mode the fakeclaudenow fires the SessionStart a real claude fires at boot, synchronously, before its capture loop. That keepsinterrupt-resume-smokecheck 5 (resume with the minted id) meaningful under the new rule.harness-wrapper-smokecheck 7 (quarantined, not run in CI) now asserts that unconfirmed mints do not become the seed.How the regression tests prove it (they fail on main)
apps/desktop/src/main/harness-runtime.test.tsruns the real generated wrapper in a shell with a fakevollithat logs every call:claude --version | -v | --help | mcp list | doctor | update | install→ novollicall and no--session-id, and a following realclaude hellostill mints (7 cases);codex --help,codex login,opencode --version→ no announce;claude -p hellowithCLAUDECODE/CLAUDE_CODE_ENTRYPOINTset → argv untouched (no--settings, no--session-id) and novollicall.packages/host-core/src/agent-commands.test.ts(session.harnessblock), checking the resume linepty/scope.tsbuilds:claude --resume 'seed-a';codexannounce →codex resume --last, notcodex resume 'seed-a';changed: truenotice;packages/shared/src/harness/wrapper.test.ts: text assertions for the scans, the nested gate and the invalid-marker skip.wrapper.tsand the four adapter files are at 100% under--coverage.Decisions
silentchannel.recordHarnessLaunchstill counts every mint/announce. Deferring it would hide exactly the broken-hooks launch that silence detection exists for. The falsesilentafterclaude --versionis fixed by the wrapper no longer calling Volli for those invocations.--help. A listed word that is not actually a subcommand would be read as a prompt and start an unannounced session. So claudeconfig, which 2.1.x no longer has, is left out, and so are the background-session verbs (attach,agents, …), codexexec/review/resume/fork/servers, opencoderun/serve/web/attach/prand cursoragent/ls/resume. Registered manifests declare none (the field is optional).opencode --continueuntil its next hook reports the id again.Not in this PR
codexinside a running claude. The ticket scopes the check to the adapter's own markers, and codex/opencode/cursor declare none yet.Local checks
vp check: pass@volli/shared,@volli/host-core,@volli/desktopand the root config: passpnpm check:protocol-schema --base origin/main: passnode scripts/check-public-content.mjs: passpackages/shared:vp test run src/harness/ src/harness-command.test.ts --coverage(scoped to the touched files): 312 passed, 100%packages/host-core:vp test run src/agent-commands.test.ts src/agent-dispatch.test.ts src/agent-services.test.ts: 236 passedapps/desktop:vp test run src/main/harness-runtime.test.ts(44 passed) andsrc/main/pty.test.ts(224 passed)CI notes
mainbreakages, not on this diff: theupdates-pane.tsxreact/purity lint (fixed by VC-294: compute the Updates status clock outside render (unbreaks main: react/purity) #923) and thegit-port typecheck errors (fixed by VC-786: drop the removed git port from tests merged beside #908 (unbreaks main typecheck) #925). Each time I mergedmaininto this branch once the fix landed (merge commits, no force-push).4f65915f2,Test (packages)failed one test that this PR does not touch:packages/host-core/src/session-runtime/crash-recovery.integration.test.ts› "reconciles an accepted command with a different persisted timestamp without a false recovery failure" (expected 'rejected' to be 'accepted'), run 39133664971.main's CI at the same base (f794e5b3c) passed that lane, so I re-ran the failed job once.