Commit Graph

47 Commits

Author SHA1 Message Date
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
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
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
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
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
82d80014bf fix(otel): address lint and test regressions from C1/C2 fixes
- Prefix unused opts param with _opts in bindOtelInstrumentation (ESLint)
- Extend IPv6 regex to cover prefix::suffix form (e.g. 2001:0db8::1) so
  the IPv6 scrub test passes correctly
- Delete orphaned sentry-pii-scrubber.test.ts files from apps/cms and
  apps/web-tanstack that imported the deleted sentry/scrub module (broke
  typecheck; the OTel-layer replacement tests are in pii-scrub-processor.test.ts)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 12:42:38 +02:00
9acf16f399 chore: address Phase 5 review polish (test descriptions, version conflict comment, mock cleanup)
I3: bind-production.test.ts instrumentation orthogonality tests updated to use
bindOtelInstrumentation as primary name (bindSentryInstrumentation alias still
wired in mock setup for deprecation-alias coverage, not in assertions).
I4: as never cast in init-server-node.ts annotated with explanation of the
sdk-trace-base / sdk-node TypeScript version conflict that necessitates it.
I5: SentryLogRecordProcessor removed from @sentry/opentelemetry mock in
no-instrumentation.ts — that class does not exist in v10.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 12:40:11 +02:00
7c74a1c9e1 fix(otel): scrub IP addresses in attribute values + log bodies (R32 compliance)
PII_KEY_SUBSTRINGS extended with all OTel HTTP semconv IP attribute keys
(http.client_ip, client.address, net.peer.ip, etc.) so they are key-redacted.
scrubValue() added to pii-scrub-processor.ts applies IPV4_REGEX / IPV6_REGEX
replacement for attribute values whose keys are not PII-keyed, and for log
record bodies that pass the substring check. Closes the gap left by deletion
of the old beforeSend value-level IP scrubbers. 5 new tests added.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 12:39:22 +02:00
4ea9a5c38e fix(otel): consolidate to single OTel SDK init at instrumentation.register hook
All three apps' instrumentation.ts files now call initOtelServerNode directly
instead of initSentryServer/initSentryServerNode, closing the startup window
where @sentry/nextjs auto-instrumentation could send unscrubbed errors before
bindAll() fires. bindOtelInstrumentation no longer calls initOtelServerNode
(SDK init belongs at app boot, binding at request scope). Orphaned sentry/
init-server*.ts files deleted; their package.json subpath exports removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 12:38:17 +02:00
301e0ff3f8 refactor(core-shared): delete Sentry scrub + orphaned server-init files (replaced by OTel processors) 2026-05-11 12:12:12 +02:00
ad609f8f01 feat(core-shared): wire PII scrub processors FIRST in OTel pipeline 2026-05-11 12:09:11 +02:00
6ec5aeb31f feat(core-shared): PII scrub processors for spans + log records 2026-05-11 12:08:20 +02:00
cdfca850ac feat(core-shared): enable OTel auto-instrumentations (http + undici + pg) 2026-05-11 12:06:00 +02:00
d5f0f51b75 feat(core-shared): MetricsProtocol + BindContext.metrics? field 2026-05-11 12:02:06 +02:00
0850711986 feat(core-shared): wire IMetrics into DI bindings 2026-05-11 12:01:01 +02:00
9835752c21 feat(core-shared): OtelMetrics impl using @opentelemetry/api metrics 2026-05-11 11:59:04 +02:00
e11fd7c897 feat(core-shared): IMetrics interface + NoopMetrics impl 2026-05-11 11:57:56 +02:00
5c9cba318a refactor(core-shared): delete SentryLogger (replaced by OtelLogger)
Some checks failed
CI / typecheck + lint + boundaries + test + build (push) Has been cancelled
CI / Playwright e2e (push) Has been cancelled
CI / Storybook smoke tests (push) Has been cancelled
Sentry PII guard (R31) / pii-guard (push) Has been cancelled
Removes sentry-logger.ts and its test now that OtelLogger is the active
ILogger impl in bind-otel-instrumentation.ts. Updates the binder test to
assert OtelLogger (not SentryLogger) is bound. Fixes TypeScript errors:
SentryLogRecordForwarder registers directly as LogRecordProcessor (not
wrapped in BatchLogRecordProcessor which expects a LogRecordExporter);
severityNumber undefined guard added.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 11:54:54 +02:00
ad64009e86 feat(core-shared): SentryLogRecordForwarder + wire OtelLogger in OTel pipeline
Adds SentryLogRecordForwarder (LogRecordProcessor impl) to sentry-bridge.ts
that forwards OTel log records to Sentry via captureException/captureMessage.
Wires it as a BatchLogRecordProcessor in init-server-node.ts. Replaces
SentryLogger with OtelLogger in bind-otel-instrumentation.ts. 7 new bridge
tests pass alongside the existing 25 tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 11:53:23 +02:00
5e795fd7ab feat(core-shared): OtelLogger impl using @opentelemetry/api-logs
Implements ILogger via OTel Logs API. captureException emits an ERROR
log record with exception.* semantic conventions and double-report guard;
captureMessage maps ILogger levels to OTel SeverityNumber; addBreadcrumb
attaches span events; setUser sets user.id span attribute. 15 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 11:49:22 +02:00
4b390e028d refactor(core-shared): delete SentryTracer (replaced by OtelTracer)
sentry/sentry-tracer.ts and its test removed. OtelTracer is now the active
ITracer implementation. Spans flow to Sentry via @sentry/opentelemetry's
SentrySpanProcessor wired in bindOtelInstrumentation → initOtelServerNode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 11:43:26 +02:00
53bfe727b4 refactor(core-shared): rename bindSentryInstrumentation → bindOtelInstrumentation
git mv bind-sentry-instrumentation → bind-otel-instrumentation; function
renamed; new impl calls initOtelServerNode and binds OtelTracer (SentryLogger
kept for Phase 3). Barrel re-exports both new name and deprecated alias
bindSentryInstrumentation for one release. ESLint allowlist updated to the
new filename. init-server-node opts gains release? field.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 11:42:07 +02:00
b61e9d2091 feat(core-shared): OtelTracer impl using @opentelemetry/api
Implements OtelTracer as ITracer replacement for SentryTracer. Uses
@opentelemetry/api's trace.getTracer + startActiveSpan, maps span.op to
a span attribute, catches exceptions via recordException + setStatus(ERROR),
and filters null attribute values. Five Vitest tests covering name/attributes,
nesting, exception recording, status mapping, and null filtering.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 11:40:43 +02:00
4c628022ce fix(core-shared): align OTel type imports to sdk-node re-exports to resolve version conflict 2026-05-11 11:28:07 +02:00
f94f09a9fa feat(core-shared): OTel barrel + ESLint allowlist for SDK packages 2026-05-11 11:25:29 +02:00
e85b8b12cf feat(core-shared): OTel NodeSDK init helper with Sentry exporter wiring 2026-05-11 11:24:55 +02:00
3a32838c71 feat(core-shared): Sentry-as-OTel-exporter bridge module 2026-05-11 11:23:49 +02:00
12aeb8bf37 feat(core-shared): OTel resource builder 2026-05-11 11:23:19 +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
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
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
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