Skip to content

fix(server): Claude subagent progress no longer re-stores the unchanged prompt - #18375

Open
Gigioxx wants to merge 1 commit into
pingdotgg:mainfrom
Gigioxx:fix/claude-subagent-progress-prompt
Open

Gigioxx wants to merge 1 commit into
pingdotgg:mainfrom
Gigioxx:fix/claude-subagent-progress-prompt

Conversation

@Gigioxx

@Gigioxx Gigioxx commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

Problem

Every Claude subagent progress tick appends two events, subagent.updated and a subagent turn-item.updated, and both repeat the full prompt even though only progress changed. Heavy subagent use grows statev2.sqlite by about 50x the subagents' real state (#18204). On my install, 41.4 MiB of the 63.3 MiB stored in these events is repeated prompt text.

Change

The fix lives entirely in the event store (OrchestrationEventStore), so the contracts, the wire, projections, and every client stay as they are. Older web, desktop, and mobile builds keep working because they still receive full events.

  • Append: when a row for the same subagent already stores the same prompt, the new row stores promptSequence (that row's sequence) and an empty prompt instead of the text. An in-memory hint remembers the latest full row per subagent. The INSERT re-checks that the row still exists with the same prompt, because the transaction that wrote it can roll back. A cold or stale hint just stores the full prompt again.
  • Read: the single read query (readApplicationRows) restores the prompt in SQL. Thread replay, catch-up, projection recovery, and the replay byte budgets (getAgentReplayStats, getReplayStats) all see the original payload.
  • Older servers: slim rows keep prompt: "", so an older server sharing the same T3 home (for example after a desktop rollback) can still decode them. It shows an empty prompt rather than failing.
  • Compaction never deletes subagent.updated or turn-item.updated rows, so the rows these pointers reference stay. ProjectionMaintenance now carries a comment about this.

Scope and approval

Triaged bug: #18204. The maintainer triage named persisting only the changed fields as an acceptable fix (comment). This PR does that at the storage layer. Live subagent progress keeps updating at the same rate, and there is no contract change.

Verification

  • stores an unchanged subagent prompt once and replays it on every update (new, OrchestrationEventStore.test.ts) appends three progress ticks and one prompt change for both event types. It asserts that only the first row of each type stores the prompt, that replay returns the original events, and that both replay budgets count the restored bytes. It fails on main because every row stores the prompt.
  • stores the full subagent prompt when its hint row was rolled back (new) rolls back the transaction that wrote the hinted row. It checks that the next append stores the full prompt, the one after it points at that new row, and both readAgentEvents and readApplicationEvents return full events. It fails on main.
  • vp test run src/persistence/OrchestrationEventStore.test.ts src/persistence/OrchestrationEventStore.sequence.test.ts src/orchestration-v2/FoundationPersistence.test.ts src/orchestration-v2/ThreadStream.test.ts src/orchestration-v2/ShellStream.test.ts src/orchestration-v2/ProjectionRecovery.test.ts: 100 passed.
  • Server tsc --noEmit is clean. Scoped vp lint and vp fmt --check are clean on the touched files.
  • I measured savings with a read-only query on my own statev2.sqlite: 14,915 subagent snapshot rows across 556 subagent records and turn items, 63.3 MiB stored, 41.4 MiB of it repeated prompts (5.7% of all V2 event payload bytes here). Rows written before this change keep their full prompts; only new events are slimmed.
  • Cross-vendor review: two rounds by Claude Opus 5.5 on code written by GPT-6 Astra. Round 1 found one medium issue (older servers could not decode slim rows) and four low ones (recency-based hint eviction, hint memory, an extra RETURNING cost on every insert, getReplayStats coverage). All five are fixed. Round 2 found no defects.
  • Not checked: a live Claude session in a running dev server, and the existing database's growth over time. This PR does not shrink existing rows; reclaiming space stays with the compaction and vacuum questions in fix(server): projection maintenance finally has an entrypoint #15759.

Implemented with GPT-6 Astra (Codex CLI) and Claude Opus 5.5 (Claude Code via T3 Code), reviewed by Claude Opus 5.5.

…ed prompt

Store a subagent prompt once in orchestration_events and point later unchanged updates at that row. Reads and replay budgets restore it in SQL, so events, the wire, and clients are unchanged. Slim rows keep an empty prompt so older servers can still decode them.

Fixes pingdotgg#18204
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 11, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Oct 11, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 0eb17fc

Macroscope's review found this PR approvable — This is a localized persistence optimization for repeated Claude subagent prompts; replayed events, wire data, projections, and clients remain unchanged. The new storage indirection and rollback behavior are covered by focused tests, with no schema, default, deployment, security, billing, or static-analysis changes.

Notes:

  • Diff unchanged. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 11, 2026 — with ChatGPT Codex Connector
@macroscopeapp
macroscopeapp Bot dismissed their stale review October 11, 2026 22:55

Dismissing prior approval to re-evaluate 0eb17fc

@coderabbitai

coderabbitai Bot commented Oct 11, 2026

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 4a4ee31c-e641-41cd-95ef-90be5a36e977

📥 Commits

Reviewing files that changed from the base of the PR and between 3f70c83 and 0eb17fc.


📒 Files selected for processing (3)
  • apps/server/src/orchestration-v2/ProjectionMaintenance.ts
  • apps/server/src/persistence/OrchestrationEventStore.test.ts
  • apps/server/src/persistence/OrchestrationEventStore.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 7 remain after this review.



📝 Walkthrough

Walkthrough

The event store now stores repeated subagent prompts by reference. Event reads restore those prompts, and replay statistics use the restored payload sizes. Tests cover prompt storage, replay, and rollback.

Changes

Subagent Prompt Storage

Layer / File(s) Summary
Write prompt anchors
apps/server/src/persistence/OrchestrationEventStore.ts, apps/server/src/persistence/OrchestrationEventStore.test.ts
Appends store an unchanged prompt by referencing an earlier full-prompt row. The prompt hint map is capped at 4096 entries. A rollback test checks that a rolled-back append leaves no event rows.
Restore prompts on reads
apps/server/src/persistence/OrchestrationEventStore.ts, apps/server/src/persistence/OrchestrationEventStore.test.ts, apps/server/src/orchestration-v2/ProjectionMaintenance.ts
Event reads restore referenced prompts, and replay statistics count restored payload bytes. Tests check replayed event payloads and statistics. A comment records that prompt-referenced rows are retained.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Suggested reviewers: juliusmarminge


Merge Risk | ⚪ Minimal · up to 0eb17

Merge Risk: ⚪ Minimal · up to 0eb17

No actionable issue is established from the supplied evidence; the change is mergeable with normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 0eb17

Normal replay preserves task text, and the inspected changes do not establish a new security exposure. Older servers can read empty task text after rollback; cross-version recovery and concurrent failure scenarios remain incompletely validated.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The reference dependency spans retained event rows within one orchestration database. Arbitrary anchor selection would require bypassing the inspected event encoding path or modifying persisted rows; no such new client or provider capability was established. The global lookup is not independently a tenant-isolation control.

Security Findings and Attack Paths

  • inferred — The candidate attack path of supplying promptSequence to retrieve another event's prompt was not substantiated through inspected production ingress. Domain events are schema-decoded, the contract excludes that field, and persistence generates references from internal hints after matching the caller's existing prompt text. This conclusion does not establish safety for uninspected ingress or privileged database mutation.

Trust Boundaries and Controls

  • observed — Provider ingress retains its existing owner-guarded, run-guarded, and unguarded write branches. Those branches and the persistence adapter are unchanged relative to the base; the PR does not introduce the unguarded fallback or widen its authority.

Resilience and Maintainability Implications

  • inferred — Cold, evicted, or invalidated hints degrade storage efficiency rather than selecting an unchecked prompt. The insertion-time check and retained anchors contain rollback-related reference failures. Continued correctness depends on retaining those event families; concurrency, interruption, and recovery guarantees beyond the supplied rollback test remain source-based conclusions.

Pre-merge checks | Passed 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description check Passed The description covers the problem, implementation, scope and approval, verification results, limitations, and agent details. It matches the repository template and provides specific test evidence.
Title check Passed The title clearly and concisely describes the primary fix: preventing unchanged Claude subagent prompts from being stored repeatedly.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants