feat(core): make path-local instruction discovery durable

Replace synthetic-message instruction injection with a durable
discovery projection so discovered AGENTS.md files survive compaction,
forks, reverts, and restarts.

- Add the instruction_file table and the durable
  session.instructions.discovered event; projection stores each
  discovered path and content with its owning assistant-message
  boundary and durable discovery order.
- Fold discovered files into the core/instructions source through
  InstructionDiscovery, absorbing SessionInstructions. Completed
  compaction rebaselines restate discovered instructions instead of
  summarizing them away.
- Re-read discovered files live at each observation so mid-session
  edits reach the model; the frozen discovery content stands in only
  when a file becomes unreadable.
- Narrate instruction file changes as per-file deltas via diffByKey,
  restating the full set only for pure reorderings.
- Fork copies discoveries within the inherited transcript, committed
  revert removes discoveries past the revert boundary, and Session
  movement clears them so the destination initializes a complete
  baseline.
This commit is contained in:
Kit Langton 2026-07-06 14:22:53 -04:00
commit 0726f09b05
28 changed files with 1166 additions and 598 deletions

View file

@ -1,17 +1,31 @@
# V2 Schema Changelog
## 2026-07-06: Make Path-Local Instruction Discovery Durable
- Add the `instruction_file` table recording which path-local `AGENTS.md` files a Session has discovered, with the owning assistant-message boundary and durable discovery order.
- Add the durable `session.instructions.discovered` event; projection stores the discovered path and content per Session. Observation re-reads discovered files live, falling back to the stored content only when a file becomes unreadable.
- Replace synthetic-message instruction injection with the durable discovery path: `InstructionDiscovery` folds discovered files into the `core/instructions` source, so completed compaction rebaselines restate them instead of summarizing them away.
- Narrate instruction file changes as per-file deltas; the full-set restatement survives only for pure reorderings.
- Fork copies discoveries within the inherited transcript, committed revert removes discoveries past the revert boundary, and Session movement clears them so the destination initializes a complete baseline.
Compatibility:
- Previously emitted synthetic instruction messages remain historical Session history. New discoveries use the durable path; the migration does not infer structured files from old free-form synthetic text.
## 2026-07-05: Rename Session Context Contracts To Instructions
- Rename the System Context algebra to `Instructions`, API-managed `SessionContextEntry` records to `InstructionEntry`, and the session-owned context checkpoint to `InstructionCheckpoint`.
- Rename the tables `session_context_entry` and `session_context_epoch` to `instruction_entry` and `instruction_checkpoint`.
- Rename the durable update event from `session.context.updated` to `session.instructions.updated`; the migration rewrites existing durable event types in place.
- Rename the durable update event from `session.context.updated` to `session.instructions.updated`.
- Rename the API-managed entry routes from `/api/session/:sessionID/context-entry` to `/api/session/:sessionID/instructions/entries` and their operation identifiers from `session.context.entry.*` to `session.instructions.entry.*`, keeping bare `session.instructions.*` free for the composed instruction surface.
- Add durable per-Session path-local instruction files and make `InstructionDiscovery` combine them with ambient global and upward-project `AGENTS.md` files.
- Record successful path-local discovery as `session.instructions.discovered`; projection stores the discovered path and content with the owning assistant-message boundary before `InstructionCheckpoint` admits it. Observation re-reads discovered files live, falling back to the stored content only when a file becomes unreadable.
- Remove the context registry seam. The runner explicitly composes instruction built-ins, discovery, selected-agent skill guidance, reference guidance, MCP guidance, and `InstructionEntry` values.
Compatibility:
- The V2 contracts remain experimental. The renamed tables, event, endpoints, schemas, and generated client names are intentionally breaking changes for beta consumers.
- Existing changelog entries retain the names that were accurate when those changes occurred.
- Behavior is unchanged: this is a vocabulary and contract rename only.
- Previously emitted synthetic instruction messages remain historical Session history. New discoveries use the instruction checkpoint path; the migration does not infer structured files from old free-form synthetic text.
## 2026-07-03: Require Durable Envelope On Durable Events

View file

@ -58,7 +58,7 @@ V2 Sessions persist the exact privileged instructions shown to the model. `Instr
The runner has no instruction registry. `loadInstructions` explicitly loads these producers concurrently and combines them in this fixed order:
1. Instruction built-ins, currently environment facts and the host-local date.
2. `InstructionDiscovery`, observing ambient `AGENTS.md` files.
2. `InstructionDiscovery`, combining ambient and path-local `AGENTS.md` files.
3. Selected-agent available-skill guidance.
4. Reference guidance.
5. Selected-agent MCP guidance.
@ -88,7 +88,7 @@ Client Runner Explicit producers InstructionChe
Agent and model selection are step-scoped. The runner selects the agent before loading agent-specific guidance; a switch admitted after the current boundary applies to the next step without restarting the current one. Changed guidance is admitted through `session.instructions.updated` while preserving the baseline. Model selection affects Model Context assembly but is not an instruction source and does not itself replace the instruction baseline.
A completed compaction causes the next physical attempt to rebaseline from current instructions. Temporarily unavailable sources are restated from the model's last applied belief where possible. A Session move resets `InstructionCheckpoint` so the destination Location initializes a complete baseline on its next run. Committed revert also resets the checkpoint.
A completed compaction causes the next physical attempt to rebaseline from current instructions. Temporarily unavailable sources are restated from the model's last applied belief where possible. A Session move resets `InstructionCheckpoint` and all path-local discoveries so the destination Location initializes a complete baseline on its next run. Committed revert also resets the checkpoint and removes path-local discoveries admitted after the revert boundary.
```text
Session InstructionCheckpoint
@ -104,9 +104,9 @@ Session InstructionCheckpoint
├─ move or committed revert ────────▶ reset
```
`InstructionDiscovery` observes ambient instructions as one ordered aggregate source. Ambient discovery canonicalizes traversal within the project root, reads global and upward-project `AGENTS.md` files, and honors `OPENCODE_DISABLE_PROJECT_CONFIG` for project files.
`InstructionDiscovery` combines ambient and path-local instructions into one ordered aggregate source. Ambient discovery canonicalizes traversal within the project root, reads global and upward-project `AGENTS.md` files, and honors `OPENCODE_DISABLE_PROJECT_CONFIG` for project files. After a successful internal `read`, path-local discovery walks from the read file's directory, or the listed directory itself, toward the Location root. `session.instructions.discovered` records newly readable files with their owning assistant-message and Location; projection stores their path and content per Session, and they join the aggregate at the next step boundary. Every observation re-reads ambient and discovered files live, so mid-session edits narrate as per-file updates; the stored discovery content stands in only when a discovered file becomes unreadable. Ambient files precede path-local files, duplicate paths are removed, and path-local files retain durable discovery order.
An unavailable observation preserves the previously applied value. A confirmed partial instruction removal emits the complete remaining aggregate with explicit supersession text; removing the final instruction emits a revocation message.
An unavailable discovery observation preserves the previously applied aggregate. A confirmed partial removal emits the complete remaining aggregate with explicit supersession text; removing the final discovered instruction emits a revocation message.
Current instruction follow-ups:
@ -141,7 +141,7 @@ Status: `complete` is usable in the native V2 path, `partial` covers only part o
| Durable Instruction Source | Environment facts and host-local date | partial | Keep selected provider/model identity in step request assembly rather than a stale Location-wide instruction value. |
| Durable Instruction Source | Global and upward project instructions | partial | Decide whether V2 also discovers legacy `CLAUDE.md` and deprecated `CONTEXT.md`. |
| Durable Instruction Source | Configured local/glob and remote URL instructions | missing | Add independent sources with explicit precedence, unavailable, and removal semantics. |
| Durable Instruction Source | Nearby nested instructions discovered after successful reads | missing | Persist discoveries and admit them at the next safe step boundary. |
| Durable Instruction Source | Nearby path-local instructions discovered after successful reads | complete | None. |
| Durable Instruction Source | Selected-agent available skill guidance and skill-body loading | partial | Guidance and body exposure are permission-filtered; remove globally denied skill definitions during request-time tool materialization. |
| Step request assembly | Placement, selected model, chronological history, and canonical lowering | complete | None. |
| Step request assembly | Selected agent, agent prompt, and effective permissions | partial | V2 uses selected-agent permissions for skill guidance and tool authorization; still apply the agent system prompt and request policy. |