@semiont/core 0.5.26 → 0.5.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-FMFOBVTE.js → chunk-CUPZGI7I.js} +8 -3
- package/dist/chunk-CUPZGI7I.js.map +1 -0
- package/dist/{chunk-XQTWEBJ5.js → chunk-JWTQJVKM.js} +35 -27
- package/dist/chunk-JWTQJVKM.js.map +1 -0
- package/dist/{chunk-I3ZOWCTH.js → chunk-PPUO5IPX.js} +6 -5
- package/dist/chunk-PPUO5IPX.js.map +1 -0
- package/dist/chunk-YLJ4XMA6.js +33 -0
- package/dist/chunk-YLJ4XMA6.js.map +1 -0
- package/dist/config/node-config-loader.d.ts +2 -2
- package/dist/config/node-config-loader.js +2 -1
- package/dist/config/node-config-loader.js.map +1 -1
- package/dist/index.d.ts +434 -117
- package/dist/index.js +33 -14
- package/dist/index.js.map +1 -1
- package/dist/openapi.d.ts +716 -0
- package/dist/openapi.js +46283 -0
- package/dist/openapi.js.map +1 -0
- package/dist/testing/axioms.js +3 -2
- package/dist/testing/axioms.js.map +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +3 -2
- package/package.json +12 -6
- package/dist/chunk-FMFOBVTE.js.map +0 -1
- package/dist/chunk-I3ZOWCTH.js.map +0 -1
- package/dist/chunk-XQTWEBJ5.js.map +0 -1
package/dist/testing/axioms.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { FaultyTransport } from '../chunk-
|
|
2
|
-
import '../chunk-
|
|
1
|
+
import { FaultyTransport } from '../chunk-PPUO5IPX.js';
|
|
2
|
+
import '../chunk-CUPZGI7I.js';
|
|
3
|
+
import '../chunk-YLJ4XMA6.js';
|
|
3
4
|
import * as fc2 from 'fast-check';
|
|
4
5
|
import { Subject } from 'rxjs';
|
|
5
6
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/state-unit-axioms.ts","../../src/liveness-axioms.ts"],"names":["fc"],"mappings":"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","file":"axioms.js","sourcesContent":["/**\n * Executable enforcement of the StateUnit pattern — the runtime twin of\n * `packages/sdk/docs/STATE-UNITS.md` and the ledger in\n * `.plans/STATE-UNIT-AXIOMS.md`. The `StateUnit` interface's own comment notes\n * the pattern is convention; this file makes it executable.\n *\n * `assertStateUnitAxioms(spec)` runs every applicable axiom against a factory in\n * one shot, throwing a labeled Error on the first violation (the axiom id is in\n * the message). It is framework-agnostic on purpose — only `rxjs` + `fast-check`,\n * no `vitest` — so it ships through `@semiont/core/testing` and any package's test\n * runner can invoke it from a single `it(...)` per state unit. It lives in core\n * (not sdk) so even packages below sdk (e.g. `http-transport`) can use it without\n * a dependency cycle.\n *\n * Axioms (random-input dimension; fast-check):\n * A5 dispose() is idempotent and total (n ∈ [1,20] calls never throw)\n * A5b post-dispose inertness — every public method is a no-op after dispose\n * A6 every pre-dispose subscriber (k ∈ [1,10]) sees `complete` on dispose\n * X3-runtime instance isolation — driving one instance never moves another's surfaces\n * Structural assertions (single-shot):\n * A1 plain-object identity (no class instance)\n * X1 no raw Subject on the public surface\n * A7-passed disposing the unit must NOT dispose an injected dependency\n * A7-owned disposing the unit MUST dispose its internally-constructed children\n */\n\nimport * as fc from 'fast-check';\nimport { Subject, type Observable } from 'rxjs';\nimport type { StateUnit } from './state-unit';\n\n/**\n * A disposable stand-in for an injected dependency. Pass one as a unit's\n * constructor arg, then list it in `setup().passedIn` so A7-passed can assert\n * the unit never disposed it. Counts calls so A7-passed also holds under the\n * repeated-dispose stress of A5.\n */\nexport interface DisposeProbe extends StateUnit {\n readonly disposeCount: number;\n}\n\nexport function disposeProbe(): DisposeProbe {\n let n = 0;\n return {\n dispose() { n += 1; },\n get disposeCount() { return n; },\n };\n}\n\ntype SetupResult<T extends StateUnit> =\n | T\n | { unit: T; passedIn?: readonly DisposeProbe[]; teardown?: () => void };\n\nexport interface StateUnitAxiomSpec<T extends StateUnit> {\n /**\n * Build a FRESH unit. Called many times (fast-check re-runs), so it must\n * return an independent instance each call. Return the bare unit, or an object\n * carrying the injected `passedIn` probes (A7-passed) and a `teardown` to\n * release per-instance resources (e.g. a mock bus).\n */\n setup: () => SetupResult<T>;\n /** Owned public Observables — Subjects the unit completes on dispose (A6, X3, post-dispose inertness). */\n surfaces?: (unit: T) => readonly Observable<unknown>[];\n /** Public input methods as zero-arg callers (A5b post-dispose, X3 drive). */\n invocations?: (unit: T) => readonly (() => unknown)[];\n /** Surfaces of internally-constructed children — must complete when the outer disposes (A7-owned). */\n ownedChildSurfaces?: (unit: T) => readonly Observable<unknown>[];\n /** fast-check run budget per property (default 30). */\n numRuns?: number;\n}\n\ninterface Normalized<T extends StateUnit> {\n unit: T;\n passedIn: readonly DisposeProbe[];\n teardown: () => void;\n}\n\nfunction normalize<T extends StateUnit>(r: SetupResult<T>): Normalized<T> {\n if (r && typeof r === 'object' && 'unit' in r) {\n return { unit: r.unit, passedIn: r.passedIn ?? [], teardown: r.teardown ?? (() => {}) };\n }\n return { unit: r as T, passedIn: [], teardown: () => {} };\n}\n\nfunction swallowAsync(value: unknown): void {\n if (value && typeof value === 'object' && typeof (value as { then?: unknown }).then === 'function') {\n (value as Promise<unknown>).then(undefined, () => {});\n }\n}\n\n/**\n * Run every applicable axiom against `spec`. Throws a labeled Error on the first\n * violation. Axioms whose accessors are omitted are skipped (e.g. A7-passed\n * runs only when `setup` returns `passedIn`; A6 only when `surfaces` is given).\n */\nexport function assertStateUnitAxioms<T extends StateUnit>(spec: StateUnitAxiomSpec<T>): void {\n const numRuns = spec.numRuns ?? 30;\n const fresh = (): Normalized<T> => normalize(spec.setup());\n\n // fast-check's default falsification message is just \"Property failed after N\n // tests {seed}\" — it drops the thrown axiom id. Prepend the axiom so a real\n // failure names itself; the seed/shrink detail is preserved.\n const run = (axiom: string, prop: Parameters<typeof fc.assert>[0]): void => {\n try {\n fc.assert(prop, { numRuns });\n } catch (e) {\n throw new Error(`${axiom}: ${e instanceof Error ? e.message : String(e)}`);\n }\n };\n\n // A1 — plain-object identity (no class instance).\n {\n const { unit, teardown } = fresh();\n const proto = Object.getPrototypeOf(unit);\n if (proto !== Object.prototype && proto !== null) {\n throw new Error('A1: state unit is not a plain object (has a class prototype)');\n }\n unit.dispose();\n teardown();\n }\n\n // X1 — no raw *origin* Subject on the public surface (expose `.asObservable()`).\n // Flag only origin Subjects — `new Subject` / `new BehaviorSubject`, the unit's own\n // state, where `.source` is undefined. Derived `AnonymousSubject`s from `Subject.lift`\n // (`shareReplay().pipe(...)`) carry a `.source` and are inert sinks (`.next()` does\n // nothing useful) — idiomatic, not the forgotten-internal-Subject smell — so exclude them.\n {\n const { unit, teardown } = fresh();\n for (const [key, value] of Object.entries(unit)) {\n if (value instanceof Subject && (value as { source?: unknown }).source === undefined) {\n throw new Error(`X1: public field \"${key}\" is a raw Subject — expose it via .asObservable()`);\n }\n }\n unit.dispose();\n teardown();\n }\n\n // A7-passed — disposing the unit must NOT dispose an injected dependency.\n {\n const { unit, passedIn, teardown } = fresh();\n unit.dispose();\n passedIn.forEach((probe, i) => {\n if (probe.disposeCount > 0) {\n throw new Error(`A7-passed: the unit disposed injected dependency #${i} (it doesn't own it)`);\n }\n });\n teardown();\n }\n\n // A5 — dispose() idempotent & total: n calls never throw; injected deps stay untouched.\n run('A5', fc.property(fc.integer({ min: 1, max: 20 }), (n) => {\n const { unit, passedIn, teardown } = fresh();\n for (let i = 0; i < n; i++) unit.dispose();\n passedIn.forEach((probe, i) => {\n if (probe.disposeCount > 0) {\n throw new Error(`injected dependency #${i} disposed under ${n} dispose() calls`);\n }\n });\n teardown();\n }));\n\n // A6 — k pre-dispose subscribers on each owned surface all see `complete` on dispose.\n if (spec.surfaces) {\n const surfaces = spec.surfaces;\n run('A6', fc.property(fc.integer({ min: 1, max: 10 }), (k) => {\n const { unit, teardown } = fresh();\n const completed: boolean[] = [];\n const subs = surfaces(unit).flatMap((o) =>\n Array.from({ length: k }, () => {\n const idx = completed.push(false) - 1;\n return o.subscribe({ complete: () => { completed[idx] = true; } });\n }),\n );\n unit.dispose();\n completed.forEach((seen, idx) => {\n if (!seen) throw new Error(`a subscriber did not see complete on dispose (k=${k}, sub #${idx})`);\n });\n subs.forEach((s) => s.unsubscribe());\n teardown();\n }));\n }\n\n // A5b — post-dispose inertness: every public method is a no-op (no throw) after dispose.\n if (spec.invocations) {\n const invocations = spec.invocations;\n run('A5b', fc.property(fc.array(fc.nat(), { maxLength: 12 }), (seq) => {\n const { unit, teardown } = fresh();\n const callers = invocations(unit);\n unit.dispose();\n for (const raw of seq) {\n if (callers.length === 0) break;\n swallowAsync(callers[raw % callers.length]());\n }\n teardown();\n }));\n }\n\n // X3-runtime — instance isolation: driving instance A never moves instance B's surfaces.\n if (spec.surfaces && spec.invocations) {\n const surfaces = spec.surfaces;\n const invocations = spec.invocations;\n run('X3-runtime', fc.property(fc.array(fc.nat(), { minLength: 1, maxLength: 8 }), (seq) => {\n const a = fresh();\n const b = fresh();\n const bSurfaces = surfaces(b.unit);\n const bCounts = bSurfaces.map(() => 0);\n const bSubs = bSurfaces.map((o, i) => o.subscribe(() => { bCounts[i] += 1; }));\n const baseline = bCounts.slice(); // initial replay captured synchronously above\n const aCallers = invocations(a.unit);\n for (const raw of seq) {\n if (aCallers.length === 0) break;\n swallowAsync(aCallers[raw % aCallers.length]());\n }\n bCounts.forEach((count, i) => {\n if (count !== baseline[i]) {\n throw new Error(`driving instance A perturbed instance B's surface #${i}`);\n }\n });\n bSubs.forEach((s) => s.unsubscribe());\n a.unit.dispose();\n b.unit.dispose();\n a.teardown();\n b.teardown();\n }));\n }\n\n // A7-owned — internally-constructed children are disposed (their surfaces complete) on outer dispose.\n if (spec.ownedChildSurfaces) {\n const { unit, teardown } = fresh();\n const childSurfaces = spec.ownedChildSurfaces(unit);\n const completed = childSurfaces.map(() => false);\n const subs = childSurfaces.map((o, i) => o.subscribe({ complete: () => { completed[i] = true; } }));\n unit.dispose();\n completed.forEach((seen, i) => {\n if (!seen) throw new Error(`A7-owned: owned child surface #${i} did not complete on outer dispose`);\n });\n subs.forEach((s) => s.unsubscribe());\n teardown();\n }\n\n // Post-dispose surface inertness: a NEW subscription after dispose completes with no `next`.\n if (spec.surfaces) {\n const { unit, teardown } = fresh();\n unit.dispose();\n spec.surfaces(unit).forEach((o, i) => {\n let nexts = 0;\n let done = false;\n o.subscribe({ next: () => { nexts += 1; }, complete: () => { done = true; } }).unsubscribe();\n if (nexts > 0) throw new Error(`A5b/inert: owned surface #${i} emitted a value after dispose`);\n if (!done) throw new Error(`A5b/inert: owned surface #${i} did not complete after dispose`);\n });\n teardown();\n }\n}\n","/**\n * Executable enforcement of the liveness axioms — the runtime twin of\n * `.plans/LIVENESS-AXIOMS.md`, and the composition-level sibling of\n * `assertStateUnitAxioms` (state-unit-axioms.ts). Where the StateUnit axioms\n * make *per-unit* wrongness mechanically detectable, these make *silence*\n * detectable: every existing enforcement tier is safety (nothing wrong is\n * delivered); these assert liveness (something is eventually delivered).\n *\n * Axioms (fault-schedule dimension; fast-check):\n * L1 Subscriber liveness — every output emits next|error within the bound,\n * under any fault schedule. Error is a permitted outcome; the forbidden\n * fourth state is pending-forever.\n * L2 Request settlement — every awaited path settles within the bound;\n * re-issues per logical request stay within the retry budget (B14: one);\n * a faulted request must be re-issued or surfaced, never swallowed.\n * L3 Delivery across lifecycle transitions — every event written to a live\n * connection reaches the output exactly once, wherever a client-initiated\n * transition (handover / reconnect / scope change) lands. Retirement is\n * by drain, never by abort (TRANSPORT-HTTP.md, Abort discipline).\n *\n * Framework-agnostic on purpose — only `rxjs` + `fast-check`, no `vitest` — so\n * it ships through `@semiont/core/testing` and any package's test runner can\n * invoke it. Deterministic virtual time: properties pass a small explicit\n * `timeoutMs` to `busRequest`; no `Date.now`, no 30 s real waits.\n */\n\nimport * as fc from 'fast-check';\nimport type { Observable, Subscription } from 'rxjs';\nimport { FaultyTransport, type FaultAction } from './faulty-transport';\n\n// ── L1/L2: liveness over a composition on FaultyTransport ────────────────\n\n/** What one fresh run of the composition exposes to the axioms. */\nexport interface LivenessScenario {\n /**\n * Live-query-shaped outputs. The harness subscribes each one; every\n * subscription must see `next` or `error` within the bound (L1).\n */\n outputs: readonly Observable<unknown>[];\n /**\n * Awaited paths. Each promise must settle — resolve or reject — within the\n * bound (L2). Rejections are fine; pending-forever is the violation.\n */\n settlements?: readonly Promise<unknown>[];\n teardown?: () => void;\n}\n\nexport interface LivenessAxiomSpec {\n /** Build a FRESH composition wired to the given transport. Called per run. */\n setup: (transport: FaultyTransport) => LivenessScenario | Promise<LivenessScenario>;\n /**\n * The timeoutMs the scenario passes to `busRequest` — the bound is derived\n * from it: (timeoutMs × (1 + retryBudget) + Σdelays) × slackFactor.\n */\n timeoutMs: number;\n /** Max sanctioned re-issues per logical request (B14 budget). Default 1. */\n retryBudget?: number;\n /** Override the generated fault schedules (teeth tests pin one). */\n scheduleArb?: fc.Arbitrary<readonly FaultAction[]>;\n /** Passed through to FaultyTransport (reply synthesis). */\n makeResponse?: (operation: string, payload: Record<string, unknown>) => unknown;\n /** fast-check run budget (default 25 — CI-fast; crank locally). */\n numRuns?: number;\n /** Real-scheduler jitter headroom on the bound (default 4×). */\n slackFactor?: number;\n}\n\n/** The five wire behaviors, uniformly weighted; delays stay small (≤5 ms). */\nexport function arbFaultAction(): fc.Arbitrary<FaultAction> {\n return fc.oneof(\n fc.constant<FaultAction>({ kind: 'deliver' }),\n fc.constant<FaultAction>({ kind: 'drop-reply' }),\n fc.integer({ min: 0, max: 5 }).map((ms): FaultAction => ({ kind: 'delay', ms })),\n fc.constant<FaultAction>({ kind: 'duplicate-reply' }),\n fc.constant<FaultAction>({ kind: 'reject-emit' }),\n );\n}\n\nexport function arbFaultSchedule(maxLength = 8): fc.Arbitrary<readonly FaultAction[]> {\n return fc.array(arbFaultAction(), { minLength: 1, maxLength });\n}\n\nfunction describeSchedule(schedule: readonly FaultAction[]): string {\n return schedule.map((a) => (a.kind === 'delay' ? `delay(${a.ms})` : a.kind)).join(',');\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Sibling of state-unit-axioms' `run`, adapted for properties that check more\n * than one axiom: fast-check's falsification message carries the seed and\n * counterexample but not the thrown axiom id (fc v4 moves the inner error to\n * `cause`), so the property captures its own labeled violation into `slot`\n * and the wrapper re-throws with the axiom id leading and fc's detail after.\n */\nasync function runLabeled(\n fallback: string,\n slot: { violation: Error | null },\n assertion: () => Promise<void>,\n): Promise<void> {\n try {\n await assertion();\n } catch (e) {\n const detail = e instanceof Error ? e.message : String(e);\n if (slot.violation) throw new Error(`${slot.violation.message}\\n${detail}`);\n throw new Error(`${fallback}: ${detail}`);\n }\n}\n\n/** Wrap a check block so its labeled throw lands in `slot` before falsifying. */\nfunction capturing(slot: { violation: Error | null }, block: () => void): void {\n try {\n block();\n } catch (e) {\n slot.violation = e instanceof Error ? e : new Error(String(e));\n throw e;\n }\n}\n\n/**\n * Run L1 + L2 against `spec` across generated fault schedules. Throws a\n * labeled Error (`L1: …` / `L2: …`) on the first violation.\n */\nexport async function assertLivenessAxioms(spec: LivenessAxiomSpec): Promise<void> {\n const retryBudget = spec.retryBudget ?? 1;\n const slack = spec.slackFactor ?? 4;\n const scheduleArb = spec.scheduleArb ?? arbFaultSchedule();\n\n const slot = { violation: null as Error | null };\n await runLabeled('liveness', slot, () =>\n fc.assert(\n fc.asyncProperty(scheduleArb, async (schedule) => {\n const delayTotal = schedule.reduce((n, a) => n + (a.kind === 'delay' ? a.ms : 0), 0);\n const bound = (spec.timeoutMs * (1 + retryBudget) + delayTotal) * slack;\n const transport = new FaultyTransport({\n schedule,\n ...(spec.makeResponse ? { makeResponse: spec.makeResponse } : {}),\n });\n const scenario = await spec.setup(transport);\n const outputs = scenario.outputs;\n const settlements = scenario.settlements ?? [];\n\n // Subscribe every output (that's what makes a live query live) and\n // track notifications; track settlement of every awaited path.\n const notified: boolean[] = outputs.map(() => false);\n const settled: boolean[] = settlements.map(() => false);\n let doneResolve: () => void = () => {};\n const allDone = new Promise<void>((resolve) => { doneResolve = resolve; });\n const check = (): void => {\n if (notified.every(Boolean) && settled.every(Boolean)) doneResolve();\n };\n const subs: Subscription[] = outputs.map((o, i) =>\n o.subscribe({\n next: () => { notified[i] = true; check(); },\n error: () => { notified[i] = true; check(); },\n }),\n );\n settlements.forEach((p, i) => {\n p.then(() => { settled[i] = true; check(); },\n () => { settled[i] = true; check(); });\n });\n check();\n\n // Wait for full liveness or the bound, whichever first.\n await Promise.race([allDone, sleep(bound)]);\n\n try {\n // L2 first: when it applies it names the mechanism (swallow, budget,\n // unsettled await); L1 below is the broader every-output net. All-\n // outputs-silent is a subset of any-output-silent, so checking L1\n // first would shadow the sharper L2 diagnoses entirely.\n capturing(slot, () => {\n // L2 — settlement: every awaited path settled.\n settled.forEach((seen, i) => {\n if (!seen) {\n throw new Error(\n `L2: settlement #${i} did not settle within ${bound}ms ` +\n `under schedule ⟨${describeSchedule(schedule)}⟩ — the forbidden fourth state`,\n );\n }\n });\n\n // L2 — retry accounting over the transport's request log.\n const issues = new Map<string, { count: number; lastFaulted: boolean }>();\n for (const entry of transport.requestLog) {\n const prior = issues.get(entry.retryKey) ?? { count: 0, lastFaulted: false };\n issues.set(entry.retryKey, {\n count: prior.count + 1,\n lastFaulted: entry.action.kind === 'drop-reply' || entry.action.kind === 'reject-emit',\n });\n }\n for (const [key, { count, lastFaulted }] of issues) {\n if (count > 1 + retryBudget) {\n throw new Error(\n `L2: request ⟨${key}⟩ issued ${count} times — exceeds the retry budget ` +\n `(1 + ${retryBudget}) under schedule ⟨${describeSchedule(schedule)}⟩`,\n );\n }\n // Swallow detection: the final issue of a logical request was\n // faulted, the composition had retry budget left but didn't use\n // it, and no output surfaced anything — the rejection went into\n // a void (the pre-B14 `catch(() => {})`).\n if (lastFaulted && count <= retryBudget && outputs.length > 0 && !notified.some(Boolean)) {\n throw new Error(\n `L2: faulted request ⟨${key}⟩ was neither re-issued nor surfaced ` +\n `under schedule ⟨${describeSchedule(schedule)}⟩ — rejection swallowed`,\n );\n }\n }\n\n // L1 — every subscription saw next|error; pending-forever is the bug.\n notified.forEach((seen, i) => {\n if (!seen) {\n throw new Error(\n `L1: output #${i} received no next/error within ${bound}ms ` +\n `under schedule ⟨${describeSchedule(schedule)}⟩ — silently pending`,\n );\n }\n });\n });\n } finally {\n subs.forEach((s) => s.unsubscribe());\n scenario.teardown?.();\n transport.dispose();\n }\n }),\n { numRuns: spec.numRuns ?? 25 },\n ),\n );\n}\n\n// ── L3: exactly-once delivery across client-initiated transitions ────────\n\n/**\n * A connection-stream-shaped subject: something that accepts writes to the\n * live connection, can be told to transition (handover / reconnect / scope\n * change), and exposes the subscriber-facing output. P3 adapts the real\n * actor's mock-connection harness to this shape; the teeth tests drive\n * reconstructed pre-fix doubles.\n */\nexport interface DeliverySubject {\n /** Write the event with this id to the currently-live connection. */\n write: (eventId: string) => void;\n /** Client-initiated lifecycle transition. */\n transition: () => void | Promise<void>;\n /** Subscriber-facing output; each emission is a delivered event id. */\n output$: Observable<string>;\n /**\n * Drain pending asynchronous delivery at end of sequence (a live connection\n * eventually flushes). Default: one macrotask tick.\n */\n settle?: () => Promise<void>;\n teardown?: () => void;\n}\n\nexport type DeliveryOp = 'write' | 'transition';\n\nexport interface DeliveryAxiomSpec {\n /** Build a FRESH subject. Called per run. */\n setup: () => DeliverySubject;\n /** Override the generated op sequences (teeth tests pin one). */\n opsArb?: fc.Arbitrary<readonly DeliveryOp[]>;\n /** Max generated sequence length (default 12). */\n maxOps?: number;\n /** fast-check run budget (default 50 — these runs are cheap). */\n numRuns?: number;\n}\n\nexport function arbDeliveryOps(maxOps = 12): fc.Arbitrary<readonly DeliveryOp[]> {\n return fc\n .array(fc.constantFrom<DeliveryOp>('write', 'transition'), { minLength: 1, maxLength: maxOps })\n // A sequence with no write asserts nothing — always exercise delivery.\n .map((ops) => (ops.includes('write') ? ops : ([...ops, 'write'] as const)));\n}\n\n/**\n * Run L3 against `spec` across generated write/transition interleavings.\n * Throws a labeled Error (`L3: …`) on the first violation: an event written\n * to a live connection delivered zero times (lost — retired by abort instead\n * of drain) or more than once (duplicate).\n */\nexport async function assertExactlyOnceDelivery(spec: DeliveryAxiomSpec): Promise<void> {\n const opsArb = spec.opsArb ?? arbDeliveryOps(spec.maxOps ?? 12);\n\n const slot = { violation: null as Error | null };\n await runLabeled('L3', slot, () =>\n fc.assert(\n fc.asyncProperty(opsArb, async (ops) => {\n const subject = spec.setup();\n const delivered: string[] = [];\n const sub = subject.output$.subscribe((id) => delivered.push(id));\n const written: string[] = [];\n try {\n for (let i = 0; i < ops.length; i++) {\n if (ops[i] === 'write') {\n const id = `e${i}`;\n written.push(id);\n subject.write(id);\n } else {\n await subject.transition();\n }\n // Deliberately no settling between ops: the interesting races are\n // transitions landing before a write's asynchronous delivery.\n }\n await (subject.settle?.() ?? sleep(0));\n\n capturing(slot, () => {\n for (const id of written) {\n const n = delivered.filter((d) => d === id).length;\n if (n === 0) {\n throw new Error(\n `L3: event ⟨${id}⟩ delivered 0 times under ⟨${ops.join(',')}⟩ — ` +\n `lost across a transition (retire by drain, never by abort)`,\n );\n }\n if (n > 1) {\n throw new Error(\n `L3: event ⟨${id}⟩ delivered ${n} times under ⟨${ops.join(',')}⟩ — duplicate delivery`,\n );\n }\n }\n });\n } finally {\n sub.unsubscribe();\n subject.teardown?.();\n }\n }),\n { numRuns: spec.numRuns ?? 50 },\n ),\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/state-unit-axioms.ts","../../src/liveness-axioms.ts"],"names":["fc"],"mappings":"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","file":"axioms.js","sourcesContent":["/**\n * Executable enforcement of the StateUnit pattern — the runtime twin of\n * `packages/sdk/docs/STATE-UNITS.md` and the ledger in\n * `.plans/STATE-UNIT-AXIOMS.md`. The `StateUnit` interface's own comment notes\n * the pattern is convention; this file makes it executable.\n *\n * `assertStateUnitAxioms(spec)` runs every applicable axiom against a factory in\n * one shot, throwing a labeled Error on the first violation (the axiom id is in\n * the message). It is framework-agnostic on purpose — only `rxjs` + `fast-check`,\n * no `vitest` — so it ships through `@semiont/core/testing` and any package's test\n * runner can invoke it from a single `it(...)` per state unit. It lives in core\n * (not sdk) so even packages below sdk (e.g. `http-transport`) can use it without\n * a dependency cycle.\n *\n * Axioms (random-input dimension; fast-check):\n * A5 dispose() is idempotent and total (n ∈ [1,20] calls never throw)\n * A5b post-dispose inertness — every public method is a no-op after dispose\n * A6 every pre-dispose subscriber (k ∈ [1,10]) sees `complete` on dispose\n * X3-runtime instance isolation — driving one instance never moves another's surfaces\n * Structural assertions (single-shot):\n * A1 plain-object identity (no class instance)\n * X1 no raw Subject on the public surface\n * A7-passed disposing the unit must NOT dispose an injected dependency\n * A7-owned disposing the unit MUST dispose its internally-constructed children\n */\n\nimport * as fc from 'fast-check';\nimport { Subject, type Observable } from 'rxjs';\nimport type { StateUnit } from './state-unit';\n\n/**\n * A disposable stand-in for an injected dependency. Pass one as a unit's\n * constructor arg, then list it in `setup().passedIn` so A7-passed can assert\n * the unit never disposed it. Counts calls so A7-passed also holds under the\n * repeated-dispose stress of A5.\n */\nexport interface DisposeProbe extends StateUnit {\n readonly disposeCount: number;\n}\n\nexport function disposeProbe(): DisposeProbe {\n let n = 0;\n return {\n dispose() { n += 1; },\n get disposeCount() { return n; },\n };\n}\n\ntype SetupResult<T extends StateUnit> =\n | T\n | { unit: T; passedIn?: readonly DisposeProbe[]; teardown?: () => void };\n\nexport interface StateUnitAxiomSpec<T extends StateUnit> {\n /**\n * Build a FRESH unit. Called many times (fast-check re-runs), so it must\n * return an independent instance each call. Return the bare unit, or an object\n * carrying the injected `passedIn` probes (A7-passed) and a `teardown` to\n * release per-instance resources (e.g. a mock bus).\n */\n setup: () => SetupResult<T>;\n /** Owned public Observables — Subjects the unit completes on dispose (A6, X3, post-dispose inertness). */\n surfaces?: (unit: T) => readonly Observable<unknown>[];\n /** Public input methods as zero-arg callers (A5b post-dispose, X3 drive). */\n invocations?: (unit: T) => readonly (() => unknown)[];\n /** Surfaces of internally-constructed children — must complete when the outer disposes (A7-owned). */\n ownedChildSurfaces?: (unit: T) => readonly Observable<unknown>[];\n /** fast-check run budget per property (default 30). */\n numRuns?: number;\n}\n\ninterface Normalized<T extends StateUnit> {\n unit: T;\n passedIn: readonly DisposeProbe[];\n teardown: () => void;\n}\n\nfunction normalize<T extends StateUnit>(r: SetupResult<T>): Normalized<T> {\n if (r && typeof r === 'object' && 'unit' in r) {\n return { unit: r.unit, passedIn: r.passedIn ?? [], teardown: r.teardown ?? (() => {}) };\n }\n return { unit: r as T, passedIn: [], teardown: () => {} };\n}\n\nfunction swallowAsync(value: unknown): void {\n if (value && typeof value === 'object' && typeof (value as { then?: unknown }).then === 'function') {\n (value as Promise<unknown>).then(undefined, () => {});\n }\n}\n\n/**\n * Run every applicable axiom against `spec`. Throws a labeled Error on the first\n * violation. Axioms whose accessors are omitted are skipped (e.g. A7-passed\n * runs only when `setup` returns `passedIn`; A6 only when `surfaces` is given).\n */\nexport function assertStateUnitAxioms<T extends StateUnit>(spec: StateUnitAxiomSpec<T>): void {\n const numRuns = spec.numRuns ?? 30;\n const fresh = (): Normalized<T> => normalize(spec.setup());\n\n // fast-check's default falsification message is just \"Property failed after N\n // tests {seed}\" — it drops the thrown axiom id. Prepend the axiom so a real\n // failure names itself; the seed/shrink detail is preserved.\n const run = (axiom: string, prop: Parameters<typeof fc.assert>[0]): void => {\n try {\n fc.assert(prop, { numRuns });\n } catch (e) {\n throw new Error(`${axiom}: ${e instanceof Error ? e.message : String(e)}`);\n }\n };\n\n // A1 — plain-object identity (no class instance).\n {\n const { unit, teardown } = fresh();\n const proto = Object.getPrototypeOf(unit);\n if (proto !== Object.prototype && proto !== null) {\n throw new Error('A1: state unit is not a plain object (has a class prototype)');\n }\n unit.dispose();\n teardown();\n }\n\n // X1 — no raw *origin* Subject on the public surface (expose `.asObservable()`).\n // Flag only origin Subjects — `new Subject` / `new BehaviorSubject`, the unit's own\n // state, where `.source` is undefined. Derived `AnonymousSubject`s from `Subject.lift`\n // (`shareReplay().pipe(...)`) carry a `.source` and are inert sinks (`.next()` does\n // nothing useful) — idiomatic, not the forgotten-internal-Subject smell — so exclude them.\n {\n const { unit, teardown } = fresh();\n for (const [key, value] of Object.entries(unit)) {\n if (value instanceof Subject && (value as { source?: unknown }).source === undefined) {\n throw new Error(`X1: public field \"${key}\" is a raw Subject — expose it via .asObservable()`);\n }\n }\n unit.dispose();\n teardown();\n }\n\n // A7-passed — disposing the unit must NOT dispose an injected dependency.\n {\n const { unit, passedIn, teardown } = fresh();\n unit.dispose();\n passedIn.forEach((probe, i) => {\n if (probe.disposeCount > 0) {\n throw new Error(`A7-passed: the unit disposed injected dependency #${i} (it doesn't own it)`);\n }\n });\n teardown();\n }\n\n // A5 — dispose() idempotent & total: n calls never throw; injected deps stay untouched.\n run('A5', fc.property(fc.integer({ min: 1, max: 20 }), (n) => {\n const { unit, passedIn, teardown } = fresh();\n for (let i = 0; i < n; i++) unit.dispose();\n passedIn.forEach((probe, i) => {\n if (probe.disposeCount > 0) {\n throw new Error(`injected dependency #${i} disposed under ${n} dispose() calls`);\n }\n });\n teardown();\n }));\n\n // A6 — k pre-dispose subscribers on each owned surface all see `complete` on dispose.\n if (spec.surfaces) {\n const surfaces = spec.surfaces;\n run('A6', fc.property(fc.integer({ min: 1, max: 10 }), (k) => {\n const { unit, teardown } = fresh();\n const completed: boolean[] = [];\n const subs = surfaces(unit).flatMap((o) =>\n Array.from({ length: k }, () => {\n const idx = completed.push(false) - 1;\n return o.subscribe({ complete: () => { completed[idx] = true; } });\n }),\n );\n unit.dispose();\n completed.forEach((seen, idx) => {\n if (!seen) throw new Error(`a subscriber did not see complete on dispose (k=${k}, sub #${idx})`);\n });\n subs.forEach((s) => s.unsubscribe());\n teardown();\n }));\n }\n\n // A5b — post-dispose inertness: every public method is a no-op (no throw) after dispose.\n if (spec.invocations) {\n const invocations = spec.invocations;\n run('A5b', fc.property(fc.array(fc.nat(), { maxLength: 12 }), (seq) => {\n const { unit, teardown } = fresh();\n const callers = invocations(unit);\n unit.dispose();\n for (const raw of seq) {\n if (callers.length === 0) break;\n swallowAsync(callers[raw % callers.length]());\n }\n teardown();\n }));\n }\n\n // X3-runtime — instance isolation: driving instance A never moves instance B's surfaces.\n if (spec.surfaces && spec.invocations) {\n const surfaces = spec.surfaces;\n const invocations = spec.invocations;\n run('X3-runtime', fc.property(fc.array(fc.nat(), { minLength: 1, maxLength: 8 }), (seq) => {\n const a = fresh();\n const b = fresh();\n const bSurfaces = surfaces(b.unit);\n const bCounts = bSurfaces.map(() => 0);\n const bSubs = bSurfaces.map((o, i) => o.subscribe(() => { bCounts[i] += 1; }));\n const baseline = bCounts.slice(); // initial replay captured synchronously above\n const aCallers = invocations(a.unit);\n for (const raw of seq) {\n if (aCallers.length === 0) break;\n swallowAsync(aCallers[raw % aCallers.length]());\n }\n bCounts.forEach((count, i) => {\n if (count !== baseline[i]) {\n throw new Error(`driving instance A perturbed instance B's surface #${i}`);\n }\n });\n bSubs.forEach((s) => s.unsubscribe());\n a.unit.dispose();\n b.unit.dispose();\n a.teardown();\n b.teardown();\n }));\n }\n\n // A7-owned — internally-constructed children are disposed (their surfaces complete) on outer dispose.\n if (spec.ownedChildSurfaces) {\n const { unit, teardown } = fresh();\n const childSurfaces = spec.ownedChildSurfaces(unit);\n const completed = childSurfaces.map(() => false);\n const subs = childSurfaces.map((o, i) => o.subscribe({ complete: () => { completed[i] = true; } }));\n unit.dispose();\n completed.forEach((seen, i) => {\n if (!seen) throw new Error(`A7-owned: owned child surface #${i} did not complete on outer dispose`);\n });\n subs.forEach((s) => s.unsubscribe());\n teardown();\n }\n\n // Post-dispose surface inertness: a NEW subscription after dispose completes with no `next`.\n if (spec.surfaces) {\n const { unit, teardown } = fresh();\n unit.dispose();\n spec.surfaces(unit).forEach((o, i) => {\n let nexts = 0;\n let done = false;\n o.subscribe({ next: () => { nexts += 1; }, complete: () => { done = true; } }).unsubscribe();\n if (nexts > 0) throw new Error(`A5b/inert: owned surface #${i} emitted a value after dispose`);\n if (!done) throw new Error(`A5b/inert: owned surface #${i} did not complete after dispose`);\n });\n teardown();\n }\n}\n","/**\n * Executable enforcement of the liveness axioms — the runtime twin of\n * `.plans/LIVENESS-AXIOMS.md`, and the composition-level sibling of\n * `assertStateUnitAxioms` (state-unit-axioms.ts). Where the StateUnit axioms\n * make *per-unit* wrongness mechanically detectable, these make *silence*\n * detectable: every existing enforcement tier is safety (nothing wrong is\n * delivered); these assert liveness (something is eventually delivered).\n *\n * Axioms (fault-schedule dimension; fast-check):\n * L1 Subscriber liveness — every output emits next|error within the bound,\n * under any fault schedule. Error is a permitted outcome; the forbidden\n * fourth state is pending-forever.\n * L2 Request settlement — every awaited path settles within the bound;\n * re-issues per logical request stay within the retry budget (B14: one);\n * a faulted request must be re-issued or surfaced, never swallowed.\n * L3 Delivery across lifecycle transitions — every event written to a live\n * connection reaches the output exactly once, wherever a client-initiated\n * transition (handover / reconnect / scope change) lands. Retirement is\n * by drain, never by abort (TRANSPORT-HTTP.md, Abort discipline).\n *\n * Framework-agnostic on purpose — only `rxjs` + `fast-check`, no `vitest` — so\n * it ships through `@semiont/core/testing` and any package's test runner can\n * invoke it. Deterministic virtual time: properties pass a small explicit\n * `timeoutMs` to `busRequest`; no `Date.now`, no 30 s real waits.\n */\n\nimport * as fc from 'fast-check';\nimport type { Observable, Subscription } from 'rxjs';\nimport { FaultyTransport, type FaultAction } from './faulty-transport';\n\n// ── L1/L2: liveness over a composition on FaultyTransport ────────────────\n\n/** What one fresh run of the composition exposes to the axioms. */\nexport interface LivenessScenario {\n /**\n * Live-query-shaped outputs. The harness subscribes each one; every\n * subscription must see `next` or `error` within the bound (L1).\n */\n outputs: readonly Observable<unknown>[];\n /**\n * Awaited paths. Each promise must settle — resolve or reject — within the\n * bound (L2). Rejections are fine; pending-forever is the violation.\n */\n settlements?: readonly Promise<unknown>[];\n teardown?: () => void;\n}\n\nexport interface LivenessAxiomSpec {\n /** Build a FRESH composition wired to the given transport. Called per run. */\n setup: (transport: FaultyTransport) => LivenessScenario | Promise<LivenessScenario>;\n /**\n * The timeoutMs the scenario passes to `busRequest` — the bound is derived\n * from it: (timeoutMs × (1 + retryBudget) + Σdelays) × slackFactor.\n */\n timeoutMs: number;\n /** Max sanctioned re-issues per logical request (B14 budget). Default 1. */\n retryBudget?: number;\n /** Override the generated fault schedules (teeth tests pin one). */\n scheduleArb?: fc.Arbitrary<readonly FaultAction[]>;\n /** Passed through to FaultyTransport (reply synthesis). */\n makeResponse?: (operation: string, payload: Record<string, unknown>) => unknown;\n /** fast-check run budget (default 25 — CI-fast; crank locally). */\n numRuns?: number;\n /** Real-scheduler jitter headroom on the bound (default 4×). */\n slackFactor?: number;\n}\n\n/** The five wire behaviors, uniformly weighted; delays stay small (≤5 ms). */\nexport function arbFaultAction(): fc.Arbitrary<FaultAction> {\n return fc.oneof(\n fc.constant<FaultAction>({ kind: 'deliver' }),\n fc.constant<FaultAction>({ kind: 'drop-reply' }),\n fc.integer({ min: 0, max: 5 }).map((ms): FaultAction => ({ kind: 'delay', ms })),\n fc.constant<FaultAction>({ kind: 'duplicate-reply' }),\n fc.constant<FaultAction>({ kind: 'reject-emit' }),\n );\n}\n\nexport function arbFaultSchedule(maxLength = 8): fc.Arbitrary<readonly FaultAction[]> {\n return fc.array(arbFaultAction(), { minLength: 1, maxLength });\n}\n\nfunction describeSchedule(schedule: readonly FaultAction[]): string {\n return schedule.map((a) => (a.kind === 'delay' ? `delay(${a.ms})` : a.kind)).join(',');\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Sibling of state-unit-axioms' `run`, adapted for properties that check more\n * than one axiom: fast-check's falsification message carries the seed and\n * counterexample but not the thrown axiom id (fc v4 moves the inner error to\n * `cause`), so the property captures its own labeled violation into `slot`\n * and the wrapper re-throws with the axiom id leading and fc's detail after.\n */\nasync function runLabeled(\n fallback: string,\n slot: { violation: Error | null },\n assertion: () => Promise<void>,\n): Promise<void> {\n try {\n await assertion();\n } catch (e) {\n const detail = e instanceof Error ? e.message : String(e);\n if (slot.violation) throw new Error(`${slot.violation.message}\\n${detail}`);\n throw new Error(`${fallback}: ${detail}`);\n }\n}\n\n/** Wrap a check block so its labeled throw lands in `slot` before falsifying. */\nfunction capturing(slot: { violation: Error | null }, block: () => void): void {\n try {\n block();\n } catch (e) {\n slot.violation = e instanceof Error ? e : new Error(String(e));\n throw e;\n }\n}\n\n/**\n * Run L1 + L2 against `spec` across generated fault schedules. Throws a\n * labeled Error (`L1: …` / `L2: …`) on the first violation.\n */\nexport async function assertLivenessAxioms(spec: LivenessAxiomSpec): Promise<void> {\n const retryBudget = spec.retryBudget ?? 1;\n const slack = spec.slackFactor ?? 4;\n const scheduleArb = spec.scheduleArb ?? arbFaultSchedule();\n\n const slot = { violation: null as Error | null };\n await runLabeled('liveness', slot, () =>\n fc.assert(\n fc.asyncProperty(scheduleArb, async (schedule) => {\n const delayTotal = schedule.reduce((n, a) => n + (a.kind === 'delay' ? a.ms : 0), 0);\n const bound = (spec.timeoutMs * (1 + retryBudget) + delayTotal) * slack;\n const transport = new FaultyTransport({\n schedule,\n ...(spec.makeResponse ? { makeResponse: spec.makeResponse } : {}),\n });\n const scenario = await spec.setup(transport);\n const outputs = scenario.outputs;\n const settlements = scenario.settlements ?? [];\n\n // Subscribe every output (that's what makes a live query live) and\n // track notifications; track settlement of every awaited path.\n const notified: boolean[] = outputs.map(() => false);\n const settled: boolean[] = settlements.map(() => false);\n let doneResolve: () => void = () => {};\n const allDone = new Promise<void>((resolve) => { doneResolve = resolve; });\n const check = (): void => {\n if (notified.every(Boolean) && settled.every(Boolean)) doneResolve();\n };\n const subs: Subscription[] = outputs.map((o, i) =>\n o.subscribe({\n next: () => { notified[i] = true; check(); },\n error: () => { notified[i] = true; check(); },\n }),\n );\n settlements.forEach((p, i) => {\n p.then(() => { settled[i] = true; check(); },\n () => { settled[i] = true; check(); });\n });\n check();\n\n // Wait for full liveness or the bound, whichever first.\n await Promise.race([allDone, sleep(bound)]);\n\n try {\n // L2 first: when it applies it names the mechanism (swallow, budget,\n // unsettled await); L1 below is the broader every-output net. All-\n // outputs-silent is a subset of any-output-silent, so checking L1\n // first would shadow the sharper L2 diagnoses entirely.\n capturing(slot, () => {\n // L2 — settlement: every awaited path settled.\n settled.forEach((seen, i) => {\n if (!seen) {\n throw new Error(\n `L2: settlement #${i} did not settle within ${bound}ms ` +\n `under schedule ⟨${describeSchedule(schedule)}⟩ — the forbidden fourth state`,\n );\n }\n });\n\n // L2 — retry accounting over the transport's request log.\n const issues = new Map<string, { count: number; lastFaulted: boolean }>();\n for (const entry of transport.requestLog) {\n const prior = issues.get(entry.retryKey) ?? { count: 0, lastFaulted: false };\n issues.set(entry.retryKey, {\n count: prior.count + 1,\n lastFaulted: entry.action.kind === 'drop-reply' || entry.action.kind === 'reject-emit',\n });\n }\n for (const [key, { count, lastFaulted }] of issues) {\n if (count > 1 + retryBudget) {\n throw new Error(\n `L2: request ⟨${key}⟩ issued ${count} times — exceeds the retry budget ` +\n `(1 + ${retryBudget}) under schedule ⟨${describeSchedule(schedule)}⟩`,\n );\n }\n // Swallow detection: the final issue of a logical request was\n // faulted, the composition had retry budget left but didn't use\n // it, and no output surfaced anything — the rejection went into\n // a void (the pre-B14 `catch(() => {})`).\n if (lastFaulted && count <= retryBudget && outputs.length > 0 && !notified.some(Boolean)) {\n throw new Error(\n `L2: faulted request ⟨${key}⟩ was neither re-issued nor surfaced ` +\n `under schedule ⟨${describeSchedule(schedule)}⟩ — rejection swallowed`,\n );\n }\n }\n\n // L1 — every subscription saw next|error; pending-forever is the bug.\n notified.forEach((seen, i) => {\n if (!seen) {\n throw new Error(\n `L1: output #${i} received no next/error within ${bound}ms ` +\n `under schedule ⟨${describeSchedule(schedule)}⟩ — silently pending`,\n );\n }\n });\n });\n } finally {\n subs.forEach((s) => s.unsubscribe());\n scenario.teardown?.();\n transport.dispose();\n }\n }),\n { numRuns: spec.numRuns ?? 25 },\n ),\n );\n}\n\n// ── L3: exactly-once delivery across client-initiated transitions ────────\n\n/**\n * A connection-stream-shaped subject: something that accepts writes to the\n * live connection, can be told to transition (handover / reconnect / scope\n * change), and exposes the subscriber-facing output. P3 adapts the real\n * actor's mock-connection harness to this shape; the teeth tests drive\n * reconstructed pre-fix doubles.\n */\nexport interface DeliverySubject {\n /** Write the event with this id to the currently-live connection. */\n write: (eventId: string) => void;\n /** Client-initiated lifecycle transition. */\n transition: () => void | Promise<void>;\n /** Subscriber-facing output; each emission is a delivered event id. */\n output$: Observable<string>;\n /**\n * Drain pending asynchronous delivery at end of sequence (a live connection\n * eventually flushes). Default: one macrotask tick.\n */\n settle?: () => Promise<void>;\n teardown?: () => void;\n}\n\nexport type DeliveryOp = 'write' | 'transition';\n\nexport interface DeliveryAxiomSpec {\n /** Build a FRESH subject. Called per run. */\n setup: () => DeliverySubject;\n /** Override the generated op sequences (teeth tests pin one). */\n opsArb?: fc.Arbitrary<readonly DeliveryOp[]>;\n /** Max generated sequence length (default 12). */\n maxOps?: number;\n /** fast-check run budget (default 50 — these runs are cheap). */\n numRuns?: number;\n}\n\nexport function arbDeliveryOps(maxOps = 12): fc.Arbitrary<readonly DeliveryOp[]> {\n return fc\n .array(fc.constantFrom<DeliveryOp>('write', 'transition'), { minLength: 1, maxLength: maxOps })\n // A sequence with no write asserts nothing — always exercise delivery.\n .map((ops) => (ops.includes('write') ? ops : ([...ops, 'write'] as const)));\n}\n\n/**\n * Run L3 against `spec` across generated write/transition interleavings.\n * Throws a labeled Error (`L3: …`) on the first violation: an event written\n * to a live connection delivered zero times (lost — retired by abort instead\n * of drain) or more than once (duplicate).\n */\nexport async function assertExactlyOnceDelivery(spec: DeliveryAxiomSpec): Promise<void> {\n const opsArb = spec.opsArb ?? arbDeliveryOps(spec.maxOps ?? 12);\n\n const slot = { violation: null as Error | null };\n await runLabeled('L3', slot, () =>\n fc.assert(\n fc.asyncProperty(opsArb, async (ops) => {\n const subject = spec.setup();\n const delivered: string[] = [];\n const sub = subject.output$.subscribe((id) => delivered.push(id));\n const written: string[] = [];\n try {\n for (let i = 0; i < ops.length; i++) {\n if (ops[i] === 'write') {\n const id = `e${i}`;\n written.push(id);\n subject.write(id);\n } else {\n await subject.transition();\n }\n // Deliberately no settling between ops: the interesting races are\n // transitions landing before a write's asynchronous delivery.\n }\n await (subject.settle?.() ?? sleep(0));\n\n capturing(slot, () => {\n for (const id of written) {\n const n = delivered.filter((d) => d === id).length;\n if (n === 0) {\n throw new Error(\n `L3: event ⟨${id}⟩ delivered 0 times under ⟨${ops.join(',')}⟩ — ` +\n `lost across a transition (retire by drain, never by abort)`,\n );\n }\n if (n > 1) {\n throw new Error(\n `L3: event ⟨${id}⟩ delivered ${n} times under ⟨${ops.join(',')}⟩ — duplicate delivery`,\n );\n }\n }\n });\n } finally {\n sub.unsubscribe();\n subject.teardown?.();\n }\n }),\n { numRuns: spec.numRuns ?? 50 },\n ),\n );\n}\n"]}
|
package/dist/testing.d.ts
CHANGED
|
@@ -98,7 +98,7 @@ declare class FaultyTransport implements ITransport {
|
|
|
98
98
|
* nothing: that request never reached the backend.
|
|
99
99
|
*/
|
|
100
100
|
queueReply(op: BusOperationKey, ...responses: unknown[]): void;
|
|
101
|
-
emit<K extends keyof EventMap>(channel: K, payload: EventMap[K], resourceScope?: ResourceId): Promise<
|
|
101
|
+
emit<K extends keyof EventMap>(channel: K, payload: EventMap[K], resourceScope?: ResourceId): Promise<number>;
|
|
102
102
|
on<K extends keyof EventMap>(channel: K, handler: (payload: EventMap[K]) => void): () => void;
|
|
103
103
|
stream<K extends keyof EventMap>(channel: K): Observable<EventMap[K]>;
|
|
104
104
|
subscribeToResource(_rid: ResourceId): () => void;
|
package/dist/testing.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { FaultyTransport, retryKeyOf } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
export { FaultyTransport, retryKeyOf } from './chunk-PPUO5IPX.js';
|
|
2
|
+
import './chunk-CUPZGI7I.js';
|
|
3
|
+
import './chunk-YLJ4XMA6.js';
|
|
3
4
|
//# sourceMappingURL=testing.js.map
|
|
4
5
|
//# sourceMappingURL=testing.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semiont/core",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.28",
|
|
4
4
|
"description": "Core types and domain logic for Semiont - Resource, Annotation, and Graph models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
"types": "./dist/testing/axioms.d.ts",
|
|
26
26
|
"import": "./dist/testing/axioms.js",
|
|
27
27
|
"default": "./dist/testing/axioms.js"
|
|
28
|
+
},
|
|
29
|
+
"./openapi": {
|
|
30
|
+
"types": "./dist/openapi.d.ts",
|
|
31
|
+
"import": "./dist/openapi.js",
|
|
32
|
+
"default": "./dist/openapi.js"
|
|
28
33
|
}
|
|
29
34
|
},
|
|
30
35
|
"engines": {
|
|
@@ -48,14 +53,15 @@
|
|
|
48
53
|
"copy-spec": "cp ../../specs/openapi.json openapi.json",
|
|
49
54
|
"generate:openapi": "npm run bundle-spec && npm run copy-spec && openapi-typescript openapi.json -o src/types.ts",
|
|
50
55
|
"generate:types": "tsx scripts/generate-types.ts",
|
|
51
|
-
"prebuild": "npm run generate:openapi && npm run generate:types",
|
|
56
|
+
"prebuild": "npm run generate:openapi && npm run generate:types && npm run generate:validators",
|
|
52
57
|
"typecheck": "tsc --noEmit",
|
|
53
58
|
"build": "npm run typecheck && tsup && tsc -p tsconfig.build.json && rollup -c rollup.dts.config.mjs && rm -rf dist-types",
|
|
54
59
|
"watch": "tsup --watch",
|
|
55
|
-
"clean": "rm -rf dist *.tsbuildinfo src/types.ts openapi.json",
|
|
60
|
+
"clean": "rm -rf dist *.tsbuildinfo src/types.ts src/generated openapi.json",
|
|
56
61
|
"test": "vitest run",
|
|
57
62
|
"test:watch": "vitest",
|
|
58
|
-
"test:coverage": "vitest run --coverage"
|
|
63
|
+
"test:coverage": "vitest run --coverage",
|
|
64
|
+
"generate:validators": "node ../../scripts/spec/generate-validators.mjs"
|
|
59
65
|
},
|
|
60
66
|
"keywords": [
|
|
61
67
|
"types",
|
|
@@ -76,7 +82,7 @@
|
|
|
76
82
|
"rollup": "^4.62.3",
|
|
77
83
|
"rollup-plugin-dts": "^6.4.1",
|
|
78
84
|
"tsup": "^8.5.1",
|
|
79
|
-
"tsx": "^4.23.
|
|
85
|
+
"tsx": "^4.23.12",
|
|
80
86
|
"typescript": "^6.0.2",
|
|
81
87
|
"vitest": "^4.1.10"
|
|
82
88
|
},
|
|
@@ -84,7 +90,7 @@
|
|
|
84
90
|
"ajv": "^8.20.0",
|
|
85
91
|
"ajv-formats": "^3.0.1",
|
|
86
92
|
"rxjs": "^7.8.1",
|
|
87
|
-
"smol-toml": "^1.
|
|
93
|
+
"smol-toml": "^1.8.0"
|
|
88
94
|
},
|
|
89
95
|
"peerDependencies": {
|
|
90
96
|
"fast-check": "^4.8.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/branded-types.ts","../src/bus-operations.ts","../src/bridged-channels.ts","../src/bus-log.ts","../src/event-bus.ts"],"names":[],"mappings":"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","file":"chunk-FMFOBVTE.js","sourcesContent":["/**\n * Branded string types for compile-time type safety\n *\n * These types are zero-cost at runtime but prevent mixing\n * different string types at compile time.\n */\n\nimport type { components } from './types';\n\n// ============================================================================\n// OPENAPI-GENERATED TYPES (use directly from spec)\n// ============================================================================\n\nexport type Motivation = components['schemas']['Motivation'];\nexport type ContentFormat = components['schemas']['ContentFormat'];\n\n// ============================================================================\n// AUTHENTICATION & TOKENS\n// ============================================================================\n\nexport type Email = string & { readonly __brand: 'Email' };\nexport type AuthCode = string & { readonly __brand: 'AuthCode' };\nexport type GoogleCredential = string & { readonly __brand: 'GoogleCredential' };\nexport type AccessToken = string & { readonly __brand: 'AccessToken' };\nexport type RefreshToken = string & { readonly __brand: 'RefreshToken' };\nexport type MCPToken = string & { readonly __brand: 'MCPToken' };\nexport type CloneToken = string & { readonly __brand: 'CloneToken' };\n\n// ============================================================================\n// SYSTEM IDENTIFIERS\n// ============================================================================\n\nexport type JobId = string & { readonly __brand: 'JobId' };\nexport type UserDID = string & { readonly __brand: 'UserDID' };\nexport type EntityType = string & { readonly __brand: 'EntityType' };\nexport type SearchQuery = string & { readonly __brand: 'SearchQuery' };\nexport type BaseUrl = string & { readonly __brand: 'BaseUrl' };\n\n// ============================================================================\n// HELPER FUNCTIONS (minimal validation, just branding)\n// ============================================================================\n\nexport function email(value: string): Email { return value as Email; }\nexport function authCode(value: string): AuthCode { return value as AuthCode; }\nexport function googleCredential(value: string): GoogleCredential { return value as GoogleCredential; }\nexport function accessToken(value: string): AccessToken { return value as AccessToken; }\nexport function refreshToken(value: string): RefreshToken { return value as RefreshToken; }\nexport function mcpToken(value: string): MCPToken { return value as MCPToken; }\nexport function cloneToken(value: string): CloneToken { return value as CloneToken; }\nexport function jobId(value: string): JobId { return value as JobId; }\nexport function userDID(value: string): UserDID { return value as UserDID; }\nexport function entityType(value: string): EntityType { return value as EntityType; }\nexport function searchQuery(value: string): SearchQuery { return value as SearchQuery; }\nexport function baseUrl(value: string): BaseUrl { return value as BaseUrl; }\n\n// Motivation is an OpenAPI enum — use its values directly, no helper needed.\n// ContentFormat is a free-form MIME string whose base type must be a\n// SupportedMediaType; validation lives in media-types.ts, not in a brand.\n\n// ============================================================================\n// HTTP URI TYPES\n// ============================================================================\n\n// Branded type definitions for HTTP URIs returned by the API\nexport type ResourceUri = string & { readonly __brand: 'ResourceUri' };\n\n// W3C flat format for content negotiation: http://localhost:4000/annotations/{id}\nexport type AnnotationUri = string & { readonly __brand: 'AnnotationUri' };\n\n// Nested format for CRUD operations: http://localhost:4000/resources/{resourceId}/annotations/{annotationId}\nexport type ResourceAnnotationUri = string & { readonly __brand: 'ResourceAnnotationUri' };\n\n// Factory functions with runtime validation\nexport function resourceUri(uri: string): ResourceUri {\n if (!uri.startsWith('http://') && !uri.startsWith('https://')) {\n throw new TypeError(`Expected ResourceUri, got: ${uri}`);\n }\n return uri as ResourceUri;\n}\n\nexport function annotationUri(uri: string): AnnotationUri {\n if (!uri.startsWith('http://') && !uri.startsWith('https://')) {\n throw new TypeError(`Expected AnnotationUri, got: ${uri}`);\n }\n return uri as AnnotationUri;\n}\n\nexport function resourceAnnotationUri(uri: string): ResourceAnnotationUri {\n if (!uri.startsWith('http://') && !uri.startsWith('https://')) {\n throw new TypeError(`Expected ResourceAnnotationUri, got: ${uri}`);\n }\n // Additional validation: must contain /resources/ and /annotations/\n if (!uri.includes('/resources/') || !uri.includes('/annotations/')) {\n throw new TypeError(`Expected nested ResourceAnnotationUri format, got: ${uri}`);\n }\n return uri as ResourceAnnotationUri;\n}\n","// ⚠ GENERATED FILE — do not edit.\n//\n// Authority: specs/src/bus/registry.json (channels, payloads, operations)\n// Regenerate: node scripts/bus/generate-ts.mjs\n// Go counterpart: node scripts/bus/generate-go.mjs → packages/sdk-go/bus\n//\n// Payload schemas themselves live in the OpenAPI components; the registry\n// names which one each channel carries. Add or change a channel THERE.\n\nimport type { EventName, EmittableChannel } from './bus-protocol';\n\n/**\n * BUS_OPERATIONS — the request/reply operations registry (Tier 1).\n *\n * Each entry declares ONE operation as the triple that was previously three\n * loose, independently-maintained facts spread across call sites:\n * - the request channel (the key — an `EmittableChannel`),\n * - the `result` channel (success reply),\n * - the `failure` channel,\n * - and, for a streaming op, an optional `progress` channel.\n *\n * `BridgedChannel` / `BRIDGED_CHANNELS` are DERIVED from this map\n * (bridged-channels.ts): every reply lands in the bridged fan-in set by\n * construction, so \"a reply channel forgotten from BRIDGED_CHANNELS\" — the\n * recurring bug class (gather:resource-complete, frame:*-add-failed) — is no\n * longer representable. See .plans/BUS-OPERATIONS-REGISTRY.md.\n *\n * `Partial<Record<EmittableChannel, …>>` enforces that every key is a real\n * emittable request. `result`/`failure`/`progress` stay `EventName` rather than\n * `BridgedChannel` to avoid a circular reference (BridgedChannel derives from\n * this map); the derivation closes the loop instead.\n */\nexport interface BusOperationSpec {\n result: EventName;\n failure: EventName;\n /** Streaming ops only: an intermediate channel that also bridges. */\n progress?: EventName;\n}\n\nexport const BUS_OPERATIONS = {\n // ── BIND ────────────────────────────────────────────────────────\n 'bind:update-body': { result: 'bind:body-updated', failure: 'bind:body-update-failed' },\n\n // ── BROWSE (reads) ──────────────────────────────────────────────\n 'browse:resource-requested': { result: 'browse:resource-result', failure: 'browse:resource-failed' },\n 'browse:anchored-text-requested': { result: 'browse:anchored-text-result', failure: 'browse:anchored-text-failed' },\n 'browse:resources-requested': { result: 'browse:resources-result', failure: 'browse:resources-failed' },\n 'browse:annotation-requested': { result: 'browse:annotation-result', failure: 'browse:annotation-failed' },\n 'browse:annotations-requested': { result: 'browse:annotations-result', failure: 'browse:annotations-failed' },\n 'browse:annotation-history-requested': { result: 'browse:annotation-history-result', failure: 'browse:annotation-history-failed' },\n 'browse:events-requested': { result: 'browse:events-result', failure: 'browse:events-failed' },\n 'browse:referenced-by-requested': { result: 'browse:referenced-by-result', failure: 'browse:referenced-by-failed' },\n 'browse:entity-types-requested': { result: 'browse:entity-types-result', failure: 'browse:entity-types-failed' },\n 'browse:tag-schemas-requested': { result: 'browse:tag-schemas-result', failure: 'browse:tag-schemas-failed' },\n 'browse:agents-requested': { result: 'browse:agents-result', failure: 'browse:agents-failed' },\n 'browse:directory-requested': { result: 'browse:directory-result', failure: 'browse:directory-failed' },\n // dormant — backend handler complete, no client caller yet (annotation-detail capability)\n 'browse:annotation-context-requested': { result: 'browse:annotation-context-result', failure: 'browse:annotation-context-failed' },\n\n // ── FRAME (KB schema writes) ────────────────────────────────────\n 'frame:add-entity-type': { result: 'frame:entity-type-add-ok', failure: 'frame:entity-type-add-failed' },\n 'frame:add-tag-schema': { result: 'frame:tag-schema-add-ok', failure: 'frame:tag-schema-add-failed' },\n\n // ── GATHER ──────────────────────────────────────────────────────\n // streaming: take-1 result + failure plus an intermediate progress channel\n 'gather:requested': { result: 'gather:complete', failure: 'gather:failed', progress: 'gather:annotation-progress' },\n 'gather:resource-requested': { result: 'gather:resource-complete', failure: 'gather:resource-failed' },\n // dormant — backend handler complete, no client caller yet (annotation summary)\n 'gather:summary-requested': { result: 'gather:summary-result', failure: 'gather:summary-failed' },\n\n // ── JOB ─────────────────────────────────────────────────────────\n 'job:create': { result: 'job:created', failure: 'job:create-failed' },\n 'job:status-requested': { result: 'job:status-result', failure: 'job:status-failed' },\n 'job:cancel-requested': { result: 'job:cancel-ok', failure: 'job:cancel-failed' },\n // worker-side: the worker claims a queued job (not an SDK call)\n 'job:claim': { result: 'job:claimed', failure: 'job:claim-failed' },\n\n // ── MARK ────────────────────────────────────────────────────────\n 'mark:create-request': { result: 'mark:create-ok', failure: 'mark:create-failed' },\n 'mark:delete': { result: 'mark:delete-ok', failure: 'mark:delete-failed' },\n 'mark:archive': { result: 'mark:archive-ok', failure: 'mark:archive-failed' },\n 'mark:unarchive': { result: 'mark:unarchive-ok', failure: 'mark:unarchive-failed' },\n 'mark:update-entity-types': { result: 'mark:update-entity-types-ok', failure: 'mark:update-entity-types-failed' },\n\n // ── MATCH ───────────────────────────────────────────────────────\n // take-1 dressed as an Observable in the SDK; no progress channel\n 'match:search-requested': { result: 'match:search-results', failure: 'match:search-failed' },\n\n // ── WEAVE ───────────────────────────────────────────────────────\n // Graph-projection rebuild, served by the Weaver (WEAVER-ISOLATION D3)\n 'weave:rebuild': { result: 'weave:rebuild-ok', failure: 'weave:rebuild-failed' },\n\n // ── SMELT ────────────────────────────────────────────\n // Anchored-text rebuild, served by the Smelter (PERSIST-ANCHORS P0)\n 'smelt:rebuild-anchors': { result: 'smelt:rebuild-anchors-ok', failure: 'smelt:rebuild-anchors-failed' },\n\n // ── YIELD ───────────────────────────────────────────────────────\n // live in-process (resource-operations.ts emits + awaits via race()); the\n // client also .on()-subscribes -ok for cache invalidation\n 'yield:create': { result: 'yield:create-ok', failure: 'yield:create-failed' },\n // dormant — handler in stower exists, no request emitter; client pre-subscribes -ok\n 'yield:update': { result: 'yield:update-ok', failure: 'yield:update-failed' },\n 'yield:clone-create': { result: 'yield:clone-created', failure: 'yield:clone-create-failed' },\n 'yield:clone-resource-requested': { result: 'yield:clone-resource-result', failure: 'yield:clone-resource-failed' },\n 'yield:clone-token-requested': { result: 'yield:clone-token-generated', failure: 'yield:clone-token-failed' },\n} as const satisfies Partial<Record<EmittableChannel, BusOperationSpec>>;\n\n/** The request-channel key of a registered operation — what `busRequest` takes. */\nexport type BusOperationKey = keyof typeof BUS_OPERATIONS;\n","// ⚠ GENERATED FILE — do not edit.\n//\n// Authority: specs/src/bus/registry.json (channels, payloads, operations)\n// Regenerate: node scripts/bus/generate-ts.mjs\n// Go counterpart: node scripts/bus/generate-go.mjs → packages/sdk-go/bus\n//\n// Payload schemas themselves live in the OpenAPI components; the registry\n// names which one each channel carries. Add or change a channel THERE.\n\nimport type { EventName } from './bus-protocol';\nimport { BUS_OPERATIONS } from './bus-operations';\n\n/**\n * BRIDGED_CHANNELS\n *\n * The set of bus channels that any concrete transport bridges into the\n * caller-supplied bus via `bridgeInto`. Transport-neutral: every concrete\n * `ITransport` shares the same set; HTTP delivers them via SSE, in-process\n * transports forward them directly from the local actor bus.\n *\n * This is the *fan-in* set — channels for events the transport receives and\n * pushes onto the client's bus. It is not the same as the channels the client\n * emits (which is open-ended).\n *\n * It is DERIVED, not hand-listed: the request/reply replies come from\n * `BUS_OPERATIONS` (bus-operations.ts), so no operation's reply can be\n * forgotten here — that was the recurring unbridged-reply bug class. The only\n * hand-maintained part is `BRIDGED_BROADCASTS`: the genuine non-request/reply\n * minority (lifecycle events and UI/infra signals that no single requester\n * owns). See .plans/BUS-OPERATIONS-REGISTRY.md.\n *\n * Resource-scoped channels (joined/left via `subscribeToResource`) are tracked\n * separately by transports that care about scope (HTTP).\n */\n\n/**\n * Bridged channels with no owning operation: job-lifecycle events (multi-viewer,\n * no single requester owns the reply), KB-global frame domain events, UI signals,\n * and SSE infrastructure. A reply channel must NOT go here — declare its\n * operation in `BUS_OPERATIONS` instead.\n */\nexport const BRIDGED_BROADCASTS = [\n 'job:report-progress',\n 'job:complete',\n 'job:fail',\n 'frame:entity-type-added',\n 'frame:tag-schema-added',\n 'beckon:focus',\n 'beckon:sparkle',\n 'bus:resume-gap',\n] as const satisfies readonly EventName[];\n\n// ── Derivation ──────────────────────────────────────────────────────────────\n// Every operation's result + failure (+ progress) channel bridges, by\n// construction. Type and runtime are derived from the same `BUS_OPERATIONS`.\n\ntype OpSpecs = (typeof BUS_OPERATIONS)[keyof typeof BUS_OPERATIONS];\n\n// Generic wrapper so the conditional distributes over each union member (a bare\n// `OpSpecs extends …` would test the whole union at once and collapse to never\n// because only the streaming ops carry `progress`).\ntype ProgressChannel<O> = O extends { progress: infer P extends EventName } ? P : never;\n\n/** The union of every reply channel declared in the registry. */\ntype RegistryReply = OpSpecs['result'] | OpSpecs['failure'] | ProgressChannel<OpSpecs>;\n\n// Iterate by typed key so each op's literal reply types survive — the element\n// type stays `RegistryReply` (no widening to `EventName`), so the composed\n// array is `BridgedChannel[]` with no narrowing assertion. The runtime proof\n// that this derived set is exactly the intended one is the equality test in\n// __tests__/bus-invariants.test.ts.\nconst REGISTRY_REPLIES = (Object.keys(BUS_OPERATIONS) as (keyof typeof BUS_OPERATIONS)[]).flatMap(\n (key) => {\n const op = BUS_OPERATIONS[key];\n return 'progress' in op ? [op.result, op.failure, op.progress] : [op.result, op.failure];\n },\n);\n\nexport const BRIDGED_CHANNELS: readonly BridgedChannel[] = [\n ...REGISTRY_REPLIES,\n ...BRIDGED_BROADCASTS,\n];\n\n/**\n * The SUBSCRIBE-side subset of `EventName` — the channels a client can receive\n * over a concrete transport. See the family note on `EventName` in\n * bus-protocol.ts (emit on an `EmittableChannel`, subscribe on a `BridgedChannel`).\n */\nexport type BridgedChannel = RegistryReply | (typeof BRIDGED_BROADCASTS)[number];\n","/**\n * Bus logging — runtime-toggleable cross-wire visibility.\n *\n * One line per event that crosses a process boundary, in a grep-able\n * format that's symmetric across frontend and backend:\n *\n * [bus EMIT] <channel> [scope=X] [cid=<first8>] <payload>\n * [bus RECV] <channel> [scope=X] [cid=<first8>] <payload>\n * [bus SSE] <channel> [scope=X] [cid=<first8>] <payload>\n *\n * Tier 1 of `.plans/OBSERVABILITY.md`. Forward-compatible with Tier 2:\n * the `cid` printed here is exactly the prefix of the W3C trace-id we\n * adopt later.\n *\n * Cost when disabled: one property read per call, zero allocations.\n *\n * Enable:\n * - Browser: `window.__SEMIONT_BUS_LOG__ = true` (DevTools or e2e init)\n * - Node: `SEMIONT_BUS_LOG=1` in the process env (read at module load)\n */\n\nimport { BRIDGED_CHANNELS } from './bridged-channels';\n\nconst NODE_BUS_LOG =\n typeof process !== 'undefined' && !!process.env?.SEMIONT_BUS_LOG;\n\nconst IS_NODE =\n typeof process !== 'undefined' && !!process.versions?.node;\n\nexport type BusOp = 'EMIT' | 'RECV' | 'SSE' | 'PUT' | 'GET';\n\nexport function busLogEnabled(): boolean {\n const g = globalThis as { __SEMIONT_BUS_LOG__?: boolean };\n if (g.__SEMIONT_BUS_LOG__) return true;\n return NODE_BUS_LOG;\n}\n\n/**\n * Optional active-span trace-id provider. When a Tier 2 OTel SDK is\n * initialized, `@semiont/observability` registers a provider here that\n * returns the active span's W3C `trace_id`. busLog appends it to each\n * emitted line so the grep-timeline correlates with the span tree in\n * an APM UI.\n *\n * Decoupling: `@semiont/core` does not depend on `@opentelemetry/api`.\n * If no provider is registered (Tier 1-only deployments, or before\n * `initObservabilityNode` runs), the field is omitted from the line —\n * same shape as before this hook existed.\n */\nlet traceIdProvider: (() => string | undefined) | undefined;\n\nexport function setBusLogTraceIdProvider(fn: (() => string | undefined) | undefined): void {\n traceIdProvider = fn;\n}\n\nexport function busLog(\n op: BusOp,\n channel: string,\n payload: unknown,\n scope?: string,\n): void {\n if (!busLogEnabled()) return;\n const cidRaw = (payload as { correlationId?: unknown } | null | undefined)?.correlationId;\n const cid = typeof cidRaw === 'string' ? cidRaw.slice(0, 8) : undefined;\n let traceId: string | undefined;\n if (traceIdProvider) {\n try { traceId = traceIdProvider(); } catch { /* noop */ }\n }\n const tag =\n `[bus ${op}] ${channel}` +\n (scope ? ` scope=${scope}` : '') +\n (cid ? ` cid=${cid}` : '') +\n (traceId ? ` trace=${traceId.slice(0, 8)}` : '');\n // eslint-disable-next-line no-console\n console.debug(tag, payload);\n}\n\n/**\n * Whether to run the unobserved-reply check on every local emit.\n *\n * On in Node (backend + worker + smelter), where a dropped reply is a real\n * delivery bug; off in the browser, where a 0-observer bridged reply just\n * means the awaiting `busRequest` already resolved/timed out (benign).\n *\n * Always-on (no env flag) by design: the failure it catches is rare and\n * high-signal, and the whole point is that it fires with zero setup — the\n * incident that motivated it (.plans/bugs/gather-resource-complete-not-bridged.md)\n * ran with bus-logging off, so a flag-gated check would have stayed silent.\n */\nexport function warnUnobservedRepliesEnabled(): boolean {\n return IS_NODE;\n}\n\n/** One line per channel per process — a missing fan-in wiring is a config\n * bug, so the first dropped reply is enough; we don't spam on retries. */\nconst unobservedReplyWarned = new Set<string>();\n\n/**\n * The silent-dropped-reply detector.\n *\n * A correlation-bearing payload is a request/reply *reply* (`*-result`,\n * `*-complete`, `*-failed`, …). If one is emitted on the backend bus with\n * **zero local observers**, nothing forwards it — no SSE subscription, no\n * in-process consumer — so the awaiting client never receives it and times\n * out 30 s later with no error logged anywhere. That is exactly how\n * `gather:resource-complete` failed when it was missing from\n * `BRIDGED_CHANNELS` (.plans/bugs/gather-resource-complete-not-bridged.md).\n *\n * Emits one WARN per channel naming the likely fix. Ignored (no warning):\n * non-reply emits (no `correlationId`), emits with observers, and — crucially —\n * channels already in `BRIDGED_CHANNELS`: a 0-observer emit there is a redundant\n * copy, not a gap (see .plans/bugs/BRIDGE-GAPS.md). So the detector fires only\n * for a genuine missing forwarder, and its remediation text is always correct.\n */\nexport function warnIfUnobservedReply(\n channel: string,\n payload: unknown,\n observerCount: number,\n): void {\n if (observerCount > 0) return;\n const cidRaw = (payload as { correlationId?: unknown } | null | undefined)?.correlationId;\n if (typeof cidRaw !== 'string' || cidRaw.length === 0) return;\n // A 0-observer emit on a *bridged* channel is a redundant copy (a global +\n // resource-scoped dual-emit, or an SSE reconnect replay), not a missing\n // forwarder — the first copy already reached the awaiting `take(1)`\n // subscriber. Only a NOT-bridged channel is a genuine drop. (`busRequest` now\n // types its reply channels `BridgedChannel`, so an unbridged reply is a\n // compile error; this runtime check covers non-`busRequest` correlation\n // emits.) See .plans/bugs/BRIDGE-GAPS.md.\n if ((BRIDGED_CHANNELS as readonly string[]).includes(channel)) return;\n if (unobservedReplyWarned.has(channel)) return;\n unobservedReplyWarned.add(channel);\n // eslint-disable-next-line no-console\n console.warn(\n `[bus DROP] ${channel} cid=${cidRaw.slice(0, 8)} emitted with 0 subscribers and not in ` +\n `BRIDGED_CHANNELS — a correlation reply with no forwarder is dropped, so the awaiting ` +\n `client times out (no error). Bridge it by declaring its operation in BUS_OPERATIONS ` +\n `(packages/core/src/bus-operations.ts) — or, if it is a non-reply broadcast, add it to ` +\n `BRIDGED_BROADCASTS (packages/core/src/bridged-channels.ts) — so transports subscribe to it.`,\n );\n}\n","/**\n * RxJS-based Event Bus\n *\n * Framework-agnostic event bus providing direct access to typed RxJS Subjects.\n *\n * Can be used in Node.js, browser, workers, CLI - anywhere RxJS runs.\n */\n\nimport { Subject } from 'rxjs';\nimport { busLog, busLogEnabled, warnIfUnobservedReply, warnUnobservedRepliesEnabled } from './bus-log';\nimport type { EventMap } from './bus-protocol';\nimport type { StoredEvent } from './event-base';\nimport type { PersistedEventType } from './persisted-events';\n\n/**\n * RxJS-based event bus\n *\n * Provides direct access to RxJS Subjects for each event type.\n * Use standard RxJS patterns for emitting and subscribing.\n *\n * @example\n * ```typescript\n * const eventBus = new EventBus();\n *\n * // Emit events\n * eventBus.get('beckon:hover').next({ annotationId: 'ann-1' });\n *\n * // Subscribe to events\n * const subscription = eventBus.get('beckon:hover').subscribe(({ annotationId }) => {\n * console.log('Hover:', annotationId);\n * });\n *\n * // Use RxJS operators\n * import { debounceTime } from 'rxjs/operators';\n * eventBus.get('beckon:hover')\n * .pipe(debounceTime(100))\n * .subscribe(handleHover);\n *\n * // Cleanup\n * subscription.unsubscribe();\n * eventBus.destroy();\n * ```\n */\nexport class EventBus {\n private subjects: Map<keyof EventMap, Subject<any>>;\n private isDestroyed: boolean;\n\n constructor() {\n this.subjects = new Map();\n this.isDestroyed = false;\n }\n\n /**\n * Get the RxJS Subject for an event\n *\n * Returns a typed Subject that can be used with all RxJS operators.\n * Subjects are created lazily on first access.\n *\n * @param eventName - The event name\n * @returns The RxJS Subject for this event\n *\n * @example\n * ```typescript\n * // Emit\n * eventBus.get('beckon:hover').next({ annotationId: 'ann-1' });\n *\n * // Subscribe\n * const sub = eventBus.get('beckon:hover').subscribe(handleHover);\n *\n * // With operators\n * eventBus.get('beckon:hover')\n * .pipe(debounceTime(100), distinctUntilChanged())\n * .subscribe(handleHover);\n * ```\n */\n get<K extends keyof EventMap>(eventName: K): Subject<EventMap[K]> {\n if (this.isDestroyed) {\n throw new Error(`Cannot access event '${String(eventName)}' on destroyed bus`);\n }\n\n if (!this.subjects.has(eventName)) {\n const subject = new Subject<EventMap[K]>();\n // When bus-log is enabled (`SEMIONT_BUS_LOG=1` or\n // `window.__SEMIONT_BUS_LOG__ = true`), wrap `.next()` so every\n // local emit on this channel produces a `[bus EMIT] <channel> ...`\n // line on `console.debug` — same shape as cross-wire emits from\n // HttpTransport. This is what makes local-only fan-out signals\n // (`beckon.hover`, `beckon.sparkle`, `mark.request`, etc.)\n // visible to the e2e bus capture and to a developer's DevTools.\n // The `busLogEnabled()` check is at first-`get` time per channel;\n // setting the flag after channels are constructed won't\n // retroactively wrap them. The bus capture fixture uses\n // `addInitScript` so the flag is set before any namespace\n // construction, which is when `get()` is first called.\n //\n // Independently, on Node we wrap `.next()` to catch *dropped replies*:\n // a correlation-bearing payload emitted with zero observers (see\n // `warnIfUnobservedReply`). This needs no flag — it's how the\n // `gather:resource-complete` bridge gap stayed invisible until a 30 s\n // timeout. The two wraps share one closure when both are active.\n const wantBusLog = busLogEnabled();\n const wantDropCheck = warnUnobservedRepliesEnabled();\n if (wantBusLog || wantDropCheck) {\n const wrapped = subject;\n const originalNext = subject.next.bind(subject);\n subject.next = (value: EventMap[K]): void => {\n if (wantBusLog) busLog('EMIT', String(eventName), value as object);\n if (wantDropCheck) warnIfUnobservedReply(String(eventName), value, wrapped.observers.length);\n originalNext(value);\n };\n }\n this.subjects.set(eventName, subject);\n }\n return this.subjects.get(eventName)!;\n }\n\n /**\n * Get the RxJS Subject for a domain event type (PersistedEventType).\n *\n * Domain event channels carry `StoredEvent`. This method avoids the need\n * for `as keyof EventMap` casts when subscribing to domain event channels\n * using runtime `PersistedEventType` strings.\n */\n getDomainEvent(eventType: PersistedEventType): Subject<StoredEvent> {\n return this.get(eventType as keyof EventMap) as unknown as Subject<StoredEvent>;\n }\n\n /**\n * Destroy the event bus and complete all subjects\n *\n * After calling destroy(), no new events can be emitted or subscribed to.\n * All active subscriptions will be completed.\n */\n destroy(): void {\n if (this.isDestroyed) {\n return;\n }\n\n for (const subject of this.subjects.values()) {\n subject.complete();\n }\n\n this.subjects.clear();\n this.isDestroyed = true;\n }\n\n /**\n * Check if the event bus has been destroyed\n */\n get destroyed(): boolean {\n return this.isDestroyed;\n }\n\n /**\n * Create a resource-scoped event bus\n *\n * Events emitted or subscribed through the scoped bus are isolated to that resource.\n * Internally, events are namespaced but the API remains identical to the parent bus.\n *\n * @param resourceId - Resource identifier to scope events to\n * @returns A scoped event bus for this resource\n *\n * @example\n * ```typescript\n * const eventBus = new EventBus();\n * const resource1 = eventBus.scope('resource-1');\n * const resource2 = eventBus.scope('resource-2');\n *\n * // These are isolated - only resource1 subscribers will fire\n * resource1.get('detection:progress').next({ status: 'started' });\n * ```\n */\n scope(resourceId: string): ScopedEventBus {\n return new ScopedEventBus(this, resourceId);\n }\n}\n\n/**\n * Resource-scoped event bus\n *\n * Provides isolated event streams per resource while maintaining the same API\n * as the parent EventBus. Events are internally namespaced by resourceId.\n */\nexport class ScopedEventBus {\n constructor(\n private parent: EventBus,\n private scopePrefix: string\n ) {}\n\n /**\n * Get the RxJS Subject for a scoped event\n *\n * Returns the same type as the parent bus, but events are isolated to this scope.\n * Internally uses namespaced keys but preserves type safety.\n *\n * @param event - The event name\n * @returns The RxJS Subject for this scoped event\n */\n get<E extends keyof EventMap>(event: E): Subject<EventMap[E]> {\n // Internally namespace the event key, but preserve return type\n const scopedKey = `${this.scopePrefix}:${event as string}`;\n\n // Access parent's subjects map directly (needs cast for private access)\n const parentSubjects = (this.parent as any).subjects as Map<string, Subject<any>>;\n\n if (!parentSubjects.has(scopedKey)) {\n parentSubjects.set(scopedKey, new Subject<EventMap[E]>());\n }\n return parentSubjects.get(scopedKey)!;\n }\n\n /** Get the RxJS Subject for a domain event type on this scoped bus. */\n getDomainEvent(eventType: PersistedEventType): Subject<StoredEvent> {\n return this.get(eventType as keyof EventMap) as unknown as Subject<StoredEvent>;\n }\n\n /**\n * Create a nested scope\n *\n * Allows hierarchical scoping like `resource-1:subsystem-a`\n *\n * @param subScope - Additional scope level\n * @returns A nested scoped event bus\n */\n scope(subScope: string): ScopedEventBus {\n return new ScopedEventBus(this.parent, `${this.scopePrefix}:${subScope}`);\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/faulty-transport.ts"],"names":[],"mappings":"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","file":"chunk-I3ZOWCTH.js","sourcesContent":["/**\n * FaultyTransport — a seeded, scriptable `ITransport` simulator for the\n * liveness axioms (`.plans/LIVENESS-AXIOMS.md`). fast-check draws a fault\n * schedule; the transport applies one `FaultAction` per request-channel emit\n * and synthesizes replies from the `BUS_OPERATIONS` registry, so real\n * compositions (`busRequest`, SWR caches, live queries) run unmodified against\n * generated wire behavior no hand-written test names.\n *\n * Home is core (not sdk/test-utils) for the same reason as\n * `assertStateUnitAxioms`: it needs only core types, and every layer —\n * including `http-transport`, below sdk — can consume it via\n * `@semiont/core/testing` without a dependency cycle.\n *\n * Deterministic-by-construction: no `Date.now`, no randomness of its own —\n * all variation comes in through the schedule (fast-check owns the seed).\n * Time is real `setTimeout` at millisecond scale; properties pass a small\n * explicit `timeoutMs` to `busRequest`, so nothing waits 30 s.\n */\n\nimport { BehaviorSubject, Subject, type Observable } from 'rxjs';\nimport type { SemiontError } from './errors';\nimport type { BaseUrl } from './branded-types';\nimport { baseUrl as makeBaseUrl } from './branded-types';\nimport type { ResourceId } from './identifiers';\nimport type { EventMap } from './bus-protocol';\nimport type { ConnectionState, ITransport } from './transport';\nimport { EventBus } from './event-bus';\nimport { BRIDGED_CHANNELS } from './bridged-channels';\nimport { BUS_OPERATIONS, type BusOperationKey } from './bus-operations';\n\n/** One wire behavior, applied to a single request-channel emit. */\nexport type FaultAction =\n | { kind: 'deliver' }\n | { kind: 'drop-reply' }\n | { kind: 'delay'; ms: number }\n | { kind: 'duplicate-reply' }\n | { kind: 'reject-emit' };\n\n/** requestLog entry — one per request-channel emit, in arrival order. */\nexport interface RequestLogEntry {\n channel: BusOperationKey;\n /** The action the schedule assigned to this emit. */\n action: FaultAction;\n correlationId: string | undefined;\n /**\n * Request identity for retry accounting: channel + payload minus the\n * per-issue fields (`correlationId`, `_trace`, `_userId`). Two emits with\n * the same key are the same logical request re-issued.\n */\n retryKey: string;\n /**\n * The payload as emitted — envelope, options, params, `correlationId` and\n * all. This is the surface for \"assert what my orchestrator actually SENT\"\n * (SDK-TESTING-DOUBLE gap 6): without it every consumer harness re-invented\n * a per-channel `transport.on(...)` wire recorder alongside this log.\n *\n * SHALLOW snapshot: the top level is copied at emit time, so a caller that\n * mutates its own payload object afterwards cannot rewrite history. Nested\n * objects are shared by reference — deep-freeze is not worth the cost in a\n * double, and no in-repo caller mutates nested request payloads.\n */\n payload: Record<string, unknown>;\n}\n\nexport interface FaultyTransportConfig {\n /**\n * The i-th request-channel emit applies `schedule[i % schedule.length]`.\n * Empty/omitted → every request delivers.\n */\n schedule?: readonly FaultAction[];\n /**\n * Synthesize the `response` value for a delivered reply. Return `undefined`\n * for a void ack (`{ correlationId }` only). Default: `{}` for every op.\n */\n makeResponse?: (operation: BusOperationKey, payload: Record<string, unknown>) => unknown;\n}\n\nfunction isOperation(channel: string): channel is BusOperationKey {\n return channel in BUS_OPERATIONS;\n}\n\n/** Stable request identity: channel + sorted payload minus per-issue fields. */\nexport function retryKeyOf(channel: string, payload: Record<string, unknown>): string {\n const entries = Object.entries(payload)\n .filter(([k]) => k !== 'correlationId' && k !== '_trace' && k !== '_userId')\n .sort(([a], [b]) => (a < b ? -1 : 1));\n return `${channel} ${JSON.stringify(entries)}`;\n}\n\nexport class FaultyTransport implements ITransport {\n readonly baseUrl: BaseUrl = makeBaseUrl('faulty://simulator');\n readonly state$ = new BehaviorSubject<ConnectionState>('open');\n private readonly errorsSubject = new Subject<SemiontError>();\n readonly errors$: Observable<SemiontError> = this.errorsSubject.asObservable();\n\n /** Every request-channel emit, in order — the L2 accounting surface. */\n readonly requestLog: RequestLogEntry[] = [];\n\n private readonly bus = new EventBus();\n private readonly schedule: readonly FaultAction[];\n private readonly makeResponse: (op: BusOperationKey, payload: Record<string, unknown>) => unknown;\n private readonly replyQueues = new Map<BusOperationKey, unknown[]>();\n private requestCount = 0;\n private readonly timers = new Set<ReturnType<typeof setTimeout>>();\n private disposed = false;\n\n constructor(cfg: FaultyTransportConfig = {}) {\n this.schedule = cfg.schedule ?? [];\n this.makeResponse = cfg.makeResponse ?? (() => ({}));\n }\n\n /**\n * Queue responses for `op`, consumed FIFO — one per request that reaches\n * the simulated backend — before falling back to `makeResponse`\n * (SDK-TESTING-DOUBLE.md, gap 2). The queue scripts the BACKEND; the fault\n * schedule scripts the WIRE. Consequences, deliberately: `duplicate-reply`\n * replays one entry's body twice, and a `drop-reply` still consumes its\n * entry (the backend answered; the wire ate it) — so \"first reply lost,\n * the retry sees the NEXT page\" is expressible. `reject-emit` consumes\n * nothing: that request never reached the backend.\n */\n queueReply(op: BusOperationKey, ...responses: unknown[]): void {\n const q = this.replyQueues.get(op) ?? [];\n q.push(...responses);\n this.replyQueues.set(op, q);\n }\n\n // ── Bus primitives ──────────────────────────────────────────────────────\n\n async emit<K extends keyof EventMap>(\n channel: K,\n payload: EventMap[K],\n resourceScope?: ResourceId,\n ): Promise<void> {\n if (this.disposed) return;\n const name = channel as string;\n if (!isOperation(name)) {\n // Non-request channel: forward as-is (scoped or global).\n const target = resourceScope === undefined\n ? this.bus.get(channel)\n : this.bus.scope(resourceScope as string).get(channel);\n target.next(payload);\n return;\n }\n\n const record = payload as Record<string, unknown>;\n const action: FaultAction = this.schedule.length === 0\n ? { kind: 'deliver' }\n : this.schedule[this.requestCount % this.schedule.length]!;\n this.requestCount += 1;\n this.requestLog.push({\n channel: name,\n action,\n correlationId: typeof record.correlationId === 'string' ? record.correlationId : undefined,\n retryKey: retryKeyOf(name, record),\n payload: { ...record },\n });\n\n if (action.kind === 'reject-emit') {\n // Models a /bus/emit 4xx: the request never reaches the bus.\n throw new Error(`FaultyTransport: emit rejected by schedule (reject-emit) on ${name}`);\n }\n\n // The request itself is observable (handlers-eye view), then the\n // simulator plays backend: synthesize the registry reply per the action.\n this.bus.get(channel).next(payload);\n\n // The backend's answer is computed ONCE per request that reaches it —\n // the reply QUEUE scripts the backend, the fault schedule scripts the\n // wire (SDK-TESTING-DOUBLE.md Phase 2). So `duplicate-reply` replays the\n // same body twice, and a `drop-reply` still consumes its queue entry:\n // the backend answered, the wire ate it.\n const queue = this.replyQueues.get(name);\n const response = queue && queue.length > 0 ? queue.shift() : this.makeResponse(name, record);\n\n const reply = (): void => {\n if (this.disposed) return;\n const replyPayload = response === undefined\n ? { correlationId: record.correlationId }\n : { correlationId: record.correlationId, response };\n const resultChannel = BUS_OPERATIONS[name].result as keyof EventMap;\n this.bus.get(resultChannel).next(replyPayload as EventMap[keyof EventMap]);\n };\n\n switch (action.kind) {\n case 'deliver':\n queueMicrotask(reply);\n break;\n case 'duplicate-reply':\n queueMicrotask(reply);\n queueMicrotask(reply);\n break;\n case 'delay': {\n const t = setTimeout(() => { this.timers.delete(t); reply(); }, action.ms);\n this.timers.add(t);\n break;\n }\n case 'drop-reply':\n break;\n }\n }\n\n on<K extends keyof EventMap>(channel: K, handler: (payload: EventMap[K]) => void): () => void {\n const sub = this.bus.get(channel).subscribe(handler);\n return () => sub.unsubscribe();\n }\n\n stream<K extends keyof EventMap>(channel: K): Observable<EventMap[K]> {\n return this.bus.get(channel);\n }\n\n subscribeToResource(_rid: ResourceId): () => void {\n // Mirrors the real HttpTransport: distinct scopes COMPOSE\n // (MULTI-RESOURCE-SCOPE). Delivery here is bus-direct and never\n // scope-gated, so acquisition needs no bookkeeping and release\n // (idempotent by construction) is a no-op.\n return () => {};\n }\n\n /**\n * Correlated-reply tracking (BUS-RESUMPTION.md Phase 2 / SDK-DEBT S1),\n * exposed for assertions: `busRequest` registers each cid here before its\n * emit and releases on settle, so a test can pin the tracked set at any\n * point of a request's lifecycle. Delivery in this double is bus-direct\n * (nothing to replay), so tracking has no behavioral effect.\n */\n readonly pendingReplies = new Set<string>();\n\n trackReply(correlationId: string): () => void {\n this.pendingReplies.add(correlationId);\n let released = false;\n return () => {\n if (released) return;\n released = true;\n this.pendingReplies.delete(correlationId);\n };\n }\n\n bridgeInto(bus: EventBus): void {\n for (const channel of BRIDGED_CHANNELS) {\n this.bus.get(channel as keyof EventMap).subscribe((payload) => {\n bus.get(channel as keyof EventMap).next(payload as EventMap[keyof EventMap]);\n });\n }\n }\n\n // ── Lifecycle ───────────────────────────────────────────────────────────\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n for (const t of this.timers) clearTimeout(t);\n this.timers.clear();\n this.state$.next('closed');\n this.state$.complete();\n this.errorsSubject.complete();\n // Completes every subject: in-flight busRequests resolve `bus.closed`.\n this.bus.destroy();\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/toml-loader.ts"],"names":["parseToml"],"mappings":"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","file":"chunk-XQTWEBJ5.js","sourcesContent":["/**\n * TOML Config Loader\n *\n * Reads ~/.semiontconfig (TOML) and .semiont/config (TOML) and produces\n * an EnvironmentConfig for the requested environment.\n *\n * File format: see TOML-XDG-CONFIG.md\n *\n * Loading sequence:\n * 1. Read .semiont/config → projectName, site, environments.<env>.* (project base)\n * 2. Read ~/.semiontconfig → defaults, environments.<env>.* (user overrides)\n * 3. Deep-merge: project base ← user overrides (user wins on conflicts)\n * Any environment name is valid (local, staging, production, custom, ...)\n * 4. Resolve ${VAR} references from process.env\n * 5. Apply inheritance: workers.<name> → workers.default → error\n * 6. Map to EnvironmentConfig shape\n */\n\nimport { parse as parseToml } from 'smol-toml';\nimport type { EnvironmentConfig, OllamaProviderConfig, AnthropicProviderConfig } from './config.types';\nimport type { PlatformType } from './config.types';\n\n/**\n * Deep merge two plain objects. Arrays and primitives in `override` replace those in `base`.\n * Nested objects are merged recursively. `override` takes precedence on conflicts.\n */\nfunction deepMerge<T extends Record<string, unknown>>(base: T, override: Partial<T>): T {\n const result = { ...base } as Record<string, unknown>;\n for (const key of Object.keys(override)) {\n const b = base[key];\n const o = override[key];\n if (o !== undefined && o !== null && typeof o === 'object' && !Array.isArray(o) &&\n b !== undefined && b !== null && typeof b === 'object' && !Array.isArray(b)) {\n result[key] = deepMerge(b as Record<string, unknown>, o as Record<string, unknown>);\n } else if (o !== undefined) {\n result[key] = o;\n }\n }\n return result as T;\n}\n\nfunction resolveEnvVars(obj: unknown, env: Record<string, string | undefined>): unknown {\n if (typeof obj === 'string') {\n return obj.replace(/\\$\\{([^}]+)\\}/g, (match, expr: string) => {\n const sepIdx = expr.indexOf(':-');\n const varName = sepIdx >= 0 ? expr.slice(0, sepIdx) : expr;\n const defaultValue = sepIdx >= 0 ? expr.slice(sepIdx + 2) : undefined;\n const value = env[varName];\n if (value !== undefined) return value;\n if (defaultValue !== undefined) return defaultValue;\n throw new Error(`Environment variable ${varName} is not set (referenced in config as ${match})`);\n });\n }\n if (Array.isArray(obj)) {\n return obj.map(item => resolveEnvVars(item, env));\n }\n if (obj !== null && typeof obj === 'object') {\n const resolved: Record<string, unknown> = {};\n for (const key in obj as Record<string, unknown>) {\n resolved[key] = resolveEnvVars((obj as Record<string, unknown>)[key], env);\n }\n return resolved;\n }\n return obj;\n}\n\n// ── Inference config types (mirrored from packages/make-meaning/src/config.ts) ─\n// Kept here to avoid a circular dependency: core cannot import make-meaning.\n\nexport interface InferenceConfig {\n type: 'anthropic' | 'ollama';\n model: string;\n maxTokens?: number;\n apiKey?: string;\n endpoint?: string;\n baseURL?: string;\n}\n\nexport interface ActorInferenceConfig {\n gatherer?: InferenceConfig;\n matcher?: InferenceConfig;\n}\n\nexport interface WorkerInferenceConfig {\n default?: InferenceConfig;\n 'reference-annotation'?: InferenceConfig;\n 'highlight-annotation'?: InferenceConfig;\n 'assessment-annotation'?: InferenceConfig;\n 'comment-annotation'?: InferenceConfig;\n 'tag-annotation'?: InferenceConfig;\n 'generation'?: InferenceConfig;\n}\n\n// ── Types for ~/.semiontconfig ────────────────────────────────────────────────\n\ninterface SemiontConfigFile {\n user?: {\n name?: string;\n email?: string;\n };\n defaults?: {\n environment?: string;\n platform?: string;\n };\n environments?: Record<string, EnvironmentSection>;\n}\n\ninterface GraphSection {\n platform?: string;\n type?: string;\n name?: string;\n uri?: string;\n username?: string;\n password?: string;\n database?: string;\n [key: string]: unknown;\n}\n\ninterface InferenceFlatSection {\n // Flat (single-provider) format: type = \"anthropic\"|\"ollama\" at this level\n type?: 'anthropic' | 'ollama';\n platform?: string;\n model?: string;\n maxTokens?: number;\n apiKey?: string;\n endpoint?: string;\n baseURL?: string;\n // Keyed (multi-provider) format: [inference.anthropic] / [inference.ollama]\n anthropic?: { platform?: string; apiKey?: string; endpoint?: string };\n ollama?: { platform?: string; baseURL?: string; port?: number };\n}\n\ninterface EnvironmentSection {\n backend?: {\n platform?: string;\n port?: number;\n publicURL?: string;\n frontendURL?: string;\n };\n frontend?: {\n platform?: string;\n port?: number;\n publicURL?: string;\n };\n site?: {\n domain?: string;\n siteName?: string;\n adminEmail?: string;\n oauthAllowedDomains?: string[];\n enableLocalAuth?: boolean;\n };\n database?: {\n platform?: string;\n image?: string;\n host?: string;\n port?: number;\n name?: string;\n user?: string;\n password?: string;\n };\n graph?: GraphSection;\n vectors?: {\n type?: 'qdrant' | 'memory';\n host?: string;\n port?: number;\n // Legacy: embedding nested under vectors (migrated to top-level)\n embedding?: {\n type?: 'voyage' | 'ollama';\n model?: string;\n apiKey?: string;\n baseURL?: string;\n endpoint?: string;\n };\n chunking?: {\n chunkSize?: number;\n overlap?: number;\n };\n };\n embedding?: {\n type?: 'voyage' | 'ollama';\n model?: string;\n apiKey?: string;\n baseURL?: string;\n endpoint?: string;\n chunking?: {\n chunkSize?: number;\n overlap?: number;\n };\n };\n inference?: InferenceFlatSection;\n 'make-meaning'?: {\n graph?: Record<string, unknown>;\n actors?: {\n gatherer?: { inference?: InferenceConfig };\n matcher?: { inference?: InferenceConfig };\n };\n default?: { inference?: InferenceConfig };\n /**\n * Resource-gather knobs. `settleTimeoutMs` bounds the semanticContext\n * read-your-writes barrier (SMELTER-INDEX-SYNC D3/D5) — how long a gather\n * waits for the vector projection to settle before degrading to an absent\n * semanticContext. Must nest INSIDE downstream watchdogs (job-worker\n * liveness, client stall watchdogs) — see SMELTER-INDEX-SYNC A4.\n */\n gather?: { settleTimeoutMs?: number };\n };\n workers?: Record<string, { inference?: InferenceConfig }>;\n actors?: Record<string, { inference?: InferenceConfig }>;\n logLevel?: 'error' | 'warn' | 'info' | 'http' | 'debug';\n}\n\n// ── File reader abstraction (same pattern as createConfigLoader) ──────────────\n\nexport type TomlFileReader = {\n readIfExists: (path: string) => string | null;\n};\n\nfunction requirePlatform(value: string | undefined, serviceName: string): PlatformType {\n if (!value) {\n throw new Error(`platform is required for service '${serviceName}' — add 'platform = \"posix\"|\"container\"|\"external\"' to its config section`);\n }\n return value as PlatformType;\n}\n\n// ── Main loader function ──────────────────────────────────────────────────────\n\n/**\n * Parse ~/.semiontconfig and .semiont/config and return EnvironmentConfig.\n *\n * @param projectRoot - Path to the project root (contains .semiont/config)\n * @param environment - Environment name (e.g. 'local', 'production'); when\n * undefined, resolved from `[defaults] environment`\n * @param globalConfigPath - Path to ~/.semiontconfig (caller resolves ~ expansion)\n * @param reader - File reader abstraction\n * @param env - Environment variables for ${VAR} resolution\n */\nexport function loadTomlConfig(\n projectRoot: string | null,\n environment: string | undefined,\n globalConfigPath: string,\n reader: TomlFileReader,\n env: Record<string, string | undefined>\n): EnvironmentConfig {\n // 1. Read + parse project config from .semiont/config (skipped when no project root)\n const projectConfigContent = projectRoot ? reader.readIfExists(`${projectRoot}/.semiont/config`) : null;\n const projectConfig = projectConfigContent\n ? (parseToml(projectConfigContent) as {\n project?: { name?: string; version?: string };\n site?: EnvironmentSection['site'];\n environments?: Record<string, EnvironmentSection>;\n })\n : undefined;\n const projectName = projectConfig?.project?.name ?? 'semiont-project';\n const projectVersion = projectConfig?.project?.version;\n const projectSite = projectConfig?.site;\n\n // 2. Read global config (optional — missing config yields empty environments)\n const globalContent = reader.readIfExists(globalConfigPath);\n const raw = globalContent ? (parseToml(globalContent) as SemiontConfigFile) : ({} as SemiontConfigFile);\n\n // 3. Resolve WHICH environment to load. `[defaults] environment` is the key the\n // launcher selects from (config.go: cfg.Defaults.Environment); the backend\n // resolves from the SAME key so one config selects the environment for both\n // halves. TWO inputs only — an explicit argument (tests pass one) and the\n // committed config — and they cannot contradict each other, because the\n // explicit one is legible at the call site. There is deliberately NO ambient\n // environment variable in this chain: `SEMIONT_ENV` was removed because an\n // invisible input that can disagree with the staged config is precisely the\n // bug shape #1108 fixed. And no silent 'local'/'development' fallback — an\n // unselected environment is a config error, not a default.\n const resolvedEnvironment = environment ?? raw.defaults?.environment;\n if (!resolvedEnvironment) {\n throw new Error(\n 'No environment selected: pass one explicitly, or declare ' +\n '`[defaults] environment` in ~/.semiontconfig.',\n );\n }\n\n // 4. A named environment with no [environments.X] section ANYWHERE is a config\n // error, not a silent empty {}. The silent {} is what let a KB declaring\n // `environment = \"staging\"` (with no [environments.staging]) load nothing and\n // let every downstream default fire — including site.domain -> 'localhost',\n // the fabricated colliding did:web:localhost identity. Fail loud instead.\n const projectHasSection =\n projectConfig?.environments != null && resolvedEnvironment in projectConfig.environments;\n const globalHasSection = raw.environments != null && resolvedEnvironment in raw.environments;\n if (!projectHasSection && !globalHasSection) {\n throw new Error(\n `Environment \"${resolvedEnvironment}\" is selected but no [environments.${resolvedEnvironment}] ` +\n 'section exists in the project (.semiont/config) or global (~/.semiontconfig) config. ' +\n 'Declare the section, or select an environment that exists.',\n );\n }\n\n // 5. Deep-merge: project base + user overrides (user wins on conflicts)\n const projectEnvSection: EnvironmentSection = projectConfig?.environments?.[resolvedEnvironment] ?? {};\n const userEnvSection: EnvironmentSection = raw.environments?.[resolvedEnvironment] ?? {};\n const envSection: EnvironmentSection = deepMerge(\n projectEnvSection as Record<string, unknown>,\n userEnvSection as Record<string, unknown>\n ) as EnvironmentSection;\n\n // 4. Resolve ${VAR} references\n const resolved = resolveEnvVars(envSection, env) as EnvironmentSection;\n\n // 5. Build make-meaning actor/worker inference config with inheritance\n // The flat [inference] section provides defaults (apiKey, maxTokens, endpoint/baseURL).\n // Actor/worker sections only need to specify type and model; missing fields fall back\n // to the flat inference section.\n const flatInference = resolved.inference;\n const makeMeaningSection = resolved['make-meaning'];\n const workersSection = resolved.workers ?? {};\n const actorsSection = resolved.actors ?? {};\n const defaultWorkerInference = workersSection['default']?.inference;\n const defaultMakeMeaningInference = makeMeaningSection?.default?.inference;\n\n function mergeWithFlatInference(specific: InferenceConfig): InferenceConfig {\n if (!flatInference) return specific;\n // For keyed sub-sections, inherit credentials from the matching provider sub-section.\n // For flat (legacy) format, flatInference.type is required to know which fields apply.\n const providerDefaults: Partial<InferenceConfig> = {};\n if (specific.type === 'anthropic') {\n const a = flatInference.anthropic;\n if (a) {\n providerDefaults.apiKey = a.apiKey;\n providerDefaults.endpoint = a.endpoint;\n } else {\n if (!flatInference.type) {\n throw new Error(\n `[environments.${resolvedEnvironment}.inference] is missing 'type'. ` +\n `Add type = \"anthropic\" or use [inference.anthropic] sub-section.`\n );\n }\n providerDefaults.apiKey = flatInference.apiKey;\n providerDefaults.endpoint = flatInference.endpoint;\n }\n } else if (specific.type === 'ollama') {\n const o = flatInference.ollama;\n if (o) {\n providerDefaults.baseURL = o.baseURL;\n } else {\n if (!flatInference.type) {\n throw new Error(\n `[environments.${resolvedEnvironment}.inference] is missing 'type'. ` +\n `Add type = \"ollama\" or use [inference.ollama] sub-section.`\n );\n }\n providerDefaults.baseURL = flatInference.baseURL;\n }\n }\n return {\n maxTokens: flatInference.maxTokens,\n ...providerDefaults,\n ...specific,\n };\n }\n\n function resolveActorInference(fromMakeMeaning?: InferenceConfig, fromActors?: InferenceConfig): InferenceConfig | undefined {\n const base = fromMakeMeaning ?? fromActors ?? defaultMakeMeaningInference;\n if (!base) return undefined;\n return mergeWithFlatInference(base);\n }\n\n const actors: ActorInferenceConfig = {};\n const gathererInference = resolveActorInference(\n makeMeaningSection?.actors?.gatherer?.inference,\n actorsSection['gatherer']?.inference\n );\n if (gathererInference) actors.gatherer = gathererInference;\n\n const matcherInference = resolveActorInference(\n makeMeaningSection?.actors?.matcher?.inference,\n actorsSection['matcher']?.inference\n );\n if (matcherInference) actors.matcher = matcherInference;\n\n const workers: WorkerInferenceConfig = {};\n const workerTypes = ['reference-annotation', 'highlight-annotation', 'assessment-annotation', 'comment-annotation', 'tag-annotation', 'generation'] as const;\n if (defaultWorkerInference) {\n workers.default = mergeWithFlatInference(defaultWorkerInference);\n }\n for (const wt of workerTypes) {\n const specific = workersSection[wt]?.inference;\n if (specific) {\n (workers as Record<string, InferenceConfig>)[wt] = mergeWithFlatInference(specific);\n }\n }\n\n // 6. Map to EnvironmentConfig\n const backend = resolved.backend;\n const site = resolved.site ?? projectSite;\n const inferenceSection = resolved.inference;\n\n // Build inference providers config.\n // Supports two formats:\n // Flat: [environments.local.inference] type = \"anthropic\"|\"ollama\" (single provider)\n // Keyed: [environments.local.inference.anthropic] / [environments.local.inference.ollama] (multi-provider)\n let inferenceProviders: EnvironmentConfig['inference'] | undefined;\n if (inferenceSection) {\n inferenceProviders = {};\n // Keyed sub-sections take priority\n if (inferenceSection.anthropic) {\n const a = inferenceSection.anthropic;\n inferenceProviders.anthropic = {\n platform: requirePlatform(a.platform, 'inference.anthropic'),\n endpoint: a.endpoint ?? 'https://api.anthropic.com',\n apiKey: a.apiKey ?? '',\n } as AnthropicProviderConfig;\n } else if (inferenceSection.type === 'anthropic') {\n inferenceProviders.anthropic = {\n platform: requirePlatform(inferenceSection.platform, 'inference'),\n endpoint: inferenceSection.endpoint ?? 'https://api.anthropic.com',\n apiKey: inferenceSection.apiKey ?? '',\n } as AnthropicProviderConfig;\n }\n if (inferenceSection.ollama) {\n const o = inferenceSection.ollama;\n inferenceProviders.ollama = {\n platform: { type: requirePlatform(o.platform, 'inference.ollama') },\n baseURL: o.baseURL,\n port: o.baseURL ? undefined : (o.port ?? 11434),\n } as OllamaProviderConfig;\n } else if (inferenceSection.type === 'ollama') {\n inferenceProviders.ollama = {\n platform: { type: requirePlatform(inferenceSection.platform, 'inference') },\n baseURL: inferenceSection.baseURL,\n port: inferenceSection.baseURL ? undefined : 11434,\n } as OllamaProviderConfig;\n }\n }\n\n // Build top-level workers/actors maps for EnvironmentConfig\n const topLevelWorkers: EnvironmentConfig['workers'] = {};\n for (const [name, w] of Object.entries(workersSection)) {\n if (w.inference) {\n topLevelWorkers[name] = { inference: { type: w.inference.type, model: w.inference.model } };\n }\n }\n const topLevelActors: EnvironmentConfig['actors'] = {};\n for (const [name, a] of Object.entries(actorsSection)) {\n if (a.inference) {\n topLevelActors[name] = { inference: { type: a.inference.type, model: a.inference.model } };\n }\n }\n // Also include make-meaning actors\n if (makeMeaningSection?.actors?.gatherer?.inference) {\n topLevelActors['gatherer'] = { inference: { type: makeMeaningSection.actors.gatherer.inference.type, model: makeMeaningSection.actors.gatherer.inference.model } };\n }\n if (makeMeaningSection?.actors?.matcher?.inference) {\n topLevelActors['matcher'] = { inference: { type: makeMeaningSection.actors.matcher.inference.type, model: makeMeaningSection.actors.matcher.inference.model } };\n }\n\n const frontend = resolved.frontend;\n\n const services: EnvironmentConfig['services'] = {};\n\n if (backend) {\n services.backend = {\n platform: { type: requirePlatform(backend.platform, 'backend') },\n port: backend.port ?? 4000,\n publicURL: backend.publicURL ?? `http://localhost:${backend.port ?? 4000}`,\n };\n }\n\n if (frontend) {\n services.frontend = {\n platform: { type: requirePlatform(frontend.platform, 'frontend') },\n port: frontend.port ?? 3000,\n siteName: site?.siteName ?? 'Semiont',\n publicURL: frontend.publicURL,\n };\n }\n\n if (resolved.graph) {\n services.graph = {\n ...resolved.graph,\n platform: { type: requirePlatform(resolved.graph.platform as string | undefined, 'graph') },\n type: (resolved.graph.type ?? 'neo4j') as import('./config.types').GraphDatabaseType,\n } as EnvironmentConfig['services']['graph'];\n } else if (makeMeaningSection?.graph) {\n services.graph = makeMeaningSection.graph as EnvironmentConfig['services']['graph'];\n }\n\n if (resolved.database) {\n services.database = {\n platform: { type: requirePlatform(resolved.database.platform, 'database') },\n type: 'postgres',\n image: resolved.database.image,\n host: resolved.database.host ?? 'localhost',\n port: resolved.database.port ?? 5432,\n name: resolved.database.name,\n user: resolved.database.user,\n password: resolved.database.password,\n } as EnvironmentConfig['services']['database'];\n }\n\n if (resolved.vectors) {\n services.vectors = {\n platform: { type: 'external' as PlatformType },\n type: (resolved.vectors.type ?? 'qdrant') as 'qdrant' | 'memory',\n host: resolved.vectors.host,\n port: resolved.vectors.port ?? 6333,\n } as EnvironmentConfig['services']['vectors'];\n }\n\n // Embedding: top-level takes precedence, fall back to legacy vectors.embedding\n const embeddingSource = resolved.embedding ?? resolved.vectors?.embedding;\n if (embeddingSource) {\n services.embedding = {\n platform: { type: 'external' as PlatformType },\n type: embeddingSource.type!,\n model: embeddingSource.model!,\n apiKey: embeddingSource.apiKey,\n baseURL: embeddingSource.baseURL,\n endpoint: embeddingSource.endpoint,\n chunking: (resolved.embedding?.chunking ?? resolved.vectors?.chunking) ? {\n chunkSize: (resolved.embedding?.chunking ?? resolved.vectors?.chunking)?.chunkSize ?? 512,\n overlap: (resolved.embedding?.chunking ?? resolved.vectors?.chunking)?.overlap ?? 64,\n } : undefined,\n } as EnvironmentConfig['services']['embedding'];\n }\n\n const config: EnvironmentConfig = {\n services,\n ...(inferenceProviders ? { inference: inferenceProviders } : {}),\n ...(Object.keys(topLevelWorkers).length > 0 ? { workers: topLevelWorkers } : {}),\n ...(Object.keys(topLevelActors).length > 0 ? { actors: topLevelActors } : {}),\n site: site ? {\n domain: site.domain ?? 'localhost',\n siteName: site.siteName,\n adminEmail: site.adminEmail,\n oauthAllowedDomains: site.oauthAllowedDomains as [string, ...string[]] | undefined,\n } : undefined,\n logLevel: resolved.logLevel,\n _metadata: {\n environment: resolvedEnvironment,\n projectRoot,\n projectName,\n projectVersion,\n ...(Object.keys(actors).length > 0 ? { actors } : {}),\n ...(Object.keys(workers).length > 0 ? { workers } : {}),\n // Always set — the loader is the ONE home of this default (D5).\n // Consuming code (make-meaning's gather path) receives a required\n // value and defaults nothing.\n gather: { settleTimeoutMs: makeMeaningSection?.gather?.settleTimeoutMs ?? 15_000 },\n },\n };\n\n return config;\n}\n\n/**\n * Create a TOML config loader backed by a file reader.\n * Drop-in replacement for createConfigLoader that reads TOML instead of JSON.\n * The caller must resolve globalConfigPath (e.g. expand '~' using process.env.HOME).\n */\nexport function createTomlConfigLoader(\n reader: TomlFileReader,\n globalConfigPath: string,\n env: Record<string, string | undefined>\n) {\n return (projectRoot: string | null, environment?: string): EnvironmentConfig => {\n return loadTomlConfig(projectRoot, environment, globalConfigPath, reader, env);\n };\n}\n"]}
|