fix(environment): persist probe snapshots so the prompt prefix stays byte-stable#6093
Merged
SivanCola merged 1 commit intoJul 6, 2026
Conversation
…byte-stable The environment section sits inside the provider-cached system-prompt prefix, but probe results were point-in-time observations with only a 5-minute in-memory cache: a 2s timeout flips a slow tool between "found" and "timeout", a GUI-launched desktop resolves a different PATH than a login shell, a cold docker daemon reports an exit error. Every flip rewrote the prefix; the desktop's fresh-system-prompt swap then propagated the drifted prompt onto every resumed session — a whole-conversation cache miss at 10x pricing plus a persisted rewrite. This was the main mechanism behind "desktop costs more than CLI" (esengine#2945, esengine#5850 comments). - Persist one probe snapshot per fingerprint under the shared cache root (ProbeOptions.SnapshotDir, opt-in; boot passes config.CacheDir). A snapshot younger than 24h serves without re-probing, so rebuilds, app relaunches, and the CLI and desktop on the same machine render identical environment bytes. 24h aligns with cacheColdAfter: past a day idle the provider cache is dead anyway, so a refresh then is free. - Flap merge on refresh: transient failures (timeout, nonzero exit) keep the previous successful observation; definitive results (found, not found, not trusted) always win, so uninstalled tools still drop out. - Desktop resume logs when it swaps a system prompt whose bytes differ from the persisted one — with deterministic composition this should only fire on genuine config changes, so a field log without one points at a new nondeterminism source. The snapshot dir is host state and stays out of the probe fingerprint.
This was referenced Jul 6, 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.
Summary
治本工程第一步:消除系统提示词前缀里最大的不确定性来源。
The environment section sits inside the provider-cached system-prompt prefix, but probe results were point-in-time observations with only a 5-minute in-memory cache. Between process restarts and rebuilds they drift for reasons invisible to the user: a 2s timeout flips a slow tool between
foundandtimeout; a GUI-launched desktop resolves a different PATH than a login shell (so the CLI and desktop compose different prompts on the same machine); a cold docker daemon reports an exit error. Every flip rewrites the prefix, and the desktop's fresh-system-prompt swap (sessionWithFreshSystemPrompt) then propagates the drifted prompt onto every resumed session — a whole-conversation cache miss at 10x miss pricing plus a persisted rewrite. This is the main mechanism identified behind "desktop costs more than CLI" (#2945, and the Desktop-vs-CLI comparison in #5850's comments).Changes:
ProbeOptions.SnapshotDir, opt-in; boot passesconfig.CacheDir()): one snapshot per probe fingerprint under<cache>/environment/. A snapshot younger than 24h serves without re-probing, so rebuilds, relaunches, and both surfaces on one machine render identical environment bytes. 24h aligns with the controller'scacheColdAfter: past a day idle the provider cache is dead anyway, so a refresh at that point costs nothing extra.timeout,exit …) keep the previous successful observation for the same probe; definitive results (found,not found,not trusted) always win, so genuinely uninstalled tools still drop out of the section.Not in this PR (follow-ups): shell resolution (
sandbox.ResolveShell) is also PATH-dependent but config-driven and rarely flaps; a swap-policy change for resumed sessions (keep the recorded prompt vs adopt the fresh one) is a product decision left untouched.Verification
TestProbeSnapshotServesAcrossRestartsWithoutReprobing(snapshot serves byte-identicalFormatSectionoutput across a simulated restart even after the tool binary disappears),TestProbeSnapshotExpiresAndAdoptsDefinitiveChanges(post-TTL refresh adopts a real version change and re-persists),TestProbeSnapshotKeepsFoundOverTransientFailure(exit-failure keeps last-good; definitivenot foundadopted),TestMergeProbeSnapshotOnlyOverlaysTransientFailures.internal/environment(+-race),internal/boot(25s),internal/cli, desktop (53s).go vetclean.REASONIX_RELEASE_CACHE_GUARD=1 go test ./internal/agent -run TestReleaseCacheHitGuardgreen.Cache impact
Cache-impact: high - this PR is itself a cache-stability fix: it removes the probe-drift class of prompt-prefix invalidation. No prompt content changes when tools are stable; the section can now be up to 24h stale relative to live tool state.
Cache-guard: new snapshot byte-stability tests above (restart-identical FormatSection assertion) plus TestReleaseCacheHitGuard run locally.
System-prompt-review: requested from @SivanCola — model-visible policy change to sign off: (1) the environment section may lag live tool state by up to 24h (new installs appear on the next refresh); (2) a transiently failing tool keeps its last-good version line until a definitive change. Both trade freshness for prefix stability.
Refs #2945, #5850, #5614.