feat(core-audit): withAudit wrapper + Audited<F> brand

This commit is contained in:
2026-05-12 21:40:28 +02:00
parent c7bd9a2f8a
commit 103e06d20a
3 changed files with 71 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
import type { IAuditLog } from "./audit-log.interface";
/**
* 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.
*/
export type Audited<F> = F & { readonly __audited: true };
/**
* Use-case wrapper applied at DI bind time. In milestone i this is a
* brand-only attachment: it does not yet automatically call `auditLog.record`.
* Use cases continue to call `auditLog.record(...)` in their own bodies; the
* wrapper exists to make "binding was bound through the audit-aware path"
* type-checkable at compile time.
*
* A future story may move auditing logic out of factory bodies and into the
* wrapper itself (driven by manifest declarations) — but that requires the
* manifest's `audits[]` entries to fully specify what gets recorded, which
* is out of scope here.
*/
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>>;
}