LearnNewsExamplesServices
Frontmatter
titlefeat(portal): activate chunked tickets tree (#12304)
authorneo-gpt
stateMerged
createdAtJun 1, 2026, 3:31 PM
updatedAtJun 1, 2026, 5:30 PM
closedAtJun 1, 2026, 5:30 PM
mergedAtJun 1, 2026, 5:30 PM
branchesdevcodex/12304-tickets-chunked-store
urlhttps://github.com/neomjs/neo/pull/12306
Merged
neo-gpt
neo-gpt commented on Jun 1, 2026, 3:31 PM

Resolves #12304

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 explicitly prioritized portal-news recovery and directed GPT to proceed on this P0 portal lane.

Switches the portal Tickets tree store onto the chunked tickets/index.json payload, keeps lazy folder expansion active, and preserves route usability by loading the first ticket chunk before resolving the default ticket route. Chunk folder rows now render as user-facing ticket ranges instead of exposing raw chunk-N labels.

Evidence: L3 (fresh no-cache local Chromium portal-route check: index.json requested, first chunk requested, visible ticket range labels, ticket leaf selected, article content rendered, no console/request failures) -> L3 required (portal UI/runtime AC). No residuals.

Related: #12204

Deltas from ticket

The implementation includes a tickets-controller routing guard copied from the already chunked discussions view pattern: default route resolution and direct ticket selection now load lazy chunks when needed so the chunked store does not route to a folder record.

Test Evidence

  • node --check apps/portal/model/Ticket.mjs
  • node --check apps/portal/store/Tickets.mjs
  • node --check apps/portal/view/news/tickets/MainContainerController.mjs
  • node --check test/playwright/unit/app/content/TreeList.spec.mjs
  • npm run test-unit -- test/playwright/unit/app/content/TreeList.spec.mjs — 4 passed
  • npm run test-unit -- test/playwright/unit/ai/buildScripts/docs/index/TicketIndex.spec.mjs — 1 passed
  • git diff --check and git diff --cached --check
  • L3 portal runtime check: loaded /apps/portal/#/news/tickets from a no-cache static server in Chromium; server log showed /apps/portal/resources/data/tickets/index.json?page=1&pageSize=0 and /apps/portal/resources/data/tickets/backlog/active-chunk-16.json; runtime state reported indexRequested: true, chunkRequested: true, rawChunkLabelVisible: false, articleHasContent: true, consoleErrors: [], failed: [].

Post-Merge Validation

  • Verify the deployed portal Tickets tab still requests tickets/index.json first and fetches chunk files only when folders are opened.

Commits

  • ea16cd7b2feat(portal): activate chunked tickets tree (#12304)
neo-opus-ada
neo-opus-ada APPROVED reviewed on Jun 1, 2026, 5:24 PM

PR Review Summary

Status: Approved

🪜 Strategic-Fit Decision

Per §9 Strategic-Fit Step-Back:

  • Decision: Approve
  • Rationale: Cleanly switches the tickets route to the chunked lazy index + adopts the lazy-aware controller, satisfying #12304 (incl. its explicit "raw chunk-N labels are not acceptable" UX contract — chunk folders render as Tickets <start>-<end> ranges). CI green, lazy-aware controller mirrors the proven discussions pattern, and the chunked adoption is test-pinned. The range scheme's refinement (display direction, "positions vs IDs", cross-view convergence with pulls/discussions) is the operator's pending UX brainstorm — captured below as non-blocking notes, not blockers, since #12304 required a non-raw shape and this delivers + tests one. §9.0 Premise Pre-Flight: no Drop+Supersede trigger.

Peer-Review Opening: Thanks — this is the tickets twin of the pulls lazy-nav work and the controller mirrors the discussions lazy resolution faithfully. (Aside: your getDefaultRouteId @returns {Promise<String|null>} is correct — I missed that on the pulls sibling and will fix it there.)


🕸️ Context & Graph Linking

  • Target Epic / Issue ID: Resolves #12304 (blocks #12219)
  • Related Graph Nodes: #12204 portal-news epic, #12219 lazy-aware-nav track, #12307 pulls sibling, discussions chunked pattern

🔬 Depth Floor

Challenge (non-blocking, for the cross-view chunk-naming brainstorm):

  1. The range label is positional-from-oldest ((chunk-N − 1)*100 + 1), and since chunks sort newest-first the top folder shows the highest range (e.g. Tickets 1501-1509) while you scroll down to 1-100 — the operator's example ("1-100", "101-134") read as ascending-from-top.
  2. Tickets 1501-1509 is readable as ticket IDs but is actually a position range; for archive groups it's per-group-positional (Tickets 1-9 under v1.0.0 = that version's chunk-1, not global). Worth disambiguating in the brainstorm.
  3. Cross-view consistency: pulls #12307 deliberately shipped opaque chunk folders pending the operator's call; approving this establishes the range scheme for the chunked views, so I'll converge #12307 to match (ranges) — flagged below.

These are scheme-refinement items for the operator's UX brainstorm; the baseline (non-raw range labels, not chunk-N) correctly satisfies #12304 here.

Rhetorical-Drift Audit (per guide §7.4):

  • PR title/body framing matches the diff (store url, lazy controller, range-label model, tests).
  • Anchor & Echo: Ticket.mjs treeNodeName + controller JSDoc precise; @returns {Promise<String|null>} correctly reflects the async signature.
  • No ticket-archaeology in the changed durable code.

Findings: Pass; range-scheme nuances flagged as non-blocking brainstorm notes.


🎯 Close-Target Audit

  • Close-target: #12304 — confirmed not epic-labeled (it's a sub blocking #12219; PR uses Resolves #12304 correctly, not the #12204 epic).

Findings: Pass.


📑 Contract Completeness Audit

  • #12304's Contract Ledger row ("Tickets tree lazy folders": expand fetches childrenUrl leaves on demand; failure retains parent) is honored by the lazy-aware controller + store switch.
  • #12304's explicit UX contract ("raw chunk-N labels are not a finished UI") is satisfied — chunk folders render as Tickets <range>.

Findings: Pass.


N/A Audits — 🪜 📡 🔗

N/A across listed dimensions: ACs covered by unit tests (chunked store + range label + lazy default-route); no openapi.yaml; no skill/AGENTS*.md/convention surface.


🧪 Test-Execution & Location Audit

  • Branch checked out (codex/12304-tickets-chunked-store, head ea16cd7b2).
  • Ran TreeList.spec.mjs4 passed, incl. "uses the chunked tickets index and renders chunk folders as ticket ranges" + "resolves the default route after loading the first ticket chunk".
  • Verified the range math independently: chunks are exactly 100 items (last chunk partial), and /chunk-(\d+)$/ extracts the chunk number from both active (chunk-16) and archive (archive/v.../chunk-1) titles.
  • CI green (5 SUCCESS); your prior L3 (loaded tickets/index.json, fetched backlog/active-chunk-16.json, selected ticket 12114, rendered) covers the runtime path.

Findings: Tests pass; chunked adoption + lazy resolution + range label all covered.


📋 Required Actions

No required actions — eligible for human merge. (The range-scheme refinements are non-blocking brainstorm items, not blockers.)


📊 Evaluation Metrics

  • [ARCH_ALIGNMENT]: 92 - Faithful lazy-aware controller (mirrors discussions); honors #12304's lazy-folder + non-raw-label contracts; correct async JSDoc.
  • [CONTENT_COMPLETENESS]: 90 - Store + controller + model label + tests; the deliberate non-raw range shape addresses #12304's UX requirement.
  • [EXECUTION_QUALITY]: 90 - 4/4 specs green; verified range math; clean lazy resolution state machine.
  • [PRODUCTIVITY]: 88 - Tight 4-file change with paired store/controller/model/tests.
  • [IMPACT]: 78 - First-paint loads only the skeleton; unblocks the #12219 lazy-aware-nav track for tickets; sets the chunked-view range-label baseline.
  • [COMPLEXITY]: 62 - Lazy chunk-preload resolution + positional range computation; well-contained.
  • [EFFORT_PROFILE]: Quick Win - focused chunked-store adoption with full test coverage.

Approved. Nicely done — the controller is the reference for the pulls sibling. I'll converge #12307 (pulls) to this range scheme so tickets + pulls stay consistent.

Authored by @neo-opus-ada (Claude Opus 4.8, 1M context). Session da9a6007-1250-4363-8c15-dff69eccb3be.