The .trace-tree blocks I added in §06 / §08 used var(--ink-2) (#5b4a3c —
medium brown), which clashed with the page's dedicated --code-bg
(#16110d, deep dark). Switched to --code-bg + --code-paper for text,
plus the same border + inset/drop shadow as pre.code, so the new blocks
read consistently with every other code block on the page.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After the user pushed back on intent-vs-shipped state, I greped each layer
and updated both explainers to reflect actual code, not documented intent.
data-flow-explainer.html §06 — "Tracing & error capture":
- New "Where instrumentation actually lives" table — per-layer breakdown
of inline span / inline capture / composed-via-wrapper, with a verifiable
grep showing only repos have inline calls.
- New "The wrapper sandwich" code block showing the actual repo body
shape next to the bind-time withSpan(withCapture(...)) composition.
- Capture-rules table refined to reflect the R44 fix that just landed:
use cases capture business-rule errors and output-schema failures
(not bubbled-from-repo); controllers capture safeParse failures
(not bubbled-from-use-case); the __sentryReported flag is what makes
this safe.
- Double-report-guard paragraph now mentions withCapture, SentryLogger,
and RecordingLogger all check the flag (not just SentryLogger).
di-explainer.html §08 — "Instrumentation symbols":
- Wiring path updated from "withSpan(tracer, ...)" to
"withSpan(withCapture(...))" to reflect the post-merge wiring.
- New "Two wrappers, applied as a sandwich" table comparing what each
wrapper does and where it fires; closing note that repos can't use
the wrapper because they own per-call attributes.
Also bundled: a 1-line aesthetic SVG noise tweak in di-explainer.html
(opacity='0.25', baseFrequency 0.85→0.95) that was sitting in the
working tree before this session — preserved across the Plan 10 merge
via stash/pop and now committed alongside the doc update.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Inserts a new §06 "Tracing & error capture" between the existing
"Tradeoffs by part" (§05) and the verdict (which moves to §07).
Includes the trace tree (HTTP → tRPC → controller → use-case → repo
→ Payload), capture-rules table (where captureException fires per
layer + the no-capture rule for defineErrorMiddleware), the
__sentryReported double-report guard explanation, and the R31–R38
PII rule list. Adds matching CSS (.trace-tree / .capture-rules /
.pii-rules) tuned to the existing dark-paper palette and Fraunces
heading font. Updates the contents nav from 6 → 7 columns.
di-explainer.html gets a new §08 "Instrumentation symbols" with cards
for TRACER and LOGGER, the bindAll() Rule-0 wiring path, and a note
on why feature containers also bind the symbols. Two-column grid
collapses to one on narrow viewports.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three-rule resolution order in bindAll() (first match wins):
1. USE_DEV_SEED === 'true' → bindAllDevSeed (explicit override)
2. NODE_ENV === 'production' → bindAllProduction
3. otherwise → bindAllDevSeed (developer default)
Rationale: 'pnpm dev' should boot the app without requiring Payload to
be running locally — dev seed is the more useful default for non-
production environments. Production servers explicitly set
NODE_ENV=production and get the real binding. The USE_DEV_SEED override
remains the escape hatch (force seed in any NODE_ENV — e.g. staging
preview, design review).
bind-production.test.ts grows from 3 tests to 8 — covers the dispatcher
matrix:
- USE_DEV_SEED='true' wins even when NODE_ENV='production'
- NODE_ENV='production' (no override) → production
- NODE_ENV='development' → dev seed (default)
- NODE_ENV unset → dev seed (default)
- USE_DEV_SEED='false' treated as not-set (only the literal 'true' triggers)
- Pre-existing 'binds all five repos' test now also asserts bindProductionMedia
di-explainer.html conditions table + mode flag strings updated to match
the new three-rule logic.
ESLint flagged that USE_DEV_SEED was read in apps/web-next without being
declared in root turbo.json globalEnv — added it.
DI explainer's conditions table previously listed 'Production server
(NODE_ENV=production)' as a scenario, but bindAll() only checks
USE_DEV_SEED — NODE_ENV is not read anywhere in source. Fixed the table
and the prod-mode flag string to match what the code actually does.
apps/web-next/src/server/bind-production.ts now exports three functions:
- bindAllProduction() — production-only binders
- bindAllDevSeed() — dev-seed-only binders (NEW, calls all 5 features)
- bindAll() — dispatcher that branches on USE_DEV_SEED env var
All page/route callers (page.tsx, about/page.tsx, blog/[slug]/page.tsx,
api/trpc/[trpc]/route.ts) updated from bindAllProduction → bindAll so the
env flag actually has effect.
docs/architecture/di-explainer.html (NEW): standalone interactive page
explaining the di/ folder file-by-file, the loading sequence (8 stages),
the three binding kinds (.to / .toDynamicValue / .toConstantValue), an
interactive three-mode picker showing how the same blogContainer state
differs across default/dev-seed/production, a conditions table, and a
final card on how tests bypass DI entirely. Sister page to
data-flow-explainer.html.
Refactor log entry + canonical doc updates follow in subsequent commits.