Adds "Asserting spans and captures" section to tdd-workflow.md with RecordingTracer/Logger usage and inline withSpan wrapping pattern for direct-injection tests. Adds R49/R50 section to testing-strategy.md covering the no-sentry guard, contract suite span assertions, and RecordingTracer/Logger field reference. Adds "TRACER / LOGGER (Plan 10)" subsection to dependency-flow.md showing the bindAll → feature-container wiring path. Adds an "src/instrumentation/" section to core-shared/AGENTS.md documenting the two interfaces, three impl pairs, withSpan helper, scrubbers, both Next.js + Vite/React init helpers, and the subpath exports. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4.7 KiB
AGENTS.md — core-shared
Generic, reusable primitives with zero business knowledge. This package is the foundation for all other packages and exports utilities, Payload field/hook definitions, and tRPC initialization.
Responsibilities
- Generic primitives — environment helpers, date utilities, type guards
- Payload utilities — field definitions (slug, SEO), blocks (CTA), access controls (is-admin), hooks (slugify, publish timestamp)
- tRPC platform —
initTRPC.create(), shared context factory, procedure builders - No business domain knowledge — no awareness of articles, users, media, or any feature
Must NOT import
- Any feature package (
@repo/auth,@repo/blog, etc.) - Any app package
- Framework-specific code (Next.js, TanStack React Query)
Public exports
From package.json:
.— all utilities, Payload exports, tRPC init./payload— Payload field/hook/block utilities only./trpc/init— tRPCinitTRPCinstance + builders. Plan 9: also exportst(the rawinitTRPC.create({...})instance) so feature packages can build their own procedures viat.procedure.use(...)./trpc/context— tRPC context factory only./trpc/define-error-middleware— Plan 9: factory that builds a tRPC middleware translating domain errors toTRPCError. TakesReadonlyArray<readonly [ErrorCtor, TRPC_ERROR_CODE_KEY]>tuples; usesinstanceofdiscrimination; preserves the original error as.cause. Owned by features: each feature passes its own constructors in viaintegrations/api/procedures.ts. core-shared never enumerates feature-specific error classes — this stays boundary-clean
Test conventions
- Tests colocated:
src/lib/slug-field.ts→src/lib/slug-field.test.ts - Vitest environment:
node - Alias:
@/resolves tosrc/ - Run:
pnpm test --filter @repo/core-shared
Covered areas:
- Slug field generation + validation
- Payload hooks (publish-at timestamp, slugify-if-missing)
- Access control helpers
src/instrumentation/
Two interfaces: ITracer (in tracer.interface.ts) and ILogger (in logger.interface.ts).
Three implementation pairs:
NoopTracer/NoopLogger— pass-through. Default everywhere.SentryTracer/SentryLogger— adapters over@sentry/nextjs. Live insentry/subfolder. Thesentry/subfolder is the only path inpackages/permitted to import@sentry/*(R40), with the additional exception ofinstrumentation/di/bind-sentry-instrumentation.{ts,test.ts}.RecordingTracer/RecordingLogger— in@repo/core-testing/instrumentation, not here.
with-span.ts: higher-order helper used at DI binding time to wrap use case + controller factory results in a span. Pattern:
const wrapped = withSpan(
tracer,
{ name: "blog.getArticles", op: "use-case" },
factory(deps),
);
Symbols: INSTRUMENTATION_SYMBOLS.TRACER, INSTRUMENTATION_SYMBOLS.LOGGER (both Symbol.for(...) so cross-realm equality holds).
sentry/scrub.ts: PII scrubbers used by every Sentry.init() call across the monorepo. Substring-based key matching catches derived names (userEmail, accessToken, apiKey, ipAddress). IPv4/IPv6 are also redacted from string values via the [redacted-ip] token.
sentry/init-server.ts + init-client.ts: centralized init helpers (Next.js flavor) that hard-code R31 (sendDefaultPii: false), R32/R33 (scrubbers), R34/R35 (replay mask flags), R37 (sample-rate defaults). Apps call these from instrumentation.ts / instrumentation-client.ts.
sentry/init-server-node.ts + init-client-react.ts: Vite/non-Next variants used by apps/web-tanstack. Same R31/R32/R33/R34/R35/R37 posture; uses @sentry/node + @sentry/react instead of @sentry/nextjs.
di/bind-noop-instrumentation.ts + bind-sentry-instrumentation.ts: bind TRACER + LOGGER symbols to a Container. Returns the resolved instances so callers can use them without container lookup.
Subpath exports (package.json#exports):
./instrumentation— barrel (interfaces + Noops + withSpan + symbols + binders + node/react init helpers)./instrumentation/sentry/init-server— Next.js server init helper./instrumentation/sentry/init-client— Next.js client init helper./instrumentation/sentry/init-server-node—@sentry/nodeserver init (TanStack Start)./instrumentation/sentry/init-client-react—@sentry/reactclient init (TanStack Start)./instrumentation/sentry/scrub—beforeSend/beforeSendTransaction(used by per-app PII test)
Boundaries:
core-shared/instrumentation/sentry/**MAY import from@sentry/*.- Everything else in
packages/core-shared/src/MUST NOT. - The eslint rule in
core-eslint/base.jsenforces the broader monorepo boundary (R40).