fix(workspace-context): reconcile resumed baselines

This commit is contained in:
fz
2026-08-04 23:11:15 +08:00
parent 01fa4ceb6e
commit 119c55e35e
16 changed files with 463 additions and 51 deletions
@@ -32,7 +32,7 @@ At the first `agent/step` of a fresh session, the plugin injects one sourced use
The injection becomes a durable `user/message` with a typed `workspace-instructions` source. Its `baseline: true` marker distinguishes a complete baseline from later deltas, and its change list persists the included scopes and content digests. In the product spine workspace instructions are registered before the skills catalog, so their `agent/step` listener injects first. The loop drains both messages before deriving the first request.
A resumed agent creates a new loop instance over persisted history. If a typed baseline remains in the visible surface, the loop retains that event and reconciles baseline plus dynamic scopes against current files before its first request. Unchanged files append nothing; files added, edited, or removed while the agent was offline append `set`, `replace`, or `remove` transitions without mutating or duplicating the original baseline. A hot plugin remount follows the same visibility rule. If no typed baseline remains visible, as after compaction shadows it, the loop composes and injects one complete current baseline.
A resumed agent creates a new loop instance over persisted history. If a typed baseline remains in the visible surface and its persisted discovery, precedence, and budget identity matches current configuration, the loop retains that event and reconciles dynamic scopes plus the baseline files retained by the current complete rendering before its first request. Unchanged files and budget-omitted files append nothing; files added, edited, removed, or dropped from the retained set while the agent was offline append `set`, `replace`, or `remove` transitions without mutating or duplicating the original baseline. An incompatible visible baseline is superseded by one recomposed complete baseline in current precedence order, with explicit model-facing replacement language; an empty current candidate set emits an explicit clear baseline. A hot plugin remount follows the same compatibility rule. If no typed baseline remains visible, as after compaction shadows it, the loop composes and injects one complete current baseline.
Compaction can shadow the baseline after this plugin's guarded `agent/step` listener has already run for the session. The `system-prompt/assemble` waterfall therefore delegates first, but restores only for an assembly explicitly marked for the loop's next model request; diagnostic assemblies remain read-only. When a prior typed baseline exists but none remains visible, the listener recomposes the current chain, rechecks cancellation and the current surface generation after every asynchronous probe, and injects before the loop drains its outbox and snapshots derived request history. A per-session settled marker prevents repeated preparation when the current generation produced no baseline; a separate queued marker plus the synchronous commit-time recheck lets concurrent preparations scan without queuing duplicate baselines.
@@ -84,7 +84,7 @@ Workspace guidance is isolated per session and shared by the demo front doors, W
Repository text remains untrusted input. Lower-authority user-role framing, explicit precedence language, and delimiter escaping reduce risk but do not eliminate prompt injection. Following a candidate symlink to its target widens that surface to off-tree content, so the permission and sandbox layers that confine `ctx.fs` to trusted roots are the boundary that treats workspace files as data rather than authority (the [instruction-symlink follow note](2026-07-21-follow-instruction-symlinks.md) owns the residual risk).
The system is event-driven rather than watch-driven. Edits are not visible at the exact filesystem mutation instant unless that mutation goes through a structured tool; externally changed baseline files are also noticed when a surface replacement or resume triggers recomposition. This keeps the design deterministic and provider-neutral.
The system is event-driven rather than watch-driven. Edits are not visible at the exact filesystem mutation instant unless that mutation goes through a structured tool; externally changed baseline files are also noticed when a surface replacement recomposes the baseline or resume reconciles its current retained set. This keeps the design deterministic and provider-neutral.
## Deferred