Commit Graph

590 Commits

Author SHA1 Message Date
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
64297a233b Merge branch 'worktree-conformance-milestone-ii': conformance milestone ii — assertFeatureConformance + boot wiring 2026-05-12 23:01:27 +02:00
83f135b5e1 fix(conformance): withCapture propagates inner brands + chain test + docstring fixes 2026-05-12 23:00:50 +02:00
046bd0829e docs(work): close story 02 — assertFeatureConformance + boot wiring 2026-05-12 22:54:45 +02:00
3a6115924b feat(auth): bindProductionAuth self-asserts conformance at tail
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 22:53:06 +02:00
5e32074c2e feat(core-shared/conformance): assertFeatureConformance helper
Adds boot-time check that every manifest-declared use case is bound
through withSpan (__instrumented) + withCapture (__captured), with
withAudit (__audited) enforced when audits[] is non-empty. Propagates
inner brands through withSpan so the outermost container-resolved
binding carries all brand markers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 22:49:18 +02:00
bbd9c1e856 feat(core-shared/conformance): re-export ConformanceError 2026-05-12 22:43:57 +02:00
49bd7e0782 feat(core-shared/conformance): ConformanceError class 2026-05-12 22:43:15 +02:00
1d8b30045a feat(core-audit): withAudit wraps and attaches runtime __audited marker 2026-05-12 22:42:16 +02:00
77fddcde78 feat(core-shared/instrumentation): withCapture attaches runtime __captured marker 2026-05-12 22:40:44 +02:00
9e21baf5fb feat(core-shared/instrumentation): withSpan attaches runtime __instrumented marker 2026-05-12 22:39:13 +02:00
a593962b3d feat(core-shared/conformance): runtime brand markers + isX predicates 2026-05-12 22:37:43 +02:00
198765ff06 docs(work): story 02 — assertFeatureConformance + boot wiring 2026-05-12 22:36:18 +02:00
925f4e4e5b docs(core-audit): TODO breadcrumb for future audit recording automation 2026-05-12 22:35:23 +02:00
8054c125d9 feat(auth): re-export authManifest + AuthManifest from package root 2026-05-12 22:34:38 +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
50313c794f Merge branch 'worktree-conformance-milestone-i': conformance milestone i — defineFeature + brands + auth.signIn proof 2026-05-12 22:23:40 +02:00
0aa5f0633d docs(work): close story 01 — defineFeature + brands + auth.signIn proof 2026-05-12 21:53:17 +02:00
bf3abea776 fix(core-audit): rename unused withAudit test param to _input 2026-05-12 21:52:06 +02:00
17bf9fd0c1 test(auth): assert unwrapped factory rejected at branded slot 2026-05-12 21:49:57 +02:00
db646c22e4 feat(auth): bind signIn through ProductionUseCase<I, O, M> branded slot
Adds explicit ProductionUseCase<SignInInput, SignInOutput, AuthManifest["useCases"]["signIn"]>
type annotation to wrappedSignIn in bind-production.ts. To satisfy the Instrumented & Captured
intersection requirement, withSpan gains a brand-preserving overload so composing
withSpan ∘ withCapture returns Instrumented<F> & Captured<F>.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-12 21:46:33 +02:00
5141314a9d feat(auth): declare authManifest with signIn/signUp/signOut 2026-05-12 21:42:55 +02:00
103e06d20a feat(core-audit): withAudit wrapper + Audited<F> brand 2026-05-12 21:41:40 +02:00
c7bd9a2f8a feat(core-shared/conformance): barrel + ./conformance subpath export 2026-05-12 21:37:18 +02:00
82cfde9c93 feat(core-shared/conformance): ProductionUseCase<I, O, M> branded slot type 2026-05-12 21:35:59 +02:00
b3784ce255 feat(core-shared/conformance): defineFeature helper + manifest types 2026-05-12 21:34:19 +02:00
a1fbd16d83 feat(core-shared/instrumentation): withCapture returns Captured<F> 2026-05-12 21:32:42 +02:00
5ac668497f feat(core-shared/instrumentation): withSpan returns Instrumented<F> 2026-05-12 21:29:43 +02:00
5f5db546ae feat(core-shared/conformance): Instrumented<F> and Captured<F> brand types 2026-05-12 21:27:05 +02:00
4976352354 docs(work): story 01 — defineFeature helper + brands 2026-05-12 21:25:28 +02:00
b2dfd91367 docs(work): scaffold docs/work and conformance-system-v1 epic 2026-05-12 21:24:03 +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
9576987637 docs(architecture): agent-first workflow design + work-shape guides
Captures the design from the brainstorm session on agent-first development
in this template. Architecture doc covers the four interlocking pillars:

- Conformance engine (manifest + brands + ESLint + boot + CI gate)
- Agent workflow (PRD -> Epic -> Story -> Task; manifest-first ordering;
  TDD per slice; in/out scope at every level)
- Local task system at docs/work/ (filesystem markdown, derived committed
  _state.json, single-writer orchestrator rule)
- Sandcastle orchestrator (implementer + reviewer loop, DAG-respecting,
  configurable retry cap)

Work-shape guides extend the architecture doc with operational detail for
frontend work (atomic design, Storybook-as-spec, component + Playwright
screenshot test gates, Storybook MCP reviewer integration) and
infrastructure work (ADR-first flow, dedicated ADR elicitation skill,
optional core packages vs. new infrastructure layers).

Phasing is conformance-first: build the enforcement system manually, then
build the dispatch substrate, then migrate remaining features through it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 21:08:44 +02:00
63d54dcddc docs(architecture): feature-conformance interactive explainer + extensions
Adds the interactive HTML explainer for the feature-conformance enforcement
design, covering the four layers (TS brands, ESLint, boot assertion, CI gate),
manifest playground, mistake catalog, layer composition, build-order milestones,
anchor points in the repo, and an "extensions" section on sharper AST checks
and code-conventions enforcement.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 21:08:34 +02:00
c5c1b1b845 docs(architecture): fix ADR slug refs in audit explainer footer
The agent that produced the explainer guessed three ADR filenames
(adr-014-instrumentation-interfaces.md, adr-017-otel-migration.md,
adr-015-events-jobs.md). The actual files use different slugs.
2026-05-11 17:16:24 +02:00
b76483c4f2 docs(architecture): audit-and-compliance HTML explainer + sibling crosslinks 2026-05-11 17:15:12 +02:00
7c915cb447 docs(architecture): surface core-audit + DPA across architecture docs
Touches the deeper architecture surfaces the Phase 6 sweep skipped:

- overview.md: split must-have (core-shared, core-cms, core-api) from
  optional (core-trpc, core-ui, core-realtime, core-events, core-audit);
  add core-audit to the Five tags optional list
- dependency-flow.md: extend the bindAll diagram with resolveAudit;
  add auditLog row to the BindContext table; rename the
  TRACER/LOGGER/METRICS heading to include AUDIT (ADR-018); note the
  R52-style boundary rule for @repo/core-audit (consume via protocol)
- vertical-feature-spec.md: target-state section now states 3 must-have
  + 5 optional cores; tag matrix includes the optional cores; bind-
  production signature destructure includes auditLog
- di-explainer.html: §08 instrumentation gains an IAuditLog block + the
  Wiring path tree shows resolveAudit + auditLog in ctx
- testing-strategy.md: RecordingAuditLog reference + reset() guidance
2026-05-11 17:06:58 +02:00
451a3cdbc3 chore(lockfile): resolve core-audit OTel devDeps after merge
pnpm install on the merged tree pulled in @opentelemetry/api,
api-logs, context-async-hooks, and sdk-trace-base under
packages/core-audit's devDependencies. The merge commit didn't fully
include the resolved lockfile entries; this commit aligns them so CI
installs cleanly.
2026-05-11 16:54:08 +02:00
56dcf48ff2 Merge branch 'worktree-audit-and-compliance': audit logging & DPA compliance (ADR-018)
Adds @repo/core-audit as the 5th optional core package (gen core-package audit), providing DPA-compliant audit logging:

- AuditEntry shape (closed enum, no payload/body), IP truncation, salted pseudonymization
- Two integration patterns: use-case calls + Payload hooks
- Sinks: NoopAuditLog, StdoutJsonAuditLog, PayloadAuditLog (append-only), MultiSinkAuditLog (settle-all + stderr fallback)
- TraceIdEnrichingAuditLog decorator bridges to OTel correlationId
- Privileged eraseSubject for GDPR via overrideAccess
- RecordingAuditLog test double in core-testing
- Generator template captured + byte-identical e2e reconstruction
- ADR-018, docs/guides/audit-and-compliance.md, 6 doc surfaces updated

28 commits, base ac8dfcca1b54ad.
2026-05-11 16:53:12 +02:00
a1b54ad833 docs: surface core-audit as 5th optional package across discovery points 2026-05-11 16:41:20 +02:00
0b68d23d58 feat(generators): wire audit entry + e2e byte-identical reconstruction test 2026-05-11 16:40:18 +02:00
3fe95694c5 feat(generators): capture core-audit as verbatim template files 2026-05-11 16:39:00 +02:00
ecb8dd65f4 docs(guide): audit-and-compliance how-to guide 2026-05-11 16:38:23 +02:00
2b0c54c013 docs(adr): ADR-018 audit logging & DPA compliance 2026-05-11 16:36:34 +02:00
c06f47b81e feat(core-audit): createAuditAfterReadHook factory for opt-in VIEW capture
Adds the afterRead hook factory for per-collection opt-in automatic VIEW
audit entry emission. Fire-and-forget design ensures failing sinks never
propagate to the user-facing read. Includes sentinel IP/UA fallbacks,
truncateIp /24 integration, shouldSkip predicate, and system actor
resolution. All 6 TDD test cases pass; both barrels updated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 16:33:59 +02:00
55993a2c93 feat(core-audit): wrap bound auditLog with TraceIdEnrichingAuditLog
bindAudit now wraps the inner sink/fan-out with TraceIdEnrichingAuditLog so
all sinks receive AuditEntry.correlationId auto-populated from the active
OTel span. bind-audit.test.ts assertions updated to check instanceof
TraceIdEnrichingAuditLog first, then .inner for the concrete sink type.
TraceIdEnrichingAuditLog exported from the package barrel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 16:31:19 +02:00
07548c4620 feat(core-audit): TraceIdEnrichingAuditLog decorator for OTel correlation
Decorator implementing IAuditLog that auto-populates AuditEntry.correlationId
from the active OTel span via currentTraceId(). Caller-supplied correlationId
always wins (explicit > implicit). eraseSubject passes through unmodified.
Adds @opentelemetry/{api,sdk-trace-base,context-async-hooks} as devDeps for
test infrastructure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 16:29:15 +02:00
098fcd0d51 feat(core-shared): currentTraceId helper for OTel-audit correlation bridge
Reads the active OTel span context via trace.getActiveSpan(); returns the
32-char hex traceId or undefined when no span is active or traceId is the
all-zeros invalid value. Re-exported from both instrumentation/otel/index
and instrumentation/index barrels.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 16:27:36 +02:00
131efd5d2f feat(core-audit): admin tRPC procedure for eraseSubject
Adds auditProcedure (adminOnly middleware + defineErrorMiddleware([])) in
core-audit/src/integrations/api/procedures.ts. Adds createAuditRouter that
captures an IAuditLog and exposes a single eraseSubject mutation with zod
input validation. Non-admins receive FORBIDDEN. Barrel re-exports
pseudonymize, createAuditErasureHook, createAuditRouter, auditRouter,
AuditRouter, auditProcedure, AdminTrpcUser. Adds AUDIT_PSEUDONYM_SALT to
turbo.json globalEnv to clear lint warnings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 16:25:09 +02:00
270897c550 feat(core-audit): createAuditErasureHook Payload afterDelete factory
Adds createAuditErasureHook in core-audit/src/hooks/. The factory returns
a CollectionAfterDeleteHook that calls auditLog.eraseSubject() when a
document is deleted. Defaults to "pseudonymize" mode; coerces numeric ids
to string; skips undefined/null/object ids. Barrel at hooks/index.ts.
6 unit tests cover all guard branches.

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