Commit Graph

297 Commits

Author SHA1 Message Date
85513ccbf9 docs: instrumentation testing patterns + dependency-flow + core-shared AGENTS update
Adds "Asserting spans and captures" section to tdd-workflow.md with
RecordingTracer/Logger usage and inline withSpan wrapping pattern for
direct-injection tests. Adds R49/R50 section to testing-strategy.md
covering the no-sentry guard, contract suite span assertions, and
RecordingTracer/Logger field reference. Adds "TRACER / LOGGER (Plan 10)"
subsection to dependency-flow.md showing the bindAll → feature-container
wiring path. Adds an "src/instrumentation/" section to core-shared/AGENTS.md
documenting the two interfaces, three impl pairs, withSpan helper, scrubbers,
both Next.js + Vite/React init helpers, and the subpath exports.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:35:28 +02:00
c640cdf6c8 docs: instrumentation conventions in CLAUDE.md / AGENTS.md / vertical-feature-spec.md
Adds the seven Plan 10 conventions to CLAUDE.md (interfaces in core-shared,
spans at bind time, throw-site capture, PII rules, three Sentry projects,
orthogonal binding). Adds an "Instrumentation conventions" section to
AGENTS.md with repo constructor/method patterns, capture-rules table,
boundary allowlist, and test rules. Appends §16 "Instrumentation & error
capture" to vertical-feature-spec.md (the spec already has 15 sections,
so appending rather than slotting in as §10 to avoid renumbering).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:33:52 +02:00
d4b23cf35d chore(turbo): declare instrumentation env vars in globalEnv
Adds WEB_NEXT_SENTRY_DSN, NEXT_PUBLIC_WEB_NEXT_SENTRY_DSN, CMS_SENTRY_DSN,
WEB_TANSTACK_SENTRY_DSN, VITE_WEB_TANSTACK_SENTRY_DSN, VITE_GIT_COMMIT_SHA,
SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT_{WEB_NEXT,CMS,WEB_TANSTACK},
SENTRY_TRACES_SAMPLE_RATE, SENTRY_ENVIRONMENT, VERCEL_GIT_COMMIT_SHA,
NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA, and VERCEL_ENV.

Clears turbo/no-undeclared-env-vars warnings on init-server.ts /
init-client.ts / bind-production.ts / next.config.mjs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:31:52 +02:00
955a763c66 feat(eslint+ci): R40 boundary rule for @sentry/* + R31 sendDefaultPii grep gate
Adds two flat-config blocks to core-eslint/base.js: (1) repo-wide
no-restricted-imports for @sentry/* with the R40 message, (2) an
allowlist override for the only paths permitted to import the Sentry
SDK directly — core-shared/instrumentation/sentry/**, the bind-sentry
DI files, the no-sentry test guards, and apps' instrumentation* /
next.config / vite.config / sentry.*.config files. Patterns use
**/-prefix so they match whether ESLint runs from the repo root or
from inside a sub-package.

Also adds the standard `argsIgnorePattern: "^_"` config (used
throughout the repo) and a Node-globals override for *.mjs/*.cjs/*.js
and *.config.{ts,tsx} so withSentryConfig in next.config.mjs lints
clean. Required adding `globals` as a core-eslint dep.

Adds .github/workflows/sentry-pii-guard.yml — a lightweight CI step
that fails any PR introducing `sendDefaultPii: true` (R31). Excludes
node_modules / dist / .next / .turbo from the grep so vendored SDK
JSDoc examples don't false-positive.

Pre-existing lint nits cleared as part of getting `pnpm lint` green:
- core-testing define-contract-suite.test.ts: void the unused
  receivedTracer (mirrors the next test's pattern)
- marketing-pages bind-dev-seed.ts: drop unused MockSiteSettingsRepository
  import
- marketing-pages get-site-settings.use-case.ts: drop the now-redundant
  eslint-disable for `_input`

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:31:15 +02:00
e1b6ecf578 feat(web-tanstack): Sentry instrumentation via @sentry/node + @sentry/react + R38 PII test
Adds initSentryServerNode + initSentryClientReact to core-shared
(Vite/non-Next variants of the existing init helpers — same R31/R32/R33
posture, R34/R35/R37 replay defaults). Extends no-sentry.ts to mock
@sentry/node + @sentry/react. Wires the web-tanstack server/client
instrumentation entry hooks and adds the R38 PII test.

Spec deviation: web-tanstack has no vite.config.ts yet (placeholder app
per its package.json). The @sentry/vite-plugin dep is added but unused
until the TanStack Start build is wired in a later plan. A minimal
src/vite-env.d.ts shims ImportMetaEnv for the client entry until the
full Vite types land.

@sentry/node and @sentry/react are added to core-shared as optional
peerDependencies so feature packages don't transitively pull them in;
they're also devDependencies of core-shared for typecheck/test runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:25:14 +02:00
d348cb9179 feat(cms): Sentry server instrumentation + withSentryConfig + R38 PII test
Adds apps/cms/instrumentation.ts (server-only — Payload admin client DSN
is out-of-scope per spec §8). Wraps the Payload-wrapped next config with
withSentryConfig. Adds the R38 PII scrubber test. Required adding
@repo/core-shared as a direct dep of cms (was only transitive before).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:14:56 +02:00
f911892d0b feat(web-next): Sentry instrumentation hooks + withSentryConfig + R38 PII test
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>
2026-05-07 20:13:39 +02:00
d4bc045a28 test(features): R50 — repo contract suites assert span shape per method
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 19:09:50 +02:00
a4efceb104 feat(core-testing): R50 — contract context gains optional getTracer accessor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 18:08:39 +02:00
a943f95929 feat(media): wire instrumentation — media repo spans + getMedia/listMedia/deleteMedia withSpan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 18:01:46 +02:00
e14a23dccd feat(navigation): wire instrumentation — header repo spans + getHeader withSpan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 17:59:14 +02:00
404cb07e79 feat(marketing-pages): wire instrumentation — site-settings + pages spans + use-case/controller withSpan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 00:26:45 +02:00
64ffb009e1 feat(auth): wire instrumentation — users repo spans + sign-in/up/out withSpan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 00:24:20 +02:00
5903cef70a feat(blog): wire instrumentation — repo spans + use-case/controller withSpan + logger capture
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 00:18:13 +02:00
64b6eb79d4 feat(core-testing): R49 guard — block real Sentry SDK init in test processes 2026-05-07 00:11:22 +02:00
05e7bf6c57 feat(core-testing): RecordingLogger + ./instrumentation subpath 2026-05-07 00:08:23 +02:00
e98d1bd2e4 feat(core-testing): RecordingTracer for span assertions 2026-05-07 00:07:01 +02:00
07e8b2e2e7 test(app): R47 — bindAll instrumentation orthogonality matrix
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>
2026-05-07 00:04:26 +02:00
efacb0e072 feat(app): bindAll() Rule 0 — DSN-driven instrumentation (orthogonal to repo mode)
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>
2026-05-07 00:03:27 +02:00
fbcee9b9f2 feat(core-shared): bindNoopInstrumentation + bindSentryInstrumentation
Adds DI binder functions for instrumentation. bindNoopInstrumentation binds
NoopTracer + NoopLogger; bindSentryInstrumentation calls initSentryServer then
binds SentryTracer + SentryLogger. Both are idempotent (unbind-first). Adds
inversify + reflect-metadata as devDependencies so container tests compile.
Re-exports from instrumentation barrel. 6 new tests (3+3).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 00:01:54 +02:00
b08da12447 fix(core-shared): TypeScript type fixes for Sentry adapter layer — null attr filter, structural event types, non-null assertions, vi.stubEnv 2026-05-06 23:56:46 +02:00
5f74230ad4 feat(core-shared): initSentryClient helper (R34, R35, R37 mandatory replay defaults) 2026-05-06 23:48:08 +02:00
a9f559117e feat(core-shared): initSentryServer helper (R31, R32, R33, R37 defaults) 2026-05-06 23:47:18 +02:00
2631b757b0 feat(core-shared): PII scrubbers — beforeSend (R32) + beforeSendTransaction (R33) 2026-05-06 23:46:42 +02:00
6d4522438d feat(core-shared): SentryLogger with double-report guard + R36 user-context strip 2026-05-06 23:45:45 +02:00
a324da09c5 feat(core-shared): SentryTracer adapter 2026-05-06 23:45:05 +02:00
e133b92fe6 feat(core-shared): symbols + barrel for instrumentation subpath 2026-05-06 23:42:26 +02:00
0ffda8078f feat(core-shared): add withSpan higher-order helper 2026-05-06 23:41:54 +02:00
fdd4e9141b feat(core-shared): add ILogger interface + NoopLogger 2026-05-06 23:41:27 +02:00
f1051ded9b feat(core-shared): add NoopTracer 2026-05-06 23:41:01 +02:00
fcd10e8774 feat(core-shared): add ITracer/ISpan interfaces 2026-05-06 23:40:35 +02:00
2c402d6b90 chore(plan-10): scaffold refactor log + ADR-014 stub 2026-05-06 23:38:27 +02:00
77a97dac9e docs(plan): Plan 10 — instrumentation + Sentry logging implementation
33-task TDD plan implementing the R31–R55 spec across 9 phases:
foundation interfaces (NoopTracer/NoopLogger/withSpan), Sentry adapters
(SentryTracer/SentryLogger with __sentryReported double-report guard,
beforeSend + beforeSendTransaction PII scrubbers), DI binders + bindAll
Rule 0 dispatcher (orthogonal to USE_DEV_SEED/NODE_ENV), test
infrastructure (RecordingTracer/RecordingLogger + no-sentry guard),
per-feature wiring for all 5 features (blog/auth/marketing-pages/
navigation/media), contract suite span assertions, three-app integration
(web-next/cms/web-tanstack including @sentry/node + @sentry/react +
@sentry/vite-plugin variants), ESLint boundary rule + CI grep gate, and
docs + HTML updates (data-flow-explainer §06, di-explainer
instrumentation symbols, ADR-014).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 22:38:49 +02:00
87674fecae docs(spec): instrumentation + Sentry logging design (R31–R55)
Defines the post-Plan-9 instrumentation subsystem: vendor-agnostic
Tracer/Logger interfaces in core-shared, full-depth tracing
(procedure → controller → use-case → repository) with use-case +
controller spans applied via withSpan at DI binding time and explicit
tracer.startSpan in every repository method, throw-site error capture
with __sentryReported double-report guard, and hard PII rules
(sendDefaultPii:false, default-mask replay, beforeSend/beforeSendTransaction
scrubbers, opaque user IDs only, build-time CI grep gate).

Three apps in scope (web-next, cms, web-tanstack), each with its own
Sentry project and DSN. Instrumentation binding is orthogonal to
USE_DEV_SEED/NODE_ENV repo binding. Optional dev-mode Sentry: NoopTracer
default, real SDK initializes only if DSN env is set.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 21:03:30 +02:00
b90570b62f docs(arch): add §05 'Tradeoffs by part' to data-flow explainer
Each folder/file in the feature anatomy gets its own card with:
- Brief one-line description
- Two-column pros/cons list (3-4 items each)

Covers 22 parts grouped into 21 cards: entities/models, entities/errors,
application/repositories interfaces, application/services interfaces,
application/use-cases, infrastructure real repo, infrastructure mock
repo, infrastructure services, interface-adapters/controllers, di/
(symbols, module, container, bind-production, bind-dev-seed),
integrations/api/procedures, integrations/api/router, integrations/cms,
ui, __factories__, __contracts__, __seeds__, src/index.ts.

Each card uses the same paper/cream palette as the rest of the page;
pros/cons differentiated by color (forest-green + / oxblood −) and a
JetBrains-Mono leading character.

Verdict section renumbered to §06; contents nav updated to 6-column
grid.
2026-05-06 19:59:16 +02:00
8f34daca36 docs(dev-seed): canonical doc updates + refactor-log entry
- 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.
2026-05-06 19:49:58 +02:00
6bf19f35c5 feat(app): bindAll() now checks NODE_ENV in addition to USE_DEV_SEED
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.
2026-05-06 19:32:00 +02:00
61dde18b53 chore(turbo): declare USE_DEV_SEED in globalEnv
Earlier commit 74b88f7 attempted this but the Edit failed silently
without a prior Read. ESLint's turbo/no-undeclared-env-vars rule was
still flagging the warning.
2026-05-06 19:21:24 +02:00
74b88f74da fix(turbo+docs): declare USE_DEV_SEED in turbo globalEnv; correct DI explainer
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.
2026-05-06 19:21:00 +02:00
68e934c0a5 feat(app): wire bindAll() + bindAllDevSeed() dispatcher; add DI explainer page
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.
2026-05-06 19:10:29 +02:00
10479c4d55 feat(features): add bind-dev-seed binders for auth/marketing-pages/navigation/media
Mirrors the canonical blog pattern landed earlier on this branch.

Per feature:
- src/__seeds__/dev.ts — lazy buildDev<Entities>() function using the
  feature's existing factory for sensible defaults
- src/di/bind-dev-seed.ts — bindDevSeed<Feature>() async function that
  rebinds the repo symbol(s) to a populated MockXRepository via
  .toConstantValue
- src/di/bind-dev-seed.test.ts — 3+ tests per feature (populates,
  reachable by id/slug, idempotent)
- package.json — adds ./di/bind-dev-seed subpath export

Tests + use cases continue to construct mocks directly; the seed never
runs from a *.test.ts path. App boot wiring (USE_DEV_SEED env branch)
follows in a separate commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 19:04:33 +02:00
e6560bc9cb feat(blog): add bind-dev-seed binder + dev seed
Sets the canonical pattern for all 5 features. Three new files:

- src/__seeds__/dev.ts — buildDevArticles() function returning 3
  realistic articles (welcome, vertical-feature-architecture,
  wip-post) built from articleFactory with id/slug/title/status
  overrides only.
- src/di/bind-dev-seed.ts — bindDevSeedBlog() async function that
  unbinds IArticlesRepository, constructs MockArticlesRepository,
  seeds it via buildDevArticles(), and rebinds via .toConstantValue.
- src/di/bind-dev-seed.test.ts — 3 tests: populated repo, welcome
  article reachable by slug, idempotent (callable twice).

package.json adds the ./di/bind-dev-seed subpath export, parallel to
./di/bind-production.

Tests + use cases continue to construct MockArticlesRepository
directly — they never go through bindDevSeedBlog. The seed only attaches
when called explicitly at app boot.
2026-05-06 19:00:31 +02:00
449a4aedf5 docs(arch): rewrite §04 framing — drop 'mock is the surprising one'
User pushback: 'I already need mock data for dev and for testing at
runtime' — i.e., the dual role of the mock is obvious, not surprising.
Earlier framing was condescending.

Reframe around 'runtime reach':
- Section blurb leads with 'three artifacts at different distances
  from runtime'
- Three-roles card intro: same neighborhood, different reach. Mock is
  reached by runtime; contract + factory only by tests.
- 'The mock has two jobs' → 'The mock is reached from two directions
  — both legitimate, neither is the test version'.
- Contract framing now leads with its real purpose: it tests the mock
  alongside the real impl so you can trust the mock as a runtime
  artifact.
2026-05-06 18:46:23 +02:00
ea17e6f998 docs(arch): expand §04 with mock vs contract vs factory distinction
User asked: 'arent mocks also related to testing?' — yes, but the mock
plays two roles where the contract and factory play one each. §04 now
opens with that framing.

What's new:
- Section title bumped to 'Mocks, contracts & factories'
- New three-roles diagram at the top of §04 visualizing the chain:
  IArticlesRepository → MockArticlesRepository + ArticlesRepository
  → articlesRepositoryContract → articleFactory
- Two ordered lists explaining the mock's dual job (DI default binding
  + direct test fake) and the contract/factory's single test-only roles
- Three new expandable code examples:
  · the mock as DI binding (real BlogModule code)
  · the mock as direct test fake (use-case test, no container)
  · the contract running against both impls (proof-of-parity)
- New CSS for .three-roles-diagram, .role-* boxes, .role-arrow with
  vertical connector lines, .role-jobs lists with counter-leading
  decimal numbering

The existing Contracts and Factories cards stay in place below — they
provide the deeper detail on each individual artifact.
2026-05-06 18:42:06 +02:00
1b7e5eac50 docs(arch): add interactive data-flow explainer page
Single-file HTML at docs/architecture/data-flow-explainer.html.
Self-contained — Google Fonts (Fraunces + JetBrains Mono) is the only
external resource; all interactivity is vanilla JS, all diagrams are
inline SVG/CSS.

Five sections:
  01. Feature anatomy — clickable folder tree, layer detail card swaps
      to explain entities / application / infrastructure / interface-
      adapters / di / integrations / ui / __factories__ / __contracts__
      / public surface.
  02. Request flow — step-through pipeline (12 stages, including the
      success/error fork) with prev/next/play and a feature picker
      (auth, blog, marketing-pages, navigation, media). Each feature
      swaps real code snippets, the procedures.ts error map, and the
      use-case/controller pattern.
  03. Dependency injection — interactive DI canvas with default/prod
      toggle so the user sees the same symbol resolving to mock vs
      real Payload-backed impl. Real module.ts and bind-production.ts
      code blocks below.
  04. Contracts and factories — expandable sections with the actual
      defineContractSuite + defineFactory code from packages/blog.
  05. Verdict — short answer (yes), tradeoffs, badge row.

Editorial aesthetic: cream paper, deep ink, oxblood accent, Fraunces
display + JetBrains Mono code. Subtle paper noise + ruled-line bg.
No CDN scripts beyond fonts.
2026-05-06 17:57:57 +02:00
881b468638 docs(refactor-logs): tick all doc-update checklist items in Plan 8 + Plan 9 logs
Combined post-Plan-9 doc-update pass complete:

Plan 8 checklist (14 items): all ticked.
- CLAUDE.md, AGENTS.md root, adding-a-feature, tdd-workflow, testing-
  strategy, vertical-feature-spec, overview, dependency-flow, ADR-012,
  per-feature AGENTS ×5, core-testing AGENTS, auth AGENTS, media AGENTS,
  Plan 7 plan/spec annotation.

Plan 9 checklist (13 items, 1 already ticked): all ticked.
- CLAUDE.md, AGENTS.md root, adding-a-feature, tdd-workflow, testing-
  strategy (already ticked previously), vertical-feature-spec, overview,
  dependency-flow, ADR-012 cross-ref, ADR-013, per-feature AGENTS,
  core-testing AGENTS, core-shared AGENTS, Plan 8 plan/spec annotation.

Final validation:
- pnpm typecheck: 14/14 packages green
- pnpm lint: 15/15 packages green
- pnpm test: 360 tests across 15 suites, all passing
- pnpm turbo boundaries: 366 files checked, no issues
2026-05-06 16:53:17 +02:00
95613ed126 docs(spec): vertical-feature-spec §9.4 — list ./ui + ./di/bind-production in exports
Doc-pass agent flagged §9.4 still listed only '.', './cms', './api' as
the allowed public surface. ./ui was added in Plan 9 and
./di/bind-production in Plan 5; both belong in the canonical list.
2026-05-06 16:50:54 +02:00
d1d792c72d docs(spec): vertical-feature-spec.md — Plan 8 + Plan 9 file shape and testing updates
§6 Feature package internal shape: now shows the post-Plan-9 layout
(entities/models, entities/errors, .repository.{mock.ts, ts,
interface.ts} naming, integrations/api/procedures.ts, ui/index.ts,
package.json ./ui subpath). Request flow box updated to show
xProcedure + xInputSchema + presenter + middleware lanes.

§10 Test placement + tooling: §10.3 now shows direct factory injection
for use-case + controller tests (the post-Plan-9 default). Router tests
retain container rebinding because tRPC resolves controllers via DI.
New §10.6 'Test obligations per layer' table maps R10, R24, R25, R26,
R27, R28 to their required layer.

§10.4 updated to reflect 360 tests across 26 packages; cross-links to
Plan 8 + Plan 9 refactor log Summary sections.

§11 doc note: ADR-012 + ADR-013 added as §11.6.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 16:49:28 +02:00
ce294b3041 docs(guide): tdd-workflow.md — Plan 9 mocking + R25/R26/R27/R28 patterns
§1 worked example rewritten to direct factory injection (no container
rebinding). §4 mocking decision tree updated. New §sections for R25
output-validation tests, R26 router error-mapping tests, R27/R28
presenter-shape tests. §9 contract-suite paths use the post-Plan-8
.mock.ts suffix.

Refactor log doc-update checklist: tdd-workflow.md ticked.
2026-05-06 16:48:39 +02:00
edc98f8f9a docs(agents): per-feature + core-testing AGENTS.md for Plan 8 + Plan 9 conventions
Each per-feature AGENTS.md now reflects the post-Plan-9 layout:
entity/error paths, public-API split (./ui), use-case schemas, presenter
pattern, feature-scoped tRPC error map, and feature-specific
errors-to-codes table.

core-testing/AGENTS.md gains a Plan 9 test-patterns section documenting
R25 (output validation), R26 (router error mapping), R27/R28
(presenter shape) test obligations.

auth: documents real PayloadUsersRepository + AuthenticationService and
the deferred session methods.
media: documents the full Clean Architecture scaffold introduced in
Plan 8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 16:47:56 +02:00