Skip to content

perf(pages): reuse bounded immutable payload reads#87

Merged
flyingrobots merged 3 commits into
mainfrom
perf/bounded-page-payload-reuse
Jul 18, 2026
Merged

perf(pages): reuse bounded immutable payload reads#87
flyingrobots merged 3 commits into
mainfrom
perf/bounded-page-payload-reuse

Conversation

@flyingrobots

Copy link
Copy Markdown
Member

Summary

  • coalesce concurrent and repeated pages.get() payload reads by immutable page OID
  • bound completed payload residence by both entry count and aggregate bytes
  • return caller-owned copies, evict failures, and preserve per-call size validation
  • keep pages.open() uncached, streaming, and outside retention authority
  • document the cache contract and v6.5.1 behavior

Why

git-warp retained observations repeatedly opened the same immutable page payloads. Metadata reuse from v6.5.0 removed part of the Git command amplification, but every pages.get() still started another blob read. The cache belongs in git-cas, which owns immutable CAS access and residency policy.

Compatibility

This changes no persisted format, handle, ref, witness, or existing method signature. pageCacheEntries and pageCacheBytes are additive constructor options. Cache residence is not retention evidence.

Verification

  • pnpm run release:verify: 14/14 steps, 6,652 observed tests across Node, Bun, and Deno
  • pnpm test: 2,029 passed, 2 skipped after review hardening
  • pnpm run lint: passed
  • Docker real-Git performance contract: 3/3 passed; an identical warm page read performs zero additional Git commands
  • Graft structural review: no breaking changes and no exported-symbol delta

Follow-up

Path-local persistent bundle derivation remains separate in #86.

Closes #85

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 30 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: efbf9628-fb48-4406-9316-915a573b2e08

📥 Commits

Reviewing files that changed from the base of the PR and between 4343163 and 3a5360d.

📒 Files selected for processing (7)
  • docs/API.md
  • docs/design/0051-bounded-page-payload-reuse/bounded-page-payload-reuse.md
  • docs/releases/v6.5.1.md
  • src/domain/services/PageService.js
  • src/helpers/boundedPromiseCache.js
  • test/unit/domain/services/PageService.test.js
  • test/unit/helpers/boundedPromiseCache.test.js
📝 Walkthrough

Walkthrough

Adds bounded LRU reuse for immutable pages.get() payloads, configurable by entry count and byte budget. Reads coalesce, results are copied per caller, failures remain retryable, oversized values are not retained, and pages.open() remains streaming.

Changes

Bounded page payload reuse

Layer / File(s) Summary
Public cache configuration
index.d.ts, index.js, src/domain/services/PageService.js, docs/API.md, docs/design/...
Adds pageCacheEntries and pageCacheBytes options, defaults, validation, and wiring into PageService.
Page payload cache implementation
src/domain/services/PageService.js
Caches successful payload reads by page OID with entry and byte bounds, caller-owned copies, retryable failures, and unchanged streaming behavior for pages.open().
Cache behavior validation
test/unit/domain/services/PageService.test.js, test/unit/facade/..., test/unit/types/..., test/integration/...
Tests coalescing, copying, eviction, byte limits, failures, invalid options, declarations, and zero-command warm reads.
Design and release documentation
GUIDE.md, CHANGELOG.md, docs/design/..., docs/releases/...
Documents the cache contract, design decisions, acceptance criteria, and v6.5.1 release behavior.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant PageService
  participant BoundedPromiseCache
  participant Persistence
  Caller->>PageService: pages.get(handle, maxBytes)
  PageService->>BoundedPromiseCache: getOrCreate(root.oid, read)
  BoundedPromiseCache->>Persistence: readBlobStream(root)
  Persistence-->>BoundedPromiseCache: payload bytes
  BoundedPromiseCache-->>PageService: cached payload
  PageService-->>Caller: copied bytes
Loading

Possibly related issues

Possibly related PRs

  • git-stunts/git-cas#63 — Introduced the immutable page storage path that this change extends with bounded payload reuse.

Suggested reviewers: git-stunts

Poem

A rabbit found pages tucked under a tree,
Reused them in bounds, from byte one to byte three.
Copies hopped out, while failures ran free,
Streams kept on flowing, uncached as can be.
“Less Git,” whispered Bun, “more time for tea!”

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: bounded immutable payload read reuse for pages.
Description check ✅ Passed It includes the required substance for the template, including rationale, verification, and closure, though the headings are organized differently.
Linked Issues check ✅ Passed The changes satisfy #85 with bounded LRU reuse, copy-on-read, retryable failures, uncached open(), docs/types, and a warm-read Git command test.
Out of Scope Changes check ✅ Passed The docs, design note, tests, and API/type updates all directly support the bounded page payload reuse feature.

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

@flyingrobots

Copy link
Copy Markdown
Member Author

@codex Self-Code Review / Code Lawyer report

Severity Open Resolved
Critical 0 0
High 0 0
Medium 0 1
Low 0 0
Markdown/style 0 1

Resolved findings

  1. Medium, API contract: DEFAULT_PAGE_CACHE_ENTRIES and DEFAULT_PAGE_CACHE_BYTES were initially exported from the internal service module. Graft classified the branch as a minor exported-surface expansion, which was inappropriate for the v6.5.1 patch contract. Commit 4343163e makes both constants private; Graft now reports no exported-symbol delta.
  2. Style gate: the zero-byte residency test initially pushed one describe callback over the repository 50-line limit. The tests were split into coherent scopes; full ESLint is green.

Open findings

None. The implementation preserves immutable OID identity, per-call root/size validation, caller-copy isolation, failure retry, bounded completed residency, streaming pages.open(), and retention-authority separation.

Evidence

  • release verification: 14/14 steps, 6,652 observed tests across Node, Bun, and Deno
  • final unit suite: 2,029 passed, 2 skipped
  • focused Docker real-Git contract: 3/3 passed, including zero additional Git commands for an identical warm pages.get()
  • git diff --check: clean
  • Graft: no breaking changes; no exported-symbol delta

Please independently confirm the conclusions and flag any missed contract or lifecycle issue.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/design/0051-bounded-page-payload-reuse/bounded-page-payload-reuse.md`:
- Around line 37-38: Update the retained-property fixture sentence to hyphenate
the compound modifier, changing “1.80 second time” to “1.80-second time” while
preserving the surrounding wording and measurements.
- Around line 44-49: Update the bounded cache eviction logic in
boundedPromiseCache so pending promise entries are never evicted when maxEntries
is exceeded; evict only settled entries, or track in-flight work separately
while preserving bounded completed-entry storage. Ensure repeated requests for
an evicted-by-capacity OID still share its existing in-flight promise, and add a
regression test covering more concurrent unique OIDs than pageCacheEntries.

In `@src/domain/services/PageService.js`:
- Around line 90-93: The bounded cache must not evict pending promises, since
doing so breaks read coalescing and can displace resident entries before weight
is known. Update the cache used by PageService’s `#payloads/getOrCreate` flow to
retain in-flight reads separately or restrict eviction to completed entries,
while preserving bounded LRU behavior for completed payloads; add a contention
test covering repeated A/B/A reads and an oversized pending read.

In `@test/integration/bundle-reference-performance.test.js`:
- Around line 120-124: Update PageService.get() to avoid resolveRoot() metadata
reads on cached page hits: either cache and reuse the validated size/type
alongside the payload, or perform the limit check before
readObjectType/readObjectSize. Preserve validation for cold or uncached reads
while ensuring warm reads produce no Git metadata I/O.

In `@test/unit/domain/services/PageService.test.js`:
- Around line 94-144: Expand the PageService cache tests to exercise true LRU
ordering and aggregate byte eviction: change the entry-count scenario to use at
least two entries and access items so the least-recently-used payload is the one
reread, then add a positive pageCacheBytes case where multiple retained payloads
exceed the total budget and verify the expected rereads through
persistence.readBlobStream. Keep the existing zero-byte and oversized-payload
coverage intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: c20f433a-5576-4bfc-b6b9-56d77476390e

📥 Commits

Reviewing files that changed from the base of the PR and between a6c9c33 and 4343163.

📒 Files selected for processing (13)
  • CHANGELOG.md
  • GUIDE.md
  • docs/API.md
  • docs/design/0051-bounded-page-payload-reuse/bounded-page-payload-reuse.md
  • docs/design/README.md
  • docs/releases/v6.5.1.md
  • index.d.ts
  • index.js
  • src/domain/services/PageService.js
  • test/integration/bundle-reference-performance.test.js
  • test/unit/domain/services/PageService.test.js
  • test/unit/facade/ContentAddressableStore.application-storage.test.js
  • test/unit/types/declaration-accuracy.test.js
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: test-unit
🧰 Additional context used
📓 Path-based instructions (3)
docs/design/**

📄 CodeRabbit inference engine (AGENTS.md)

Use docs/design/ directory for durable design contracts and proof plans

Files:

  • docs/design/README.md
  • docs/design/0051-bounded-page-payload-reuse/bounded-page-payload-reuse.md
GUIDE.md

📄 CodeRabbit inference engine (AGENTS.md)

Use GUIDE.md for orientation and productive-fast path documentation

Files:

  • GUIDE.md
CHANGELOG.md

📄 CodeRabbit inference engine (AGENTS.md)

Use CHANGELOG.md to record the historical truth of merged behavior

Files:

  • CHANGELOG.md
🧠 Learnings (3)
📚 Learning: 2026-02-28T19:21:13.982Z
Learnt from: flyingrobots
Repo: git-stunts/git-cas PR: 15
File: test/unit/domain/services/CasService.envelope.test.js:326-330
Timestamp: 2026-02-28T19:21:13.982Z
Learning: In fuzz tests for cryptographic operations, use a seeded PRNG (e.g., xorshift32) for control-flow variables such as plaintext size selection and recipient index selection to ensure reproducibility. Continue to use randomBytes() for cryptographic keys and nonces to preserve realistic randomness and avoid security anti-patterns. This guideline applies to test files that perform fuzz testing of crypto logic; implement a consistent seed setup (e.g., fixed seed in test initialization) and document the rationale to enable deterministic replays across runs.

Applied to files:

  • test/unit/facade/ContentAddressableStore.application-storage.test.js
  • test/unit/types/declaration-accuracy.test.js
  • test/integration/bundle-reference-performance.test.js
  • test/unit/domain/services/PageService.test.js
📚 Learning: 2026-03-30T19:53:48.000Z
Learnt from: flyingrobots
Repo: git-stunts/git-cas PR: 29
File: docs/design/TR-010-planning-index-consistency-review.md:121-131
Timestamp: 2026-03-30T19:53:48.000Z
Learning: In this repo, CHANGELOG.md entries should be user-facing and descriptive (bullet points) rather than cycle-ID headings (e.g., use a phrase like “Planning-index consistency review” instead of a “TR-010 — …” heading). When searching the changelog, don’t rely on grepping for cycle IDs (e.g., “TR-010”) because it may cause false negatives; search for the descriptive keywords/phrases from the bullet entries instead.

Applied to files:

  • CHANGELOG.md
📚 Learning: 2026-07-13T17:00:46.222Z
Learnt from: flyingrobots
Repo: git-stunts/git-cas PR: 65
File: src/domain/helpers/isCanonicalCollectionKey.js:21-35
Timestamp: 2026-07-13T17:00:46.222Z
Learning: In git-stunts/git-cas, the codebase is intended to run on multiple JavaScript runtimes (Node, Bun, and Deno), not just Node. During code review, don’t suggest replacing existing portable helper logic with newer Node-only built-ins (e.g., Node 20+ APIs like `String.prototype.isWellFormed()`) unless the change preserves Bun/Deno compatibility (via portable/polyfill implementations or safe runtime gating). If a file includes manual implementations (such as `src/domain/helpers/isCanonicalCollectionKey.js`), treat them as intentional to avoid requiring a higher host built-in baseline.

Applied to files:

  • src/domain/services/PageService.js
🪛 LanguageTool
docs/design/0051-bounded-page-payload-reuse/bounded-page-payload-reuse.md

[grammar] ~38-~38: Use a hyphen to join words.
Context: ...onds, including 32 blob reads and a 1.80 second time to first reading. - Page OID...

(QB_NEW_EN_HYPHEN)

🔇 Additional comments (10)
index.d.ts (1)

709-712: LGTM!

index.js (1)

136-137: LGTM!

Also applies to: 158-159, 180-181, 240-240, 378-379, 631-633, 658-660, 682-684

docs/design/0051-bounded-page-payload-reuse/bounded-page-payload-reuse.md (1)

1-36: LGTM!

Also applies to: 39-43, 50-71, 76-143

test/unit/domain/services/PageService.test.js (1)

1-14: LGTM!

Also applies to: 75-92, 147-172

test/unit/facade/ContentAddressableStore.application-storage.test.js (1)

75-86: LGTM!

test/unit/types/declaration-accuracy.test.js (1)

116-117: LGTM!

src/domain/services/PageService.js (2)

7-11: LGTM!

Also applies to: 20-47, 136-146, 204-210


85-90: 🚀 Performance & Scalability

Verify that warm reads avoid repeated Git metadata work.

get() calls resolveRoot() before consulting #payloads; resolveRoot() invokes object-type and size reads on every call. Unless those persistence operations are independently cached, an identical warm pages.get() can still issue Git-backed metadata commands, conflicting with the zero-additional-command objective. Confirm this with the real-Git command-count test and add a validated metadata fast path if needed.

docs/design/README.md (1)

14-14: LGTM!

docs/API.md (1)

83-84: LGTM!

Comment thread docs/design/0051-bounded-page-payload-reuse/bounded-page-payload-reuse.md Outdated
Comment thread src/domain/services/PageService.js Outdated
Comment thread test/integration/bundle-reference-performance.test.js
Comment thread test/unit/domain/services/PageService.test.js
@flyingrobots

Copy link
Copy Markdown
Member Author

@codex Self-Code Review / Code Lawyer re-review after 3a5360d2

Severity Open Resolved
Critical 0 0
High 0 0
Medium / Major 0 3
Low / Minor 0 1
Markdown / style 0 1

Review disposition

All five CodeRabbit findings were valid and are addressed:

  1. Pending work now lives in a separate non-evicting in-flight map, while only settled entries participate in bounded LRU residence.
  2. A/B/A contention beyond pageCacheEntries coalesces to one read per OID.
  3. Oversized pending work cannot displace a completed resident.
  4. Resident and in-flight page hits bypass Git metadata while every caller still enforces its own maxBytes.
  5. Tests now prove true two-entry LRU ordering and positive aggregate-byte eviction; the compound modifier is hyphenated.

No additional correctness, lifecycle, compatibility, or documentation findings remain in the current diff.

Evidence

  • pnpm run release:verify: 14/14 steps, 6,673 observed tests
  • Unit: Node 2,035; Bun 2,034; Deno 2,025
  • Real-Git integration: 193/193 on each of Node, Bun, and Deno
  • Focused cache contracts: 30/30
  • Pre-push lint and 2,035-test Node unit gate: green
  • git diff --check: clean
  • Graft: no breaking changes and no exported API delta
  • Clean worktree against freshly fetched origin/main

Please independently confirm the conclusions and flag any missed contract or lifecycle issue.

@flyingrobots
flyingrobots merged commit ad5b91b into main Jul 18, 2026
6 checks passed
@flyingrobots
flyingrobots deleted the perf/bounded-page-payload-reuse branch July 18, 2026 23:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: bound and reuse immutable page payload reads

1 participant