Final sweep for setup-process bookkeeping not caught by template-reset-v1.
ADRs drop Plan-N qualifiers; spec collapses the historical 11-phase
migration table; scaffolding guide drops "Phase added" column; comment
prefixes referencing R-numbers in test describes / eslint inline comments
are normalized. Architecture-level rule IDs (R40, R52, E0, J0, etc.) are
preserved where they serve as stable cross-references in ADRs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
I3: bind-production.test.ts instrumentation orthogonality tests updated to use
bindOtelInstrumentation as primary name (bindSentryInstrumentation alias still
wired in mock setup for deprecation-alias coverage, not in assertions).
I4: as never cast in init-server-node.ts annotated with explanation of the
sdk-trace-base / sdk-node TypeScript version conflict that necessitates it.
I5: SentryLogRecordProcessor removed from @sentry/opentelemetry mock in
no-instrumentation.ts — that class does not exist in v10.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All three apps' instrumentation.ts files now call initOtelServerNode directly
instead of initSentryServer/initSentryServerNode, closing the startup window
where @sentry/nextjs auto-instrumentation could send unscrubbed errors before
bindAll() fires. bindOtelInstrumentation no longer calls initOtelServerNode
(SDK init belongs at app boot, binding at request scope). Orphaned sentry/
init-server*.ts files deleted; their package.json subpath exports removed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The sentry-pii-scrubber.test.ts file tested the now-deleted sentry/scrub.ts
module. PII scrubbing is now validated in core-shared/otel/pii-scrub-processor.test.ts
at the correct layer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
apps/web-next/bind-production.ts imports bindOtelInstrumentation instead
of bindSentryInstrumentation. Test mock tracks both names via the same
spy so existing assertions on bindSentryInstrumentation still pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- AGENTS.md (root): marks core-ui as optional in the package table and
boundary rules; points per-package docs to the .hbs template
- apps/storybook/AGENTS.md: rewrites around no-core-ui-by-default;
stories glob and globals.css import described as post-scaffold steps
- apps/web-next/AGENTS.md: cross-reference updated to template file
- apps/web-tanstack/AGENTS.md: cross-reference updated to template file
- docs/architecture/data-flow-explainer.html: core-ui bullet notes
optional status + generator command
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removal across all three consumers:
- apps/storybook: strips @repo/core-ui dep, clears stories glob (now []),
removes globals.css import from preview.ts
- apps/web-next: strips @repo/core-ui dep + transpilePackages entry
- apps/web-tanstack: strips @repo/core-ui dep
- packages/core-ui: deleted entirely (28 files)
No app pages needed surgery — neither web-next nor web-tanstack source
files imported @repo/core-ui directly. The storybook app referenced it
only via the stories glob and the globals.css preview import.
Gates: 40/40 tasks successful, all 4 e2e byte-identical reconstructions
pass (realtime, events, trpc, ui).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Five fixes surfaced by the branch-wide code review on the realtime layer:
- server.ts: replace dynamic `import("@repo/auth/di/container")` with a
static top-of-file import. The dynamic-import workaround from 6a0ac63 is
no longer needed once the root tsconfig + TSX_TSCONFIG_PATH expose
decorator metadata to tsx; verified by booting `pnpm dev` clean.
- server.ts: correct the inline structural type for `validateSession` to
match the real `IAuthenticationService` contract (non-nullable, throws
on invalid session) and wrap the call in try/catch so unauthenticated
bubbles to a `null` return instead of dead-code `result ? ... : null`.
- bind-production.ts: extract `maybeRegisterRealtimePing()` that wraps the
built-in ping inbound handler in the same `withSpan(withCapture(...))`
sandwich the realtime-handler generator emits (R41–R44), so the
proof-of-life channel models the convention rather than registering raw.
- bind-production.test.ts: add 4 tests for the `REALTIME_PING_DISABLED`
env-gate (registered when unset in both binders, not registered when
"true", treated as enabled when "1").
- docs/guides/realtime.md: correct the integration-test reference at
line 285 — the test does not call `bindAllDevSeed()`; it builds the
Socket.IO server inline and exercises gates 1+2 only (gates 3+4 live in
socket-io-realtime-server.test.ts).
- adr-016: add a "Known follow-ups" section recording 6 lower-priority
refinements deferred from this branch (bridge stub test scaffolding,
registry register/registerChannel precedence, channel-template dot
constraint, server bare catch{}, BindAllDeps Partial widening, AGENTS.md
anchor count phrasing).
CI gates: lint 0 errors / 4 warnings (pre-existing turbo.json warnings),
typecheck clean, 24 web-next tests pass (was 20; 4 new env-gate tests),
boundaries 0 issues across 504 files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- no-direct-socket-io: extend allowlist to cover apps/*/src/**/*.test.ts so
the realtime-ping e2e integration test can import socket.io/socket.io-client
directly; add two valid test cases to keep the rule's own test suite green
- tsconfig.json (root): add root-level tsconfig with experimentalDecorators +
emitDecoratorMetadata and no "include" so tsx 4.21.0's createFilesMatcher
resolves decorator config for all workspace packages, not just web-next's
own source tree
- web-next dev script: pass TSX_TSCONFIG_PATH=../../tsconfig.json so the
custom Node server uses the root tsconfig for all modules it loads
- next.config.mjs: add @repo/core-events and @repo/core-realtime to
transpilePackages so Next.js webpack can resolve their workspace source files
- server.ts: replace static authContainer import with a dynamic import inside
IRealtimeAuthenticator.authenticate so Inversify decorators are applied only
after bindAll() has already populated the container
All CI gates pass: lint (0 errors), typecheck, 20 tests (incl. realtime-ping
e2e), boundaries (0 issues).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extends bindAll/bindAllProduction/bindAllDevSeed to accept BindAllDeps
and thread realtime + realtimeRegistry as the 6th and 7th positional args
into each per-feature binder. Adds bindRealtimeBridge stub (empty allowlist
in v1). bindAll accepts optional deps with InMemoryRealtimeBroadcaster
fallback so existing page-level callers stay type-safe.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces `next dev` / `next start` with a custom Node http server that
co-hosts Next.js and Socket.IO on the same port, wiring in the
RealtimeHandlerRegistry and session-cookie-based IRealtimeAuthenticator.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
End-to-end proof-of-life. bindAllDevSeed wires InMemoryEventBus +
InMemoryJobQueue across all features. signUpController publishes
auth.user.signed-up; marketing-pages' handler enqueues
marketing-pages.send-welcome-email; the in-memory queue dispatches
the wrapped job which records on RecordingMailerService.
Adds ./di/container, ./di/symbols, ./services/mailer, and
./services/recording-mailer to auth + marketing-pages exports so
the e2e test can resolve from the per-feature containers without
deep-importing.
resolveEventsAndJobsProduction wires PayloadJobsEventBus + PayloadJobQueue
against the bootstrapped Payload instance; resolveEventsAndJobsDevSeed
wires InMemoryEventBus + InMemoryJobQueue. Each per-feature binder now
receives (bus, queue) so Phase 7 generators can subscribe handlers and
register job tasks at the <gen:event-handlers>/<gen:jobs> anchors.
TypeScript 6 deprecates `baseUrl` in favor of resolving `paths`
relative to the file that defines them. Earlier commit (bde40e4)
silenced the warning via `ignoreDeprecations`; this commit does
the actual migration so the warning goes away on its merits.
Changes:
1. tsconfig.base.json: drop `baseUrl: "."`. Add an explicit `./`
prefix to every `paths` entry so they resolve relative to the
base config's location (the repo root) — same behavior as
before, but no baseUrl needed. (TypeScript requires path entries
to be relative or absolute when baseUrl is absent; bare paths
like "packages/..." are not allowed.)
2. apps/web-next/tsconfig.json: drop baseUrl. The `@/*` mapping's
target was already "./src/*" — relative-from-tsconfig-file is
the new default, so no other change.
3. apps/cms/tsconfig.json: same — drop baseUrl, paths already use
"./" prefix.
4. apps/storybook/tsconfig.json: same.
5. apps/web-tanstack/tsconfig.json: same.
Generator templates (turbo/generators/templates/feature/tsconfig.json.hbs)
already omit baseUrl, so future-generated features inherit the new
posture.
Reverts the ignoreDeprecations setting added in bde40e4 — no longer
needed.
Verified:
- pnpm typecheck 14/14
- pnpm lint 15/15
- pnpm test 26/26
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds apps/web-next/instrumentation.ts (server) and instrumentation-client.ts
(browser) hooks, wraps next.config.mjs with withSentryConfig (R52), and adds
the R38 per-app PII scrubber smoke test.
Spec deviation: extend PII_KEY_SUBSTRINGS with "ipaddress" so keys like
ipAddress trigger key-level redaction (tighter posture than the spec's
substring list; existing scrub.test.ts still passes).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extends bind-production.test.ts with a vi.mock for @repo/core-shared/instrumentation
that wraps bindSentryInstrumentation and bindNoopInstrumentation in vi.fn (so call
counts are observable while real implementations still run). Adds 4 orthogonality
tests covering: DSN absent + production env, DSN set + dev env, Sentry + dev seed,
Noop + production — verifying instrumentation choice is independent of repo mode.
Total: 6 original + 4 new = 10 passing tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces resolveInstrumentation() in apps/web-next/src/server/bind-production.ts:
reads WEB_NEXT_SENTRY_DSN; if set, calls bindSentryInstrumentation; else Noop.
Both bindAllProduction and bindAllDevSeed call resolveInstrumentation() at the
top. Exports __resetBindStateForTests() and __getInstrumentationForTests() for
test helpers. Adds inversify + reflect-metadata as direct dependencies of web-next.
Existing 6 tests still pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CLAUDE.md Key Conventions: 'App bootstrap' rule rewritten as 'Three
binding modes per feature' — describes USE_DEV_SEED + NODE_ENV
resolution order and the new ./di/bind-dev-seed export.
- AGENTS.md (root): exports list now mentions ./ui + ./di/bind-dev-seed;
Per-feature public-API surface table gains a row; Apps section shows
the bindAll() dispatcher with three-rule logic.
- docs/architecture/vertical-feature-spec.md §6: file shape now
includes bind-dev-seed.ts, bind-dev-seed.test.ts, __seeds__/dev.ts;
package.json exports list updated to include ./di/bind-dev-seed.
- docs/architecture/data-flow-explainer.html: anatomy tree gains
__seeds__/ row; LAYERS.di description updated with new binders +
cross-link to di-explainer.html; new LAYERS.seeds entry; public-
surface card expanded to six subpaths.
- docs/superpowers/refactor-logs/2026-05-06-input-output-unification.md
§7: new 'Post-Plan-9: dev-seed binders' entry summarizing the rollout
(commits, per-feature additions, app wiring, tests, turbo, docs).
- bind-production.test.ts: dispatcher tests use vi.stubEnv (typesafe
way to test process.env in TypeScript 5+ with @types/node read-only
process.env types). 4 dispatcher tests + 2 bindAllProduction tests
= 7 tests total.
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.
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.
Straggler fixes: web-next and web-tanstack app callers did not pass {}
to queryOptions()/caller calls after Plan 9 added .input(z.object({}).strict())
to siteSettings and header procedures. All 360 tests pass, full typecheck
green across 14 packages. Refactor log §7 updated with verification summary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Per-package tags + root boundaries block now enforce the same three-tag
model as eslint-plugin-boundaries:
- app → may depend on: app, core, core-composition, feature, tooling
- feature → may depend on: core, tooling
- core → may depend on: core, core-composition, tooling
- core-composition (core-api, core-cms) → may depend on: core, feature, tooling
- tooling (core-eslint, core-typescript) → may depend on: tooling
Tags applied: 4 apps (app), 3 core foundation packages (core),
2 core composition packages (core-composition), 5 features (feature),
2 tooling packages (tooling). All test suites pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aligns tooling packages with the core-* naming convention used by all
other foundation packages (core-shared, core-cms, core-api, core-trpc,
core-ui). Updates ~50 files: package.json names, devDependencies,
tsconfig extends, eslint.config imports, vitest.config imports, AGENTS.md
references, and the boundaries plugin patterns to match the new paths.
The tooling-specific patterns in boundaries/elements are now ordered BEFORE
the broader core-* pattern to ensure correct first-match-wins behavior.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
next-env.d.ts is a generated file using triple-slash references that
TypeScript requires. ESLint exemption added in apps/web-next config only.
Also declare CI, DATABASE_URL, PAYLOAD_SECRET, NODE_ENV in turbo.json
globalEnv so turbo/no-undeclared-env-vars stops warning.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
All public pages (site settings, header, pages, articles) now bypass
Payload's access control checks when reading, as they should be publicly
accessible without authentication. This fixes 403 Forbidden errors on
homepage and article rendering.