Frontmatter
| title | fix(portal): keep chunked index data fresh (#12309) |
| author | neo-gpt |
| state | Merged |
| createdAt | Jun 1, 2026, 6:34 PM |
| updatedAt | Jun 1, 2026, 7:31 PM |
| closedAt | Jun 1, 2026, 7:31 PM |
| mergedAt | Jun 1, 2026, 7:31 PM |
| branches | dev ← codex/12309-portal-index-data-order |
| url | https://github.com/neomjs/neo/pull/12311 |

PR Review Summary
Status: Approved
🪜 Strategic-Fit Decision
Per §9 Strategic-Fit Step-Back:
- Decision: Approve
- Rationale: This is the correct complementary half of the #12309 fix. #12310 (merged) corrected the generator; this PR fixes the consumed reality the operator actually sees — the committed
index.jsonwas stale ondev, and the service worker served/resources/cache-first so even a corrected file reloaded stale. Both layers are now pinned with recurrence guards. No blocking defects; the one cross-consumer concern is non-blocking (safe via cache-fallback). Approve over Approve+Follow-Up because no concrete follow-up is required now (the cross-consumer note is a watch-item, not a tracked gap).
Peer-Review Opening: Strong, self-aware fix — the "Evolution" section naming this a verification-boundary error (generator proven in isolation, consumed JSON + SW cache layer left unverified) is exactly the right framing, and the new committed-data guards make sure the boundary stays pinned. Approving; one non-blocking cross-consumer note below to keep on the radar.
🕸️ Context & Graph Linking
- Target Issue ID: Resolves #12309 (leaf bug, not epic — valid close-target)
- Related Graph Nodes: #12310 (merged generator half), Epic #12204 (Portal news), #12313 (my sibling pulls-theme fix — no overlap)
🔬 Depth Floor
Challenge: The /resources/data/ addition to ServiceBase.networkFirstPaths is a base-level default, so it flips cache behavior for every Neo app's /resources/data/, not just the portal — a cross-consumer default change (shared-build default = cross-consumer contract). It is safe because it is network-first with cache fallback (offline still resolves, and it re-caches), and it is correct for content-synced app data. But any consumer serving large, rarely-changing data under /resources/data/ now pays an online network round-trip per load (cache only on failure). Non-blocking — the data-freshness semantics justify the default — but worth an explicit awareness note; if a future consumer needs cache-first data under that path, a portal-scoped override or a cacheFirstPaths exception list would be the surgical follow-up (hypothesis — needs V-B-A before implementation).
Secondary (minor): the interceptor matches via request.url.includes('/resources/data/') (substring) — broad, though the path is specific enough that accidental matches are unlikely.
Rhetorical-Drift Audit (§7.4):
- PR description: the L3 framing ("Neural Link runtime inspection ... found stale
Portal.store.Pullschunk order after reload") matches a genuine runtime-inspection claim; not overshooting the diff. - Anchor & Echo: the
networkFirstPathsJSDoc accurately states the mechanical reason (framework-version-independent data must reflect fresh syncs). -
[RETROSPECTIVE]: n/a (no tag); the "Evolution" prose accurately characterizes the verification-boundary miss. - Linked anchors: #12310 genuinely is the generator half it cites.
Findings: Pass.
🧠 Graph Ingestion Notes
[RETROSPECTIVE]: The decisive lesson is the verification boundary: a generator/unit fix proven in isolation is not proven in the consumed substrate. The visible Portal runs through (a) committedindex.jsonand (b) the service-worker cache layer — both must be verified, not just the generator output. This PR's committed-data order guards + SW-policy test institutionalize that boundary so the next chunk-order change can't regress silently.[KB_GAP]: "Generator output ≠ consumed data" — committedapps/portal/resources/data/**is the runtime source of truth; a generator change is inert until the committed artifact is regenerated AND the SW cache policy lets the fresh copy through.
N/A Audits — 📑 📡 🔗 🛂 🔌
N/A across listed dimensions: bug fix with no new public-API contract (Contract Ledger), no openapi.yaml touch (MCP budget), no new skill/convention (Cross-Skill), no novel architectural abstraction (Provenance), and the SW change is a cache-policy default, not a wire-format/payload-schema change.
🎯 Close-Target Audit
- Close-targets identified:
Resolves #12309(own line, valid syntax) - #12309 confirmed not
epic-labeled (leaf bug) → valid close-target
Findings: Pass. Observation (non-blocking): both #12310 (merged) and this PR carry Resolves #12309. This is not a premature-close hazard — PRs target dev, not the default branch, so GitHub does not auto-close on dev-merge; #12309 closes once at the dev→main release, to which both PRs legitimately contribute (complementary halves). Verified: #12310 MERGED 2026-06-01T16:15Z, #12309 still OPEN.
🪜 Evidence Audit
- PR body contains an
Evidence:declaration (L3 Neural Link runtime inspection → L3 required; residual = post-merge SW update confirmation). - Residual explicitly listed in
## Post-Merge Validation(reload Portal under the SW, confirm descending chunk ranges for pulls + tickets). - Two-ceiling distinction honored: shipped at L3 with the residual being the browser-controlled SW update (genuine post-merge boundary, not under-probing).
Findings: Pass — Evidence declaration present and honest; the post-merge residual is a real browser-SW-lifecycle boundary, appropriately deferred.
🧪 Test-Execution & Location Audit
- Branch checked out locally (
gh pr checkout 12311, headbbcef046c). - Canonical location: generator guards in
test/playwright/unit/ai/buildScripts/docs/index/, SW test intest/playwright/unit/worker/— both correct perunit-test.md. - Ran the 3 related specs: 8 passed (940ms) — TicketIndex + PortalContentIndexes (committed-index chunk-order guards + the #12310 generator tests) + ServiceBase (network-first-before-generic-cache).
Findings: Tests pass; locations correct.
📋 Required Actions
No required actions — eligible for human merge.
📊 Evaluation Metrics
[ARCH_ALIGNMENT]: 92 — extends the existingnetworkFirstPathsconfig + reuses the committed-data-guard test pattern; idiomatic. 8 deducted:/resources/data/lands on the BASE default, changing cache behavior for every Neo app (cross-consumer flip) where a portal-scoped override would be more surgical — mitigated by network-first-with-cache-fallback.[CONTENT_COMPLETENESS]: 95 — Fat body (root cause, deltas, evidence ladder, evolution, post-merge validation, commit);networkFirstPathsJSDoc updated with the data-freshness rationale. 5 deducted: the newexpectChunkFoldersDescendingguard's>1assertion silently couples to the committed data always having a multi-chunk group; no JSDoc note on that assumption.[EXECUTION_QUALITY]: 92 — checked out; 8 related tests green locally; committed-data guards + SW-policy test + L3 Neural Link verification of the actual stale-cache failure mode. 8 deducted: substringincludes('/resources/data/')match is broad; the guard's data-coupling noted above.[PRODUCTIVITY]: 100 — closes the exact verification-boundary gap #12310 left (stale committed data + SW cache-first). I considered whether it overshoots scope (no), under-delivers (no — data + cache + guards all addressed), or misses an AC (no — both post-merge items map to the operator's reported symptom); none apply.[IMPACT]: 60 — fixes a visible Portal regression + a service-worker caching-correctness gap + adds recurrence guards; substantive but localized to portal data + one SW config entry.[COMPLEXITY]: 45 — Moderate: three layers (committed-data regen, SW cache policy, test guards), each delta small and well-isolated; the SW cache-layer reasoning is the main cognitive load for a reader.[EFFORT_PROFILE]: Quick Win — small surface, high ROI: fixes the visible regression and pins both verification boundaries (consumed JSON + SW cache) against recurrence.
Approved — clean, well-tested, and the verification-boundary guards are the durable win here. Nice catch on the SW cache layer; that one would have been easy to miss. Over to @tobiu for the merge gate.
Resolves #12309
Authored by GPT-5.5 (Codex Desktop). Session 019e7f45-ad55-75e0-bfff-a21c2385df00.
FAIR-band: over-target [20/30] — taking this lane despite over-target because the operator surfaced a P0 post-merge Portal regression, and this branch corrects the consumed-data/cache verification miss while context is fresh.
Regenerates the committed Portal pull-request and ticket chunk root indexes so the consumed data now matches the chunk-number ordering fixed by #12310. It also makes generated
/resources/data/JSON network-first in the service worker, because Neural Link showed the Portal could still reload stale chunk index JSON from the generic/resources/cache after the file order was fixed locally.Evidence: L3 (Neural Link runtime inspection of Portal store/service-worker config plus focused unit guards for committed indexes and ServiceBase fetch policy) -> L3 required (visible Portal tree ordering with service-worker cache in play). Residual: post-merge Portal reload must confirm the browser-controlled service worker updates to the new policy.
Deltas from ticket
The initial #12310 generator fix was not enough after merge. The visible app consumes committed
apps/portal/resources/data/{pulls,tickets}/index.json, and those files were still stale ondev. After regeneration, Neural Link also showed thatuseServiceWorker: "dist/production"kept/resources/cache-first, so this PR includes the narrow cache-policy correction for generated app data JSON.Test Evidence
node buildScripts/docs/index/pulls.mjsnode buildScripts/docs/index/tickets.mjsnode --check src/worker/ServiceBase.mjsnode --check test/playwright/unit/worker/ServiceBase.spec.mjsnpm run test-unit -- test/playwright/unit/ai/buildScripts/docs/index/TicketIndex.spec.mjs test/playwright/unit/ai/buildScripts/docs/index/PortalContentIndexes.spec.mjs test/playwright/unit/worker/ServiceBase.spec.mjspassed: 8 tests.git diff --checkPortal.store.Pullschunk order after reload while Portal haduseServiceWorker: "dist/production"andServiceBase.cachePathscovered/resources/; this falsified the earlier generator-only fix as complete.Post-Merge Validation
#/news/pullsunder the service worker and confirm the Latest group descends by PR chunk range withoutPRs 1-100appearing betweenPRs 601-700andPRs 501-600.#/news/ticketsand confirm Backlog chunk folders descend by chunk number.Commits
bbcef046c— regenerate consumed Portal indexes, guard committed chunk order, and make generated data JSON network-first inServiceBase.Evolution
The miss was a verification-boundary error: #12310 proved the generator output in isolation, but review did not validate the committed consumed JSON nor the service-worker cache layer that the Portal actually runs through. This PR pins both boundaries.