Files
agentic-dev/docs/superpowers/plans/2026-05-12-conformance-milestone-ii.md
Danijel Martinek 31d5123737 plan(conformance): milestone ii — assertFeatureConformance + boot wiring
12-task implementation plan for the runtime boot-time check of the
conformance system. Reifies the phantom-type brands from milestone i as
non-enumerable runtime markers via Object.defineProperty, and ships
assertFeatureConformance(container, manifest, symbols, ctx) which walks
the manifest, resolves each use case from the feature's container, and
throws ConformanceError synchronously when a binding is missing a
required brand.

Per-feature self-assertion: each bindProductionX(ctx) calls
assertFeatureConformance at its tail, so the boot check runs once per
feature and is forward-compatible with future apps wiring those binders.

Also bundles the two forward-looking items the milestone-i reviewer
flagged (re-export authManifest from auth root barrel; TODO breadcrumb
in withAudit for future automation).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 22:33:20 +02:00

46 KiB

Conformance Milestone ii — assertFeatureConformance + boot wiring

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Ship the boot-time runtime check of the conformance system. withSpan / withCapture / withAudit attach non-enumerable runtime markers; assertFeatureConformance(container, manifest, symbols, ctx) resolves each manifest-declared use case from the feature's container and verifies the bound function carries the required markers. Each feature's bindProductionX(ctx) self-asserts at the tail; pnpm dev refuses to boot on drift.

Architecture: The phantom-type seam shipped in milestone i becomes a reified type seam at runtime. Each wrapper attaches its brand as a non-enumerable, non-configurable property (Object.defineProperty(wrapped, "__instrumented", { value: true, enumerable: false, writable: false, configurable: false })). Predicate helpers (isInstrumented, isCaptured, isAudited) read those markers. assertFeatureConformance walks the manifest's useCases, resolves each binding by the symbol map the binder declares inline, and throws ConformanceError synchronously when a binding is missing a required brand. Per-feature self-assertion (called at the end of bindProductionAuth(ctx)) is forward-compatible: when cms and web-tanstack eventually wire bindProductionAuth, they inherit the boot check for free.

Tech Stack: TypeScript (strict), Vitest, Inversify (existing DI). Object.defineProperty for non-enumerable runtime markers. No new dependencies.


File structure

Create

  • packages/core-shared/src/conformance/brand-runtime.ts — runtime marker attachment + predicates
  • packages/core-shared/src/conformance/brand-runtime.test.ts — attachBrand + predicate tests
  • packages/core-shared/src/conformance/conformance-error.tsConformanceError class
  • packages/core-shared/src/conformance/assert-bindings.tsassertFeatureConformance
  • packages/core-shared/src/conformance/assert-bindings.test.ts — positive + negative assertion tests
  • docs/work/conformance-system-v1/02-boot-assertions/_story.md — story 02 record

Modify

  • packages/core-shared/src/instrumentation/with-span.ts — call attachBrand(wrapped, "__instrumented")
  • packages/core-shared/src/instrumentation/with-capture.ts — call attachBrand(wrapped, "__captured")
  • packages/core-shared/src/instrumentation/with-span.test.ts — add runtime brand assertion
  • packages/core-shared/src/instrumentation/with-capture.test.ts — add runtime brand assertion
  • packages/core-audit/src/with-audit.ts — wrap (not passthrough) + attachBrand(wrapped, "__audited") + TODO breadcrumb
  • packages/core-audit/src/with-audit.test.ts — add runtime brand assertion + adjust passthrough expectations
  • packages/core-shared/src/conformance/index.ts — re-export brand-runtime helpers + ConformanceError + assertFeatureConformance
  • packages/auth/src/index.ts — re-export authManifest + AuthManifest at the auth package root
  • packages/auth/src/di/bind-production.ts — call assertFeatureConformance at the tail
  • docs/work/conformance-system-v1/_epic.md — flip story 02 status and checkbox at closeout

No file changes (verified at closeout)

  • packages/blog/, packages/media/, packages/navigation/, packages/marketing-pages/ — no manifests yet; their bind-production stays unchanged
  • apps/cms/, apps/web-tanstack/ — no server bootstrap yet; nothing to wire

Task 1: Re-export authManifest from auth root barrel

Surfaces the manifest at the package boundary so future stories (and the boot-assertion's caller) can read it without a deep import.

Files:

  • Modify: packages/auth/src/index.ts

  • Step 1: Append the re-export

Add these lines at the bottom of packages/auth/src/index.ts:

// Feature conformance manifest (added in conformance milestone i, exposed
// here in milestone ii so the boot-time assertion and future tooling can
// read the contract from the package boundary).
export { authManifest, type AuthManifest } from "./feature.manifest";
  • Step 2: Verify typecheck passes

Run: pnpm --filter @repo/auth typecheck Expected: PASS.

  • Step 3: Commit
git add packages/auth/src/index.ts
git commit -m "feat(auth): re-export authManifest + AuthManifest from package root"

Task 2: Add TODO breadcrumb in withAudit

The withAudit wrapper currently does nothing but cast (with a void auditLog; to silence unused). Leave a clear forward pointer for the future story that wires automated audit recording.

Files:

  • Modify: packages/core-audit/src/with-audit.ts

  • Step 1: Replace the function body's existing comment block

In packages/core-audit/src/with-audit.ts, the body currently looks like:

export function withAudit<Args extends unknown[], R>(
  // The auditLog is part of the signature for two reasons: (1) callers must
  // pass it at bind time, ensuring the dep is available, and (2) future
  // versions of this wrapper will use it to emit audit events from the
  // declarative manifest entry directly.
  auditLog: IAuditLog,
  fn: (...args: Args) => Promise<R>,
): Audited<(...args: Args) => Promise<R>> {
  void auditLog;
  return fn as Audited<(...args: Args) => Promise<R>>;
}

Adjust the inline comment to point at the future story that wires automated recording. Replace ONLY the inline comment on auditLog (do not touch the function body yet — Task 7 changes the body):

export function withAudit<Args extends unknown[], R>(
  // TODO(conformance milestone iii+): wire automated recording from manifest
  // `audits[]` declarations. For now, the wrapper exists to:
  //   (1) require callers to pass the auditLog at bind time (dep is available)
  //   (2) attach the `__audited` brand so the boot-time assertion can verify
  //       mutating use cases were bound through the audit-aware path.
  auditLog: IAuditLog,
  fn: (...args: Args) => Promise<R>,
): Audited<(...args: Args) => Promise<R>> {
  void auditLog;
  return fn as Audited<(...args: Args) => Promise<R>>;
}

The function body is unchanged in this task; we only enriched the comment.

  • Step 2: Verify typecheck and tests still pass
pnpm --filter @repo/core-audit typecheck
pnpm --filter @repo/core-audit test with-audit

Both PASS, no regressions.

  • Step 3: Commit
git add packages/core-audit/src/with-audit.ts
git commit -m "docs(core-audit): TODO breadcrumb for future audit recording automation"

Task 3: Scaffold docs/work record for story 02

Files:

  • Create: docs/work/conformance-system-v1/02-boot-assertions/_story.md

  • Step 1: Write the story file

Create docs/work/conformance-system-v1/02-boot-assertions/_story.md with EXACTLY this content:

---
id: 02-boot-assertions
epic: conformance-system-v1
title: assertFeatureConformance + boot wiring
type: technical-story
status: in-progress
feature: core-shared
depends-on: [01-define-feature-helper]
blocks: [03-eslint-rules]
---

## Goal
Runtime boot-time verification that every manifest-declared use case is bound
through the brand-attaching wrappers. Each feature's `bindProductionX(ctx)`
self-asserts at the tail; `pnpm dev` refuses to boot on drift.

## Why
Type casts can mask unwrapped factories; manifest edits can drift from
binders without TypeScript noticing. Boot assertions catch what the type
system can't see — at zero cost during the inner agent feedback loop, and
synchronously at startup so failures fire loudly.

## Done when
- `withSpan`, `withCapture`, `withAudit` attach non-enumerable runtime markers
  matching the type-level brand names
- `assertFeatureConformance(container, manifest, symbols, ctx)` resolves each
  manifest use case and throws `ConformanceError` on a missing brand
- `auth.bindProductionAuth(ctx)` self-asserts at the tail
- `pnpm dev` boots cleanly for the existing `auth` wiring; rebinding `signIn`
  with an unwrapped factory causes `pnpm dev` to throw at startup

## In scope
- Runtime marker attachment via `Object.defineProperty(fn, "__brand", { … })`
  (non-enumerable, non-writable, non-configurable)
- `isInstrumented` / `isCaptured` / `isAudited` predicates
- `ConformanceError` class (extends `Error`)
- `assertFeatureConformance(container, manifest, symbols, ctx)` helper
- Wiring into `packages/auth/src/di/bind-production.ts` (tail-of-binder
  self-assertion)
- `withAudit` upgraded from passthrough to a thin wrapper that attaches its
  runtime brand without changing observable behaviour

## Out of scope
- `assertConformance` over a multi-feature container collection at the app's
  `bindAll()` (current per-feature self-assertion is sufficient and
  forward-compatible)
- Wiring boot assertions into `cms` and `web-tanstack` — neither has a
  `bind-production.ts` yet; they'll inherit the check whenever they grow one
- Manifests for `blog`, `media`, `navigation`, `marketing-pages` (their
  `bindProductionX` stays unchanged in this story)
- Automated audit recording driven by manifest `audits[]` declarations
  (deferred to a later story)

## Tasks
- [ ] Re-export `authManifest` from auth root barrel
- [ ] TODO breadcrumb in `withAudit` pointing at future automation
- [ ] Runtime marker helpers (`attachBrand`, `isInstrumented`, `isCaptured`, `isAudited`)
- [ ] `withSpan` attaches runtime `__instrumented` marker
- [ ] `withCapture` attaches runtime `__captured` marker
- [ ] `withAudit` wraps + attaches runtime `__audited` marker
- [ ] `ConformanceError` class
- [ ] `assertFeatureConformance` helper + tests
- [ ] Conformance barrel + subpath exports updated
- [ ] `bindProductionAuth` self-asserts at the tail
- [ ] Final verification + story closeout
  • Step 2: Commit
git add docs/work/conformance-system-v1/02-boot-assertions/_story.md
git commit -m "docs(work): story 02 — assertFeatureConformance + boot wiring"

Task 4: Runtime marker helpers — attachBrand + predicates

The runtime marker module is the heart of milestone ii: a small set of helpers that attach non-enumerable brand flags and read them back. The phantom-type brand names (__instrumented, __captured, __audited) become real (non-enumerable) properties at runtime.

Files:

  • Create: packages/core-shared/src/conformance/brand-runtime.ts

  • Create: packages/core-shared/src/conformance/brand-runtime.test.ts

  • Step 1: Write the failing test

Create packages/core-shared/src/conformance/brand-runtime.test.ts with EXACTLY this content:

import { describe, it, expect } from "vitest";
import {
  attachBrand,
  isInstrumented,
  isCaptured,
  isAudited,
} from "@/conformance/brand-runtime";

describe("brand-runtime", () => {
  it("attachBrand adds a non-enumerable property and returns the same reference", () => {
    const fn = () => {};
    const result = attachBrand(fn, "__instrumented");
    expect(result).toBe(fn);
    expect(isInstrumented(fn)).toBe(true);
    // Non-enumerable: must not show up in Object.keys
    expect(Object.keys(fn)).not.toContain("__instrumented");
  });

  it("predicates return false for unwrapped functions", () => {
    const fn = () => {};
    expect(isInstrumented(fn)).toBe(false);
    expect(isCaptured(fn)).toBe(false);
    expect(isAudited(fn)).toBe(false);
  });

  it("predicates discriminate between brands", () => {
    const instrumented = () => {};
    attachBrand(instrumented, "__instrumented");
    expect(isInstrumented(instrumented)).toBe(true);
    expect(isCaptured(instrumented)).toBe(false);
    expect(isAudited(instrumented)).toBe(false);

    const captured = () => {};
    attachBrand(captured, "__captured");
    expect(isInstrumented(captured)).toBe(false);
    expect(isCaptured(captured)).toBe(true);
    expect(isAudited(captured)).toBe(false);

    const audited = () => {};
    attachBrand(audited, "__audited");
    expect(isAudited(audited)).toBe(true);
  });

  it("composing brands stacks them on the same function", () => {
    const fn = () => {};
    attachBrand(fn, "__instrumented");
    attachBrand(fn, "__captured");
    attachBrand(fn, "__audited");
    expect(isInstrumented(fn)).toBe(true);
    expect(isCaptured(fn)).toBe(true);
    expect(isAudited(fn)).toBe(true);
  });

  it("attached brands are non-writable and non-configurable", () => {
    const fn = () => {};
    attachBrand(fn, "__instrumented");
    const desc = Object.getOwnPropertyDescriptor(fn, "__instrumented");
    expect(desc?.writable).toBe(false);
    expect(desc?.configurable).toBe(false);
    expect(desc?.enumerable).toBe(false);
    expect(desc?.value).toBe(true);
  });

  it("predicates return false for non-function inputs", () => {
    expect(isInstrumented(null)).toBe(false);
    expect(isInstrumented(undefined)).toBe(false);
    expect(isInstrumented(42)).toBe(false);
    expect(isInstrumented("string")).toBe(false);
    expect(isInstrumented({})).toBe(false);
  });
});
  • Step 2: Run test to verify it fails
pnpm --filter @repo/core-shared test conformance/brand-runtime

Expected: FAIL — module not found.

  • Step 3: Write brand-runtime.ts

Create packages/core-shared/src/conformance/brand-runtime.ts with EXACTLY this content:

/**
 * Runtime brand attachment + predicates. The companion to the phantom-type
 * brands defined in `./brands.ts`: at compile time the brand is a structural
 * intersection; at runtime it is a non-enumerable, non-writable,
 * non-configurable property with the same name.
 *
 * Why non-enumerable: a wrapped function should not leak the marker through
 * `Object.keys`, `JSON.stringify`, `for…in`, or spread. The marker only
 * shows up to explicit lookups via `Reflect.has` or direct property access.
 *
 * Why non-writable + non-configurable: the marker is meant to be permanent
 * once attached. The wrapper is the only caller; the marker is a one-shot
 * commitment, not a mutable flag.
 */

type Brand = "__instrumented" | "__captured" | "__audited";

/**
 * Attaches the brand as a non-enumerable property on the given function.
 * Returns the same reference (no allocation). Idempotent: calling twice with
 * the same brand throws because the property is non-configurable — wrappers
 * never double-wrap, so this is the correct safety net.
 */
export function attachBrand<F extends object>(fn: F, brand: Brand): F {
  Object.defineProperty(fn, brand, {
    value: true,
    enumerable: false,
    writable: false,
    configurable: false,
  });
  return fn;
}

function hasBrand(fn: unknown, brand: Brand): boolean {
  if (typeof fn !== "function" && (typeof fn !== "object" || fn === null)) {
    return false;
  }
  return (fn as Record<string, unknown>)[brand] === true;
}

export function isInstrumented(fn: unknown): boolean {
  return hasBrand(fn, "__instrumented");
}

export function isCaptured(fn: unknown): boolean {
  return hasBrand(fn, "__captured");
}

export function isAudited(fn: unknown): boolean {
  return hasBrand(fn, "__audited");
}
  • Step 4: Run tests to verify they pass
pnpm --filter @repo/core-shared test conformance/brand-runtime

Expected: PASS, 6 tests.

  • Step 5: Re-export from the conformance barrel

Append to packages/core-shared/src/conformance/index.ts (preserving existing exports):

export {
  attachBrand,
  isInstrumented,
  isCaptured,
  isAudited,
} from "./brand-runtime";

Re-run typecheck to confirm the barrel resolves:

pnpm --filter @repo/core-shared typecheck

PASS.

  • Step 6: Commit
git add packages/core-shared/src/conformance/brand-runtime.ts packages/core-shared/src/conformance/brand-runtime.test.ts packages/core-shared/src/conformance/index.ts
git commit -m "feat(core-shared/conformance): runtime brand markers + isX predicates"

Task 5: withSpan attaches runtime __instrumented marker

Files:

  • Modify: packages/core-shared/src/instrumentation/with-span.ts

  • Modify: packages/core-shared/src/instrumentation/with-span.test.ts

  • Step 1: Add a failing runtime brand assertion to with-span.test.ts

Append this new describe block at the END of packages/core-shared/src/instrumentation/with-span.test.ts (after the existing describe("withSpan — brand", …) block):

import { isInstrumented } from "@/conformance/brand-runtime";

describe("withSpan — runtime brand", () => {
  it("attaches __instrumented as a non-enumerable property on the wrapped function", async () => {
    const { tracer } = makeRecordingTracer();
    const fn = async (a: number) => a + 1;
    const wrapped = withSpan(tracer, { name: "test.brand", op: "use-case" }, fn);
    expect(isInstrumented(wrapped)).toBe(true);
    expect(Object.keys(wrapped)).not.toContain("__instrumented");
  });
});

Note: place the import { isInstrumented } line near the top of the file alongside the other imports — the location of the import was shown inline above for context but it belongs in the imports block.

  • Step 2: Run test to verify it fails
pnpm --filter @repo/core-shared test with-span

Expected: at least one new test FAILS — wrapped does not yet have __instrumented attached.

  • Step 3: Update with-span.ts to attach the runtime marker

Update packages/core-shared/src/instrumentation/with-span.ts. The current file (after milestone i Task 11's brand-preserving overload) needs an attachBrand call before the return. Replace the body of the implementation function so it looks like this — note the new import and the attachBrand(wrapped, "__instrumented") line:

import type { ITracer, SpanOpts } from "./tracer.interface";
import type { Instrumented } from "../conformance/brands";
import { attachBrand } from "../conformance/brand-runtime";

export function withSpan<Args extends unknown[], R, Extra extends object>(
  tracer: ITracer,
  opts: SpanOpts | ((args: Args) => SpanOpts),
  fn: ((...args: Args) => Promise<R>) & Extra,
): Instrumented<((...args: Args) => Promise<R>) & Extra>;
export function withSpan<Args extends unknown[], R>(
  tracer: ITracer,
  opts: SpanOpts | ((args: Args) => SpanOpts),
  fn: (...args: Args) => Promise<R>,
): Instrumented<(...args: Args) => Promise<R>>;
export function withSpan<Args extends unknown[], R>(
  tracer: ITracer,
  opts: SpanOpts | ((args: Args) => SpanOpts),
  fn: (...args: Args) => Promise<R>,
): Instrumented<(...args: Args) => Promise<R>> {
  const wrapped: (...args: Args) => Promise<R> = (...args) => {
    const resolved = typeof opts === "function" ? opts(args) : opts;
    return tracer.startSpan(resolved, () => fn(...args));
  };
  attachBrand(wrapped, "__instrumented");
  // Cast is the type-level concession — the brand is now also a non-enumerable
  // runtime property attached above by `attachBrand`.
  return wrapped as Instrumented<(...args: Args) => Promise<R>>;
}

Important: keep BOTH overload signatures (the brand-preserving one added in milestone i Task 11 plus the original). The implementation signature is the third one shown; only the body changes (adds attachBrand call, updated comment).

  • Step 4: Run typecheck and tests
pnpm --filter @repo/core-shared typecheck
pnpm --filter @repo/core-shared test with-span

Both PASS. All existing tests still green plus the new runtime brand test.

  • Step 5: Commit
git add packages/core-shared/src/instrumentation/with-span.ts packages/core-shared/src/instrumentation/with-span.test.ts
git commit -m "feat(core-shared/instrumentation): withSpan attaches runtime __instrumented marker"

Task 6: withCapture attaches runtime __captured marker

Same pattern as Task 5.

Files:

  • Modify: packages/core-shared/src/instrumentation/with-capture.ts

  • Modify: packages/core-shared/src/instrumentation/with-capture.test.ts

  • Step 1: Add a failing runtime brand assertion to with-capture.test.ts

Append this new describe block at the END of packages/core-shared/src/instrumentation/with-capture.test.ts. Also add import { isCaptured } from "@/conformance/brand-runtime"; near the other imports at the top of the file:

describe("withCapture — runtime brand", () => {
  it("attaches __captured as a non-enumerable property on the wrapped function", async () => {
    const logger = makeLogger();
    const fn = async (a: number) => a + 1;
    const wrapped = withCapture(logger, { layer: "use-case" }, fn);
    expect(isCaptured(wrapped)).toBe(true);
    expect(Object.keys(wrapped)).not.toContain("__captured");
  });
});
  • Step 2: Run test to verify it fails
pnpm --filter @repo/core-shared test with-capture

Expected: new test FAILS.

  • Step 3: Update with-capture.ts to attach the runtime marker

Modify packages/core-shared/src/instrumentation/with-capture.ts. Add the attachBrand import alongside the existing imports at the top:

import type { ILogger } from "./logger.interface";
import type { Captured } from "../conformance/brands";
import { attachBrand } from "../conformance/brand-runtime";
import { isReported, markReported } from "./reported-flag";

Keep the existing JSDoc block intact (do not modify the doc text). Modify the body of withCapture so it ends with attachBrand(wrapped, "__captured"); before the return:

export function withCapture<Args extends unknown[], R>(
  logger: ILogger,
  tags: Record<string, string>,
  fn: (...args: Args) => Promise<R>,
): Captured<(...args: Args) => Promise<R>> {
  const wrapped: (...args: Args) => Promise<R> = async (...args) => {
    try {
      return await fn(...args);
    } catch (err) {
      if (!isReported(err)) {
        logger.captureException(err, { tags });
        markReported(err);
      }
      throw err;
    }
  };
  attachBrand(wrapped, "__captured");
  return wrapped as Captured<(...args: Args) => Promise<R>>;
}
  • Step 4: Run typecheck and tests
pnpm --filter @repo/core-shared typecheck
pnpm --filter @repo/core-shared test with-capture

Both PASS.

  • Step 5: Commit
git add packages/core-shared/src/instrumentation/with-capture.ts packages/core-shared/src/instrumentation/with-capture.test.ts
git commit -m "feat(core-shared/instrumentation): withCapture attaches runtime __captured marker"

Task 7: withAudit wraps + attaches runtime __audited marker

Milestone i implemented withAudit as a passthrough cast (return fn as Audited<...>). For runtime brand detection that doesn't pollute the caller's fn, the wrapper now creates a thin wrapper function and attaches the marker to that new function. Observable behaviour is unchanged.

Files:

  • Modify: packages/core-audit/src/with-audit.ts

  • Modify: packages/core-audit/src/with-audit.test.ts

  • Step 1: Update the test to assert the runtime brand AND identity invariants

Replace the entire contents of packages/core-audit/src/with-audit.test.ts with:

import { describe, it, expect, expectTypeOf, vi } from "vitest";
import { withAudit, type Audited } from "@/with-audit";
import type { IAuditLog } from "@/audit-log.interface";
import { isAudited } from "@repo/core-shared/conformance";

function makeAuditLog(): IAuditLog {
  return {
    record: vi.fn().mockResolvedValue(undefined),
    eraseSubject: vi.fn().mockResolvedValue(undefined),
  };
}

describe("withAudit", () => {
  it("returns an Audited<F>", () => {
    const auditLog = makeAuditLog();
    const fn = async (_input: { id: string }) => ({ ok: true });
    const wrapped = withAudit(auditLog, fn);
    expectTypeOf(wrapped).toMatchTypeOf<Audited<typeof fn>>();
  });

  it("attaches __audited as a non-enumerable property on the wrapped function", () => {
    const auditLog = makeAuditLog();
    const fn = async () => ({ ok: true });
    const wrapped = withAudit(auditLog, fn);
    expect(isAudited(wrapped)).toBe(true);
    expect(Object.keys(wrapped)).not.toContain("__audited");
  });

  it("does NOT pollute the original input function with the brand", () => {
    const auditLog = makeAuditLog();
    const fn = async () => ({ ok: true });
    const wrapped = withAudit(auditLog, fn);
    expect(isAudited(fn)).toBe(false);
    expect(wrapped).not.toBe(fn);
  });

  it("passes input and output through unchanged", async () => {
    const auditLog = makeAuditLog();
    const fn = async (input: { id: string }) => ({ ok: true, id: input.id });
    const wrapped = withAudit(auditLog, fn);
    const result = await wrapped({ id: "abc" });
    expect(result).toEqual({ ok: true, id: "abc" });
  });

  it("propagates errors", async () => {
    const auditLog = makeAuditLog();
    const err = new Error("boom");
    const wrapped = withAudit(auditLog, async () => {
      throw err;
    });
    await expect(wrapped()).rejects.toBe(err);
  });
});

Note the new third test: wrapped !== fn and fn is NOT branded. This pins down the wrap-not-passthrough invariant.

  • Step 2: Run tests to verify they fail
pnpm --filter @repo/core-audit test with-audit

Expected: at least the new tests FAIL (the current passthrough makes wrapped === fn and isAudited(wrapped) returns false).

  • Step 3: Update with-audit.ts to wrap + attach the runtime brand

Replace the entire body of packages/core-audit/src/with-audit.ts with:

import type { IAuditLog } from "./audit-log.interface";
import { attachBrand } from "@repo/core-shared/conformance";

/**
 * Phantom-type brand attached at wrap time by `withAudit`. The conformance
 * system uses this as the type-level seam for mutating use cases that
 * declare `audits: [...]` in their manifest — without `__audited`, the
 * binding is not assignable to `ProductionUseCase<I, O, M>` when M demands
 * it. At runtime the brand is a non-enumerable property attached by
 * `attachBrand` from `@repo/core-shared/conformance`, so the boot-time
 * assertion can verify the binding went through the audit-aware path.
 */
export type Audited<F> = F & { readonly __audited: true };

/**
 * Use-case wrapper applied at DI bind time. The wrapper is a thin closure
 * that forwards to `fn` unchanged and carries the `__audited` brand. The
 * forward closure (instead of returning `fn` directly) keeps the brand on
 * a fresh function so the caller's original `fn` is not mutated — important
 * when the same factory output is used elsewhere unwrapped (dev-seed paths,
 * tests).
 */
export function withAudit<Args extends unknown[], R>(
  // TODO(conformance milestone iii+): wire automated recording from manifest
  // `audits[]` declarations. For now, the wrapper exists to:
  //   (1) require callers to pass the auditLog at bind time (dep is available)
  //   (2) attach the `__audited` brand so the boot-time assertion can verify
  //       mutating use cases were bound through the audit-aware path.
  auditLog: IAuditLog,
  fn: (...args: Args) => Promise<R>,
): Audited<(...args: Args) => Promise<R>> {
  void auditLog;
  const wrapped: (...args: Args) => Promise<R> = (...args) => fn(...args);
  attachBrand(wrapped, "__audited");
  return wrapped as Audited<(...args: Args) => Promise<R>>;
}

attachBrand is imported from @repo/core-shared/conformance — Task 4 added that export to the conformance barrel, so the import should resolve cleanly. If it doesn't, complete Task 4 first.

  • Step 4: Run typecheck and tests
pnpm --filter @repo/core-audit typecheck
pnpm --filter @repo/core-audit test with-audit

Both PASS. 5 tests green.

  • Step 5: Commit
git add packages/core-audit/src/with-audit.ts packages/core-audit/src/with-audit.test.ts
git commit -m "feat(core-audit): withAudit wraps and attaches runtime __audited marker"

Task 8: ConformanceError class

Files:

  • Create: packages/core-shared/src/conformance/conformance-error.ts

  • Create: packages/core-shared/src/conformance/conformance-error.test.ts

  • Step 1: Write the failing test

Create packages/core-shared/src/conformance/conformance-error.test.ts with EXACTLY this content:

import { describe, it, expect } from "vitest";
import { ConformanceError } from "@/conformance/conformance-error";

describe("ConformanceError", () => {
  it("extends Error with the standard shape", () => {
    const err = new ConformanceError("auth.signIn: missing __instrumented brand");
    expect(err).toBeInstanceOf(Error);
    expect(err).toBeInstanceOf(ConformanceError);
    expect(err.message).toBe("auth.signIn: missing __instrumented brand");
    expect(err.name).toBe("ConformanceError");
  });

  it("preserves a stack trace", () => {
    const err = new ConformanceError("test");
    expect(typeof err.stack).toBe("string");
  });
});
  • Step 2: Run test to verify it fails
pnpm --filter @repo/core-shared test conformance/conformance-error

Expected: FAIL (module not found).

  • Step 3: Write conformance-error.ts

Create packages/core-shared/src/conformance/conformance-error.ts with EXACTLY this content:

/**
 * Thrown by `assertFeatureConformance` when a binding does not match the
 * manifest's declared shape. The boot assertion lets this propagate
 * synchronously so `pnpm dev` refuses to start on drift.
 */
export class ConformanceError extends Error {
  constructor(message: string) {
    super(message);
    this.name = "ConformanceError";
    // Maintain a proper prototype chain across down-compilation.
    Object.setPrototypeOf(this, ConformanceError.prototype);
  }
}
  • Step 4: Run test to verify it passes
pnpm --filter @repo/core-shared test conformance/conformance-error

Expected: PASS, 2 tests.

  • Step 5: Commit
git add packages/core-shared/src/conformance/conformance-error.ts packages/core-shared/src/conformance/conformance-error.test.ts
git commit -m "feat(core-shared/conformance): ConformanceError class"

Task 9: Extend conformance barrel with ConformanceError

Brand-runtime exports were added to the barrel in Task 4. This task adds the ConformanceError export. (assertFeatureConformance will be added in Task 10.)

Files:

  • Modify: packages/core-shared/src/conformance/index.ts

  • Step 1: Append the ConformanceError re-export

Add this line to the bottom of packages/core-shared/src/conformance/index.ts:

export { ConformanceError } from "./conformance-error";
  • Step 2: Verify typecheck
pnpm --filter @repo/core-shared typecheck

PASS.

  • Step 3: Commit
git add packages/core-shared/src/conformance/index.ts
git commit -m "feat(core-shared/conformance): re-export ConformanceError"

Task 10: assertFeatureConformance helper

Files:

  • Create: packages/core-shared/src/conformance/assert-bindings.ts

  • Create: packages/core-shared/src/conformance/assert-bindings.test.ts

  • Modify: packages/core-shared/src/conformance/index.ts (one more export)

  • Step 1: Write the failing test

Create packages/core-shared/src/conformance/assert-bindings.test.ts with EXACTLY this content:

import { describe, it, expect, vi } from "vitest";
import "reflect-metadata";
import { Container } from "inversify";
import { defineFeature } from "@/conformance/define-feature";
import { ConformanceError } from "@/conformance/conformance-error";
import { assertFeatureConformance } from "@/conformance/assert-bindings";
import { withSpan } from "@/instrumentation/with-span";
import { withCapture } from "@/instrumentation/with-capture";
import type { ITracer, ISpan, SpanOpts } from "@/instrumentation/tracer.interface";
import type { ILogger } from "@/instrumentation/logger.interface";
import type { BindContext } from "@/di/bind-context";

function makeTracer(): ITracer {
  return {
    startSpan: async (opts: SpanOpts, fn: (span: ISpan) => Promise<unknown>) => {
      const span: ISpan = { setAttribute: () => {}, setStatus: () => {} };
      return fn(span);
    },
  };
}

function makeLogger(): ILogger {
  return {
    captureException: vi.fn(),
    captureMessage: vi.fn(),
    addBreadcrumb: vi.fn(),
    setUser: vi.fn(),
  };
}

function makeCtx(): BindContext {
  return { tracer: makeTracer(), logger: makeLogger() };
}

describe("assertFeatureConformance", () => {
  it("passes when every use case is bound through withSpan + withCapture", () => {
    const container = new Container();
    const sym = Symbol("test.signIn");
    const ctx = makeCtx();
    const bound = withSpan(
      ctx.tracer,
      { name: "test.signIn", op: "use-case" },
      withCapture(ctx.logger, { feature: "test", layer: "use-case" }, async (x: number) => x + 1),
    );
    container.bind(sym).toConstantValue(bound);

    const manifest = defineFeature({
      name: "test",
      requiredCores: [],
      useCases: {
        signIn: { mutates: false, audits: [], publishes: [], consumes: [] },
      },
      realtimeChannels: [],
      jobs: [],
    } as const);

    expect(() =>
      assertFeatureConformance(container, manifest, { signIn: sym }, ctx),
    ).not.toThrow();
  });

  it("throws when a use case binding is missing the __instrumented brand", () => {
    const container = new Container();
    const sym = Symbol("test.signIn");
    const ctx = makeCtx();
    const unwrapped = async (x: number) => x + 1;
    container.bind(sym).toConstantValue(unwrapped);

    const manifest = defineFeature({
      name: "test",
      requiredCores: [],
      useCases: {
        signIn: { mutates: false, audits: [], publishes: [], consumes: [] },
      },
      realtimeChannels: [],
      jobs: [],
    } as const);

    expect(() =>
      assertFeatureConformance(container, manifest, { signIn: sym }, ctx),
    ).toThrow(ConformanceError);
    expect(() =>
      assertFeatureConformance(container, manifest, { signIn: sym }, ctx),
    ).toThrow(/test\.signIn.*__instrumented/);
  });

  it("throws when a use case binding is missing the __captured brand", () => {
    const container = new Container();
    const sym = Symbol("test.signIn");
    const ctx = makeCtx();
    // withSpan-only — no withCapture wrap
    const partial = withSpan(
      ctx.tracer,
      { name: "test.signIn", op: "use-case" },
      async (x: number) => x + 1,
    );
    container.bind(sym).toConstantValue(partial);

    const manifest = defineFeature({
      name: "test",
      requiredCores: [],
      useCases: {
        signIn: { mutates: false, audits: [], publishes: [], consumes: [] },
      },
      realtimeChannels: [],
      jobs: [],
    } as const);

    expect(() =>
      assertFeatureConformance(container, manifest, { signIn: sym }, ctx),
    ).toThrow(/__captured/);
  });

  it("throws when a mutating use case with audits is missing the __audited brand", () => {
    const container = new Container();
    const sym = Symbol("test.signUp");
    const ctx = makeCtx();
    const wrappedNoAudit = withSpan(
      ctx.tracer,
      { name: "test.signUp", op: "use-case" },
      withCapture(ctx.logger, { feature: "test" }, async (x: number) => x + 1),
    );
    container.bind(sym).toConstantValue(wrappedNoAudit);

    const manifest = defineFeature({
      name: "test",
      requiredCores: [],
      useCases: {
        signUp: {
          mutates: true,
          audits: ["user.created"],
          publishes: [],
          consumes: [],
        },
      },
      realtimeChannels: [],
      jobs: [],
    } as const);

    expect(() =>
      assertFeatureConformance(container, manifest, { signUp: sym }, ctx),
    ).toThrow(/__audited/);
  });

  it("passes for a mutating use case with empty audits (no __audited required)", () => {
    const container = new Container();
    const sym = Symbol("test.signUp");
    const ctx = makeCtx();
    const wrappedNoAudit = withSpan(
      ctx.tracer,
      { name: "test.signUp", op: "use-case" },
      withCapture(ctx.logger, { feature: "test" }, async (x: number) => x + 1),
    );
    container.bind(sym).toConstantValue(wrappedNoAudit);

    const manifest = defineFeature({
      name: "test",
      requiredCores: [],
      useCases: {
        signUp: {
          mutates: true,
          audits: [],
          publishes: [],
          consumes: [],
        },
      },
      realtimeChannels: [],
      jobs: [],
    } as const);

    expect(() =>
      assertFeatureConformance(container, manifest, { signUp: sym }, ctx),
    ).not.toThrow();
  });

  it("throws when no symbol is provided for a manifest use case", () => {
    const container = new Container();
    const ctx = makeCtx();
    const manifest = defineFeature({
      name: "test",
      requiredCores: [],
      useCases: {
        signIn: { mutates: false, audits: [], publishes: [], consumes: [] },
      },
      realtimeChannels: [],
      jobs: [],
    } as const);
    expect(() => assertFeatureConformance(container, manifest, {}, ctx)).toThrow(
      /no symbol provided/,
    );
  });

  it("throws when the container cannot resolve the symbol", () => {
    const container = new Container();
    const sym = Symbol("test.signIn");
    const ctx = makeCtx();
    const manifest = defineFeature({
      name: "test",
      requiredCores: [],
      useCases: {
        signIn: { mutates: false, audits: [], publishes: [], consumes: [] },
      },
      realtimeChannels: [],
      jobs: [],
    } as const);
    expect(() =>
      assertFeatureConformance(container, manifest, { signIn: sym }, ctx),
    ).toThrow(ConformanceError);
  });
});
  • Step 2: Run test to verify it fails
pnpm --filter @repo/core-shared test conformance/assert-bindings

Expected: FAIL (module not found).

  • Step 3: Write assert-bindings.ts

Create packages/core-shared/src/conformance/assert-bindings.ts with EXACTLY this content:

import type { Container } from "inversify";
import type { FeatureManifest } from "./define-feature";
import { isInstrumented, isCaptured, isAudited } from "./brand-runtime";
import { ConformanceError } from "./conformance-error";
import type { BindContext } from "../di/bind-context";

/**
 * Runtime check that every manifest-declared use case is bound through the
 * brand-attaching wrappers (`withSpan` → `__instrumented`,
 * `withCapture` → `__captured`, `withAudit` → `__audited` when required).
 *
 * Called at the tail of each feature's `bindProductionX(ctx)` so:
 *   - `pnpm dev` refuses to boot on drift (synchronous throw)
 *   - The check runs once per feature, not per request
 *   - Future apps that wire `bindProductionX` inherit the check for free
 *
 * The `symbols` map is declared inline by the feature's binder; the manifest
 * holds the contract, the binder holds the container symbols. This keeps
 * the manifest free of DI-coupling while letting each feature declare its
 * own wiring keys.
 */
export function assertFeatureConformance(
  container: Container,
  manifest: FeatureManifest,
  symbols: Record<string, symbol>,
  _ctx: BindContext,
): void {
  void _ctx; // future: also check ctx.bus / ctx.auditLog presence vs requiredCores
  for (const [name, useCase] of Object.entries(manifest.useCases)) {
    const sym = symbols[name];
    if (!sym) {
      throw new ConformanceError(
        `${manifest.name}.${name}: no symbol provided in symbols map`,
      );
    }
    let bound: unknown;
    try {
      bound = container.get(sym);
    } catch (cause) {
      throw new ConformanceError(
        `${manifest.name}.${name}: container could not resolve symbol (${String(cause)})`,
      );
    }
    if (!isInstrumented(bound)) {
      throw new ConformanceError(
        `${manifest.name}.${name}: missing __instrumented brand — was withSpan applied at bind time?`,
      );
    }
    if (!isCaptured(bound)) {
      throw new ConformanceError(
        `${manifest.name}.${name}: missing __captured brand — was withCapture applied at bind time?`,
      );
    }
    if (useCase.mutates && useCase.audits.length > 0) {
      if (!isAudited(bound)) {
        throw new ConformanceError(
          `${manifest.name}.${name}: declares audits but binding is missing __audited brand — was withAudit applied at bind time?`,
        );
      }
    }
  }
}
  • Step 4: Re-export assertFeatureConformance from the conformance barrel

Append to packages/core-shared/src/conformance/index.ts:

export { assertFeatureConformance } from "./assert-bindings";
  • Step 5: Run tests and typecheck
pnpm --filter @repo/core-shared typecheck
pnpm --filter @repo/core-shared test conformance/assert-bindings

Both PASS. 7 tests green.

  • Step 6: Commit
git add packages/core-shared/src/conformance/assert-bindings.ts packages/core-shared/src/conformance/assert-bindings.test.ts packages/core-shared/src/conformance/index.ts
git commit -m "feat(core-shared/conformance): assertFeatureConformance helper"

Task 11: Wire assertFeatureConformance into bindProductionAuth

Files:

  • Modify: packages/auth/src/di/bind-production.ts

  • Step 1: Add the imports

Open packages/auth/src/di/bind-production.ts. Add these two import lines alongside the existing imports at the top:

import { assertFeatureConformance } from "@repo/core-shared/conformance";
import { authManifest } from "../feature.manifest";

(The AuthManifest type import added in milestone i Task 11 stays as-is.)

  • Step 2: Call the assertion at the tail

At the very end of the bindProductionAuth(ctx) function body — AFTER all bindings have been registered and AFTER the existing // <gen:event-handlers> / // <gen:jobs> / // <gen:realtime-handlers> anchor comments — add:

  // Boot-time conformance check: refuses to start if any use-case binding
  // is missing a required brand (withSpan / withCapture / withAudit).
  assertFeatureConformance(
    authContainer,
    authManifest,
    {
      signIn: AUTH_SYMBOLS.ISignInUseCase,
      signUp: AUTH_SYMBOLS.ISignUpUseCase,
      signOut: AUTH_SYMBOLS.ISignOutUseCase,
    },
    ctx,
  );

The closing } of the function should come immediately after.

  • Step 3: Run typecheck and tests
pnpm --filter @repo/auth typecheck
pnpm --filter @repo/auth test

Both PASS. 81 tests green, no regressions.

  • Step 4: Verify web-next boots cleanly
pnpm --filter @repo/web-next test

PASS. The existing bind-production.test.ts exercises bindAllDevSeed / bindAllProduction; both should now silently pass the conformance assertion for auth.

  • Step 5: Commit
git add packages/auth/src/di/bind-production.ts
git commit -m "feat(auth): bindProductionAuth self-asserts conformance at tail"

Task 12: Final verification + story closeout

Files:

  • Modify: docs/work/conformance-system-v1/02-boot-assertions/_story.md

  • Modify: docs/work/conformance-system-v1/_epic.md

  • Step 1: Run the full verification matrix

pnpm typecheck
pnpm test
pnpm lint
pnpm turbo boundaries

All four MUST pass. If any fail, STOP and report — do not attempt to fix in this task.

  • Step 2: Tick the story's task checkboxes and flip status

Edit docs/work/conformance-system-v1/02-boot-assertions/_story.md:

(a) Change frontmatter status: in-progressstatus: done.

(b) Change all 11 - [ ] task checkboxes in the Tasks section to - [x]:

## Tasks
- [x] Re-export `authManifest` from auth root barrel
- [x] TODO breadcrumb in `withAudit` pointing at future automation
- [x] Runtime marker helpers (`attachBrand`, `isInstrumented`, `isCaptured`, `isAudited`)
- [x] `withSpan` attaches runtime `__instrumented` marker
- [x] `withCapture` attaches runtime `__captured` marker
- [x] `withAudit` wraps + attaches runtime `__audited` marker
- [x] `ConformanceError` class
- [x] `assertFeatureConformance` helper + tests
- [x] Conformance barrel + subpath exports updated
- [x] `bindProductionAuth` self-asserts at the tail
- [x] Final verification + story closeout
  • Step 3: Tick story 02 in the epic

Edit docs/work/conformance-system-v1/_epic.md. Change:

- [ ] 02 — `assertConformance` + boot wiring (later plan)

to:

- [x] [02 — `assertFeatureConformance` + boot wiring](02-boot-assertions/_story.md)

(Note: changes the text to a proper link AND ticks the checkbox in one edit.)

  • Step 4: Commit the milestone close
git add docs/work/conformance-system-v1/02-boot-assertions/_story.md docs/work/conformance-system-v1/_epic.md
git commit -m "docs(work): close story 02 — assertFeatureConformance + boot wiring"

Done — what this leaves behind

  • attachBrand / isInstrumented / isCaptured / isAudited in @repo/core-shared/conformance (non-enumerable runtime markers)
  • ConformanceError class
  • assertFeatureConformance(container, manifest, symbols, ctx) helper
  • withSpan / withCapture / withAudit all attach their runtime brand
  • withAudit upgraded from passthrough to thin-wrapper (preserves input function purity)
  • authManifest exposed at packages/auth/src/index.ts
  • bindProductionAuth self-asserts conformance at its tail
  • pnpm dev (which calls bindAllDevSeedbindDevSeedAuth → currently does NOT call bindProductionAuth, so this story does not yet break dev seed even if the assertion would fail; production paths via bindProductionAuth are covered)
  • All gates green (typecheck, test, lint, boundaries)

What comes next (separate plans)

  • Milestone iii — AST-aware ESLint rules. Five rules in @repo/core-eslint: manifest-usecase-signature-matches, no-undeclared-event-publish, no-undeclared-audit, required-cores-installed, feature-must-have-manifest. Read the manifest, walk the use-case AST, surface drift in the editor.
  • Milestone iv — CI drift gate. pnpm conformance aggregates event closure, generator drift, required-cores ↔ workspace mismatch.
  • Generator updates. turbo gen feature emits feature.manifest.ts + contracts stubs + test stubs in canonical shape; CI re-runs and diffs.
  • Apply the conformance pattern to blog, media, navigation, marketing-pages. Each gets its own manifest + self-asserting bind-production (1 small plan per feature, or one bundled plan).
  • Dev-seed slot typing. Extend ProductionUseCase<I, O, M> (or define a sibling DevSeedUseCase<...>) to bind-dev-seed.ts paths so the same drift catches in dev mode.
  • Future: withAudit automation. Wire automated audit emission from manifest audits[] declarations (deferred per TODO in withAudit).