Commit Graph

79 Commits

Author SHA1 Message Date
7d38ff3bb9 plan(conformance): milestone vi — feature migrations 2026-05-13 00:06:48 +02:00
19611fb92c plan(conformance): milestone v — generator updates 2026-05-13 00:00:32 +02:00
b5771fc4ba plan(conformance): milestone iv — CI drift gate 2026-05-12 23:55:14 +02:00
fb23980d85 plan(conformance): milestone iii.b — AST-aware ESLint rules 2026-05-12 23:47:18 +02:00
f22f747aa9 plan(conformance): milestone iii.a — structural ESLint rules
10-task plan for standing up the conformance ESLint plugin in
@repo/core-eslint and shipping three structural rules:

- feature-must-have-manifest (warn): use-case files require a manifest
- usecase-must-have-test-file (error): TDD sibling test enforcement
- required-cores-installed (error): manifest cores ↔ workspace.yaml

Scope deliberately excludes manifest-AST analysis (no-undeclared-event-
publish, no-undeclared-audit) — those require parsing the manifest's TS
source as JS and walking the use-case AST, deferred to plan iii.b.

Uses regex-based manifest source extraction to avoid pulling in the
TypeScript compiler API at lint time. Manifest shape is constrained by
the literal `as const` form that defineFeature enforces, so the regex
path is sufficient.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 23:15:35 +02:00
31d5123737 plan(conformance): milestone ii — assertFeatureConformance + boot wiring
12-task implementation plan for the runtime boot-time check of the
conformance system. Reifies the phantom-type brands from milestone i as
non-enumerable runtime markers via Object.defineProperty, and ships
assertFeatureConformance(container, manifest, symbols, ctx) which walks
the manifest, resolves each use case from the feature's container, and
throws ConformanceError synchronously when a binding is missing a
required brand.

Per-feature self-assertion: each bindProductionX(ctx) calls
assertFeatureConformance at its tail, so the boot check runs once per
feature and is forward-compatible with future apps wiring those binders.

Also bundles the two forward-looking items the milestone-i reviewer
flagged (re-export authManifest from auth root barrel; TODO breadcrumb
in withAudit for future automation).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 22:33:20 +02:00
31906b9e3e plan(conformance): milestone i — defineFeature + brands + auth.signIn proof
13-task implementation plan for the type-level seam of the conformance system.
Ships brand types (Instrumented/Captured/Audited), defineFeature helper,
ProductionUseCase branded slot, withAudit wrapper, authManifest, and rebinds
auth.signIn through the branded slot — with a negative type test asserting
unwrapped factories are rejected at the slot.

Each task is a single red→green TDD cycle with one commit. Companion
docs/work/conformance-system-v1/ epic + story records are created early in
the plan so subsequent agents have full context when picking up later
stories.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 21:18:23 +02:00
ac8dfcc5d4 docs(plan): audit logging & DPA compliance (6 phases, ~30 commits)
Implementation plan for the spec at docs/superpowers/specs/2026-05-11-
audit-and-compliance-design.md. Six phases:

- Phase 1: AuditLogProtocol + AuditEntry type + truncateIp helper in
  core-shared; BindContext.auditLog? (5th generic).
- Phase 2: @repo/core-audit optional package — NoopAuditLog,
  StdoutJsonAuditLog, append-only audit-logs Payload collection,
  PayloadAuditLog (record), MultiSinkAuditLog fan-out, bindAudit
  binder with prod salt validation, RecordingAuditLog in core-testing.
- Phase 3: GDPR erasure plumbing — pseudonymize helper (sha256 +
  AUDIT_PSEUDONYM_SALT), PayloadAuditLog.eraseSubject via
  overrideAccess, createAuditErasureHook Payload afterDelete factory,
  admin tRPC procedure (audit.eraseSubject).
- Phase 4: OTel correlation bridge — currentTraceId() in core-shared,
  TraceIdEnrichingAuditLog decorator wraps inner sinks at bindAudit
  time. Explicit caller correlationId wins.
- Phase 5: createAuditAfterReadHook factory for opt-in per-collection
  VIEW capture; fire-and-forget semantics with stderr fallback.
- Phase 6: ADR-018 + audit-and-compliance.md guide + generator template
  at turbo/generators/templates/core-package/audit/ + byte-identical
  snapshot + e2e test + 6 doc surface refreshes (template-tiers,
  scaffolding-doc, CLAUDE.md, AGENTS.md, data-flow-explainer, README).

Total: ~30 commits expected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:01:11 +02:00
40b5b1a94f docs(spec): audit logging & DPA compliance design
Six-phase design for @repo/core-audit (5th optional package).

Phase 1: AuditLogProtocol + AuditEntry type + truncateIp helper in
  core-shared; BindContext.auditLog? optional field.
Phase 2: @repo/core-audit package with NoopAuditLog + PayloadAuditLog
  (append-only collection) + StdoutJsonAuditLog (structured JSON) +
  MultiSinkAuditLog fan-out wrapper + RecordingAuditLog in core-testing.
Phase 3: GDPR erasure plumbing — eraseSubject impls, pseudonymize helper
  (sha256-with-salt), admin tRPC procedure, createAuditErasureHook
  Payload afterDelete hook factory.
Phase 4: OTel correlation bridge — currentTraceId() helper,
  TraceIdEnrichingAuditLog decorator wraps inner sinks at bind time so
  AuditEntry.correlationId auto-populates from active OTel span.
Phase 5: createAuditAfterReadHook factory for opt-in per-collection
  automatic VIEW capture; reference wiring documented (printed by
  generator as a diff, NOT auto-installed in auth).
Phase 6: ADR-018, audit-and-compliance.md guide, generator template
  + byte-identical snapshot + e2e test, doc refreshes (CLAUDE.md,
  AGENTS.md, template-tiers, data-flow-explainer, README,
  scaffolding-doc).

Compliance grounded in DPA "Logging & Monitoring" requirements:
closed action enum (VIEW/CREATE/UPDATE/DELETE/EXPORT/PERMISSION_CHANGE),
required tenant field, type-enforced "what NOT to log" (no payload/
body/oldValue/newValue fields), IP /24 v4 + /48 v6 truncation, sha256-
salted pseudonymization, append-only Payload collection with privileged
overrideAccess erasure path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:46:33 +02:00
76870816d1 docs(plan): OpenTelemetry migration (5 phases, ~30 tasks, ~25 commits)
Implementation plan for the spec at docs/superpowers/specs/2026-05-11-
opentelemetry-migration-design.md. Five phases:

- Phase 1: OTel SDK infrastructure (resource builder + Sentry-as-exporter
  bridge + NodeSDK init helper + ESLint allowlist for OTel SDK packages).
  No behavior swap yet.
- Phase 2 (TDD): OtelTracer impl using @opentelemetry/api; bind-sentry-
  instrumentation renamed to bind-otel-instrumentation with deprecation
  alias; delete SentryTracer.
- Phase 3 (TDD): OtelLogger impl using @opentelemetry/api-logs;
  LogRecordProcessor wired into init helper; delete SentryLogger.
  Breadcrumbs become span events; setUser sets user.id span attribute.
- Phase 4 (TDD): New IMetrics interface + Noop/Otel/Recording impls;
  MetricsProtocol added to bind-protocols; BindContext.metrics? optional
  field. Sentry metrics exporter deferred (experimental).
- Phase 5 (TDD): HTTP/undici/pg auto-instrumentations; PII scrub
  processors (PiiScrubSpanProcessor + PiiScrubLogRecordProcessor) run
  FIRST in OTel pipeline; delete sentry/scrub.ts + orphaned init files;
  core-testing/setup/no-sentry.ts → no-instrumentation.ts (mocks both
  Sentry and OTel SDK); ADR-017 + ADR-014 status header; doc refreshes.

Total: ~30 tasks across 6 phases (including Phase 0 read-first), ~25
expected commits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:15:33 +02:00
cb0e33b0e8 docs(spec): OpenTelemetry migration design
Five-phase migration of server-side instrumentation from Sentry-direct
SDK calls to OpenTelemetry SDK with @sentry/opentelemetry as the (initial)
exporter. Vendor neutrality: swap vendors = swap exporters, never rewrite
tracer/logger/metrics impls.

Phase 1: OTel SDK infrastructure (no behavior swap).
Phase 2: OtelTracer replaces SentryTracer (uses @opentelemetry/api).
Phase 3: OtelLogger replaces SentryLogger (pure OTel Logs API via
  @opentelemetry/api-logs; breadcrumbs become span events; user.id as
  span attribute).
Phase 4: New IMetrics interface + Noop/Otel/Recording impls; added to
  BindContext as metrics? with corresponding MetricsProtocol in
  core-shared/di/bind-protocols.ts.
Phase 5: HTTP/undici/pg auto-instrumentations; PII scrubbing migrates
  from Sentry beforeSend hooks to OTel SpanProcessor/LogRecordProcessor;
  delete remaining Sentry-direct files; ADR-017 supersedes ADR-014's
  impl section while keeping R31-R51 interface decisions authoritative.

Server-only scope. Browser keeps Sentry SDK directly (replay + native
error UX); future spec extends to browser when OTel-Browser matures.

Companion ADR will be assigned at implementation time (expected ADR-017).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:04:37 +02:00
09ac0bba6c docs(plan): core-ui component generator (5 phases, ~7 commits)
Implementation plan for the spec at docs/superpowers/specs/2026-05-11-core-
ui-component-generator-design.md. Five phases:

- Phase 1: add splice anchors to core-ui tier barrel templates +
  regenerate the byte-identical ui snapshot
- Phase 2: create the 4 Handlebars template files
  (component.tsx + stories + test + index)
- Phase 3 (TDD): register the setGenerator block, implement
  coreUiComponentActions + printCoreUiComponentNextSteps, add unit
  tests for registration shape, action sequence, and PascalCase
  validation
- Phase 4: scaffolding reference doc + CLAUDE.md Quick Start +
  AGENTS.md Key Commands
- Phase 5: manual smoke test (scaffold one component per tier, verify
  file layout + spliced barrels + core-ui gates) + final repo gates

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 08:51:53 +02:00
5878b8f493 docs(spec): core-ui component generator design
2-phase design for `pnpm turbo gen core-ui-component`. Prompts for tier
(atom/molecule/organism) + name (PascalCase) and emits the established
4-file component pattern (component.tsx, component.stories.tsx,
component.test.tsx, index.ts) into the matching `packages/core-ui/src/<tier>s/`
folder. Splices the new export into the tier barrel via `// <gen:<tier>s>`
anchors.

Phase A adds the anchors to the core-ui template's three tier barrels and
regenerates the byte-identical reconstruction snapshot. Phase B ships the
generator, templates, tests, and docs. Refuses to run if core-ui isn't
scaffolded; doesn't touch Storybook config (existing stories glob covers
new component stories).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 08:47:27 +02:00
54958170ab docs(plan): core-package generator + template slimming (8 phases, ~50 tasks)
Implementation plan for the design at docs/superpowers/specs/2026-05-09-core-
package-generator-design.md. Eight phases (numbered Phase 0..7 in the plan; Phase
0 is the read-first orientation, Phases 1-7 implement spec phases 0-5 plus a
final cross-doc sweep).

Phase 1 ships BindContext with bounded generics over protocol types in core-
shared. Phase 2 ships the generator framework (entry, prompt, dispatch table —
empty). Phases 3-6 each capture one optional package as a verbatim template,
ship the generator action, and remove the package from main with byte-identical
reconstruction verified via a snapshot. Phase 7 is the final cross-doc sweep
(template-tiers.md, README updates, HTML explainer pass).

Companion ADR will be assigned at implementation time (expected ADR-017).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 12:15:23 +02:00
26374253de docs(spec): core-package generator + template slimming design
6-phase design for slimming the default template to a minimal kernel
and providing turbo generators that scaffold optional core packages
(realtime, events, trpc, ui) back when needed.

Phase 0 introduces a BindContext object in core-shared with bounded
generics over minimal protocol types; optional packages keep their full
interfaces but extends-link to the protocols. This lets feature binders
take a single ctx arg and lets optional packages disappear without
breaking typechecks. Phases 1-5 ship the generator framework + per-
package templates + per-package removal from main.

Companion ADR will be assigned at implementation time (expected ADR-017).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:57:46 +02:00
82002a0ee8 docs(plan): realtime layer implementation plan (45 tasks, 11 phases) 2026-05-08 20:31:26 +02:00
500d835f0e docs(spec): realtime layer (Socket.IO) design
Long-form design for the bidirectional realtime layer the user
brainstormed on 2026-05-08. Builds on ADR-015 (events and jobs);
hybrid pattern where IRealtimeBroadcaster is layered alongside
IEventBus, with a bridge for forwarding allowlisted bus events to
realtime channels.

v1 ships: @repo/core-realtime package, custom Node server in
apps/web-next, cookie-session auth, four scope kinds, two
generators (gen realtime channel|handler), three new anchors per
feature, RecordingRealtimeBroadcaster test helper, realtime-ping
proof-of-life. Dashboard, DB-backed roles/permissions, multi-instance
fanout, and a generic core-package generator are deferred — captured
in §13 / §14 / §15.

Companion HTML explainer at realtime-auth-explainer.html (project root,
uncommitted) walks the four-checkpoint auth model visually. ADR-016
will be created during implementation.
2026-05-08 19:51:06 +02:00
c531b81544 docs(adr-015): cross-feature events and background jobs
Also folds in the spec correction noted in the plan's known follow-up
\#1: subscribe takes consumerFeature: string as a second arg between
descriptor and handler. § 3.3 and § 5.4 updated.
2026-05-08 17:05:05 +02:00
c2a32363a8 docs(plan): bring production-bus task auto-registration into scope
gen event consume now emits a second file: an __events-<publisher>-
<event>.task.ts Payload task that delegates to the consumer's
container-resolved wrapped handler. The bind block also binds the
wrapped handler into the per-feature container by symbol so the
task can resolve it. With this, PayloadJobsEventBus is fully wired
end-to-end with no manual per-event task hand-write required.
Removes the corresponding Known Follow-up item.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 11:28:25 +02:00
42fb3996d3 docs(plan): events and jobs implementation plan
56 bite-sized tasks across 9 phases implementing the spec at
docs/superpowers/specs/2026-05-08-events-and-jobs-design.md:
core-shared/jobs (IJobQueue + 2 impls), core-events package
(IEventBus + 2 impls), recording test helpers, two ESLint rules,
existing-feature anchor retrofit (5 features × 6 anchors), bindAll
bus/queue swap, three Plop generators with anchor-comment protocol,
end-to-end proof-of-life (sign-up → welcome email), and the full
documentation set (ADR-015 + new guide + AGENTS/CLAUDE/scaffolding
updates). Self-review caught and fixed one type-inconsistency
(3-arg subscribe) and explicitly deferred the production task-
registration gap. TDD-ordered with one commit per task.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 11:20:19 +02:00
cf41d11eff docs(spec): cross-feature events and background jobs design
Long-form design for a future ADR-015. Defines IEventBus (new
@repo/core-events) and IJobQueue (@repo/core-shared/jobs); the bind/swap
rules; the events/, events/handlers/, jobs/, integrations/cms/jobs/
folder layout; the on-<publisher>-<event-kebab>.handler.ts naming rule;
the span+capture sandwich extension with op: "event-handler" and
op: "job"; three new ESLint rules; RecordingEventBus and RecordingJobQueue
for tests; pnpm turbo gen event {publish|consume} and gen job generators
plus the // <gen:*> anchor-comment protocol; and the existing-feature
retrofit. Status: draft pending user review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 10:43:53 +02:00
f0775d6ecc feat(instrumentation): close R44 gap — throw-site capture for use cases + controllers
Plan 10 documented R44 (capture at originating-throw layer) but only the
R43 repo leg was wired. captureException had zero call sites in any
controller or use-case body. This commit closes the gap.

Mechanism:
- Extract __sentryReported flag helpers into core-shared/instrumentation/
  reported-flag.ts. SentryLogger switches to importing them; RecordingLogger
  carries an inlined copy (tooling → core boundary disallows the import).
- Add withCapture(logger, tags, fn) higher-order wrapper paralleling
  withSpan. On throw: capture-with-tags, mark, re-throw. Bail if the flag
  was already set — covers the bubbled-from-repo case so each error
  surfaces in the logger exactly once with the inner-most layer's tags.
- Apply withSpan(withCapture(factory)) in every feature's bind-production
  and bind-dev-seed: auth (3 use cases × 3 controllers), blog (3×3),
  marketing-pages (2×2), navigation (1×1), media (3×3). Span is outermost
  so the errored span timing reflects the capture-and-rethrow.
- RecordingLogger.captureException now also honours the flag — test
  capture counts stay honest when both repo and outer layer wrap.

Tests:
- packages/core-shared/src/instrumentation/with-capture.test.ts —
  4 cases covering success, capture-on-throw, mark-on-capture, no-double
  via the flag.
- packages/blog/tests/r44-no-double-capture.test.ts — 3 cases: repo throw
  → 1 capture with repo tags; controller parse fail → 1 capture with
  controller tags; success → 0 captures.

Verification: pnpm test 26/26, pnpm lint 15/15, pnpm typecheck 14/14.

Docs: ADR-014 and the refactor log gain a "Post-merge follow-up" section
recording the gap, the fix, and the underlying lesson (don't describe
intent as shipped state — grep first).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:28:22 +02:00
60967a630d docs(plan-10): finalize ADR-014 + tick refactor log
Replaces the ADR-014 stub with the full Accepted-status decision record:
context, the 7 numbered decisions (vendor-neutral interfaces, full-depth
instrumentation, throw-site capture, PII rules, three Sentry projects,
ESLint boundary, Recording* test pair), alternatives considered,
positive/negative consequences, and an "execution notes" section
covering the spec deviations and surprises encountered.

Updates the refactor log: ticks all 33 tasks, populates "Decisions
deviated from spec" (PII key list extended with ipaddress; spec
section appended as §16 not §10; vite.config skipped; HTML section
numbering kept conservative) and "Notable surprises" (apps needed
direct core-shared deps; deep subpath exports for dynamic import;
peerDependenciesMeta.optional for @sentry/node and @sentry/react;
pre-existing lint debt; allowlist patterns needed **/-prefix for
flat-config glob matching from sub-package cwd).

Final verification (run before commit):
- pnpm test  → 26/26 tasks pass
- pnpm lint  → 15/15 tasks pass (warnings-only)
- pnpm typecheck → 14/14 tasks pass
- R31 grep gate (sendDefaultPii: true) → clean, no matches

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:41:54 +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
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
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
732fa63f69 docs(refactor-log): tick testing-strategy.md in Plan 9 doc-update checklist
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 16:47:39 +02:00
ef2b8e300e docs(plan-9): doc-pass slice 1 — CLAUDE.md, core-shared AGENTS, architecture, plan-8 annotations
First slice of the combined Plan 8 + Plan 9 doc-update pass:
- CLAUDE.md Key Conventions: append schema-in-use-case, presenter,
  controller unknown input, feature-scoped tRPC error mapping, public
  surface split (./ui)
- packages/core-shared/AGENTS.md: document defineErrorMiddleware export
  + t re-export from trpc/init
- docs/superpowers/plans/2026-05-05-plan-8-*.md and matching spec:
  one-line note that some controller/router patterns shifted in Plan 9;
  link to the Plan 9 refactor log
- docs/architecture/overview.md: data-flow box now shows xProcedure +
  xInputSchema + xOutputSchema.parse + presenter + middleware lanes;
  three explanatory paragraphs added (schemas, presenter, error mapping)
- docs/architecture/dependency-flow.md: app-side ./ui subpath note,
  allowed/disallowed examples updated for Plan 9 paths

Remaining doc-pass items (root AGENTS.md, per-feature AGENTS.md ×5,
core-testing AGENTS.md, adding-a-feature.md, tdd-workflow.md,
testing-strategy.md, vertical-feature-spec.md) follow in subsequent
commits — to be dispatched in parallel.
2026-05-06 16:43:13 +02:00
3dc843ca4b docs(refactor-log): reconcile commit count + test delta inconsistencies
Final reviewer flagged two changelog inaccuracies:
- Summary said 14 commits; actual is 15 (88db39b..HEAD).
- §7 Task 8 said +144 tests; correct delta is +35 (325 → 360, +11%).
  The +144 figure was a typo from the implementer's draft.

Both reconciled. Plan 9 ships.
2026-05-06 16:15:50 +02:00
36548942d4 docs(adr): ADR-013 input/output unification + Plan 9 changelog summary
Records the Plan 9 architectural decision (schemas in use-case file,
runtime output validation, presenter pattern, feature-scoped error
middleware, ./ui subpath split). ADR-012 gets a one-line cross-
reference to the new ADR. Refactor log gets a Summary section with
commit table and conformance checklist.

Plan 9 complete. The deferred doc-update pass (CLAUDE.md / AGENTS.md /
guides) — combined with the still-pending Plan 8 items — is the next
follow-up.

Refactor log: Summary, doc-update checklist
Spec: R29, R30
2026-05-06 16:10:27 +02:00
2df137c70c chore(plan-9): final verification + changelog summary
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>
2026-05-06 16:07:36 +02:00
2b67964213 refactor(media): unify use-case I/O schemas + presenter + feature error map
Per Plan 9 (spec R1-R28):
- Use cases: input + output schemas (getMedia, listMedia); deleteMedia
  has input schema only (void output, R12 — no presenter).
- Controllers: unknown input + identity presenter on getMedia/listMedia;
  Promise<void> on deleteMedia.
- New integrations/api/procedures.ts with mediaProcedure
  ([InputParseError → BAD_REQUEST], [MediaNotFoundError → NOT_FOUND]).
- Router uses mediaProcedure + .input(xInputSchema).
- src/index.ts exports schemas + types; src/ui/index.ts placeholder
  (media has no queries today); package.json adds ./ui subpath.
- R25 + R26 tests added.

Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18–R20, R22–R26

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 15:41:08 +02:00
aff0ce092d docs(refactor-log): record R6 fix-up under §7 2026-05-06 15:33:53 +02:00
27c79e6e1f refactor(navigation): unify use-case I/O schemas + presenter + feature error map
Per Plan 9 (spec R1-R28):
- getHeader use case: input z.object({}).strict() (R5); output =
  headerSchema parsed at runtime.
- getHeader controller: unknown input + identity presenter.
- New integrations/api/procedures.ts with navigationProcedure
  ([InputParseError → BAD_REQUEST], [HeaderNotFoundError → NOT_FOUND]).
- Router uses navigationProcedure + .input(getHeaderInputSchema).
- src/index.ts: remove headerQuery; export schemas + IUseCase/Controller
  aliases.
- src/ui/index.ts (NEW); package.json adds ./ui subpath.
- R25 + R26 tests added.

Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18–R20, R22–R26
2026-05-06 15:23:30 +02:00
f4adf315af refactor(marketing-pages): unify use-case I/O schemas + presenter + feature error map
Per Plan 9 (spec R1-R28):
- Use cases: input + output schemas (getPageBySlug, getSiteSettings).
  Site-settings input is z.object({}).strict() per R5 (uniform input).
- Controllers: unknown input + identity presenter; void output not
  applicable (both use cases return data).
- New integrations/api/procedures.ts with marketingPagesProcedure
  ([InputParseError → BAD_REQUEST], [PageNotFoundError → NOT_FOUND]).
- Router uses marketingPagesProcedure + .input(xInputSchema).
- src/index.ts: remove pageBySlugQuery/siteSettingsQuery; export
  schemas + types + IUseCase/IController aliases.
- src/ui/index.ts (NEW); package.json adds ./ui subpath.
- R25 output-validation tests + R26 router error-mapping test.

Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18–R20, R22–R26
2026-05-06 15:15:02 +02:00
86070b236a refactor(blog): unify use-case I/O schemas + presenter + feature error map
Per Plan 9 (spec R1-R28):
- Use cases: input + output schemas (getArticles, createArticle,
  getArticleBySlug). Output validated via outputSchema.parse before
  return. status field uses articleStatusSchema (was loose `string`).
- Controllers: receive `unknown`; safeParse with use-case schema;
  identity presenter (R11) on every controller.
- New integrations/api/procedures.ts with blogProcedure
  ([InputParseError → BAD_REQUEST], [ArticleNotFoundError → NOT_FOUND]).
- Router uses blogProcedure + .input(xInputSchema) for all 3 procedures.
- src/index.ts: remove articleBySlugQuery/listArticlesQuery re-exports;
  export schemas + types + IUseCase/IController aliases.
- src/ui/index.ts (NEW): query builders moved here; package.json adds
  ./ui subpath.
- New tests: R25 output-validation per use case; R26 router error-
  mapping (NOT_FOUND on missing slug, BAD_REQUEST on schema fail).

Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18–R20, R22–R26

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 15:04:53 +02:00
5b61674fe9 docs(refactor-log): populate §6.3 with auth presenter-shape test note
Spec reviewer noted §6.3 was missed during Task 3 commit. The presenter
tests exist in code (sign-in / sign-up controller tests assert cookie
shape, not full use-case output); the changelog just didn't record it.
Pure docs change.
2026-05-06 13:01:39 +02:00
2bbec70a4e refactor(auth): unify use-case I/O schemas + presenter + feature error map
Per Plan 9 (spec R1-R28):
- Use cases: input + output schemas (signIn, signUp); input-only for
  signOut (void output). Use case body validates output via
  outputSchema.parse before returning.
- Controllers: receive `unknown`; safeParse with the use-case schema;
  presenter (returning cookie) for signIn/signUp; void return for
  signOut.
- New integrations/api/procedures.ts with authProcedure built via
  defineErrorMiddleware([[InputParseError,"BAD_REQUEST"],
  [AuthenticationError,"UNAUTHORIZED"], [UnauthenticatedError,
  "UNAUTHORIZED"], [UnauthorizedError,"FORBIDDEN"]]).
- Router uses authProcedure + .input(xInputSchema) for every procedure.
- src/index.ts exports schemas + types + IUseCase/IController aliases.
- package.json gains ./ui subpath; src/ui/index.ts placeholder
  (auth has no query builders today).
- New tests: R25 output-validation per use case (signIn, signUp);
  R26 router error-mapping (UNAUTHORIZED on missing user,
  BAD_REQUEST on schema fail).

Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18, R19, R22–R26
2026-05-06 12:58:10 +02:00
e25b1f7a1c feat(core-shared): add defineErrorMiddleware factory + export t
Factory takes [[ErrorCtor, TRPC_CODE], ...] tuples and returns a tRPC
middleware that translates matching domain errors to TRPCError. Discrim-
inates by instanceof; preserves original error as cause; unmapped
errors propagate (tRPC then wraps them as INTERNAL_SERVER_ERROR with
the original error as .cause — middleware does not interfere).

core-shared never enumerates feature errors — each feature passes its
own constructors in via integrations/api/procedures.ts (Tasks 3-7).

Also exports the `t` instance from trpc/init.ts so feature procedure
files can do t.procedure.use(...).

Also fixes tsconfig.json: rootDir set to "." and @/* path alias added
so test files using @/ resolve correctly under tsc --noEmit.

Refactor log: §1, §2, §4
Spec: R13–R17
2026-05-06 11:43:45 +02:00
61baaae99a docs(refactor-log): scaffold Plan 9 input/output unification changelog
Empty section template plus the doc-update checklist that the
post-Plan-9 follow-up pass will work through (combined with the still-
pending Plan 8 items so docs are written once).

Spec: docs/superpowers/specs/2026-05-06-input-output-unification-design.md §10, R30.
2026-05-06 11:00:47 +02:00
88db39b3a3 docs(plan): Plan 9 — input/output unification implementation plan
9 tasks, TDD throughout, one commit per task:

1. Refactor changelog scaffold
2. core-shared/trpc/define-error-middleware.ts factory + tests
3. auth migration (3 use cases — schemas + presenter + procedures.ts + router + ./ui + tests)
4. blog migration (3 use cases)
5. marketing-pages migration (2 use cases)
6. navigation migration (1 use case)
7. media migration (3 use cases)
8. Final verification + boundary sweep
9. ADR-013 + final changelog summary

Every step has concrete code; no placeholders. Self-review shows full
spec coverage (R1–R30) with each rule mapped to one or more tasks.

Spec: docs/superpowers/specs/2026-05-06-input-output-unification-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:29:28 +02:00
4b6b61ab4c docs(spec): Plan 9 — input/output unification + presenter pattern + feature-scoped error mapping + public-surface cleanup
Codifies a single source of truth for use-case input/output contracts:

- Every use case exports xInputSchema/XInput and xOutputSchema/XOutput
  from its own file; controllers and tRPC procedures import the same
  schema. Use case body runtime-validates output via .parse before
  returning.
- Controllers gain a co-located top-level `function presenter`
  (Lazar-style) that reshapes entity output to view DTO; controller
  return type = ReturnType<typeof presenter>.
- Domain error → TRPCError mapping moves to per-feature
  integrations/api/procedures.ts via a defineErrorMiddleware factory
  in core-shared/trpc/. core-shared never enumerates feature errors.
- Per-feature public-API surface cleaned: feature root = contracts
  only (types, errors, schemas, IUseCase aliases, router type); new
  ./ui subpath holds query builders / components.

30 numbered rules using RFC-2119 MUST/SHOULD language so every
enforceable decision is citable from CLAUDE.md and per-feature AGENTS.md
during the post-Plan-9 doc-update pass. Includes file-shape templates,
migration order (~9 commits), doc-update mapping per rule, and an
ADR-013 mandate.

Spec: docs/superpowers/specs/2026-05-06-input-output-unification-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:17:50 +02:00
bffc6a96b3 docs(plan-8): partial Lazar doc-update pass (CLAUDE.md, overview.md, ADR-012, Plan 7 annotations)
First slice of the Plan 8 deferred doc-update checklist:
- CLAUDE.md Key Conventions: factory-function use cases/controllers,
  entities/models/<x>.ts paths, .toDynamicValue DI bindings, direct
  injection in tests
- docs/architecture/overview.md data-flow box updated to factory style
  (controller resolved via container.get<IXController>; use case factory
  takes deps as args)
- docs/decisions/adr-012-lazar-conformance.md created — records the
  conformance decision and four intentional divergences
- docs/superpowers/plans/2026-05-05-plan-7-tdd-foundation.md and the
  matching spec annotated with a "pre-Plan-8 layout" note pointing at
  the refactor log

Remaining Plan 8 doc-update items (root AGENTS.md, per-feature AGENTS.md,
adding-a-feature.md, tdd-workflow.md, testing-strategy.md,
vertical-feature-spec.md §6/§10, core-testing AGENTS.md) intentionally
paused — Plan 9 (input/output unification) will change overlapping
content, so resuming after Plan 9 lands avoids double-churn.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:17:35 +02:00
ee070c39b0 chore(refactor-log): complete Plan 8 changelog summary + Task 10 verification
All conformance checks pass per spec §12 acceptance criteria. Summary
section populated with 9 task commits, file count breakdown, and
verification results. Doc-update checklist (deferred) remains untouched
— ready for follow-up doc pass.

Test count: 244 → 325 (+81). All features now structurally conformant
with Lazar Nikolov Clean Architecture pattern (with intentional
divergences documented in spec §4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 00:30:43 +02:00
8a36d803b3 feat(media): full Clean Architecture scaffold
Media is now a complete vertical-feature package mirroring auth/blog
structure: entities (models + errors), application (repositories +
use-cases), infrastructure (real Payload-backed + mock siblings),
interface-adapters (per-use-case controllers), DI (symbols + module +
container + bind-production), integrations/api (mediaRouter), factory,
contract suite, and feature integration tests.

Wired into:
- packages/core-api/src/root.ts (added `media: mediaRouter`)
- apps/web-next/src/server/bind-production.ts (calls bindProductionMedia)
- tsconfig.base.json (added @repo/media/api and ./di/bind-production aliases)

56 new tests in @repo/media (13 test files); core-api router test updated
to assert media. procedures. All 26 turbo tasks green.

Refactor log: §2, §4.1, §4.2, §5.1, §6.1
Spec: §6.5

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 00:29:05 +02:00
69623b995d refactor(navigation): factory-style use case + controller
- Use case (get-header) → factory function with IGetHeaderUseCase alias
- Controller renamed header.controller.ts → get-header.controller.ts (verb-noun); converted to factory function with IGetHeaderController alias
- DI module wires factories with .toDynamicValue()
- tRPC router resolves controller via container
- Use case + controller tests refactored to direct factory injection (no container rebinding)
- container.test.ts verifies IGetHeaderUseCase + IGetHeaderController symbols

Refactor log: §1, §4.1, §4.2, §5.1
Spec: §6.4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 00:19:15 +02:00
353a41b244 refactor(marketing-pages): factory-style use cases + per-use-case controllers
- Use cases (get-page-by-slug, get-site-settings) → factory functions with I*UseCase aliases
- Controllers split: pages.controller.ts → 2 single-responsibility files
- DI module wires factories with .toDynamicValue()
- tRPC router resolves controllers via container

Refactor log: §2, §3, §4.1, §4.2, §5.1
Spec: §6.3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 00:14:27 +02:00
700d311052 refactor(blog): factory-style use cases + per-use-case controllers + getArticleBySlug
- Use cases (create-article, get-articles, get-article-by-slug NEW) → factory functions
- Controllers split: articles.controller.ts → 3 single-responsibility files
- DI module wires factories with .toDynamicValue()
- tRPC router resolves controllers via container

Refactor log: §2, §3, §4.1, §4.2, §5.1
Spec: §6.2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 00:08:15 +02:00