Commit Graph

131 Commits

Author SHA1 Message Date
b66759a1ab fix(auth): derive clientIp server-side, drop it from sign-in input
clientIp was part of the public signInInputSchema, so any client could
spoof its own rate-limit bucket or dodge IP throttling entirely (audit
finding B2). The schema no longer carries it (strict parsing rejects it
with BAD_REQUEST); instead the web-next tRPC fetch adapter derives it in
createTrpcContext from x-forwarded-for (first hop) / x-real-ip — trust
caveat documented — and the router threads ctx.clientIp to the
controller as a second, server-only argument typed outside the input
schema (SignInRequestContext).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:28:56 +02:00
00fcc9d9a1 fix(core-shared): set CSP on forwarded request headers for nonce
Next.js only injects the nonce into its own scripts when it can read it
from the request's Content-Security-Policy header. Setting the CSP only
on the response left hydration scripts un-nonced in production (A9).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:24:01 +02:00
5f38a3efce build: bump vitest past GHSA-5xrq-8626-4rwp; coverage-v8 everywhere
pnpm audit --prod --audit-level=critical (the new CI gate) failed on
vitest <3.2.6 (critical, arbitrary file read/execute via the UI
server). Bump vitest + @vitest/coverage-v8 in-range across the
workspace and add @vitest/coverage-v8 to every package that runs
vitest but lacked it (core-audit, core-cms, core-eslint, core-testing,
core-trpc, apps/cms, web-next, web-tanstack, turbo/generators) so
'pnpm test -- --coverage' works in every package. No compound test
scripts exist, so the vitest-last pass-through concern does not apply.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 16:44:48 +02:00
16310c5d62 test(core-shared): assert PII scrub runs before Sentry processors
The previous init-server-node tests only checked that an SDK handle
came back — the ADR-017 §7 invariant (PiiScrubSpanProcessor /
PiiScrubLogRecordProcessor registered BEFORE any exporter-facing
processor) was untested. Capture the NodeSDK constructor config via a
local vi.mock override and assert processor ordering for both the
empty-DSN and DSN-set paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 16:32:47 +02:00
9b04fae975 fix(core-shared): derive Analyzed + RateLimited brands in binding slot
ProductionUseCase<I, O, M> only demanded Instrumented + Captured (+
Audited for mutating-with-audits). The boot assertion additionally
requires __analyzed for non-empty analyticsEvents and __rateLimited for
non-empty rateLimit, so the type-level gate under-promised what boot
enforces. The slot now derives both from the manifest entry; the
feature-scoped requiresConsent brand stays boot-only (documented).
Also make IAnalytics extend AnalyticsProtocol from
core-shared/di/bind-protocols so narrowing the ctx protocol fails
typecheck in core-analytics instead of drifting silently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 16:25:09 +02:00
danijel-lf
5b74939a51 feat(conformance): implement ReadOnly brand and reader generator
- Add ReadOnly<F> phantom brand to core-shared/conformance (compile-time
  enforcement that readers only wrap non-mutating use cases)
- Add isReadOnly runtime predicate for boot-time assertReaderPurity
- Scaffold pnpm turbo gen reader: creates integrations/readers/ with
  interface, implementation, test, barrel, and adds ./reader export
  subpath to package.json
2026-05-28 22:01:51 +02:00
danijel-lf
b97e6105d3 feat(conformance): wire cross-feature reader pattern into docs and schema
Add reads field to UseCaseManifest, update CLAUDE.md with Q0-Q3 rules,
add ./reader subpath to AGENTS.md exports table, and cascade reader
conventions through conformance quickref, adding-a-feature guide, and
scaffolding guide. Moves gen reader from deferred to planned.
2026-05-28 20:55:34 +02:00
a540f3afb1 feat(web-tanstack): wire security headers middleware and nonce threading
Register core-shared/security/tanstack server middleware in app.config.ts
as a Nitro/H3 hook that emits the six security headers and forwards the
per-request nonce. Update instrumentation-client to read the nonce from
<meta name="csp-nonce"> and pass it to initSentryClientReact.

Add nonce support to initSentryClientReact (feedbackIntegration receives
styleNonce/scriptNonce), mirroring the initSentryClient pattern already
in place for web-next.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 10:33:09 +00:00
b681e906ea feat(web-next): wire security headers middleware and nonce threading
- Add apps/web-next/middleware.ts calling withSecurityHeaders() from
  core-shared/security/next; exports matcher config excluding static assets
- Update layout.tsx to call getNonce() and render <meta name="csp-nonce">
  so client-side JS can read the per-request nonce
- Update instrumentation-client.ts to read nonce from csp-nonce meta tag
  and pass it to initSentryClient for feedbackIntegration CSP compliance
- Add nonce option to initSentryClient (InitClientOpts.nonce) and thread
  styleNonce + scriptNonce into feedbackIntegration when provided
- Add middleware test asserting all six headers, prod/dev CSP shape, and
  x-nonce presence; add feedbackIntegration nonce tests to core-shared

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 10:10:12 +00:00
a48af7e91c feat(core-shared): add TanStack Start security header adapter
Exports withSecurityHeaders() and getNonce() from the
./security/tanstack subpath. withSecurityHeaders() returns all six
security headers plus x-nonce for use inside a TanStack/Nitro H3
server middleware; getNonce() reads x-nonce from the node request
headers forwarded by that middleware.

Mirrors the ./security/next adapter pattern while staying free of
any @tanstack/start dependency — the adapter works with plain H3
IncomingMessage types that TanStack Start exposes at wiring time
(Story 09).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 09:56:03 +00:00
a736ed621d feat(core-shared): add Next.js security header middleware adapter
Implements security/next subpath with withSecurityHeaders() middleware
and getNonce() Server Component helper. Middleware generates a per-request
nonce, calls buildSecurityHeaders, sets all six headers + x-nonce on the
response, and forwards the nonce via request headers for Server Component
access. Adds next as optional peer + dev dependency.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 09:46:07 +00:00
96274ba856 feat(core-shared): add security headers module with CSP builder and nonce util
Adds framework-agnostic security headers module to core-shared/security:
- SecurityHeadersConfig + CspMode types
- generateNonce() using crypto.randomBytes(16)
- buildSecurityHeaders() emitting all six headers (HSTS, X-Frame-Options,
  X-Content-Type-Options, Referrer-Policy, Permissions-Policy, CSP) with
  prod (strict-dynamic + nonce threading) and dev (unsafe-inline/eval +
  ws/localhost) CSP modes; URL validation throwing InvalidSecurityHeadersConfig
  on malformed allowedConnect/Img/FontOrigins
- Full unit test suite (24 tests, 100% coverage on runtime files)
- Exported from core-shared barrel and ./security subpath

Blocks story 07 (framework adapters) and stories 08-09 (app wiring).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 09:33:13 +00:00
cb61f51ee1 feat(core-shared): add withRateLimit wrapper and conformance enforcement
- Add withRateLimit(rateLimit, fn) in rate-limit/with-rate-limit.ts,
  attaching the RateLimited brand at DI bind time
- Extend wireUseCase to accept optional rateLimit?: IRateLimit and
  compose withRateLimit innermost (before analytics/audit); propagate
  __rateLimited through analytics + audit inline wrappers
- Extend withSpan and withCapture PROPAGATED_BRANDS to include
  __rateLimited so the outermost binding carries the brand
- Extend assertFeatureConformance to require __rateLimited brand when
  manifest.useCases[name].rateLimit.length > 0; refactored into
  helper functions to stay within complexity thresholds
- Add rateLimit?: IRateLimit to BindContext; default to NoopRateLimit
  in web-next bindAllProduction and bindAllDevSeed aggregators
- Unit tests for withRateLimit brand attachment, factory passthrough,
  and composition; synthetic fixture tests for conformance errors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 09:00:31 +00:00
5ddc8e6484 feat(core-shared): add NoopRateLimit and InMemoryRateLimit implementations
NoopRateLimit always allows with Infinity remaining — zero-overhead default
for apps without a wired rate-limit impl. InMemoryRateLimit uses a Map-backed
fixed-window with check-at-read expiry and an injected clock for testability.
Both exported from the core-shared barrel.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 08:30:35 +00:00
c62de6fce9 feat(core-shared): add rate-limit type primitives and manifest field
Adds IRateLimit, RateLimitBudget, RateLimitDecision to a new
rate-limit sub-module; adds RateLimited<F> brand and isRateLimited
predicate following the Captured/ConsentChecked pattern; extends
UseCaseManifest with rateLimit?: readonly RateLimitBudget[] so
features can declare rate-limit gates in their manifests.

Exports new types from @repo/core-shared/rate-limit and
@repo/core-shared/conformance. Blocks stories 02, 03, and 04.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 08:21:42 +00:00
6b66064386 feat(auth): migrate anonymous consent on signUp when cc_consent cookie present
Adds ConsentFactoryProtocol / ConsentGrantMeta / ConsentProtocol to
core-shared/di/bind-protocols so feature binders can wire per-user
consent without a hard dep on the optional @repo/core-consent package.
BindContext gains an optional consentFactory? field following the same
pattern as bus?, auditLog?, etc.

signUpUseCase gains a 4th optional dep (consentFactory). When present
and the input includes a cookieHeader containing cc_consent=<categories>,
the use case calls consent.grant for each category with
method:"signup-migration" and returns a clearCookie payload (Max-Age:0)
so the anonymous cookie is cleared on the HTTP response.

Tests use RecordingConsent from @repo/core-testing to assert migration
call shape and cookie-clear; no-cookie and no-factory branches are also
covered. All coverage bands hold at 100% for use-cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 21:52:08 +00:00
b992fee088 feat(core-consent): extend generator with consent template + fix withCapture brand propagation
- Add consent to CORE_PACKAGE_GENERATORS in turbo/generators/config.ts so
  pnpm turbo gen core-package consent is a valid command (not hand-rollable)
- Create turbo/generators/templates/core-package/consent/ mirroring the
  analytics template shape (AGENTS.md, package.json, tsconfig, turbo, vitest,
  eslint, src/index.ts scaffolds)
- Regenerate packages/core-consent/ from the new template (replaces the
  previous hand-rolled attempt that violated the generator-first rule)
- Add __consentChecked to withCapture PROPAGATED_BRANDS so the brand bubbles
  through the full withSpan→withCapture wrapper chain to the outermost binding
  that assertFeatureConformance reads

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 11:01:17 +00:00
9cb2fa321c feat(core-consent): scaffold package with types, IConsent, withConsent brand wrapper
- Add packages/core-consent with ConsentCategory, ConsentState,
  UserConsentState types and IConsent interface
- Add withConsent wrapper attaching __consentChecked brand at bind time;
  unit tests assert brand attachment and factory passthrough
- Add ConsentChecked<F> type to core-shared/conformance/brands.ts and
  isConsentChecked helper to brand-runtime.ts
- Extend FeatureManifest with requiresConsent?: readonly string[] field
- Extend assertFeatureConformance to require __consentChecked brand when
  requiresConsent.length > 0; synthetic fixture tests cover pass/fail cases
- Propagate __consentChecked in withSpan PROPAGATED_BRANDS so the outermost
  binding carries the brand

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 10:40:40 +00:00
dd339b11b1 feat(core-shared): extend audit action enum with consent and restriction types
Adds CONSENT_GRANT, CONSENT_WITHDRAW, RESTRICT, UNRESTRICT to the
AuditAction closed enum per GDPR Art. 7 and Art. 18 requirements.

core-consent and core-dsr optional cores (Epic B Stories 03/06) emit
these action types via core-audit's IAuditLog channel; the values must
exist in core-shared's enum before either optional core can be built.
No change to IAuditLog's interface surface — new values flow through
AuditEntry.action automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 10:16:30 +00:00
f8bb2f4094 feat(core-shared): add subject-linkage types and extend PII defaults
Introduces SubjectLinkKind, SubjectLink, and CollectionSubject types to
packages/core-shared/src/payload/subject-linkage-types.ts, establishes the
ambient CollectionCustom.subject declaration (parallel to custom.pii / custom.retention
from Epic A), and extends PAYLOAD_AUTH_PII_DEFAULTS with processingRestrictedAt and
consentState as DSR-managed excluded fields. Applies the first canonical usage of
custom.subject = { kind: "self", field: "id" } on the auth users collection.
2026-05-19 10:11:09 +00:00
7ea38bc5b9 feat(core-shared): add retention-purge background job
Adds retention-purge.job.ts to packages/core-shared/src/payload/retention-purge/.
Walks every Payload collection's custom.retention.purgeSchedule, registers one
scheduled job per collection via IJobQueue, queries rows past their activeRetention
period (by createdAt for from-creation, updatedAt for from-last-access), and applies
pseudonymize (null PII fields) or hard-delete per postDeletion.action. Emits one
IAuditLog.record entry per processed row; gracefully skips when auditLog is absent.

Unit tests cover: schedule registration, trigger-type routing, hard-delete branch,
pseudonymize branch, audit emission, graceful auditLog skip, no-activeRetention
short-circuit, and input validation error cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:56:14 +00:00
0d4be0a4f4 fix(coverage): exempt .d.ts files from diff coverage gate
Ambient declaration files have no runtime code so v8 coverage
never generates DA records for them. Without an allowlist entry,
coverage:diff reports no-coverage-data for every .d.ts in the
diff. Add /\.d\.ts$/ to ALLOWED_GLOBS with a companion test.

Also configure @vitest/coverage-v8 for core-shared and add
targeted vitest exclusions for infrastructure files that are not
unit-testable (DI symbols, interface files, tRPC context, Sentry
SDK init) — bringing core-shared into the L2 aggregate and making
the L1 diff gate enforce coverage on new executable code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:26:50 +00:00
a94e8032b5 feat(core-shared): add PII and retention type primitives
Introduces PiiCategory, DataProcessingPurpose, RetentionTrigger,
RetentionAction, FieldPii, FieldRetention, PAYLOAD_AUTH_PII_DEFAULTS,
PurgeSchedule, and CollectionRetention in core-shared/payload/.
Augments payload's FieldCustom and CollectionCustom interfaces via
ambient declaration so downstream collection configs gain typed
custom.pii and custom.retention / custom.authPii fields.

Credential fields (password, salt, hash, resetPasswordToken,
resetPasswordExpiration, loginAttempts, lockUntil, apiKey, apiKeyIndex)
are null in PAYLOAD_AUTH_PII_DEFAULTS to exclude security material
from DPA mapping. Adds @vitest/coverage-v8 and coverage exclusions
for boilerplate infrastructure files so coverage:diff is gated on
new executable code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 18:23:24 +00:00
a832a7dfaa feat(core-shared): add AnalyticsProtocol to BindContext and BindProductionContext
Adds analytics?: Analytics generic field to both BindContext and
BindProductionContext in bind-context.ts, mirroring the pattern used by
IEventBus, IAuditLog, and IJobQueue. AnalyticsProtocol already existed
in bind-protocols.ts and is re-exported from the @repo/core-shared/di
barrel via the existing wildcard export.

Also adds a type-level test for AnalyticsProtocol in bind-protocols.test.ts
to match test coverage for the other protocol types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 15:38:48 +00:00
92b17f7d64 feat(core-shared): add Analyzed brand check to assertFeatureConformance
Mirrors the existing Audited check: when a use case declares
analyticsEvents.length > 0 and the bound function lacks the __analyzed
brand, assertFeatureConformance throws ConformanceError at boot time.

Adds three synthetic conformance tests: passes when brand present +
events declared, throws naming Analyzed when events declared + brand
missing, passes when events empty + brand absent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 15:19:29 +00:00
32018e8a7b feat(core-shared): extend wireUseCase with analytics arg and Analyzed brand propagation
Add AnalyticsProtocol to bind-protocols, extend WireUseCaseOptions with
optional analytics field, and compose the __analyzed brand inline in
wireUseCase (innermost, before withAudit) when analytics is provided.

Propagate __analyzed through withCapture and withSpan PROPAGATED_BRANDS
so the outermost container binding carries the brand for boot-time
assertion checks (Story 05).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 15:12:57 +00:00
0ee0355f5e feat(core-shared): add analyticsEvents field to UseCaseManifest
Add optional `analyticsEvents?: readonly string[]` to `UseCaseManifest`
in `define-feature.ts` so manifests can declare which analytics events a
use case emits. Field defaults to absent (treated as []) — all existing
manifests remain valid without changes.

Update the feature generator template to emit `analyticsEvents: []` so
newly scaffolded features are analytics-declaration-ready from day one.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 11:57:49 +00:00
d128106fd2 feat(core-shared): add Analyzed brand and isAnalyzed type guard
Adds the `Analyzed<F>` phantom-type brand to brands.ts and the
`isAnalyzed` type-guard to brand-runtime.ts, mirroring the existing
Instrumented/Captured/Audited pattern. Exports both from the
conformance index so Story 04 (wireUseCase) can key off the brand
without a circular dep.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 11:41:48 +00:00
1bbe866a5c feat(core-shared): add wireUseCase helper to conformance barrel
Encapsulates withSpan(withCapture(withAudit?(factory(deps)))) composition
and container binding into a single helper, eliminating the structural
boilerplate clone groups repeated across every feature binder pair.

Callers pass { container, symbol, factory, deps, feature, layer, name,
tracer, logger, auditLog? } and get back a fully brand-stacked, container-
bound wired value. Idempotent: unbinds an existing symbol before rebinding.

withAudit lives in core-audit which core-shared cannot import (dependency
inversion: core-audit depends on core-shared). The audit path here replicates
the same semantics — forwarding wrapper + __audited brand — without the
circular dependency.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 17:28:57 +00:00
f7baa8bfd1 feat(core-shared/conformance): manifest coverage schema + vitest helper
First implementation milestone of the agent-first coverage architecture
(ADR-020, PRD 2026-05-13). Lands the keystone — coverage bands as a
typed declaration in feature.manifest.ts plus a helper that derives
vitest threshold shapes from them.

New file packages/core-shared/src/conformance/coverage.ts (self-
contained, no relative imports — loadable at vitest config time):
- CoverageBand / CoverageBands / CoverageManifest / VitestThresholds
  types
- DEFAULT_COVERAGE_BANDS (baseline 80/75/80/80; entities 100/100/100/
  100; use-cases + controllers 100/95/100/100) — matches ADR-011
- DEFAULT_MUTATION_SCORE (80) + DEFAULT_MUTATION_TARGETS (entities +
  use-cases)
- getCoverageBands / getMutationConfig — manifest -> resolved bands,
  with default fallback for missing layers
- vitestThresholdsFromBands / vitestThresholdsFromManifest — convert
  to vitest's coverage.thresholds shape with the layer-to-glob
  mapping

define-feature.ts gains the optional coverage field on FeatureManifest
(imports its type from coverage.ts to avoid a relative-import cycle
at config-load time).

Exposed via two subpaths: @repo/core-shared/conformance (re-exports
for source/test code) and @repo/core-shared/conformance/coverage
(direct subpath safe to load from vitest configs, bypasses the index
re-export chain that Node ESM doesn't auto-extension-resolve).

Auth wired as proof-of-concept:
- packages/auth/src/feature.manifest.ts declares its coverage section
- packages/auth/vitest.config.ts imports the helper +
  DEFAULT_COVERAGE_BANDS and emits thresholds via
  vitestThresholdsFromBands(DEFAULT_COVERAGE_BANDS) — no more
  hand-maintained per-glob thresholds block.

Verified: 175/175 tests pass; 14/14 typechecks clean; auth coverage
green (21 tests, 93.77% overall, all per-layer 100% bands hold).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:51:13 +02:00
5d61343068 chore: gitignore *.local files at project level + strip phase residuals
Previously .claude/settings.local.json was only excluded by the user's
global ~/.config/git/ignore — fresh clones of this template would have
accidentally committed per-user Claude Code settings. Add an explicit
project-level rule (*.local, *.local.*, **/settings.local.json) so the
template ships with the protection baked in.

Also strips two missed "phase" residuals from
core-shared/instrumentation/otel/init-server-node.ts (the word leaked
through the earlier sweep — generic future-work qualifier, not a
setup-history reference, but cleaner without it).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:10:53 +02:00
841655573b docs(adr): rename ADR-012 — drop Lazar; update title + content + cross-refs
- Rename docs/decisions/adr-012-lazar-conformance.md → adr-012-feature-conventions.md
- Strip "Lazar", "Plan 8/9/10/11", "refactor-logs" refs from all ADRs,
  architecture docs, HTML explainers, and feature/core AGENTS.md files
- Update all incoming links in docs/, packages/*/AGENTS.md, HTML explainers

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:07:37 +02:00
17ae157365 refactor: strip Phase/Plan/R-number references from source comments 2026-05-13 09:51:45 +02:00
83f135b5e1 fix(conformance): withCapture propagates inner brands + chain test + docstring fixes 2026-05-12 23:00:50 +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
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
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
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
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
a3b7100d10 feat(core-shared): BindContext.auditLog? field (5th generic)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 16:04:58 +02:00
a7e383593a feat(core-shared): AuditLogProtocol + ./audit subpath export
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 16:04:29 +02:00