Files
gstack/test/fixtures/ceo-section-s-trace-report.md
T
Garry TanandOpenAI Codex 9f81911136 v1.86.0.0 feat: route outside reviews by harness (#2850)
* feat: add a restricted and supervised Claude Code runner

Preserve configured authentication and models while enforcing tool access, strict completion JSON, bounded output and process cleanup. Cover argv, failure handling, session metadata and Windows process containment.

* feat: route outside reviews by harness and migrate wrapper installs

Use Claude Code from Codex and Codex from other supported hosts, with shared invocation rendering, positive gate validation and per-phase provenance. Rename /claude to /claude-code, repair managed shared and copied installations safely, and generate native Kiro skills. Add installed-workflow, failure-injection and live cross-harness regression coverage.

* test: recognize CEO mode labels without terminal spacing

The paid workflow rendered SCOPEEXPANSION at option 4, but its driver required a literal space. Match the leading mode title without cursor-spacing artifacts and ignore adjacent preview text. Preserve missing-target failures and downstream posture assertions.

* test: isolate plan-count fixtures before starting review workflows

Seed the complete test plan in a private git repository before launching Claude, so a bare slash command cannot review the live workspace while a delayed fixture message remains queued. Preserve count thresholds, parsers and budgets. Add initial-context and installed-discovery tests, and retain startup/terminal diagnostics on failed evaluations.

* test: stabilize review fixtures and Claude eval startup

Preserve source boundaries in workflow judge inputs, isolate CEO mode plans, and wait for interactive trust input readiness. Keep startup failure evidence and retain existing models, budgets, and assertions.

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* test: classify collapsed review modes and isolate seeded findings

Keep review questions out of the setup count when terminal cursor positioning removes spaces. State existing webhook safeguards so the five-finding control measures its seeded defects without accidental extra security and concurrency gaps. Preserve question bands and the paired control.

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* test: isolate browser daemon state across free shards

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* test: stabilize native review counting and interactive navigation

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* chore: prepare v1.82.0.0 release

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* fix: eliminate browser and process-cleanup test flakes

Pin every CI surface to Bun 1.4.0 to avoid extra-stdio finalizers closing
reused live sockets. Add an isolated GC/listener regression that fails on
Bun 1.3.13, and prevent coordinated rollback to an affected CI runtime.

Check renderer cleanup against the render's own staging directory so
concurrent renders cannot invalidate the assertion. Make the no-pgrep
process-tree walk tolerate disappearing /proc entries, and synchronize
its test fixture through child readiness and pipe EOF instead of sleeps.

Validation: 9,157 passed, 31 skipped, zero failures across 556 files with
retries disabled. Build, all-host generation freshness, and skill checks
passed. All three races have failing-before/passing-after regressions.

* fix: count completed native review questions in evals

* fix: drive review navigation from confirmed native choices

* fix: require complete section-loading eval reports

* test: isolate telemetry HTTP transport from local assertions

* fix: keep review input on the active native question

* test: let tunnel revocation daemon choose an available port

* test: allocate available ports for pairing and watchdog fixtures

* fix: stabilize planning eval navigation and phase reporting

* test: isolate installed runtime paths in planning evals

* test: stabilize review evidence and concurrent refresh fixtures

* fix: resolve design findings before editing the plan

* fix: honor and persist disabled outside plan reviews

* fix: preserve planning decisions and terminal evidence

Load installed host reviews at autoplan phase entry and wait for completed
reviewers and saved artifacts. Reuse approved remedies while preserving
individual finding decisions.

Drive interactive evals from the current terminal viewport, bind native
questions across scrolling, and require complete native report evidence.
Cover captured stale menus, permission lifecycles, setup classification,
and disabled-review tool availability with deterministic regressions.

Advance release metadata and the upgrade migration to the unclaimed
1.83.0.0 slot.

* fix: drive native review questions and preserve current plans

Use the native single-choice keyboard protocol and current terminal viewport,
with per-question navigation inside packets and completed-call coverage.
Keep permissions, multi-select menus, and Submit controls distinct.

Send Autoplan reviewers the amended implementation plan, keep its review record
separate, and supply retained application contracts in the chain fixture.
Clarify individual DevEx decisions and complete CEO fix options; use one active
plan destination for the section-loading report.

* fix: preserve complete plan-review decisions

* fix: recognize native plan dialogs and reviewer controls

* fix: preserve review decisions and phase completion

* fix: recognize completed reviews without losing findings

* fix: preserve review continuity and native eval completion

* test: fix native review completion and eval retry isolation

* test: handle native review menus and complete eval fixtures

* test: fix native review setup, completion, and isolation failures

* test: limit native skill discovery to runtime assets

* fix: bind Autoplan reviews to full ordered phase inputs

* test: fix planning eval routing, counting, and timeout handling

* chore: advance queued release to v1.84.0.0

* fix: preserve complete review inputs and planning decisions

* fix: reconcile review approvals and preserve phase obligations

* fix: preserve review obligations and unblock eval permissions

Carry recorded Autoplan requirements into blind phase inputs, require Eng
review approvals before exit, and exercise combined asynchronous flows in
CEO reviews. Correct native finding and handoff classification and unblock
repeated report edits using scoped request identities.

* fix: retain plan requirements and complete native review dialogs

* fix: complete native review prompts and retain plan references

* fix: preserve review inputs and classify native eval evidence

* fix: check competing completion orders in CEO reviews

* fix: recognize review decisions and require phase methodology

Require the current phase methodology before Autoplan snapshots. Correct
substantive decision, closed handoff, and cache-finding classification, and
honor the recommended implementation approach in native review dialogs.

Add captured-transcript regressions without changing review thresholds,
provider models, retries, or deadlines.

* test: bind native review decisions and close completed handoffs

* fix: complete review dialogs and verify methodology delivery

* fix: preserve review evidence and unblock native eval prompts

* fix: handle native review question completions

* fix: recognize native review narration and controls

* fix: count native review decisions and isolate eval fixtures

* test: verify seeded review coverage and current artifact permissions

* test: isolate model and brain-aware skill renders

* fix: repair native workflow evaluation and clarify review steps

* fix: stabilize workflow eval evidence and review guidance

* test: repair native workflow observation and fixture isolation

* fix: recognize completed workflow evidence and owned skill reads

* test: repair seeded workflow delivery and completion evidence

* test: recognize current review evidence across native forms

* test: handle native review variants and permission redraws

* fix: honor review preferences and recognize native eval evidence

* test: recognize completed review decisions and queued permissions

* test: match current review contracts and partial-line edits

* test: recognize completed workflow evidence and bounded human waits

* fix: preserve review entry gates and native eval interactions

* fix: recognize native workflow evidence and preserve review gates

* test: recognize current review evidence and preconfigure workflow fixtures

* test: recognize completed review findings and scoped artifact permissions

* fix: stabilize native workflow review and permission evidence

* fix: recognize current review evidence and scoped edit confirmations

Clarify Design and engineering review entry instructions and Design scoring.
Recognize required legacy coverage and public Autoplan completion recaps.
Bind the pending Edit confirmation to its exact file, ordered digest, and
one-request approval when a preceding command display remains visible.
Keep reviews within their existing size limits and preserve scope gates
when extracting workflow fixtures from either supported preamble header.

Keep failure outcomes, review thresholds, provider choices, and eval budgets.

* fix: recover review workflow progress and eval evidence

* fix: recognize valid review evidence and scope selection

* test: fix review evidence parsing and repeated artifact prompts

* test: recognize valid review decisions and pending native cards

* fix(plan-eng-review): keep final navigation consistent with approved tasks

* test: recognize valid review evidence and bind legacy diff requests

* fix: stabilize review eval evidence and harness repair guidance

* docs: update project documentation for v1.85.0.0

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* test: fix Windows CI fixtures and credential scan

Rebase captured JSON values and filesystem evidence using the appropriate
path convention. Compile native fake CLIs on Windows and synchronize pipe
holder readiness, with cleanup retained when assertions fail.

Assemble synthetic credential fixtures at runtime so the added-line scan
keeps enforcing the same gate without flagging its own rejection controls.

Discover generated skills directly for the empty-find regression check,
avoiding a recursive scan through saved evaluation artifacts and dependencies.

* fix: preserve source renders on Windows

Compare canonical generator paths using native separators so an output
sidecar pointing at the source cannot overwrite its skill or metadata.
Keep the regression fixture isolated from the real checkout and expose
freshness diagnostics before asserting subprocess status.

Detach Windows drain-test pipe holders from the fake provider's automatic
child cleanup while preserving the enclosing runner job and its assertions.

* fix: clarify outside review fallback and CEO decisions

Render one applicable own-harness fallback path and retain native review,
disabled policy, and missing-coverage semantics. Align report field names
and mode labels, and make the existing per-cut scope approval explicit.

Regenerate skill outputs and keep the workflow judge's model, thresholds,
and retry policy unchanged.

* chore: move release to free version slot (v1.86.0.0)

PR #2852 now claims v1.85.0.0. Align the release metadata and
rename migration so upgrades from that version still receive it.

Co-Authored-By: OpenAI Codex <noreply@openai.com>

* fix: include engineering review prerequisites and restore branch context

* fix: recognize coverage diagrams and clarify design review instructions

* fix: preserve file identities and join Windows test processes

---------

Co-authored-by: OpenAI Codex <noreply@openai.com>
2026-09-14 14:32:45 -07:00

37 KiB
Raw Blame History

Plan: cache profile summaries in one process

Measured problem and accepted scope

The existing profile-summary service has one active process. A one-week trace shows repeated reads of about 900 hot keys: DB CPU is 70%, with read p95 120 ms. Add a process-local LRU wrapper to the existing repository. Acceptance targets are at least 60% cache hits, DB CPU below 50%, and read p95 below 60 ms, with the existing error-rate and correctness SLOs unchanged. This is an internal backend change with no UI, API, schema, pricing, or developer onboarding change.

Existing contracts retained

  • All reads and writes use this repository in the same process; there are no external DB writers. Multi-process operation remains unsupported and startup rejects that configuration while caching is enabled.
  • Authentication and authorization run before repository access. Keys encode the authenticated tenant ID and validated profile ID without ambiguity. Values are immutable profile-summary DTOs; secrets and cache keys are never logged. Cached results cannot bypass authorization.
  • The existing LRU adapter supports 1000 entries, a 16 MiB byte cap, and a 30-second TTL. Recorded hot data fits those limits. Absent records use a distinct sentinel with a 10-second TTL; undefined means a cache miss.
  • Cache operations are synchronous and atomic in the single JS event loop. On any cache failure the existing adapter bypasses the cache until an empty cache is reinitialized; repository errors keep the current typed API error mapping. The existing per-key single-flight wrapper coalesces simultaneous misses and releases on failure.
  • A read already in progress when a write commits may return its earlier DB snapshot to that caller. Every read begun after that write completes must observe the committed version. TTL expiry is not a substitute for this rule.

Proposed wrapper integration

Keep the current read-through repository interface and shared adapters. These are the complete new read/write ordering rules; no additional version checks or coordination between a cache fill and a write are proposed:

async function readProfile(key) {
  const cached = cache.get(key);
  if (cached !== undefined) return cached;
  const value = await repository.read(key);
  cache.set(key, value);
  return value;
}

async function writeProfile(key, update) {
  const saved = await repository.write(key, update);
  cache.delete(key);
  return saved;
}

Verification and rollout

Existing repository contract tests cover tenant isolation, key validation, absence, DB failures, and authorization. New wrapper tests cover hit/miss, eviction and byte limits, TTL, adapter-failure fallback, successful-write invalidation, failed-write preservation, and concurrent-miss coalescing. The rollout uses the existing runtime feature flag: enable for 10% of keys, then 50%, then all keys after one healthy hour at each stage. Monitor hit/miss, eviction, cache bytes, fallback errors, DB CPU, and read p95 without raw IDs. On error-rate or latency regression, disable the flag immediately; both reads and writes bypass the cache while disabled, and enabling creates an empty cache. Cold starts remain within the existing DB capacity. The service owner monitors the rollout and records the results against the acceptance targets.

Out of scope

Distributed caching, cross-process coherence, prewarming, changing consistency semantics, or adding new product surfaces. The repository interface preserves a future replacement path without introducing a general cache framework now.


CEO Review (HOLD SCOPE)

Mode: HOLD SCOPE — the plan's scope is accepted as stated. This review makes it bulletproof: catches failure modes, tests every edge case, ensures observability, maps every error path. No expansion surfaced.

Approach confirmed: thin wrapper around the existing repository, reusing the existing LRU adapter, single-flight coalescing, and feature-flag rollout. Minimal viable and architecturally sound — the right call.


Step 0: Nuclear Scope Challenge

0A. Premise Challenge

  1. Right problem? Yes. DB CPU at 70% and p95 at 120ms with 900 stable hot keys is a textbook read-cache opportunity. A one-week trace backing the hot-key profile makes this measurement-driven, not speculative.
  2. Direct path? Yes. A process-local LRU is the most direct intervention: zero network hops, zero consistency overhead, zero schema change.
  3. What if nothing done? DB CPU continues climbing as traffic grows; latency degrades further. Real pain point, evidenced by the trace.

0B. Existing Code Leverage

  • Existing LRU adapter: fully reused, no new cache library
  • Existing single-flight wrapper: reused for concurrent-miss coalescing
  • Existing feature flag: reused for staged rollout
  • Existing repository contract tests: extended, not replaced
  • Existing tenant isolation and key validation: unchanged and inherited

No parallel implementation; no rebuild of existing functionality.

0C. Dream State Mapping

  CURRENT STATE                  THIS PLAN                  12-MONTH IDEAL
  DB CPU 70%          --->       LRU wraps repository  ---> DB CPU <50%, p95 <60ms
  read p95 120ms                 60%+ cache hits              stable under 10x hot traffic
  all reads hit DB               900 hot keys served          future: multi-process if
  single process OK              from process memory           service scales (separate plan)

0C-bis. Implementation Alternatives

APPROACH A: Thin wrapper (this plan)
  Summary: Add readProfile/writeProfile wrapper around existing repository, reuse LRU adapter.
  Effort:  S
  Risk:    Low
  Pros:    Minimal diff; zero new dependencies; fully reversible via flag
           Inherits existing adapter's eviction, TTL, byte-cap, and bypass logic
  Cons:    Process-local only; no warm restart; cross-process unsupported by design
  Reuses:  existing LRU adapter, single-flight wrapper, feature flag, contract tests

APPROACH B: Decorator/Interceptor pattern
  Summary: Wrap the repository interface with a cache decorator injected at construction.
  Effort:  M
  Risk:    Low
  Pros:    Cleaner separation; easier to swap caching strategies later
  Cons:    More indirection; no material runtime difference for this scope
  Reuses:  same LRU adapter and flag

APPROACH C: Redis sidecar
  Summary: Replace process-local LRU with a Redis-backed cache for future multi-process use.
  Effort:  XL
  Risk:    High
  Pros:    Solves cross-process coherence; supports horizontal scale
  Cons:    New infrastructure dependency; network latency per read; out of stated scope
  Reuses:  nothing from current adapter

RECOMMENDATION: Approach A. The problem is single-process, the data fits in memory, and approach A is fully reversible with zero new dependencies. Approach B adds abstraction without runtime benefit. Approach C is explicitly out of scope and introduces infrastructure risk.

Auto-decided: Approach A selected (recommended, no human present).

0D. HOLD SCOPE Analysis

  1. Complexity check: The wrapper touches 1 module (repository), adds 2 functions, and extends 1 test file. Well within the 8-file threshold. No smell.
  2. Minimum set: The plan is already minimal. The wrapper, tests, and feature flag are all required for correctness and safe rollout.
  3. Stated invariants and acceptance criteria are preserved as the baseline.

0E. Temporal Interrogation

  HOUR 1 (foundations):    Implementer needs: exact LRU adapter API (get/set/delete
                           return contracts, synchronous guarantees, bypass semantics)
  HOUR 2-3 (core logic):  Ambiguity: post-await guard needed before cache.set (see
                           Section 1 finding). Without it the stale-re-insertion race
                           silently violates the stated ordering invariant.
  HOUR 4-5 (integration): Surprise: feature flag applies per-key to BOTH read and write
                           paths consistently — confirm flag evaluation is idempotent per key.
  HOUR 6+ (polish/tests): Need explicit test for write-during-in-flight-read scenario.

(CC+gstack compresses these 6 human hours to ~20-30 minutes of wall time.)


Section 1: Architecture Review

System Architecture

  ┌─────────────────────────────────────────────────────────────┐
  │            profile-summary service (single process)          │
  │                                                             │
  │  ┌──────────────┐  readProfile/writeProfile  ┌───────────┐ │
  │  │   Callers    │ ─────────────────────────► │ Wrapper   │ │
  │  └──────────────┘                            │  (NEW)    │ │
  │                                              └─────┬─────┘ │
  │                                    ┌───────────────┤       │
  │                                    │               │       │
  │                               ┌────▼────┐    ┌────▼────┐  │
  │                               │  LRU    │    │ Repos-  │  │
  │                               │ Cache   │    │  itory  │  │
  │                               │(adapter)│    │(existing│  │
  │                               └─────────┘    └────┬────┘  │
  │                                                   │       │
  │                                             ┌─────▼─────┐ │
  │                                             │ Database  │ │
  │                                             └───────────┘ │
  └─────────────────────────────────────────────────────────────┘

Coupling: The wrapper couples callers to the LRU adapter. Before: callers → repository → DB. After: callers → wrapper → (cache OR repository) → DB. The added coupling is justified: the adapter is an internal implementation detail, not a public contract.

Scaling: The LRU is bounded at 1000 entries / 16 MiB. Under 10x load, cache hit rate stays constant (hot keys are stable); DB load drops proportionally. Under 100x load, the 1000-entry limit may not hold all hot keys — but that is explicitly out of scope for this plan and properly left to a future distributed-cache plan.

Single points of failure: The cache is one. It fails open (bypass mode) per the plan.

Rollback posture: Disable the runtime feature flag. Instant bypass — no code change or deploy required.

Data Flow — All Four Paths

READ FLOW:
  KEY ──► cache.get(key)
              │
       ┌──────┴──────────────────────────────┐
       │ hit (cached !== undefined)          │ miss (undefined)
       ▼                                    ▼
  return cached                    single-flight.acquire(key)
                                            │
                                   await repository.read(key)
                                            │
                              ┌─────────────┼────────────────┐
                              │ nil/absent  │ value          │ error
                              ▼             ▼                ▼
                         sentinel       cache.set(key,v)  typed API error
                         (10s TTL)      return value      bypass cache

WRITE FLOW:
  KEY, UPDATE ──► await repository.write(key, update)
                           │
               ┌───────────┼───────────┐
               │ success   │           │ error
               ▼           │           ▼
         cache.delete(key) │    typed API error (cache NOT deleted — preserved)
         return saved      │
                           │

Critical Finding: Stale Re-insertion After Write Invalidation

CRITICAL GAP — The plan states: "Every read begun after that write completes must observe the committed version. TTL expiry is not a substitute for this rule." The proposed wrapper violates this invariant.

Race sequence (possible in the JS event loop at await boundaries):

  t1: readProfile(key)  → cache miss → single-flight → await DB read (suspends)
  t2: writeProfile(key) → await DB write (suspends)
  t3: DB write completes → cache.delete(key) → writeProfile returns
  t4: DB read (from t1) completes → returns OLD snapshot
  t5: cache.set(key, OLD_VALUE)  ← stale value re-inserted after invalidation!
  t6: next readProfile(key) → cache HIT → returns stale value  ← INVARIANT VIOLATED

The plan says "no additional version checks or coordination between a cache fill and a write are proposed," but the stated ordering invariant requires exactly that guard to prevent t5.

Fix: add a synchronous post-await check before cache.set. Because cache.get and cache.set are synchronous (no await), the check+set pair is atomic in the JS event loop — the write's cache.delete cannot interleave between them:

async function readProfile(key) {
  const cached = cache.get(key);
  if (cached !== undefined) return cached;
  const value = await repository.read(key);
  // Guard: only cache if no write invalidated this key while we were reading DB.
  // Safe because cache.get and cache.set are synchronous — write's cache.delete
  // cannot interleave between these two lines.
  if (cache.get(key) === undefined) {
    cache.set(key, value);
  }
  return value;
}

Auto-decided (D1): Add post-await guard to readProfile. Recommended option accepted.

State Machine: Cache Entry

  [DISABLED]  ──(flag enable)──►  [EMPTY]
      ▲                               │
      │ (flag disable)          (first read for key)
      │                               │
      │                               ▼
      │                          [MISS/BYPASS]
      │                               │
      │                         (DB read completes)
      │                               │
      │                               ▼
      │                          [CACHED]  ◄──── (subsequent reads)
      │                               │
      │                         (write or eviction or TTL)
      │                               │
      │                               ▼
      │                          [INVALIDATED]
      │                               │
      │                         (next read: miss → DB)
      │                               ▼
      │                          [CACHED again]
      │
      └────── (cache failure → BYPASS until reinitialized)

Invalid transitions prevented: write to absent key cannot create cache entry (write only deletes); sentinel entries expire on 10s TTL, not promoted to normal entries.

Security Architecture

Auth boundary: authentication and authorization happen before repository access. The wrapper sits inside that boundary. Keys encode tenant ID and profile ID — the wrapper cannot be used to bypass authorization. No new attack surface.


Section 2: Error & Rescue Map

METHOD/CODEPATH WHAT CAN GO WRONG EXCEPTION CLASS
readProfile cache.get throws CacheAdapterError
readProfile repository.read rejects typed DBError
readProfile cache.set throws CacheAdapterError
writeProfile repository.write rejects typed DBError
writeProfile cache.delete throws CacheAdapterError
EXCEPTION CLASS RESCUED? RESCUE ACTION USER SEES
CacheAdapterError (any op) Y Adapter enters bypass mode; all subsequent ops go to DB until cache is reinitialized Transparent — no degraded response
typed DBError (read) Y Existing typed error mapping; bypass unchanged Existing error response
typed DBError (write) Y Existing typed error mapping; cache NOT deleted (failed-write preservation) Existing error response

No catch-all handlers. No silent swallows. All cache failures are non-blocking by design (bypass mode). Repository error handling is unchanged.

Section 2 result: 5 paths mapped, 0 CRITICAL GAPS.


Section 3: Security & Threat Model

THREAT LIKELIHOOD IMPACT MITIGATED?
Cross-tenant cache access Low High YES — keys encode authenticated tenant ID; no ambiguity
Cache poisoning via key manipulation Low High YES — keys derived from validated inputs; wrapper doesn't accept raw user input
PII leakage in logs Low High YES — plan explicitly excludes raw IDs from monitoring
Stale data serving sensitive fields Med Med PARTIAL — stale re-insertion gap (Section 1) closes with T1 fix
New attack surface (endpoints) N/A N/A NO new endpoints introduced

No new secrets, no new dependencies, no injection vectors. The stale-data risk from the re-insertion gap is mitigated by T1.

Section 3 result: 0 new attack vectors. 1 stale-data risk closed by T1.


Section 4: Data Flow & Interaction Edge Cases

READ DATA FLOW:
  KEY ──► VALIDATE (auth layer, pre-wrapper) ──► CACHE LOOKUP
    │                                                  │
    ▼                                           ┌──────┴──────┐
  [nil?]  undefined = cache miss               HIT           MISS
  [empty?] key cannot be empty (validated)      │             │
  [wrong?] upstream validated                  return      await DB
                                               cached       read
                                                          │
                                                     ┌────┴────┐
                                                  value      absent
                                                     │          │
                                                post-await   sentinel
                                                guard check  (10s TTL)
                                                     │
                                                cache.set
                                                (if key still absent)

Async ordering edge cases:

SCENARIO HANDLED? HOW
Concurrent reads for same key (miss) YES Single-flight coalesces
Write during in-flight read (same key) GAP → FIXED by T1 Post-await guard prevents stale re-insertion
Write after read completes (normal ordering) YES cache.delete removes stale value before next read
Multiple writes to same key in sequence YES Each write deletes; final state is post-last-write TTL miss
Adapter failure during read YES Bypass mode; read goes to DB
Adapter failure during write delete YES Bypass mode; subsequent reads miss to DB
Feature flag disabled mid-request YES Both read and write bypass; no partial state

No UI edge cases — backend-only change.

Section 4 result: 1 edge case mapped (stale re-insertion), covered by T1 fix.


Section 5: Code Quality Review

The proposed code is 10 lines across 2 functions. Review:

  • Organization: wrapper is a thin shell around existing repository — correct pattern; fits existing structure.
  • DRY: no repetition. Single-flight and LRU are reused, not rebuilt.
  • Naming: readProfile, writeProfile, key, value, saved, cached — all intention-revealing.
  • Error handling: relies on adapter bypass semantics; no catch-all.
  • Cyclomatic complexity: each function has 1-2 branches. Well within limit.
  • Over-engineering: none. No unnecessary abstractions.
  • Under-engineering: the missing post-await guard (addressed in T1) is the sole fragility.

Section 5 result: 0 issues beyond the T1 finding from Section 1.


Section 6: Test Review

Test Diagram

NEW DATA FLOWS:
  - Read path: cache hit (all TTL states)
  - Read path: cache miss → DB → cache.set
  - Read path: cache miss → DB → post-await guard blocks stale re-insertion (T2: MISSING)
  - Write path: success → cache.delete
  - Write path: failure → cache NOT deleted (preserved)
  - Concurrent reads: single-flight coalescing
  - Adapter failure: bypass mode on any op

NEW CODEPATHS:
  - cache.get → hit branch
  - cache.get → miss branch → DB → cache.set
  - cache.get → miss branch → DB → post-await guard (key no longer absent → skip set)
  - cache.delete on write success
  - cache.delete skipped on write failure
  - adapter bypass on cache error

NEW BACKGROUND JOBS / ASYNC WORK:
  - None

NEW INTEGRATIONS / EXTERNAL CALLS:
  - None (existing DB calls, no new integrations)

NEW ERROR/RESCUE PATHS:
  - CacheAdapterError → bypass mode (Section 2)

Coverage Gap

The plan lists these test cases: hit/miss, eviction/byte limits, TTL, adapter-failure fallback, successful-write invalidation, failed-write preservation, concurrent-miss coalescing.

Missing: write-during-in-flight-read. This is the specific interleaving that produces the stale re-insertion (Section 1). Without it, the post-await guard added by T1 is untested.

Test spec header:

describe('readProfile — write-during-in-flight-read', () => {
  it('does not cache the stale value when a write invalidates the key during a DB read', async () => {
    // Arrange: pause the DB read mid-flight using a controlled promise
    // Act: start readProfile → suspend at DB read → run writeProfile → complete DB read
    // Assert: cache.get(key) returns undefined after both settle
    //         next readProfile goes to DB (not stale cache hit)
  });
});

Auto-decided (D2): Add test spec for write-during-in-flight-read. Recommended option accepted.

Test Ambition Check

  • "Ship at 2am on a Friday" test: the write-during-in-flight-read test (T2) is that test — it catches the silent stale-read failure.
  • "Hostile QA" test: force adapter failure mid-sequence; verify bypass, then re-enable and verify empty cache.
  • Chaos test: cycle the feature flag rapidly under concurrent read/write load; assert no stale reads escape.

Section 6 result: 1 gap (write-during-in-flight-read test). Addressed by T2.


Section 7: Performance Review

DIMENSION ASSESSMENT
N+1 queries None introduced. Cache reduces DB calls, not adds.
Memory 16 MiB cap is explicit; 900 hot key DTOs are small; bounded.
DB indexes No new queries; existing indexes unchanged.
Caching opportunities This plan IS the caching. All hot reads covered.
Slow paths Cold start: 900 cache misses on restart. Spread over time by single-flight coalescing and rolling traffic. Plan claims within existing DB capacity — reasonable given 900 reads over 30s TTL window.
Connection pool No new connections. Cache eliminates DB round-trips.

Cold-start analysis: 900 hot keys × average read latency ≈ 900 DB reads over the first ~30 seconds of traffic. Current DB handles ~N reads/s at 70% CPU. If N >> 30, cold start is within capacity. Plan states this explicitly — the service owner should verify against the current read rate during rollout monitoring.

Section 7 result: 0 issues. Cold start assertion is a monitoring checkpoint, not a plan gap.


Section 8: Observability & Debuggability Review

Metrics specified in plan: hit/miss rate, eviction rate, cache bytes, fallback errors, DB CPU, read p95. This is complete for the acceptance criteria.

Gap: alert thresholds not specified.

The plan says "monitor" but doesn't define when the service owner should be paged vs. just watching. For a staged rollout with an active owner, manual monitoring is acceptable. But for ongoing operation post-100% rollout, the missing thresholds become an operational gap.

Suggested thresholds (P3 TODO, not blocking ship):

  • Page if: hit rate < 40% sustained for 5 minutes (cache not working)
  • Page if: fallback error rate > 1% (adapter instability)
  • Warn if: cache bytes > 14 MiB (near 16 MiB cap, possible eviction pressure)

Logging: secrets and raw IDs excluded per plan. Structured log lines at bypass entry/exit and eviction spikes would aid post-incident debugging. Not required for ship.

Debuggability at 3 weeks post-ship: With hit/miss, eviction, and fallback error metrics, you can reconstruct most incident scenarios. The stale-read scenario (before T1 fix) would have been invisible — this is why T1 is P1.

Runbook for fallback errors: Disable the feature flag → service reverts to direct DB → investigate adapter state → re-enable creates empty cache.

Auto-decided (D3): Alert thresholds as P3 TODO. Non-blocking.

Section 8 result: 1 minor gap (alert thresholds). Addressed as P3 TODO (T3).


Section 9: Deployment & Rollout Review

CHECK STATUS
DB migration None required.
Feature flag YES — existing runtime flag; staged rollout 10% → 50% → 100%
Rollout order Flag enable is the deploy; no schema changes, no migration sequencing needed.
Rollback plan Disable flag → instant bypass → empty cache on re-enable. Full rollback < 1 minute.
Deploy-time risk window Flag-gated; old and new behavior coexist cleanly. 10% of keys test the wrapper while 90% go direct.
Environment parity Staging test assumed; plan says "existing DB capacity" — verify staging has representative load.
Post-deploy verification Hit rate, fallback errors, DB CPU at each stage; one healthy hour before advancing.
Smoke tests Existing contract tests; new wrapper tests (T1+T2) must pass before flag enable.

"10% of keys" flag semantics: The rollout applies consistently to both read and write paths for a given key. This is the only correct interpretation — partial application would create inconsistency (reads cache, writes don't invalidate). Recommend confirming flag implementation applies to both paths per key in the same call.

Section 9 result: 0 risks. Flag semantics worth verifying in implementation.


Section 10: Long-Term Trajectory Review

DIMENSION ASSESSMENT
Technical debt Minimal. Thin wrapper, no new abstraction layer.
Path dependency None. Plan explicitly preserves future replacement path ("without introducing a general cache framework now").
Knowledge concentration Plan is self-contained and clear. A new engineer reading it in 12 months will understand the problem, the invariant, and the fix.
Reversibility 5/5 — feature flag disable reverts instantly to baseline. One-hour rollback, zero data risk.
Ecosystem fit Standard read-through LRU pattern in JS. No unusual choices.
The 1-year question Reads cleanly. Acceptance targets, invariants, and out-of-scope items are all explicit.

Future trajectory: if the service scales to multiple processes, this plan's design makes that upgrade path clear — the "Out of scope" section names distributed caching and cross-process coherence as the next tier. The current interface can be replaced without changing callers.

Section 10 result: Reversibility 5/5, 0 debt items.


Section 11: Design & UX Review

SKIPPED — no UI scope detected. This is a backend-only change with no user-visible interactions, screens, or state changes.


Outside Voice

Codex review skipped (codex_reviews disabled). Re-enable: gstack-config set codex_reviews enabled.


Required Outputs

NOT in scope (considered and deferred)

Item Rationale
Distributed caching Out of stated scope; single-process design is the constraint
Cross-process coherence Explicitly excluded; multi-process startup is rejected by design
Cache prewarming Not needed; hot keys warm within first TTL window via normal traffic
Changing consistency semantics No requirement; existing read-through model is sufficient
New product surfaces (API, UI, schema) Backend-only change; no new surfaces planned
General cache framework Would over-engineer; specific adapter is the right size for this problem
Alert threshold automation P3 TODO; manual monitoring sufficient during rollout and initial operation

What already exists

Component Status
LRU adapter (1000 entries, 16 MiB, 30s TTL) Reused unchanged
Single-flight miss coalescing Reused unchanged
Runtime feature flag Reused for staged rollout
Repository contract tests (tenant isolation, key validation, absence, DB failures, authorization) Extended with wrapper tests
Tenant ID + profile ID key encoding Unchanged; wrapper inherits this property
Typed API error mapping Unchanged; wrapper preserves these error responses

Dream state delta

  CURRENT STATE              THIS PLAN DELTA           12-MONTH IDEAL
  DB CPU 70%        --->     DB CPU < 50%        --->  Stable at < 50% under 10x traffic growth
  read p95 120ms             read p95 < 60ms            read p95 < 60ms sustained
  all 900 hot reads          60%+ hot reads served       full hot-key coverage; optional
  hit DB directly            from process memory          distributed cache if multi-process
                                                          needed (separate plan)

This plan closes the gap from current state to 12-month ideal for the single-process constraint. The distributed-cache path is preserved, not foreclosed.

Error & Rescue Registry

METHOD FAILURE EXCEPTION RESCUED? RESCUE ACTION USER SEES
readProfile cache.get throws CacheAdapterError YES Adapter enters bypass; DB read proceeds Transparent
readProfile DB read rejects typed DBError YES Existing typed error mapping Existing error response
readProfile cache.set throws CacheAdapterError YES Adapter enters bypass; read returns DB value Transparent
writeProfile DB write rejects typed DBError YES Existing typed error mapping; cache NOT deleted Existing error response
writeProfile cache.delete throws CacheAdapterError YES Adapter enters bypass; subsequent reads go to DB Transparent

Failure Modes Registry

CODEPATH FAILURE MODE RESCUED? TEST? USER SEES LOGGED?
readProfile Cache adapter failure YES YES (adapter-failure fallback) Nothing (transparent) YES (bypass entry)
readProfile DB read error YES YES (existing contract tests) Existing error response YES (existing)
readProfile Stale re-insertion after write NO (gap) → FIXED T1 NO (gap) → ADDED T2 Silent stale read Not without T1+T2
writeProfile DB write error YES YES (failed-write preservation) Existing error response YES (existing)
writeProfile Cache delete failure YES YES (adapter-failure fallback) Nothing (transparent) YES (bypass entry)
Feature flag disable All cache ops bypassed N/A YES (existing flag tests) Nothing (transparent) YES (flag events)

CRITICAL GAP before T1+T2: Stale re-insertion after write is RESCUED=N, TEST=N, USER SEES=Silent. T1 and T2 close this gap.

Diagrams Summary

Architecture, data flow, state machine, and error flow produced in sections above. Deployment sequence and rollback are feature-flag based and described in Section 9 prose (no sequence diagram needed — disable flag = rollback, one step).

Stale Diagram Audit

No existing ASCII diagrams found in the plan or referenced files. This plan introduces 4 new diagrams (system architecture, read flow, state machine, cross-reference in Section 4). All current and consistent with the proposed implementation.


Implementation Tasks

Synthesized from this review's findings. Each task derives from a specific finding above. Run with Claude Code; checkbox as you ship.

  • T1 (P1, human: ~30min / CC: ~5min) — readProfile wrapper — Add post-await guard to prevent stale re-insertion after write invalidation

    • Surfaced by: Section 1 (Architecture) — stale re-insertion race; write's cache.delete can execute between the DB read's await and cache.set, allowing an old snapshot back into cache
    • Files: repository wrapper module (readProfile function)
    • Verify: T2 test passes; run existing contract tests; confirm cache.get returns undefined for a key that was written while its read was in-flight
    • Change: after await repository.read(key), replace unconditional cache.set(key, value) with if (cache.get(key) === undefined) { cache.set(key, value); }
  • T2 (P2, human: ~1h / CC: ~10min) — wrapper tests — Add test for write-during-in-flight-read scenario

    • Surfaced by: Section 6 (Tests) — the post-await guard (T1) is untested without a controlled interleaving test
    • Files: wrapper test file
    • Verify: test fails without T1 fix; passes with it; is deterministic (no timing dependency — use controlled promise resolution)
    • Test: pause readProfile at the DB read using a deferred promise; run writeProfile to completion; resolve DB read; assert cache.get(key) === undefined after both settle
  • T3 (P3, human: ~30min / CC: ~5min) — observability — Define alert thresholds for ongoing cache operation post-rollout

    • Surfaced by: Section 8 (Observability) — monitoring metrics are specified but alert thresholds are not; fine during active-owner rollout, operational gap post-stabilization
    • Files: alerting config / runbook
    • Thresholds: hit rate < 40% sustained 5 min → page; fallback error rate > 1% → page; cache bytes > 14 MiB → warn

No new tasks from Sections 3, 5, 7, 9, 10, 11.


Completion Summary

+====================================================================+
|             MEGA PLAN REVIEW — COMPLETION SUMMARY                  |
+====================================================================+
| Mode selected        | HOLD SCOPE                                  |
| System Audit         | SKIPPED (per run configuration)             |
| Step 0               | HOLD SCOPE confirmed; Approach A selected   |
| Section 1  (Arch)    | 1 CRITICAL GAP (stale re-insertion) → T1   |
| Section 2  (Errors)  | 5 error paths mapped, 0 GAPS               |
| Section 3  (Security)| 0 issues found, 0 High severity            |
| Section 4  (Data/UX) | 1 edge case mapped (stale re-insertion)     |
| Section 5  (Quality) | 0 issues found                             |
| Section 6  (Tests)   | Diagram produced, 1 gap (T2)               |
| Section 7  (Perf)    | 0 issues found                             |
| Section 8  (Observ)  | 1 minor gap (alert thresholds → T3)        |
| Section 9  (Deploy)  | 0 risks flagged                            |
| Section 10 (Future)  | Reversibility: 5/5, debt items: 0         |
| Section 11 (Design)  | SKIPPED (no UI scope)                      |
+--------------------------------------------------------------------+
| NOT in scope         | written (7 items)                           |
| What already exists  | written (6 components)                      |
| Dream state delta    | written                                     |
| Error/rescue registry| 5 methods, 0 CRITICAL GAPS (post-T1)       |
| Failure modes        | 6 total, 1 CRITICAL GAP (closed by T1+T2)  |
| TODOS.md updates     | 1 item (T3, P3, alert thresholds)          |
| Scope proposals      | 0 proposed, 0 accepted (HOLD SCOPE)        |
| CEO plan             | skipped (HOLD SCOPE)                        |
| Outside voice        | DISABLED (codex_reviews=disabled)           |
| Lake Score           | 3/3 recommendations chose complete option  |
| Diagrams produced    | 4 (architecture, read flow, state machine,  |
|                      |    data flow with shadow paths)             |
| Stale diagrams found | 0                                           |
| Unresolved decisions | 0 (D1, D2, D3 all auto-decided)            |
+====================================================================+

Auto-decided decisions (no human present):

  • D1: Add post-await guard (stale re-insertion fix) → recommended option accepted → T1
  • D2: Add write-during-in-flight-read test → recommended option accepted → T2
  • D3: Alert thresholds as P3 TODO → recommended option accepted → T3

GSTACK REVIEW REPORT

Review Trigger Why Runs Status Findings
CEO Review /plan-ceo-review Scope & strategy 1 issues_open mode: HOLD_SCOPE, 1 critical gap (stale re-insertion → T1+T2)
Outside Review disabled Independent 2nd opinion 0 DISABLED codex_reviews=disabled per config
Eng Review /plan-eng-review Architecture & tests (required) 0
Design Review /plan-design-review UI/UX gaps 0
DX Review /plan-devex-review Developer experience gaps 0

OUTSIDE COVERAGE: codex_reviews=disabled; outside review step skipped per isolated config. Re-enable: gstack-config set codex_reviews enabled.

VERDICT: CEO Review complete — 1 critical gap found and addressed (T1: post-await guard; T2: interleaving test). Eng review required before shipping.

NO UNRESOLVED DECISIONS