convex/ (schema, functions, deploy role for :3210) moved to
joelclaw-api; apps/web consumes generated api/types via link:.
sessions schema is a deliberate temporary v.union (auth + call
telemetry shapes) — separation chartered. All four readback checks
pass: deploy clean, tsc clean, no old-path refs, live read works.
Worker-authored, steering-verified.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
notFound() is a runtime API that requires workUnitAsyncStorage context.
Calling it inside 'use cache' causes InvariantError during prerendering.
CachedArticleContent now returns null when post not found, and the
caller (StaticArticleShell) handles notFound() in request context.
Also uses cacheLife('minutes') so new articles appear without deploy.
getPost() now caches for minutes instead of max, so new articles
appear within minutes of Convex upsert. Explicit tag revalidation
makes them appear instantly. 404 check moved outside cache boundary
in [slug]/page.tsx so stale null results don't block new content.
getPost() no longer uses 'use cache' — null results were cached
indefinitely, blocking new articles until a redeploy.
Now: getPost() fetches from Convex on every request (uncached).
CachedArticleContent receives post as prop, caches only MDX rendering.
New articles appear immediately after Convex upsert + tag revalidation.
- posts.ts: strip leading frontmatter/metadata before rendering
- content-review.ts: normalize content on fetch/persist to prevent
future writes from reintroducing raw frontmatter
- seed-articles.ts: defensive strip on seed path
Fixes frontmatter metadata rendering as visible article body text.
CFP-2 made getPost/getAllPosts async for Convex reads, but Next.js 16
with PPR rejects uncached async data access outside <Suspense>.
ALL article pages failed prerender with 'Uncached data was accessed
outside of <Suspense>'.
CFP-2 and CFP-3 need to land together — Convex reads require
'use cache' boundaries first.
retries: 0 made worker restarts fatal — Inngest couldn't retry
the step on the new worker. With retries: 2, the 1s restart window
is covered by Inngest's built-in retry backoff.
ADR-0156 rewritten: blue/green port swap > drain-then-restart.
Inngest is step-level stateless — we don't need to wait for runs,
just for the current in-flight step.
- Titles wrap fully instead of truncating
- Relevance text shows complete (no line-clamp)
- Date shown as relative time (2d ago) above title, not stealing width
- Single type badge (repo/article/video) replaces full tag list
- Source URL removed from index (shown on detail page)
- Tighter card spacing for better scan density
- Re-removed duplicate self-hosting discovery (also from Vault source)