α
AlphaSteve
← Home

Frontend audit — 2026-05-25

Summary

The frontend is largely coherent with the new vault structure. Parser, route generation, and content-collection IDs all work correctly for the current vault contents (PLTR full bundle + FCN first-read with shelve-with-trigger decision). Three issues to address:

  1. P1 — Daily-Scans/ folder is unmapped. The user spec says "AM scan output → Daily-Scans/YYYY-MM-DD-AM.md," but no collection has ../AlphaSteve/Daily-Scans as a base. The dailies index page reads from the research collection (13-Research/2026-MM/YYYY-MM-DD-{AM,PM}.md) instead. If the scheduled-task spec is now authoritative, dailies will silently stop appearing as soon as the scan writer moves to Daily-Scans/. Today's Daily-Scans/2026-05-25.md (no AM/PM suffix) is invisible to the site.
  2. P2 — Ticker-prefixed wiki-links unresolved. wiki-links.ts:37 matches [PLTR](/theses/PLTR), [PLTR-calibration](/theses/PLTR), [PLTR-dashboard](/theses/PLTR), [PLTR-model](/theses/PLTR) but NOT [PLTR-thesis](/theses/PLTR), [PLTR-shadow-matrix](/theses/PLTR), or [PLTR-consensus-gap](/theses/PLTR). The new filenames inside the dated bundle folder all carry these prefixes, so cross-links from PLTR.md and elsewhere fall through to /brain/pltr-thesis (404).
  3. P2 — First-read wiki-links unresolved. [first-read-2026-05-25](/brain/first-read-2026-05-25) falls through to /brain/first-read-2026-05-25 rather than /theses/<TICKER>/first-read/2026-05-25. There's no way to know the ticker from the filename alone, so this needs either a [FCN/first-read-2026-05-25](/theses/FCN/first-read/2026-05-25) convention or an index lookup.

Everything else (parser, page logic, schema, build cleanliness) checks out.

Findings by category

Content config — src/content/config.ts

  • All nine collections declared with generateId: preserveId (lines 25–167). Verified that PLTR's MAY2026 folder, the ticker landing PLTR/PLTR.md, and the AM/PM filenames 2026-05-25-AM are all preserved with original casing.
  • Theses schema (lines 47–96) declares thesis-bundle fields and uses .passthrough(), so first-read fields (decision, decision_rationale, shelve_trigger, shelve_horizon, first_read_date) flow through untyped but accessible. Fine for read-only rendering.
  • Missing collection: daily-scans. Vault now contains AlphaSteve/Daily-Scans/ (e.g., 2026-05-25.md). No glob covers it. See P1.
  • 12-Portfolio/Daily-Notes/2026-05-25.md exists but portfolioCollection uses pattern: '*.md' (line 27), so subfolders are excluded — likely intentional (only Portfolio/Performance/Transactions are exposed). Worth confirming.
  • research glob is recursive (line 100). It picks up 13-Research/2026-05/*-AM.md, 13-Research/2026-05/*-PM.md, _house-view.md, _long-form-template.md, plus Themes/ (currently empty) and README.md. The dailies and papers filters tolerate this — _house-view.md and README.md will appear as research entries but are not surfaced by any page (no harm).

Parser — src/lib/thesis-bundle.ts

  • parseEntry (lines 21–81) handles all four required cases:
    • New layout PLTR/PLTR - MAY2026/PLTR-thesis — splits cleanly, fileName='PLTR-thesis' which buildCoverage then strips via stripTickerPrefix (line 177) to 'thesis'. Correct.
    • First-read FCN/first-read-2026-05-25 — handled in buildCoverage at lines 132–148 (before parseEntry is even called). Captures date, decision, decisionRationale. Correct.
    • Landing PLTR/PLTR — short-circuited in buildCoverage lines 126–130 (idParts[0] === idParts[1]). Stored on tickerLandings. Correct (though nothing consumes landing yet — see P3).
    • Revisions PLTR/PLTR - MAY2026/revisions/2026-05-23-original-EPV-only — fileParts has 2 elements with first='revisions', captured as revisionName. Correct.
    • Legacy <TICKER> - <MMMYYYY>/file — branch at lines 39–45 still supported, isLegacy=true. Correct.
  • buildCoverage (lines 118–228) correctly emits coverage for both "has thesis" tickers (lines 202–213) and "first-read only" tickers (lines 216–225). Both branches attach tickerLandings.get(ticker).
  • coverageState (lines 231–241) returns correct values for: covered (has thesis, no first-read), mixed (both), shelved (first-read only, latest decision = shelve-with-trigger), pipeline (anything else with first-reads). Matches spec.
  • Minor — landing file unused. Coverage.landing is populated but no page renders it. PLTR.md contains a useful summary block; the ticker page currently shows the latest thesis bundle directly. Not a bug, just unrealized capability (P3).

Pages

  • index.astro (dashboard) — counters work: latestByTicker.length = covered count (1 for PLTR), pipelineCount for continue/pass first-reads with no thesis, shelfCount for shelve-with-trigger first-reads. Watchlist counter uses thesesByVerdict['pass-with-trigger'] (PLTR = 1). Dailies derive from research collection (4 entries today). Papers filter long-form/ prefix (currently 0). All sound.
  • theses/index.astro — splits into Published (has thesis) + Pipeline (first-read only). Today renders PLTR in Published, FCN in Pipeline with decision='shelve-with-trigger' → orange "shelve with trigger" badge. Correct.
  • theses/[ticker].astro — three branches: hasThesis (PLTR), firstRead-only (FCN), neither. All present. Variant URL generation for tickerSlug.toLowerCase() and legacy slugified folder name (lines 21–30) is correct.
  • theses/[ticker]/[instance].astro — only generates paths where inst.thesis !== null (line 17), preventing 404s for first-read-only tickers. Correct.
  • theses/[ticker]/first-read/[date].astro — iterates cov.firstReads, renders body and (for shelve-with-trigger) extracts shelve_trigger/shelve_horizon from frontmatter. Will render correctly for FCN today. Correct.
  • theses/[ticker]/[instance]/revisions/[date].astro — iterates inst.revisions, uses fileName (stripped of .md) as params.date. Matches the ThesisInstance.astro revision link (line 170 of component). Correct.
  • shelf.astro — filters to cov.firstReads[0].decision === 'shelve-with-trigger' AND !hasThesis. FCN renders. Correct.
  • watchlist.astro — filters theses to d.verdict === 'pass-with-trigger'. PLTR renders. Correct.
  • dailies/index.astro and [slug].astro — both filter research collection by /\d{4}-\d{2}-\d{2}-(AM|PM)/. Works for 13-Research/2026-05/2026-05-25-AM.md. Will silently break if writer moves to Daily-Scans/ (P1).
  • papers/index.astro and [slug].astro — filter research by long-form/ prefix. Empty today but no error.
  • brain/index.astro and [slug].astro — list soul, frameworks, risk, optimization. All four collections currently populated. Slug uses .toLowerCase() (line 14 of [slug].astro) and matches the link generation in the index. Correct. Note: Optimization/Daily/ and Optimization/Closed/ subfolders get picked up by the recursive glob, so their IDs are Daily/2026-05-24 and would render under /brain/daily/2026-05-24 — fine but unsignposted.
  • portfolio.astro — reads three flat files by id (Portfolio, Performance, Transactions). All present, casing preserved by preserveId. Correct.
  • calibration/[slug].astro — only individual calibration entries are routable (e.g., /calibration/kit-debrief-001-PLTR). No index page. Used by wiki-links (kit-debrief-001-PLTR/calibration/...). Note that active="brain" is set, so nav highlights Reference. Fine but inconsistent with not surfacing calibration from /brain (P3).

Layout — src/layouts/Layout.astro

  • Nav (lines 12–21) includes all eight expected sections: Dashboard, Portfolio, Watchlist, Shelf, Theses, Dailies, Papers, Reference.
  • active prop type (line 7) accepts exactly those eight keys. Every page passes a valid key. No TS error.
  • [PLTR](/theses/PLTR)/theses/PLTR via the /^[A-Z]{1,5}(-calibration|-dashboard|-model)?$/ rule. Correct.
  • [PLTR-calibration](/theses/PLTR), [PLTR-dashboard](/theses/PLTR), [PLTR-model](/theses/PLTR)/theses/PLTR. Correct.
  • [PLTR-thesis](/theses/PLTR), [PLTR-shadow-matrix](/theses/PLTR), [PLTR-consensus-gap](/theses/PLTR)NOT handled. Falls to /brain/<lowercased> (404). See P2.
  • [YYYY-MM-DD-AM](/brain/yyyy-mm-dd-am)/dailies/YYYY-MM-DD-AM (line 43). Correct.
  • [first-read-YYYY-MM-DD](/brain/first-read-yyyy-mm-dd) — falls to catchall /brain/first-read-YYYY-MM-DD (404). See P3 — also impossible to resolve without ticker context.
  • [Watchlist](/watchlist), [Portfolio](/portfolio), soul files, frameworks, calibration entries — all mapped. Correct.

Build risks (static-build dry-read)

  • No TypeScript errors observed in the page files. getStaticPaths returns objects with the right shape everywhere checked.
  • No null-access risk in the rendered cards: every .thesis?.data / .firstRead?.entry?.data access is optional-chained.
  • The marked parse runs server-side at build time; renderMarkdown is wrapped in try/catch on every page that uses it.
  • verdict_date / last_refresh / etc. are coerced via dateOrString then re-formatted by formatDate. PLTR's 2026-05-24 round-trips cleanly.
  • Risk: if a future thesis omits decision_rationale and the first-read filename pattern shifts, fr.entry?.data?.decision_rationale is already optional-chained — no crash.

Render cases (today's vault)

  1. PLTR (full thesis exists)/theses shows it under Published; /theses/PLTR renders the latest instance via ThesisInstance.astro with all four tabs (thesis, matrix, consensus, calibration) plus revisions (2). /watchlist table includes PLTR (verdict pass-with-trigger). Counters: theses=1, watchlist=1, shelf=0, pipeline=0.
  2. FCN (first-read with decision=shelve-with-trigger)/theses shows it under Pipeline. /theses/FCN renders first-read landing with the "Shelve" badge, shelve_trigger and shelve_horizon cards, full markdown body. /shelf includes FCN row with $115 trigger. Counters: shelf=1.
  3. Hypothetical: new ticker with decision=continue (no thesis yet) — appears in /theses Pipeline with green "Continue" badge. /theses/<TICKER> shows first-read landing with "Continue" badge and a note "No full thesis yet." Not on watchlist/shelf. Counter: pipeline=+1.
  4. Hypothetical: new ticker with decision=pass — same as case 3 with muted "Pass" badge. Counter: pipeline=+1.
  5. Hypothetical: new ticker with decision=shelve-with-trigger — identical to FCN behavior. Counter: shelf=+1.
  6. Hypothetical: ticker with first-read + later full thesis (mixed) — Published card displays first-read count in the metadata strip (line 147 of theses/index.astro). The /theses/<TICKER> page shows the thesis (hasThesis branch wins); first-reads are reachable via direct URL /theses/<TICKER>/first-read/<date> but no in-page link from the thesis surfaces them. Minor UX gap (P3).

P1 — pick one and commit:

  1. If Daily-Scans/ is the new source of truth, add a dailyScansCollection rooted at ../AlphaSteve/Daily-Scans with pattern: '*.md' and generateId: preserveId; update dailies/index.astro and dailies/[slug].astro to read from it; tighten the filename pattern to /^\d{4}-\d{2}-\d{2}-(AM|PM)$/ so the in-flight 2026-05-25.md (no suffix) is excluded until renamed.
  2. Or keep dailies in 13-Research/YYYY-MM/ and update the scheduled-task spec / writer accordingly.

P2 — extend wiki-link map (src/lib/wiki-links.ts:37):

  • Add -thesis, -shadow-matrix, -consensus-gap to the suffix capture group so [PLTR-thesis](/theses/PLTR) resolves to /theses/PLTR. Change regex to /^[A-Z]{1,5}(-calibration|-dashboard|-model|-thesis|-shadow-matrix|-consensus-gap)?$/.

P2 — first-read wiki-link convention:

  • Decide on a stable form. Two options: (a) require [FCN/first-read-2026-05-25](/theses/FCN/first-read/2026-05-25) and add a path-aware resolver branch; (b) build a build-time index of first-read-* → ticker and resolve by lookup. Option (a) is cheaper.

P3 — surface ticker landing (PLTR.md):

  • Coverage.landing is parsed but never rendered. Consider showing the landing's summary table above the thesis tabs on /theses/<TICKER>, or use it when no thesis exists yet but the landing was hand-created.

P3 — mixed-state cross-links:

  • On a ticker page where a full thesis exists AND there are first-reads, surface the first-reads (e.g., a "Pipeline history" section above Coverage history). Currently the only signal is the small first-read count chip on /theses index.

P3 — calibration discoverability:

  • /calibration/[slug] exists but nothing links to it from /brain. Either add a Calibration section to the brain index, or remove the route if calibration is meant to be private.

P3 — Optimization/Daily entries:

  • Recursive glob picks up Optimization/Daily/*.md; they become routes /brain/daily/2026-05-24 not listed anywhere. Either restrict to *.md (flat) or render the subfolder structure in the brain index.