Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 199 additions & 0 deletions docs/todos/2026-06-19-issue-287-prompt-cache-system-mutation/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# Issue 287 Prompt Cache System Mutation Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Keep OpenCode's system prompt stable after first-turn memory context injection by moving volatile file enrichment into message parts.

**Architecture:** Preserve the current file-stash sources and `/agentmemory/enrich` request shape. `experimental.chat.system.transform` remains responsible only for stable first-turn instructions/context; `chat.message` becomes the volatile enrichment injection point and tags injected text so prompt observation ignores it.

**Tech Stack:** TypeScript ESM, OpenCode plugin hook object, Vitest, mocked `fetch`.

---

## Sprint Contract

Goal: Fix issue #287 without changing API, schema, auth, dependencies, versioning, or remote boundaries.

Scope:
- Modify `plugin/opencode/agentmemory-capture.ts`.
- Modify `plugin/opencode/README.md`.
- Add a focused test file such as `test/opencode-prompt-cache.test.ts`.
- Update `docs/todos/2026-06-19-issue-287-prompt-cache-system-mutation/todo.md`.

Non-goals:
- Do not change `/agentmemory/enrich`, REST endpoint registration, MCP tools, persisted schemas, auth behavior, package versions, dependency manifests, or provider code.
- Do not remove first-turn `AGENTMEMORY_INSTRUCTIONS` or `/context` system injection.
- Do not run or rely on `upstream`.

Acceptance criteria:
- `chat.system.transform` appends stable first-turn instructions/context but never file-specific `/enrich` context.
- `chat.message` appends returned enrich context to `output.parts` as a text part.
- Processed stashed files are cleared after successful message-part injection.
- The prompt observation payload excludes injected enrich text.
- OpenCode README no longer documents file enrichment as system-prompt injection.

Intended verification:
- Red: `corepack pnpm exec vitest run --exclude test/integration.test.ts test/opencode-prompt-cache.test.ts` fails on the current code.
- Green: the same targeted test passes after implementation.
- Targeted existing tests: `corepack pnpm exec vitest run --exclude test/integration.test.ts test/opencode-auto-context.test.ts test/integration-plaintext-http.test.ts test/context-injection.test.ts test/hook-source-smoke.test.ts`.
- Broader checks: `corepack pnpm run lint`, `corepack pnpm run build`, `corepack pnpm test`.
- Security gates: `semgrep scan --config p/default --error --metrics=off .`; after staging, `gitleaks protect --staged --redact`.

## Feature / Verification Matrix

| Change | Verification method | Status | Evidence |
| --- | --- | --- | --- |
| Remove `/enrich` from system transform | New handler-level red/green test | Pending | Not run |
| Add `/enrich` message-part injection | New handler-level red/green test | Pending | Not run |
| Exclude injected context from prompt observation | New handler-level red/green test | Pending | Not run |
| Update docs | Stale-reference search and diff inspection | Pending | Not run |
| Preserve existing behavior | Existing targeted tests and full checks | Pending | Not run |

## Files

- Create: `test/opencode-prompt-cache.test.ts`
- Modify: `plugin/opencode/agentmemory-capture.ts`
- Modify: `plugin/opencode/README.md`
- Modify: `docs/todos/2026-06-19-issue-287-prompt-cache-system-mutation/todo.md`

## Task 1: Add failing OpenCode prompt-cache regression

**Files:**
- Create: `test/opencode-prompt-cache.test.ts`

- [ ] **Step 1: Add a plugin loader and fetch recorder**

Use the existing import/reset pattern from `test/integration-plaintext-http.test.ts`: reset modules, set `AGENTMEMORY_URL=http://localhost:3111`, stub `globalThis.fetch`, import `AgentmemoryCapturePlugin`, and instantiate it with `{ worktree: "/tmp/project" }`.

- [ ] **Step 2: Write the system-transform regression**

Test flow:
1. Start a session through the plugin `event` handler.
2. Call `experimental.chat.system.transform` once to consume first-turn stable context.
3. Stash `src/a.ts` through `tool.execute.before`.
4. Call `experimental.chat.system.transform` again with `output.system = ["base"]`.
5. Assert no `/agentmemory/enrich` request was made during that second system-transform call.
6. Assert `output.system` remains `["base"]`.

Expected red result on current code: the second system-transform call posts to `/agentmemory/enrich` and appends the mocked enrich context to `output.system`.

- [ ] **Step 3: Write the message-part injection regression**

Test flow:
1. Start a fresh session.
2. Stash `src/b.ts` through `tool.execute.before`.
3. Call `chat.message` with `output.parts = [{ type: "text", text: "user prompt" }]`.
4. Assert `/agentmemory/enrich` was called with `{ sessionId: "ses-2", files: ["src/b.ts"], toolName: "enrich_inject" }`.
5. Assert `output.parts` contains the user text plus a text part whose `text` is the mocked enrich context and whose `synthetic` flag is true.
6. Assert the `/agentmemory/observe` prompt payload is `"user prompt"` and does not contain the enrich context.
7. Call `chat.message` again with a new prompt and no new stashed file, then assert no second `/enrich` request occurs.

Expected red result on current code: `chat.message` does not call `/enrich` and does not append an enrich text part.

- [ ] **Step 4: Run the red test**

Run:

```bash
corepack pnpm exec vitest run --exclude test/integration.test.ts test/opencode-prompt-cache.test.ts
```

Expected: the new tests fail for the two issue-specific reasons above.

## Task 2: Move volatile enrich injection to `chat.message`

**Files:**
- Modify: `plugin/opencode/agentmemory-capture.ts`

- [ ] **Step 1: Add message-part enrich injection after file stashing**

Inside the existing `"chat.message"` handler, after file parts are added to `stashFor(sid)` and before prompt observation, read `const stash = stashFor(sid)`, return early if empty, call `postJson("/enrich", { sessionId: sid, files, toolName: "enrich_inject" })`, and append `{ type: "text", text: enrichCtx, synthetic: true }` to `output.parts` when `enrichCtx` is a non-empty string.

- [ ] **Step 2: Preserve stash deletion semantics**

Delete only the files included in the enrich request, and only after appending the message part. Keep the existing ten-file slice and `MAX_STASHED_FILES` behavior.

- [ ] **Step 3: Remove the volatile system-transform block**

Delete the `stashFor(sid)` through `output.system.push(enrichCtx)` block from `experimental.chat.system.transform`. Leave the first-turn instructions/context block unchanged.

- [ ] **Step 4: Run the targeted green test**

Run:

```bash
corepack pnpm exec vitest run --exclude test/integration.test.ts test/opencode-prompt-cache.test.ts
```

Expected: the new tests pass.

## Task 3: Update OpenCode README

**Files:**
- Modify: `plugin/opencode/README.md`

- [ ] **Step 1: Update the file-enrichment table**

Change the enrichment row from `experimental.chat.system.transform` / `output.system[]` to `chat.message` / `output.parts[]`. Keep memory context injection documented as `experimental.chat.system.transform` / `output.system[]`.

- [ ] **Step 2: Rewrite the two-layer pipeline text**

Describe `experimental.chat.system.transform` as first-turn stable system context only, and `chat.message` as volatile file-enrichment message-part injection.

- [ ] **Step 3: Update the prompt layout diagram**

Show a stable system prompt and a message stream containing user message plus optional file enrichment. Remove wording that says per-turn file enrichment mutates the system prompt.

- [ ] **Step 4: Search stale references**

Run:

```bash
rg -n "Enrichment inject|output\\.system\\[\\]|system prompt.*file enrichment|file enrichment.*system prompt|output\\.system\\.push\\(enrichCtx\\)" plugin/opencode README.md test
```

Expected: no stale OpenCode README/test references claim file enrichment is injected through `output.system[]`; source may still contain first-turn system context references.

## Task 4: Focused cleanup and verification

**Files:**
- Modify touched files only if needed.
- Modify: `docs/todos/2026-06-19-issue-287-prompt-cache-system-mutation/todo.md`

- [ ] **Step 1: Simple-code pass**

Inspect only the active diff for duplicate stash handling, confusing local names, unnecessary comments, or over-broad helper extraction. Preserve behavior, prompt layout, request shape, auth, API, schema, persistence, and versioning.

- [ ] **Step 2: Run targeted existing tests**

Run:

```bash
corepack pnpm exec vitest run --exclude test/integration.test.ts test/opencode-prompt-cache.test.ts test/opencode-auto-context.test.ts test/integration-plaintext-http.test.ts test/context-injection.test.ts test/hook-source-smoke.test.ts
```

Expected: all targeted tests pass.

- [ ] **Step 3: Run broader verification**

Run:

```bash
corepack pnpm run lint
corepack pnpm run build
corepack pnpm test
semgrep scan --config p/default --error --metrics=off .
```

Expected: all pass, or blockers are recorded with closest targeted evidence.

- [ ] **Step 4: Update task record**

Record red/green evidence, final verification, Sprint Contract status, Feature / Verification Matrix status, review notes, and residual risks in `docs/todos/2026-06-19-issue-287-prompt-cache-system-mutation/todo.md`.

## Self-Review

- Spec coverage: issue validity, red/green regression, plugin fix, docs update, verification, and security gates are covered.
- Placeholder scan: no unresolved placeholders or broad "handle edge cases" steps remain.
- Boundary check: no dependency, version, API, auth, schema, MCP, REST, provider, or remote changes are planned.
- Delegation check: arena validity was delegated. Implementation is tightly coupled around one plugin handler pair, so the lead agent will implement inline after the failing test and use focused review/verification rather than overlapping worker edits.
Loading
Loading