AST-aware ESLint rule that catches auditLog.record({ type: "X" }) calls
in use-case files where X is not declared in the matching
manifest.useCases[name].audits array.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AST-aware ESLint rule that catches bus.publish("X") calls in use-case
files where X is not declared in the matching manifest.useCases[name].publishes array.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>