refactor(core): simplify v2 system context epochs

This commit is contained in:
Kit Langton 2026-06-04 19:49:19 -04:00
commit 00c4114911
30 changed files with 997 additions and 828 deletions

View file

@ -27,7 +27,7 @@ Watcher-backed caches are a later efficiency optimization for roots with proven
| `EventV2.subscribe(...)` | Expose advisory events as scoped Effect streams. |
| `State.create(...)` | Rebuild replayable plugin and config contribution state from scoped transforms. |
| `SynchronizedRef.modifyEffect(...)` | Serialize effectful state refresh and store the next value only after success. |
| `SystemContext` | Convert coherent source samples into immutable baseline parts, chronological updates, unavailable state, and removal tombstones. |
| `SystemContext` | Convert coherent source samples into one immutable baseline, chronological updates, unavailable state, and removal tombstones. |
| `LocationServiceMap` | Own and clean up Location-scoped services, watcher subscriptions, and observation caches together. |
The missing reusable piece is deliberately small: retain the last successful value, mark it stale, and serialize refresh attempts.
@ -128,7 +128,7 @@ sequenceDiagram
## Observation Units
Compose refreshables around coherent observations that share one invalidation policy. Do not create one uniformly per rendered Context Component or one aggregate cache for unrelated source kinds.
Compose refreshables around coherent observations that share one invalidation policy. Do not create one uniformly per rendered Context Source or one aggregate cache for unrelated source kinds.
```text
local built-in discovery
@ -153,13 +153,13 @@ Add a Location-scoped service:
```ts
export interface InstructionContext.Interface {
readonly loadAmbient: () => Effect.Effect<ReadonlyArray<SystemContext.Component>>
readonly loadAmbient: () => Effect.Effect<SystemContext.SystemContext>
}
```
`InstructionContext` owns instruction discovery, stable source identity, deterministic ordering, and source loading. `SystemContext` remains unaware of files and URLs.
Each effective source becomes one independently keyed component:
Each effective instruction becomes one independently keyed `SystemContext.Source<string>` closed into the aggregate context with `SystemContext.make(...)`:
```text
core/instructions/file/<stable-hash-of-normalized-absolute-path>
@ -192,7 +192,7 @@ sequenceDiagram
Runner->>Instructions: loadAmbient
Instructions->>Files: discover and read AGENTS.md files
Files-->>Instructions: coherent current observation
Instructions-->>Runner: independently keyed components
Instructions-->>Runner: composed SystemContext
Runner->>Epoch: compare and durably admit changes
```
@ -208,19 +208,19 @@ observation
-> what bytes or temporary failure does each identity currently produce?
```
| Observation | Component outcome |
| Observation | Source outcome |
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| Local scan succeeds and discovers readable file | Available component with exact contents. |
| Local scan succeeds and a previously discovered file is absent | Remove component so `SystemContext` emits a tombstone. |
| Local scan succeeds and discovers readable file | Available source with exact contents. |
| Local scan succeeds and a previously discovered file is absent | Remove source so `SystemContext` emits a tombstone. |
| Local scan fails transiently | Preserve the domain-owned prior source graph as unavailable or fail the current turn; never emit mass removals. |
| Known local file read fails transiently | Preserve the component as `SystemContext.unavailable`. |
| Known local file read fails transiently | Preserve the source as `SystemContext.unavailable`. |
| Known local file read reports not-found after discovery | Invalidate discovery and report unavailable until a coherent rescan confirms removal. |
| Empty local file | Available exact content, not absence. |
| URL returns `2xx` body | Available component with exact contents. |
| URL returns `2xx` body | Available source with exact contents. |
| URL times out or returns transient failure | `SystemContext.unavailable`. |
| URL returns `404` or `410` | Decide the explicit removal contract before URL implementation. |
Instruction removal text must be model-meaningful. If instruction component keys hash source identities, add source-specific removal rendering before unlink support is considered complete:
Instruction removal text must be model-meaningful. If instruction source keys hash source identities, add source-specific removal rendering before unlink support is considered complete:
```text
Instructions removed: /repo/packages/core/AGENTS.md
@ -234,7 +234,7 @@ Implement only:
```text
global config AGENTS.md
+ upward project AGENTS.md ancestors
+ one keyed component per file
+ one keyed source per file
+ direct safe-turn observation
```
@ -263,7 +263,7 @@ empty file
transient scan failure
transient file-read failure
deterministic ordering
restart with durable checkpoint
restart with durable structured snapshots
```
## Future Watcher Optimization
@ -316,7 +316,7 @@ Start with direct safe-turn loading:
```text
safe provider-turn boundary
-> fetch URL
-> emit available or unavailable component
-> emit available or unavailable source
```
If measurements show excessive requests, add a URL-specific invalidation policy later:
@ -375,7 +375,7 @@ Nested instructions discovered after successful read-tool activity remain a Sess
1. Add and unit-test `Refreshable.make(load)` with `get` and `invalidate`.
2. Add model-meaningful instruction removal rendering support before unlink lands.
3. Add Location-scoped `InstructionContext` for global and upward project `AGENTS.md` only.
4. Compose instruction components into `SessionSystemContext.load()`.
4. Compose instruction sources into `SessionSystemContext.load()`.
5. Observe local instructions directly at each safe provider boundary.
6. Test add, edit, unlink, empty file, transient scan failure, transient read failure, restart, and deterministic ordering.
7. Add configured local exact paths and globs.
@ -386,11 +386,10 @@ Nested instructions discovered after successful read-tool activity remain a Sess
## Open Questions
1. Should source-specific removal rendering extend `SystemContext.Component`, or should `InstructionContext` retain removal metadata in a separate component registry?
2. Should the first local scan failure preserve prior discovered sources as unavailable, or fail the current provider turn until a coherent rescan succeeds?
3. Should configured URL sources treat `404` and `410` as confirmed removals?
4. What root-specific watcher API cleanly models ignore policy and callback health?
5. Should own-process file mutations publish an advisory invalidation event synchronously after commit?
1. Should the first local scan failure preserve prior discovered sources as unavailable, or fail the current provider turn until a coherent rescan succeeds?
2. Should configured URL sources treat `404` and `410` as confirmed removals?
3. What root-specific watcher API cleanly models ignore policy and callback health?
4. Should own-process file mutations publish an advisory invalidation event synchronously after commit?
## Compression Line

View file

@ -687,23 +687,23 @@ Compatibility:
- Foreground V2 bash execution is unchanged.
- Reintroduce background bash only with durable status observation, completion delivery, and explicit cancellation semantics.
## 2026-06-04: Initialize Durable Session Context Epochs
## 2026-06-04: Add Durable Session Context Snapshots
Affected schema:
- Add synchronized `session.next.context.initialized.1` Session events.
- Add `session_context_epoch` for one active immutable keyed baseline, component-hash checkpoint, and baseline sequence per Session.
- Add `session_context_epoch` for one active immutable baseline string, structured JSON snapshot, and baseline sequence per Session.
Change:
- Lazily initialize one durable Context Epoch at the first safe provider-turn boundary.
- Lower its exact keyed baseline parts through `LLMRequest.system` for every provider turn in the epoch.
- Lazily initialize one durable Context Epoch snapshot at the first safe provider-turn boundary.
- Lower its exact baseline string through `LLMRequest.system` for every provider turn in the epoch.
- Reuse the stored baseline verbatim after restart or producer changes instead of resampling privileged initial context.
- Keep ordinary Session transcript APIs unchanged.
- Compare later observations against an overwriteable codec-encoded structured snapshot rather than rendered-text hashes.
- Expose admitted chronological context as first-class `system` Session messages while keeping the active baseline in bounded context state.
Compatibility:
- The unpublished Context Epoch schema is consolidated into one database migration and this adds one synchronized Session event type.
- The unpublished Context Epoch schema is consolidated into one database migration; baseline and structured snapshots are operational state rather than synchronized event history.
- Existing experimental V2 Session databases remain disposable across incompatible pre-launch event-schema changes.
- Chronological context updates, replacement epochs after compaction or model switches, project instructions, skills guidance, and plugin transforms remain follow-up slices.
@ -711,21 +711,21 @@ Compatibility:
Affected schema:
- Add synchronized `session.next.context.updated.1` Session events.
- Add `session_context_epoch.revision` for transactional checkpoint advancement.
- Add `session_context_message` for hidden chronological keyed context updates ordered by Session aggregate sequence.
- Add synchronized `session.next.context.updated.1` Session events containing only exact combined model-visible text.
- Add `session_context_epoch.revision` for transactional structured-snapshot advancement.
- Add the first-class `system` Session message projection for chronological context updates.
Change:
- Refresh Location-scoped Context Components at each safe provider-turn boundary.
- Keep the stored baseline immutable while admitting changed component values as runner-private chronological `Message.system(...)` history.
- Emit an explicit tombstone update and advance component-hash checkpoints transactionally when a component is removed.
- Keep ordinary Session transcript APIs unchanged while runner history merges visible Session messages and hidden context updates by durable aggregate sequence.
- Reconcile Location-scoped Context Sources at each safe provider-turn boundary using one coherent observation.
- Keep the stored baseline immutable while admitting changed source renderings as chronological `Message.system(...)` history.
- Advance the overwriteable structured snapshot atomically with the rendered System-message event.
- Emit the previously stored model-meaningful removal rendering when a source is removed.
- Reject chronological system updates that would split a local tool call from its result across provider protocols; use wrapped user fallback when Anthropic native system-update placement is unsupported.
Compatibility:
- The unpublished Context Epoch schema remains consolidated into one database migration and this adds one synchronized Session event type.
- The synchronized event log retains only text actually shown to the model, not internal structured snapshots.
- Existing experimental V2 Session databases remain disposable across incompatible pre-launch event-schema changes.
- Replacement epochs after compaction or model switches, project instructions, skills guidance, and plugin transforms remain follow-up slices.
@ -733,18 +733,17 @@ Compatibility:
Affected schema:
- Add synchronized `session.next.context.replaced.1` Session events.
- Add nullable `session_context_epoch.replacement_seq` for idempotent lazy replacement requests.
Change:
- Mark the active Context Epoch for replacement after a model switch or completed compaction projection.
- Persist the triggering aggregate sequence so same-target replay cannot reopen an already-settled replacement.
- Render and persist the fresh immutable baseline lazily at the next safe provider-turn boundary.
- Exclude hidden chronological updates from earlier epochs when assembling active provider history.
- Render and overwrite the fresh immutable baseline and structured snapshot lazily at the next safe provider-turn boundary.
- Exclude chronological System messages from earlier epochs when assembling active provider history.
Compatibility:
- The unpublished Context Epoch schema remains consolidated into one database migration and this adds one synchronized Session event type.
- Baseline replacement is bounded operational state and does not add permanent synchronized events.
- Existing experimental V2 Session databases remain disposable across incompatible pre-launch event-schema changes.
- Compaction execution, project instructions, skills guidance, and plugin transforms remain follow-up slices.