test(server): windowed history pages are checked against the full index at the window edges #35877
main fromrefs/pull/35877/head·merged by t3dotgg(GitHub profile, opens in a new tab) View on GitHubAn independent review of #34573 planted 23 bugs in the windowed history read. Four of them change a page a client can request and still passed every test. They still pass on main today, after #35405. A fifth was caught at the review and stopped being caught later: #23420 added a kind to the generated list, which shifted the seeded values.
The generated test a page read from a window equals the page read from the full index now catches all five. Each page is still compared with the page the full index returns for the same request, so there are no hand-written expected values. No product code changes.
A new fifth thread puts three things below one window:
- a user turn under a hidden queued turn
- the start of a long run that folds
- the start of the run before it, which has later rows among the first rows of the long run
The fourth thread now has a fixed late notification. It is a turn, then many rolled-back rows, then a late notification of that turn, then 149 one-row turns. One page ends with exactly those 149 turns above the notification.
| Planted bug | Failing request | Window page | Full-index page |
|---|---|---|---|
| No read of a folded run below the window | Fifth thread: first work-folding page, from the newest row | 500 rows, long run not folded | 500 rows, both runs folded |
| Rows below the trusted bound are trusted | Fifth thread: first work-folding page, from the newest row | 500 rows, older run not folded | 500 rows, both runs folded |
| A user turn below the window is ignored | Fifth thread: work-folding page that ends at the reply deep in the stopped run | 75 rows | 309 rows, back to the first user turn |
olderUserTurn reads one row | Fifth thread: work-folding page that ends at the reply deep in the stopped run | 75 rows | 309 rows, back to the first user turn |
No startedRuns (a late notification counted as a turn) | Fourth thread: work-folding page that ends at the active run | 150 rows, stops at the notification | 244 rows, back to the turn start |
Each bug was planted locally and never committed. Before this change, all 85 tests in ProjectionStore.test.ts and threadHistoryPaging.test.ts passed with each one. Now each one fails this test. The two threads do not depend on the seed: with eight other seeds they caught all five.
Of the 23 planted bugs, the tests now catch 19. The other four are the ones the review reported as not caught.
The test goes from about 770 ms to about 940 ms.
Created with Claude Fable 5.2 in Claude Code (T3 Code).
🤖 Generated with Claude Code
- 1
github-actions[bot](GitHub profile, opens in a new tab) added labelsvouch:trusted
github-actions[bot](GitHub profile, opens in a new tab) added labelssize:M
macroscopeapp[bot](GitHub profile, opens in a new tab) approved these changes
Thread transfer impact#
✅ Thread transfer remains within every enforced ceiling.
Provider Metric Main baseline This PR Impact PR ceiling Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅ Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅ Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅ Codex Live turn WebSocket decoded 21.5 KiB 21.5 KiB 0 B (0.0%) 24.4 KiB ✅ Codex Live turn messages 1 1 0 (0.0%) 8 ✅ Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅ Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅ Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅ Claude Live turn WebSocket decoded 21.9 KiB 21.9 KiB 0 B (0.0%) 24.4 KiB ✅ Claude Live turn messages 1 1 0 (0.0%) 8 ✅ Other scenarios#
All 64 scenario measurements match
main.All 64 scenario measurements
Provider Scenario Metric Main baseline This PR Impact PR ceiling Codex short turn resumeWebSocket decoded10.5 KiB 10.5 KiB 0 B (0.0%) 12.7 KiB ✅ Codex short turn resumeWebSocket messages2 2 0 (0.0%) 2 ✅ Codex long turn running, cold openHTTP decoded281.7 KiB 281.7 KiB 0 B (0.0%) 302.7 KiB ✅ Codex long turn running, cold openrows75 75 0 (0.0%) 75 ✅ Codex long turn running, history pageHTTP decoded92.4 KiB 92.4 KiB 0 B (0.0%) 107.4 KiB ✅ Codex long turn running, history pagerows75 75 0 (0.0%) 75 ✅ Codex long turn finished, cold openHTTP decoded381.5 KiB 381.5 KiB 0 B (0.0%) 410.2 KiB ✅ Codex long turn finished, cold openrows151 151 0 (0.0%) 151 ✅ Codex long turn finished, socket cold openWebSocket decoded381.6 KiB 381.6 KiB 0 B (0.0%) 410.2 KiB ✅ Codex long turn finished, socket cold openWebSocket messages2 2 0 (0.0%) 2 ✅ Codex long turn finished, socket cold openrows151 151 0 (0.0%) 151 ✅ Codex long turn finished, work pageHTTP decoded186.2 KiB 186.2 KiB 0 B (0.0%) 200.2 KiB ✅ Codex long turn finished, work pagerows150 150 0 (0.0%) 150 ✅ Codex idle thread resumeWebSocket decoded65 B 65 B 0 B (0.0%) 200 B ✅ Codex idle thread resumeWebSocket messages1 1 0 (0.0%) 1 ✅ Codex fleet shell snapshotHTTP decoded42.4 KiB 42.4 KiB 0 B (0.0%) 53.7 KiB ✅ Codex fleet shell snapshotrows27 27 0 (0.0%) 27 ✅ Codex fleet shell subscribeWebSocket decoded65 B 65 B 0 B (0.0%) 200 B ✅ Codex fleet shell subscribeWebSocket messages1 1 0 (0.0%) 1 ✅ Codex fleet shell resume checkHTTP decoded18 B 18 B 0 B (0.0%) 100 B ✅ Codex fleet shell resume checkrows0 0 0 0 ✅ Codex stale shell reloadHTTP decoded42.4 KiB 42.4 KiB 0 B (0.0%) 53.7 KiB ✅ Codex stale shell reloadrows27 27 0 (0.0%) 27 ✅ Codex stale shell resumeWebSocket decoded140 B 140 B 0 B (0.0%) 400 B ✅ Codex stale shell resumeWebSocket messages2 2 0 (0.0%) 2 ✅ Codex stale todo list cold openHTTP decoded72.4 KiB 72.4 KiB 0 B (0.0%) 83.0 KiB ✅ Codex stale todo list cold openrows75 75 0 (0.0%) 75 ✅ Codex stale todo list cold opennodes2 2 0 (0.0%) 4 ✅ Codex stale todo list cold opensubagents2 2 0 (0.0%) 4 ✅ Codex stale todo list cold openplans1 1 0 (0.0%) 2 ✅ Codex stale todo list cold openproviderTurns1 1 0 (0.0%) 2 ✅ Codex stale todo list cold opencheckpoints1 1 0 (0.0%) 2 ✅ Claude short turn resumeWebSocket decoded10.6 KiB 10.6 KiB 0 B (0.0%) 12.7 KiB ✅ Claude short turn resumeWebSocket messages2 2 0 (0.0%) 2 ✅ Claude long turn running, cold openHTTP decoded283.3 KiB 283.3 KiB 0 B (0.0%) 302.7 KiB ✅ Claude long turn running, cold openrows75 75 0 (0.0%) 75 ✅ Claude long turn running, history pageHTTP decoded93.4 KiB 93.4 KiB 0 B (0.0%) 107.4 KiB ✅ Claude long turn running, history pagerows75 75 0 (0.0%) 75 ✅ Claude long turn finished, cold openHTTP decoded384.2 KiB 384.2 KiB 0 B (0.0%) 410.2 KiB ✅ Claude long turn finished, cold openrows151 151 0 (0.0%) 151 ✅ Claude long turn finished, socket cold openWebSocket decoded384.3 KiB 384.3 KiB 0 B (0.0%) 410.2 KiB ✅ Claude long turn finished, socket cold openWebSocket messages2 2 0 (0.0%) 2 ✅ Claude long turn finished, socket cold openrows151 151 0 (0.0%) 151 ✅ Claude long turn finished, work pageHTTP decoded188.1 KiB 188.1 KiB 0 B (0.0%) 200.2 KiB ✅ Claude long turn finished, work pagerows150 150 0 (0.0%) 150 ✅ Claude idle thread resumeWebSocket decoded66 B 66 B 0 B (0.0%) 200 B ✅ Claude idle thread resumeWebSocket messages1 1 0 (0.0%) 1 ✅ Claude fleet shell snapshotHTTP decoded43.0 KiB 43.0 KiB 0 B (0.0%) 53.7 KiB ✅ Claude fleet shell snapshotrows27 27 0 (0.0%) 27 ✅ Claude fleet shell subscribeWebSocket decoded66 B 66 B 0 B (0.0%) 200 B ✅ Claude fleet shell subscribeWebSocket messages1 1 0 (0.0%) 1 ✅ Claude fleet shell resume checkHTTP decoded18 B 18 B 0 B (0.0%) 100 B ✅ Claude fleet shell resume checkrows0 0 0 0 ✅ Claude stale shell reloadHTTP decoded43.0 KiB 43.0 KiB 0 B (0.0%) 53.7 KiB ✅ Claude stale shell reloadrows27 27 0 (0.0%) 27 ✅ Claude stale shell resumeWebSocket decoded140 B 140 B 0 B (0.0%) 400 B ✅ Claude stale shell resumeWebSocket messages2 2 0 (0.0%) 2 ✅ Claude stale todo list cold openHTTP decoded73.4 KiB 73.4 KiB 0 B (0.0%) 83.0 KiB ✅ Claude stale todo list cold openrows75 75 0 (0.0%) 75 ✅ Claude stale todo list cold opennodes2 2 0 (0.0%) 4 ✅ Claude stale todo list cold opensubagents2 2 0 (0.0%) 4 ✅ Claude stale todo list cold openplans1 1 0 (0.0%) 2 ✅ Claude stale todo list cold openproviderTurns1 1 0 (0.0%) 2 ✅ Claude stale todo list cold opencheckpoints1 1 0 (0.0%) 2 ✅ Baseline:
95cb068· PR result:77de3cb· Source CI: successScenario and decoded snapshot size
10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
- Codex decoded thread snapshot: 108.5 KiB
- Claude decoded thread snapshot: 108.8 KiB
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.
No actionable comments were generated in the recent review.
Walkthrough
-
The window-equivalence test now runs five rounds. It adds cases for cancelled queued turns, long folded runs, late wake notifications, and overlapping run ownership. Page-read checks now use recorded page-end item IDs.
Changes: Projection window-equivalence test
Layer / File(s) Summary Generated histories and page checks
apps/server/src/orchestration-v2/ProjectionStore.test.tsThe test adds a fifth-round run mix and changes the fourth-round history to include a rolled-back run, a late wake, and 149 one-row runs. It adds long-fold work rows and adjusts run ownership, wake selection, and assistant replies. Page-read checks use recorded page-end item IDs. Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Other
Possibly related PRs
- pingdotgg/t3code#33305: Changes the thread snapshot window query, which the expanded window-equivalence tests exercise at folded-group and user-turn boundaries.
- pingdotgg/t3code#35405: Changes history paging behavior at kept-row boundaries, which is related to the test’s page-boundary checks.
Suggested reviewers:
alb11747,juliusmarminge
Merge Risk:
Minimal · up to77de3-
This PR only adds test coverage for windowed history paging and does not change product behavior. No concrete merge-blocking risk was found.
Pre-merge checks:
4-
Check name Status Explanation Title check The title names the change: a test in the server package that checks windowed history pages against the full index at the window edges. The raw summary describes a window-equivalence test that compare… Description check The description follows the template's main sections in substance. It states the problem (an independent review found planted bugs that the existing tests missed). It explains the change (a generated … Linked Issues check Check skipped because no linked issues were found for this pull request. Out of Scope Changes check Check skipped because no linked issues were found for this pull request. Full details: Title check
-
Explanation
The title names the change: a test in the server package that checks windowed history pages against the full index at the window edges. The raw summary describes a window-equivalence test that compares window pages with the full index, and the objectives say the same. The title is specific and matches the changeset. It is a test-only change, and the title says so with the test prefix. The title is a little long at 91 characters, but it is still clear.
Full details: Description check
-
Explanation
The description follows the template's main sections in substance. It states the problem (an independent review found planted bugs that the existing tests missed). It explains the change (a generated test now compares window pages with the full-index page, plus new threads for specific cases). It states that no product code changes. It gives verification detail: a table of planted bugs, the seed check, the number of bugs caught, and the runtime change. The Scope section does not link a bug issue. It cites a PR (
#34573) and a review, and it does not say why a test-only addition needs no issue or whether a maintainer asked for it. The template also asks for the model and harness used. The description says 'Created with Claude Fable 5.2 in Claude Code', so that part is present. The Problem section does not state a user-facing bug, because this PR adds tests for planted bugs, so the framing is less direct than the template expects. Overall the description is mostly complete.Resolution
Optional improvements: add a short Scope note that explains why no issue is linked (test-only change for planted bugs) or link the review issue. State the Problem as the coverage gap in plain terms, so it does not depend on the external PR for context.
-
Finishing Touches
-
Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info-
Run configuration-
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: t3/test-window-edge-cases
- File: .coderabbit.config.ts
- Commit: 77de3cb
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
8e046a46-dada-42ac-a29a-607a51ac15de
Commits-
Reviewing files that changed from the base of the PR and between 75c243783f8f21fec6b8c765ec6dd92fed231bf5 and 77de3cb309b1d197c56d160d22ce8d37ba9302ab.
Files selected for processing: 1-
apps/server/src/orchestration-v2/ProjectionStore.test.ts
Included review availability: This review used your included allowance. 8 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 10 reviews per hour.
-
-
macroscopeapp[bot](GitHub profile, opens in a new tab) approved these changes
t3dotgg(GitHub profile, opens in a new tab) merged this
f539020t3dotgg(GitHub profile, opens in a new tab) closed this
Sign in to join this conversation.
Approvability#
Verdict: Approved at
77de3cbMacroscope's review found this PR approvable — This change expands history-pagination window-edge tests within an ignored test file. It does not change production behavior or introduce material operational risk.
Notes:
- No code objects were reviewed. Approvability was decided on eligibility alone.
You can add or adjust custom eligibility rules. [Learn more](https://docs.macroscope.com/approvability#example-custom-eligibility-rules).