Webpack (Next.js transpilePackages) resolves from .ts source directly
and cannot find .js files. The bind-production binders already used
extensionless imports; align bind-dev-seed to match. Also fixes the
turbo gen feature template so new features are consistent.
bind-production.types.test.ts imported feature.manifest and the sign-in
use case with `../` parent paths. Test files import src modules via the
`@/` alias per the repo convention — this clears the way for the new
no-relative-parent-import-in-tests rule.
cookie.ts was the only entity model in the feature packages without a
sibling test. Covers minimal/full attributes, invalid sameSite, and a
missing required field.
The signUp use case calls `bus.publish(userSignedUpEvent, ...)` but its
manifest entry declared `publishes: []`. The conformance event graph was
blind to the entire auth -> marketing-pages welcome-email flow as a
result. Declaring "auth.user.signed-up" makes `pnpm conformance` surface
the event and its publisher.
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>
Implements the Payload-backed IConsent that reads/writes users.consentState
and emits CONSENT_GRANT/CONSENT_WITHDRAW audit entries via injected auditLog.
Adds RecordingConsent test double in core-testing for unit-test injection.
Adds bindProductionConsent/bindDevSeedConsent DI binders and InMemoryConsent
for dev/seed contexts. Contract tests cover grant/withdraw/isGranted round-trip,
audit entry shape, metadata persistence (bannerVersion/policyVersion/method),
and getCategories reflection of state.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Tag displayName as identification-username PII and declare daily purge
with 30-day post-deletion hard-delete retention. PAYLOAD_AUTH_PII_DEFAULTS
covers email/credentials automatically — no authPii override needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each feature's bind-production.ts already ends with
assertFeatureConformance(), but that check only fired on `pnpm dev`.
Adds a smoke test per feature that invokes the binder with a Noop ctx,
so missing __instrumented / __captured / __audited brands now fail
under `pnpm test` (and therefore in CI), closing the gap between the
TypeScript brand layer and the boot-time runtime assertion.
Replace inline withSpan + withCapture blocks for signIn, signUp, and
signOut use cases in both bind-production.ts and bind-dev-seed.ts with
wireUseCase calls. Removes 27 lines of boilerplate per binder file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
- Regenerate audit + realtime core-package e2e snapshots (template
Phase-label changes altered file hashes)
- Fix pre-existing lint error in auth authentication.service.ts:
rename unused params to _user / _sessionId, drop stale eslint-disable
comments that were on wrong lines
- Mark story tasks 1-9 done; rebuild _state.json
Co-Authored-By: Claude Opus 4.7 (1M context) <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>
- di-explainer.html: update stale JS data strings from positional-arg
form (bindAllProduction(config), bindProductionBlog(config,tracer,...))
to ctx-arg form (bindAllProduction(deps), bindProductionBlog(ctx)) with
a note on ctx shape.
- auth/sign-up.use-case: change bus param from IEventBus to
EventBusProtocol|undefined; guard bus.publish with if(bus) so the use
case is safe when core-events is absent (Phase 3+).
- auth/bind-production + bind-dev-seed: drop as IEventBus cast and unused
IEventBus import; ctx.bus is now passed directly (typed as
EventBusProtocol|undefined).
- marketing-pages/bind-production + bind-dev-seed: drop as IJobQueue cast
and unused IJobQueue import; wrap event-handler DI block in if(queue)
guard so the handler is only bound when core-jobs is wired.
- core-shared/src/index.ts: add `export * from "./di"` as the plan
specified (subpath export alone is no longer the only access path).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extend bindProductionAuth and bindDevSeedAuth to 7-arg signatures.
Fix RecordingRealtimeBroadcaster scope type to structurally match ChannelScope.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
signUpUseCase now takes an IEventBus and publishes userSignedUpEvent
after creating the user (synthesizing email from username since auth
is username-based). Use case mocks-default in module.ts get a fresh
InMemoryEventBus per resolution; bind-production / bind-dev-seed wire
the shared bus passed by bindAll. Tests updated to inject
RecordingEventBus, including a new test that asserts publish on
success and silence on failure.
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>
Mirrors the canonical blog pattern landed earlier on this branch.
Per feature:
- src/__seeds__/dev.ts — lazy buildDev<Entities>() function using the
feature's existing factory for sensible defaults
- src/di/bind-dev-seed.ts — bindDevSeed<Feature>() async function that
rebinds the repo symbol(s) to a populated MockXRepository via
.toConstantValue
- src/di/bind-dev-seed.test.ts — 3+ tests per feature (populates,
reachable by id/slug, idempotent)
- package.json — adds ./di/bind-dev-seed subpath export
Tests + use cases continue to construct mocks directly; the seed never
runs from a *.test.ts path. App boot wiring (USE_DEV_SEED env branch)
follows in a separate commit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Spec reviewer caught a systemic gap during Task 6 (navigation) review:
Plan 8 left every feature's domain error class with a constructor that
didn't set this.name = '<ClassName>'. Plan 9 spec R6 requires it.
Fixed across all 10 error files:
- auth: AuthenticationError, UnauthenticatedError, UnauthorizedError, InputParseError
- blog: ArticleNotFoundError, InputParseError
- marketing-pages: PageNotFoundError, InputParseError
- navigation: HeaderNotFoundError, InputParseError
- media: MediaNotFoundError, InputParseError
Functionally a no-op — defineErrorMiddleware uses instanceof, not name —
but ensures correct serialization, stack traces, and JSON inspection.
Refactor log: §7
Spec: R6
Code-quality reviewer flagged:
- R25 'malformed output' tests used .rejects.toThrow(/parse|invalid/i)
which could match unrelated errors. Replaced with
.rejects.toBeInstanceOf(ZodError) for both sign-in and sign-up.
- sign-in controller test asserted result.name only as truthy; the
parallel sign-up test was already precise (toBe('session')). Tightened
to match.
61 tests still passing for @repo/auth.
Per Plan 9 (spec R1-R28):
- Use cases: input + output schemas (signIn, signUp); input-only for
signOut (void output). Use case body validates output via
outputSchema.parse before returning.
- Controllers: receive `unknown`; safeParse with the use-case schema;
presenter (returning cookie) for signIn/signUp; void return for
signOut.
- New integrations/api/procedures.ts with authProcedure built via
defineErrorMiddleware([[InputParseError,"BAD_REQUEST"],
[AuthenticationError,"UNAUTHORIZED"], [UnauthenticatedError,
"UNAUTHORIZED"], [UnauthorizedError,"FORBIDDEN"]]).
- Router uses authProcedure + .input(xInputSchema) for every procedure.
- src/index.ts exports schemas + types + IUseCase/IController aliases.
- package.json gains ./ui subpath; src/ui/index.ts placeholder
(auth has no query builders today).
- New tests: R25 output-validation per use case (signIn, signUp);
R26 router error-mapping (UNAUTHORIZED on missing user,
BAD_REQUEST on schema fail).
Refactor log: §1, §2, §3.1, §3.2, §3.3, §5.1, §5.2, §6.1, §6.2
Spec: R1–R6, R8–R15, R18, R19, R22–R26
- Use cases (sign-in, sign-up, sign-out) → factory functions with I*UseCase aliases
- Controllers → factory functions with I*Controller aliases
- DI symbols + module updated with .toDynamicValue() bindings for factories
- New: real UsersRepository (Payload-backed, SanitizedConfig, contract-tested)
- New: real AuthenticationService (node:crypto hashing/UUIDs; createSession/
validateSession/invalidateSession deferred — see refactor log §7)
- bindProductionAuth swaps both mocks for real impls (was a no-op before)
- Tests refactored to construct mocks and inject directly (no container rebinding)
- Feature test constructs full chain via direct factory injection
Refactor log: §2, §4.1, §4.2, §5.1, §5.2, §6.1, §7
Spec: §6.1, §7
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All 5 features (auth, blog, marketing-pages, navigation; media has no
entities yet) now follow Lazar's pattern:
- entities/<x>.ts → entities/models/<x>.ts
- entities/errors.ts → entities/errors/<domain>.ts + errors/common.ts
Updates all import paths across factories, contracts, tests, use cases,
controllers, repositories, integrations, and src/index.ts exports.
navigation divergence: had no errors.ts; errors/header.ts +
errors/common.ts added as new forward-looking stubs.
Refactor log: docs/superpowers/refactor-logs/2026-05-05-lazar-pattern-conformance.md
Spec: §5, §9.3
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each repository interface now has a contract suite under
src/__contracts__/. Both Mock and Payload implementations run the
same suite, eliminating mock-vs-real drift. Payload impls back the
contract with an in-memory stub via vi.mock('payload') + a small
buildPayloadStub helper.
Spec: §5.2, §6.4
- Add navItemFactory to navigation (spec §5.1 — was missing)
- Refactor blog/router.test.ts to use articleFactory (eliminate new Date())
- headerFactory uses sequence for logoId (deterministic buildList output)
- Align media/tsconfig.json with other features (jsx + tests/ include)
- Refactor auth/container.test.ts to use userFactory
Reviewer: superpowers:code-reviewer (Task 3 of Plan 7).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds src/__factories__/<entity>.factory.ts to auth, blog, marketing-pages,
navigation, media. Each factory uses defineFactory from @repo/core-testing
with stable date defaults (2026-01-01) so snapshot diffs reflect SUT
behavior only. Refactors mechanical inline-fixture tests to use factories.
Also adds vitest.config.ts and tsconfig path alias to @repo/media (lacked
both), and adds @repo/core-testing devDependency to @repo/media.
Spec: §5.1, §6.3