Skip to content

Phase 1 cache rewrite — long-lived design and execution plan - #967

Open
AnthonyMDev wants to merge 26 commits into
mainfrom
cache-rewrite/phase-1-plan
Open

Phase 1 cache rewrite — long-lived design and execution plan#967
AnthonyMDev wants to merge 26 commits into
mainfrom
cache-rewrite/phase-1-plan

Conversation

@AnthonyMDev

@AnthonyMDev AnthonyMDev commented May 7, 2026

Copy link
Copy Markdown
Contributor

Phase 1 Cache Rewrite — Long-lived plan branch

This is the long-lived feature branch that holds the four Phase 1 design docs (summary, plan, execution, perf) and accumulates every implementation PR as it merges. Not merged into main until all PRs in the stack have merged into it — see execution plan §10 done conditions. Each implementation PR's diff is reviewed independently and merges into this branch, not into main directly.


Progress Tracker

Last updated: 2026-05-29 · In-plan PRs merged: 11 / 37 (≈ 30%) · Active phase: 1A · Latest activity: PR-008b merged (#1005) — position-keyed records DDL with (cache_key, field_name, position) PK; schema version stays at v3 (aligned with Apollo iOS 3.x); doc references to v4 corrected in the same PR. ADR 0007 (#1003) also merged — selection-set-aware cache reads.

Status legend

Symbol Meaning
Merged into cache-rewrite/phase-1-plan
🟡 Open / in review
Not started

Phase 0 — Design lock, ADRs, performance baseline ✅

Five Architecture Decision Records establishing the design contract, plus a 2.x performance baseline used as the reference dataset for the eventual 3.0-alpha comparison.

Slot PR # Title Status Merged
PR-001 #968 ADR 0001 — major version bump rationale 2026-05-07
PR-002 #969 ADR 0002 — Record abstraction (field-aware CachedField) 2026-05-07
PR-003 #970 ADR 0003 — TTL semantics (tri-state, scoped, read-mode split) 2026-05-07
PR-004 #971 ADR 0004 — Watcher × TTL 2026-05-11
PR-004b #972 ADR 0005 — stale-tolerance API surface 2026-05-11
PR-004a #980 macOS 2.x cache baseline benchmark harness + dataset 2026-05-26

Phase 0: 6 of 6 merged. Phase complete.

Phase 1A — SQLite schema rewrite + field-aware Record (11 PRs)

End state: 3.0-alpha tag with new SQLite row-per-field schema and field-aware Record shipping. Performance gates green; comparison dataset published.

Slot PR # Title Status Merged
PR-005 #998 introduce CachedField type (no consumers yet) 2026-05-26
PR-006 #987 change Record.fields type to [CacheKey: CachedField] 2026-05-26
PR-007 #999 schema_metadata table + version detection 2026-05-26
PR-008 #1000 new schema DDL — records table with composite PK + SchemaVersion + SQLiteSchema namespace 2026-05-27
PR-008b #1005 replace records DDL with position-keyed schema per ADR 0006 (schema version stays at v3) 2026-05-29
PR-009 row-per-element CRUD against position-keyed schema
PR-010 switch SQLiteNormalizedCache to new schema; drop-and-rebuild migration
PR-011 SQLite performance-gate harness on iPhone 16 Pro
PR-011a comprehensive performance measurement harness (Tier 1 + Tier 2)
PR-011b alpha-vs-2.x comparison reporter + published dataset
PR-012 tag 3.0-alpha; release notes; changelog

Phase 1A: 5 of 11 merged. Next up: PR-009 (row-per-element CRUD against the position-keyed schema). Note: the ADR 0007 sub-phase 1A.5 (PRs PR-009a–h for selection-set-aware field projection) is approved as a design but not yet reflected in §8 — pending a follow-up restructure PR after PR-009 lands.

Phase 1B — @cacheControl codegen end-to-end (7 PRs)

End state: codegen emits cacheControl: metadata on Selection.Field. Runtime stores but does not yet enforce TTL — landed in Phase 1C.

Slot PR # Title Status Merged
PR-013 @cacheControl directive definitions (JS frontend)
PR-014 precedence resolution algorithm + JS unit tests
PR-015 bridge resolved cacheControlMaxAge through CompilationResult
PR-016 Selection.CacheControlDirective runtime type
PR-017 IR.Field exposes cacheControlMaxAge
PR-018 SelectionSetTemplate emits cacheControl: parameter
PR-019 regenerate TestCodeGenConfigurations; snapshot tests

Phase 1B: 0 of 7 merged. Blocked on Phase 1A.

Phase 1C — TTL evaluation, read-mode split, stale-tolerance API (8 PRs)

End state: TTL is enforced on strict reads; permissive reads mark staleness; watcher uses permissive reads; .revalidateCache cache policy ships.

Slot PR # Title Status Merged
PR-020 TimeProvider protocol + ApolloStore integration
PR-021 TTLEnforcement enum + ApolloStore.load(_:ttlEnforcement:)
PR-022 TTL check in CacheDataExecutionSource.resolveField
PR-022a stale-tolerance API surface (RequestConfiguration.ttlEnforcement, Source.cache(containsStaleFields:), MissingValueReason, .revalidateCache)
PR-023 GraphQLResultNormalizer injects writtenAt on cache writes
PR-024 GraphQLDependencyTracker computes earliestExpiry + containsStaleFields
PR-025 watcher uses .permissive on didChangeKeys re-read
PR-026 TTLTests.swift covering all 9 sample scenarios + boundary cases

Phase 1C: 0 of 8 merged. Blocked on Phase 1B.

Phase 1D — Opt-in watcher refresh, hardening, beta (5 PRs)

End state: 3.0-beta tag pushed. Migration guide live. Internal beta cycle complete with zero P0/P1 issues.

Slot PR # Title Status Merged
PR-027 GraphQLQueryWatcher.automaticallyRefreshOnExpiry flag + timer
PR-028 InMemoryNormalizedCache parity for TTL
PR-029 migration guide in Documentation.docc for 3.0
PR-030 demonstrate @cacheControl usage in TestCodeGenConfigurations
PR-031 tag 3.0-beta; final changelog; release announcement draft

Phase 1D: 0 of 5 merged. Blocked on Phase 1C.

Supporting PRs (governance / docs, not in §8)

These don't ship code in the main stack but capture project-wide decisions (workflow conventions, design clarifications).

PR # Title Status Merged
#988 docs(cache): codify inline-documentation conventions 2026-05-20
#991 docs(cache): note Phase 1A writtenAt default + Phase 1C migration plan 2026-05-26
#997 docs(cache): add progress-tracker update to §4.7 on-merge checklist 2026-05-26
#1002 docs(cache): ADR 0006 — list storage strategy (Accepted: in-place row-per-element with position) 2026-05-29
#1004 docs(cache): rewrite §7.1/§7.2/§7.3 and amend §8 PR-009 per ADR 0006 (PR-008b slot added) 2026-05-29
#1003 docs(cache): ADR 0007 — selection-set-aware cache reads with per-field column projection 2026-05-29

ℹ️ About PR #981. The original PR-005 was opened as #981 stacked on PR-004a's branch. When PR-004a (#980) merged with --delete-branch, GitHub auto-closed #981. The work was rebased onto the post-#980 plan branch and re-opened as #998, which was approved and merged. #981 is closed without merging (superseded).


How this tracker stays current

Per execution plan §4.7, when an implementation PR merges into this branch, the agent updates the corresponding row above: flips 🟡 → ✅, fills in the merge date, and adjusts the per-phase / overall counters. The update is mechanical (gh api repos/.../pulls/967 -X PATCH -F body=@…) and happens immediately after the rebase of the next stacked PR.

Design documents

The plan branch ships four design docs that are the source of truth for the rest of the work:

AnthonyMDev and others added 2 commits May 7, 2026 11:55
Adds the engineering plan and manager-facing summary for Phase 1 of the
cache rewrite (3.0). Phase 1 scope is foundations (SQLite restructure +
field-aware Record) and TTL via @CacheControl; Phase 2 features
(@onDelete, eviction, ChainedNormalizedCache) are deferred.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the workflow document that an AI agent (Claude Code) follows when
executing the Phase 1 cache rewrite. Defines branch and PR conventions,
per-PR loop, quality gates, escalation triggers, the 31 stacked PRs that
make up Phase 1, and session-bootstrap steps for resuming work across
sessions.

Companion to the engineering design plan (apollo-ios/Design/cache-rewrite-phase1-plan.md);
the engineering plan specifies what to build, this document specifies
how to ship it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@apollo-librarian

apollo-librarian Bot commented May 7, 2026

Copy link
Copy Markdown

✅ Docs preview has no changes

The preview was not built because there were no changes.

Build ID: 4c7c53c810f7a990ec254e95
Build Logs: View logs


✅ AI Style Review — No Changes Detected

No MDX files were changed in this pull request.

Review Log: View detailed log

This review is AI-generated. Please use common sense when accepting these suggestions, as they may not always be accurate or appropriate for your specific context.

@netlify

netlify Bot commented May 7, 2026

Copy link
Copy Markdown

Deploy Preview for apollo-ios-docc canceled.

Name Link
🔨 Latest commit 840d6ce
🔍 Latest deploy log https://app.netlify.com/projects/apollo-ios-docc/deploys/6a42d5cd8790b90008ed6cca

Update execution plan §3, §7, §8, and §10 so that
`cache-rewrite/phase-1-plan` is the long-lived base for the entire 31-PR
stack. PR-001 bases on the plan branch (not main); subsequent PRs stack
as before. The plan branch itself is only merged into main after every
PR in the stack has merged into it.

Plan revisions can land directly on the plan branch and propagate down
through every open stacked PR via rebase. The 3.0-alpha and 3.0-beta
release tags are cut from the plan branch; 3.0 final is cut from main
after the plan branch merges.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@AnthonyMDev AnthonyMDev changed the title docs(cache): Phase 1 cache rewrite — design and execution plan docs(cache): Phase 1 cache rewrite — long-lived design and execution plan May 7, 2026
AnthonyMDev and others added 9 commits May 7, 2026 13:14
Adds a fourth Phase 1 design doc — cache-rewrite-phase1-perf.md —
specifying the performance measurement methodology and the published
comparison dataset that will accompany the 3.0-alpha tag. Covers four
measurement tiers (end-to-end ApolloClient.fetch, NormalizedCache
protocol level, raw SQLite, memory/CPU profiling) across synthetic,
real-schema, and stress workloads. Methodology mirrors Zach's existing
benchmark (50 iterations, mean/std-dev/P50/P95/P99, multi-device) so
SQLite numbers can compare directly against the published Confluence
baseline.

Adds three new PRs to the execution plan:
- PR-004a (Phase 0): capture 2.x performance baseline dataset
- PR-011a (Phase 1A): comprehensive measurement harness for Tier 1+2
- PR-011b (Phase 1A): alpha-vs-2.x comparison reporter

Updates Phase 1A exit criteria so the 3.0-alpha tag is gated not only
on SQLite gates green, but also on no `regressed` verdict in the
published dataset (or all such regressions explicitly accepted).

Timeline impact:
- Phase 0: 2 wk -> 3 wk (engineer + calendar)
- Phase 1A: 4 wk -> 5 wk effort; 6-7 -> 7-8 calendar
- Total Phase 1: 17 -> 19 engineer-weeks; 21-24 -> 23-26 calendar; with
  25% contingency 27-30 -> 29-33 (~6.5-7.5 months)

Companion plan, summary, and execution docs updated with cross-refs.
PR count goes 31 -> 34.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Update execution plan §2 and §7 to remove the blanket "max 2 stacked
unmerged PRs" cap and replace it with a PR-type-aware policy:

- ADR PRs (Phase 0 docs) merge into cache-rewrite/phase-1-plan as
  they are approved. One or two sit in active review at any time.
- Code PRs (Phase 1A through 1D) stay open as a long-running stack
  with no preset cap; the reviewer batches them at end-of-phase or as
  convenient.

The agent pauses only on explicit reviewer instruction, §6 escalation
triggers, or genuine state dependencies between in-flight PRs. The
agent does not unilaterally merge any PR — merges remain reviewer-
initiated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Apollo iOS 3.0 ships the Phase 1 cache rewrite as a coordinated breaking release: SQLite schema change, public Record API change, generated code shape change, and TTL evaluation behavior. Captures four rejected alternatives (2.x feature flag, staged minor releases, parallel cache module, hold-for-Phase-2) and the positive/negative consequences.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ld) (#969)

Record.fields changes type from [CacheKey: any Hashable & Sendable] to [CacheKey: CachedField], where CachedField carries the field's value alongside its writtenAt epoch timestamp. The record[key] subscript stays backward-compatible (returns Value? by unwrapping .value), so the executor and most consumers don't change. The breaking surface is restricted to code that iterates record.fields directly. Captures three rejected alternatives (parallel side-channel, lazy proxy) and the positive/negative/neutral consequences — including the Hashable/Equatable semantics change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…, read-mode split) (#970)

Three interlocking decisions defining the runtime behavior of @CacheControl: tri-state maxAge (nil / 0 / N>0; bare @CacheControl is a codegen error); selection-set-scoped TTL (any expired field in the current query → whole-query miss; fields outside the selection ignored); strict-vs-permissive read-mode split on ApolloStore.load (strict enforces TTL on consumer-initiated reads, permissive bypasses TTL only — not genuine missing-value errors — for watcher re-reads on didChangeKeys). Captures six rejected alternatives across the three sub-decisions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ming)

Updates ADR 0003, engineering plan, and execution plan ahead of ADR 0005
(PR-004b) which will document the consumer-facing stale-tolerance API:
- RequestConfiguration.ttlEnforcement: TTLEnforcement = .strict
- Source.cache(containsStaleFields: Bool) — staleness signal as
  associated value on the cache source case (structurally inapplicable
  to network responses)
- JSONDecodingError.MissingValueReason — diagnostic distinction between
  absent and expired
- .revalidateCache case on CachePolicy.Query.CacheAndNetwork — built-in
  SWR pattern; always reads permissively as part of its semantics

ADR 0003 §2.3 read-mode table and §2.4 pseudocode updated to reflect
that permissive mode marks staleness on the response (rather than
silently returning) and that the throwing path uses MissingValueReason.

Engineering plan §4.2 pseudocode updated to match. §6.4 documents the
Source enum shape change and the GraphQLDependencyTracker extension to
compute both earliestExpiry and the staleness flag.

Execution plan §8 Phase 1C: adds PR-022a for the stale-tolerance API
surface (~450 LoC); expands PR-022 and PR-024 to cover staleness
tracking. Phase 1C goes from 7 PRs to 8 PRs; total stack 34 → 36.

The intersection .revalidateCache + ttlEnforcement = .strict is
documented as redundant with .cacheFirst + ttlEnforcement = .strict
(accepted small cost of a composable two-axis design).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e propagating reads) (#971)

Merging ADR 0004 (Watcher × TTL: opt-in auto-refresh, permissive propagating reads) into the plan branch per the ADR-merge-as-approved policy. Approved post-meeting.
Merging ADR 0005 (Stale-tolerance API surface — RequestConfiguration.ttlEnforcement, Source.cache(containsStaleFields:), MissingValueReason, .revalidateCache) into the plan branch. Revised post-review to clarify .revalidateCache honors ttlEnforcement on the internal read (resolving the orthogonality inconsistency with Alternative F). Approved post-meeting.
Approved by Anthony — codifies the inline-documentation conventions established during PR-005 review.
AnthonyMDev and others added 7 commits May 26, 2026 12:41
…997)

Approved as part of the manager-tracker workflow setup. The single failing unit test on the docs-only branch is unrelated — pre-existing flaky test (`test__cancellingTask__propogatesTaskCancellationToInterceptors`).
…lan (#991)

Approved — companion to the PR-006 stack discussion. Documents the Phase 1A interim writtenAt default and the Phase 1C migration trigger.
…004a) (#980)

PR-004a — macOS 2.x cache baseline benchmark harness + dataset. All CI green. Approved.
…998)

PR-005 — introduce CachedField type. Approved as #981 prior to PR-004a's merge invalidating that PR's base; this is the rebased equivalent.
… (PR-006) (#987)

PR-006 — change Record.fields type to [CacheKey: CachedField]. Approved by reviewer; rebased onto post-#998 plan branch tip after #981's chain reorganization. Full Apollo-UnitTestPlan verified locally (970 tests passing).
#999)

PR-007 — schema_metadata table + version read/write. Foundation for PR-008/010 migration logic.
… (PR-008) (#1000)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AnthonyMDev and others added 4 commits May 29, 2026 09:31
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#1004)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…08b) (#1005)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AnthonyMDev and others added 3 commits June 2, 2026 13:56
…g design, 009g-bis) (#1014)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-plan

# Conflicts:
#	Tuist/ProjectDescriptionHelpers/Targets/Target+ApolloPerformanceTests.swift
@AnthonyMDev AnthonyMDev changed the title docs(cache): Phase 1 cache rewrite — long-lived design and execution plan Phase 1 cache rewrite — long-lived design and execution plan Jul 28, 2026
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.

1 participant