@demlik/tea 0.14.0 → 0.15.0

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.
Files changed (77) hide show
  1. package/dist/agent/index.d.ts +14 -13
  2. package/dist/agent/index.js +6 -6
  3. package/dist/{chunk-F2US5BW6.js → chunk-22POWGFA.js} +17 -11
  4. package/dist/chunk-22POWGFA.js.map +1 -0
  5. package/dist/{chunk-HYDWG35Q.js → chunk-3B5X7SBB.js} +4 -4
  6. package/dist/{chunk-HYDWG35Q.js.map → chunk-3B5X7SBB.js.map} +1 -1
  7. package/dist/{chunk-RQULHGYH.js → chunk-66PY5WYF.js} +15 -3
  8. package/dist/{chunk-RQULHGYH.js.map → chunk-66PY5WYF.js.map} +1 -1
  9. package/dist/{chunk-AQ6ZIMEA.js → chunk-AYS5N6WY.js} +121 -37
  10. package/dist/chunk-AYS5N6WY.js.map +1 -0
  11. package/dist/{chunk-HUKZQX6U.js → chunk-L3TND7LA.js} +3 -3
  12. package/dist/{chunk-HUKZQX6U.js.map → chunk-L3TND7LA.js.map} +1 -1
  13. package/dist/{chunk-I5MQMJDW.js → chunk-Q5CQTBFA.js} +3 -3
  14. package/dist/{chunk-I5MQMJDW.js.map → chunk-Q5CQTBFA.js.map} +1 -1
  15. package/dist/{chunk-F7FMAWLA.js → chunk-QPEVCJ5Q.js} +3 -3
  16. package/dist/{chunk-F7FMAWLA.js.map → chunk-QPEVCJ5Q.js.map} +1 -1
  17. package/dist/{chunk-Z2L3LSNV.js → chunk-TCLBCERH.js} +17 -7
  18. package/dist/chunk-TCLBCERH.js.map +1 -0
  19. package/dist/{chunk-BLJ2JQSH.js → chunk-V46HSVCK.js} +3 -3
  20. package/dist/{chunk-BLJ2JQSH.js.map → chunk-V46HSVCK.js.map} +1 -1
  21. package/dist/{chunk-LYLTKJWM.js → chunk-VTQI2NHP.js} +3 -3
  22. package/dist/{chunk-LYLTKJWM.js.map → chunk-VTQI2NHP.js.map} +1 -1
  23. package/dist/{core-CTzMJ82M.d.ts → core-DnzqWy6u.d.ts} +1 -1
  24. package/dist/do/index.d.ts +13 -12
  25. package/dist/do/index.js +7 -7
  26. package/dist/{durable-effects-B0-qGQDy.d.ts → durable-effects-CWzA-o2B.d.ts} +1 -1
  27. package/dist/extension/index.d.ts +3 -3
  28. package/dist/extension/index.js +1 -1
  29. package/dist/flow/index.d.ts +15 -26
  30. package/dist/flow/index.js +8 -8
  31. package/dist/idempotency/index.d.ts +3 -3
  32. package/dist/idempotency/index.js +2 -2
  33. package/dist/{index-4vZzljCD.d.ts → index-C2DwkjlP.d.ts} +4 -4
  34. package/dist/{index-B5BZ-_cT.d.ts → index-CA_7I5g9.d.ts} +277 -87
  35. package/dist/{index-DJWIER_3.d.ts → index-CSyMYDAB.d.ts} +1 -1
  36. package/dist/{index-6A7dB8f6.d.ts → index-CuNO9m8i.d.ts} +2 -2
  37. package/dist/{index-TvRb1KVf.d.ts → index-DrIRb_Ch.d.ts} +1 -1
  38. package/dist/{index-q0hXFeZ0.d.ts → index-HSYgG2Yt.d.ts} +50 -15
  39. package/dist/{index-NjrT3fL2.d.ts → index-KXqTRJyb.d.ts} +4 -4
  40. package/dist/{index-DMCeMPMJ.d.ts → index-ZCMhnVKN.d.ts} +1 -1
  41. package/dist/index.d.ts +66 -6
  42. package/dist/index.js +1 -1
  43. package/dist/jev/index.d.ts +34 -22
  44. package/dist/jev/index.js +178 -126
  45. package/dist/jev/index.js.map +1 -1
  46. package/dist/{machine-CdIcN2Xm.d.ts → machine-DGlPWCWI.d.ts} +34 -26
  47. package/dist/machine-viz/index.d.ts +1 -1
  48. package/dist/machine-viz/index.js +1 -1
  49. package/dist/mem/index.d.ts +2 -2
  50. package/dist/mem/index.js +1 -1
  51. package/dist/node/index.d.ts +2 -2
  52. package/dist/node/index.js +1 -1
  53. package/dist/paginate/index.d.ts +6 -17
  54. package/dist/paginate/index.js +4 -4
  55. package/dist/parity/index.d.ts +3 -3
  56. package/dist/parity/index.js +2 -2
  57. package/dist/pbt/index.d.ts +1 -1
  58. package/dist/pbt/index.js +1 -1
  59. package/dist/persistence/index.d.ts +5 -5
  60. package/dist/persistence/index.js +3 -3
  61. package/dist/protocol-D8VbH-VH.d.ts +54 -0
  62. package/dist/react/index.d.ts +2 -2
  63. package/dist/react/index.js +1 -1
  64. package/dist/resilience/index.d.ts +8 -7
  65. package/dist/resilience/index.js +5 -5
  66. package/dist/{runtime-types-LWDoi943.d.ts → runtime-types-CMF13BBh.d.ts} +1 -1
  67. package/dist/testing/index.d.ts +147 -3
  68. package/dist/testing/index.js +95 -2
  69. package/dist/testing/index.js.map +1 -1
  70. package/dist/timing/index.d.ts +4 -4
  71. package/dist/timing/index.js +3 -3
  72. package/dist/{types-DP3f5NIl.d.ts → types-BseNPIhr.d.ts} +1 -1
  73. package/dist/work-queue/index.d.ts +4 -4
  74. package/package.json +1 -1
  75. package/dist/chunk-AQ6ZIMEA.js.map +0 -1
  76. package/dist/chunk-F2US5BW6.js.map +0 -1
  77. package/dist/chunk-Z2L3LSNV.js.map +0 -1
@@ -1,59 +1,6 @@
1
- import { a as CmdOf, b as CmdDef, i as CmdValue, C as Cmd } from './core-CTzMJ82M.js';
1
+ import { a as CmdOf, b as CmdDef, i as NoCtx, C as Cmd } from './core-DnzqWy6u.js';
2
2
  import { RetryState, AnyRetryPolicy } from './retry-backoff/index.js';
3
- import { T as TtlCache, D as DeadlineExceeded, a as DeadlineSub } from './index-q0hXFeZ0.js';
4
-
5
- /**
6
- * The closed set of cross-module Msg/Cmd discriminant strings. Declared `as
7
- * const` so each entry is usable as both a value (construction / reducer keys /
8
- * switch labels) and, via `typeof MsgType.X`, a literal type (`readonly type:`
9
- * fields). The single source of truth for issue #60.
10
- */
11
- declare const MsgType: {
12
- /** The "run the port for `key`" effect Cmd resilient-call emits. */
13
- readonly ResilientRun: "resilient_run";
14
- /** PRIVATE success settle Msg (read only by `agentEvents`, #47). */
15
- readonly ResilientOk: "resilient_ok";
16
- /** Failure settle Msg — routed to the `fail` verb (back off via retry). */
17
- readonly ResilientErr: "resilient_err";
18
- /** Begin a run. */
19
- readonly AgentStart: "agent_start";
20
- /** PRIVATE tool-fan-out success settle Msg (read only by `agentEvents`, #47). */
21
- readonly AgentToolOk: "agent_tool_ok";
22
- /** Tool-fan-out failure settle Msg. */
23
- readonly AgentToolErr: "agent_tool_err";
24
- /**
25
- * Re-fire the one outstanding effect on rehydrate (the do↔agent seam). Fired
26
- * by `do/host`'s `autoBoot` via the typed `agentBootMsg` constructor, matched
27
- * by the agent reducer — see `AgentBootPort` in `../agent`.
28
- */
29
- readonly AgentBoot: "agent_boot";
30
- /**
31
- * Stop the run from outside and settle it `cancelled` — what an `AbortSignal`
32
- * handed to `driveToDone` / a defined agent's `run` dispatches on abort. A
33
- * transition, never a throw: the outcome lands in the Model, so a reload reads
34
- * a run that ended rather than one to resume.
35
- */
36
- readonly AgentCancel: "agent_cancel";
37
- /**
38
- * The "summarize the oldest N turns" effect Cmd the agent emits when its
39
- * `CompactionPolicy` asks to compact before a brain call. A DEDICATED
40
- * round-trip (design B1), distinct from the brain call's `resilient_run`, so
41
- * compaction is its own honest `Awaiting` state — see `../agent`.
42
- */
43
- readonly CompactRun: "compact_run";
44
- /** Compaction round-trip resolved — carries the summary text the fold-back folds. */
45
- readonly CompactOk: "compact_ok";
46
- /** Compaction round-trip failed (exhausted retry) — surfaced as data, not a stall. */
47
- readonly CompactErr: "compact_err";
48
- /** Refresh port resolved — carries the fresh `Token`. */
49
- readonly TokenRefreshed: "token_refreshed";
50
- /** Refresh port rejected — carries the rejection (errors are data). */
51
- readonly TokenRefreshFailed: "token_refresh_failed";
52
- /** The 401 the consumer dispatches when a guarded call comes back unauthorized. */
53
- readonly Unauthorized: "unauthorized";
54
- };
55
- /** The union of every discriminant string in the protocol. */
56
- type MsgTypeValue = (typeof MsgType)[keyof typeof MsgType];
3
+ import { T as TtlCache, D as DeadlineExceeded, a as DeadlineSub, s as subscribeDeadline } from './index-HSYgG2Yt.js';
57
4
 
58
5
  /**
59
6
  * @packageDocumentation
@@ -404,13 +351,46 @@ interface DeadlineConfig {
404
351
  /** Budget of in-process time from the moment a call starts, in ms. */
405
352
  readonly ms: number;
406
353
  }
354
+ /**
355
+ * The family every unnamed knob speaks: `resilient_run` / `resilient_ok` /
356
+ * `resilient_err`. Identical to the `MsgType.Resilient*` literals, which stay
357
+ * the vocabulary of every knob that passes no name.
358
+ */
359
+ declare const DEFAULT_RESILIENT_NAME = "resilient";
360
+ type DefaultResilientName = typeof DEFAULT_RESILIENT_NAME;
361
+ /** The run Cmd's `type` for the `N` family. */
362
+ type ResilientRunType<N extends string> = `${N}_run`;
363
+ /** The success settle Msg's `type` for the `N` family. */
364
+ type ResilientOkType<N extends string> = `${N}_ok`;
365
+ /** The failure settle Msg's `type` for the `N` family. */
366
+ type ResilientErrType<N extends string> = `${N}_err`;
407
367
  /**
408
368
  * The resilience knob. EVERY field is optional: omit a brick and its gate is
409
369
  * skipped entirely (the slice still carries a default brick state so the shape
410
370
  * stays uniform across configs, but the gate is never consulted). An empty
411
371
  * config `{}` is a valid pass-through — a bare effect with no resilience at all.
372
+ *
373
+ * `N` is the knob's Msg-name family (see {@link ResilientName}); it is carried on
374
+ * the config so the run Cmd and the two settle Msgs are named from ONE place.
412
375
  */
413
- interface ResilientConfig {
376
+ interface ResilientConfig<N extends string = DefaultResilientName> {
377
+ /**
378
+ * What this knob's Cmd and settle Msgs are called: `<name>_run`, `<name>_ok`,
379
+ * `<name>_err`. Omit it and the family is `resilient` — `resilient_run` /
380
+ * `resilient_ok` / `resilient_err`, exactly as before this parameter existed.
381
+ *
382
+ * Name a knob when a machine mounts more than one of the resilient family.
383
+ * Two unnamed knobs meet in ONE `resilient_ok` cell whose payload is the union
384
+ * of both results, and the consumer discriminates by hand on `key` — which the
385
+ * type checker cannot see. Under distinct names each knob settles into its own
386
+ * cell, already narrowed to its own payload.
387
+ *
388
+ * The name is a value AND a type: the settle Msg types are generic in `N`, and
389
+ * `N` is not inferable from `I` / `R`, so an opted-in knob spells all three
390
+ * type arguments — `createResilientCall<In, Out, "jev">({ name: "jev", … })`.
391
+ * The `name` field is typed at `N`, so the two cannot drift apart.
392
+ */
393
+ readonly name?: N;
414
394
  /**
415
395
  * The backoff brick. Omit and a failure is terminal (no backoff, no timer).
416
396
  *
@@ -523,7 +503,7 @@ interface ResilientState<I, R> {
523
503
  * consumer's `handlers(ports)` interprets it; it carries no closure — `input`
524
504
  * is plain data (invariant 3).
525
505
  */
526
- declare function runCmdDef<I, R>(): CmdDef<"resilient_run", {
506
+ declare function runCmdDef<I, R, N extends string = DefaultResilientName>(name?: N): CmdDef<`${N}_run`, {
527
507
  readonly key: string;
528
508
  readonly input: I;
529
509
  }, R, {
@@ -533,23 +513,48 @@ declare function runCmdDef<I, R>(): CmdDef<"resilient_run", {
533
513
  readonly [detail: string]: unknown;
534
514
  readonly _tag: "port_rejected";
535
515
  }, unknown>;
536
- type RunCmdDef<I, R> = ReturnType<typeof runCmdDef<I, R>>;
537
- type RunCmd<I> = CmdOf<RunCmdDef<I, unknown>>;
538
- /** Settle Msgs the `handlers` port dispatches back. `at` is stamped at the boundary. */
539
- type SucceedMsg<R> = {
540
- readonly type: typeof MsgType.ResilientOk;
516
+ type RunCmdDef<I, R, N extends string = DefaultResilientName> = ReturnType<typeof runCmdDef<I, R, N>>;
517
+ type RunCmd<I, N extends string = DefaultResilientName> = CmdOf<RunCmdDef<I, unknown, N>>;
518
+ /**
519
+ * Settle Msgs the `handlers` port dispatches back. `at` is stamped at the
520
+ * boundary. Both are generic in the knob's name family `N`, so two knobs named
521
+ * apart land in two `update` cells whose payloads are already narrowed — the
522
+ * `key` switch a single shared cell forces is gone.
523
+ */
524
+ type SucceedMsg<R, N extends string = DefaultResilientName> = {
525
+ readonly type: ResilientOkType<N>;
541
526
  readonly key: string;
542
527
  readonly result: R;
543
528
  readonly at: number;
544
529
  };
545
- type FailMsg = {
546
- readonly type: typeof MsgType.ResilientErr;
530
+ type FailMsg<N extends string = DefaultResilientName> = {
531
+ readonly type: ResilientErrType<N>;
547
532
  readonly key: string;
548
533
  readonly error: unknown;
549
534
  readonly at: number;
550
535
  };
551
- /** The retry / deadline timer Msg — `DeadlineExceeded`, keyed by the call `key`. */
552
- type ResilientTimerMsg = DeadlineExceeded;
536
+ /**
537
+ * The deadline Msg tag this knob's timers dispatch, derived from its name the
538
+ * same way `<name>_ok` / `<name>_err` are. The DEFAULT family keeps the bare
539
+ * `"deadline_exceeded"` literal — that is the tag every machine wired before
540
+ * the name existed already handles, and `mountResilientCall` still returns a
541
+ * `deadline_exceeded` cell for an unnamed knob.
542
+ */
543
+ type ResilientDeadlineType<N extends string = DefaultResilientName> = N extends DefaultResilientName ? "deadline_exceeded" : `${N}_deadline`;
544
+ /**
545
+ * The name the deadline Sub carries for the `N` family — `undefined` for the
546
+ * default family (no name at all, so the bare literal is dispatched), the name
547
+ * itself otherwise. One conditional, so the value and {@link
548
+ * ResilientDeadlineType} can never disagree about which family is unnamed.
549
+ */
550
+ type DeadlineNameOf<N extends string = DefaultResilientName> = N extends DefaultResilientName ? undefined : N;
551
+ /**
552
+ * The retry / deadline timer Msg — a `DeadlineExceeded` whose tag is this
553
+ * knob's ({@link ResilientDeadlineType}), keyed by the call `key` through the
554
+ * Sub `id`. Bare `ResilientTimerMsg` is the default family's, so it is the same
555
+ * `DeadlineExceeded` it has always been.
556
+ */
557
+ type ResilientTimerMsg<N extends string = DefaultResilientName> = DeadlineExceeded<DeadlineNameOf<N>>;
553
558
  /**
554
559
  * The plain-data error a deadline-failed call settles with. A `{_tag, ...}`
555
560
  * sentinel — NEVER a `new Error(...)` — so the slice stays JSON-serializable
@@ -562,6 +567,15 @@ type DeadlineExceededError = {
562
567
  readonly id: string;
563
568
  readonly atMs: number;
564
569
  };
570
+ /**
571
+ * What `handlers(ports)` returns: the interpret cell for this knob's run Cmd,
572
+ * under that Cmd's own name. A named knob contributes `<name>_run`, so two
573
+ * knobs' handler records merge into one `interpret` without either shadowing
574
+ * the other.
575
+ */
576
+ type ResilientHandlers<I, R, N extends string = DefaultResilientName> = {
577
+ readonly [K in ResilientRunType<N>]: (cmd: RunCmd<I, N>, ctx: NoCtx) => Promise<SucceedMsg<R, N> | FailMsg<N>>;
578
+ };
565
579
  /** Ports the consumer supplies to `handlers`. */
566
580
  interface ResilientPorts<I, R> {
567
581
  /** The fallible work this knob wraps. Throws on failure → routed to `fail`. */
@@ -579,27 +593,17 @@ interface ResilientPorts<I, R> {
579
593
  * `withResilience` (`../with-resilience`) — see the migration map at the top
580
594
  * of this module.
581
595
  */
582
- declare function createResilientCall<I, R>(config: ResilientConfig, rng?: () => number): {
596
+ declare function createResilientCall<I, R, N extends string = DefaultResilientName>(config: ResilientConfig<N>, rng?: () => number): {
597
+ name: N;
583
598
  init: () => ResilientState<I, R>;
584
- attempt: (s: ResilientState<I, R>, key: string, input: I, at: number) => readonly [ResilientState<I, R>, readonly RunCmd<I>[]];
599
+ attempt: (s: ResilientState<I, R>, key: string, input: I, at: number) => readonly [ResilientState<I, R>, readonly RunCmd<I, N>[]];
585
600
  resume: (s: ResilientState<I, R>, at: number) => ResilientState<I, R>;
586
- succeed: (s: ResilientState<I, R>, key: string, msg: SucceedMsg<R>) => readonly [ResilientState<I, R>, readonly RunCmd<I>[]];
587
- fail: (s: ResilientState<I, R>, key: string, msg: FailMsg) => readonly [ResilientState<I, R>, readonly RunCmd<I>[]];
588
- settleFailed: (s: ResilientState<I, R>, key: string, error: unknown) => readonly [ResilientState<I, R>, readonly RunCmd<I>[]];
589
- onTimer: (s: ResilientState<I, R>, msg: ResilientTimerMsg) => readonly [ResilientState<I, R>, readonly RunCmd<I>[]];
590
- subs: (s: ResilientState<I, R>) => readonly DeadlineSub[];
591
- handlers: (ports: ResilientPorts<I, R>) => {
592
- resilient_run: (cmd: CmdValue<"resilient_run", {
593
- readonly key: string;
594
- readonly input: I;
595
- }, {
596
- readonly [detail: string]: unknown;
597
- readonly _tag: "deadline_exceeded";
598
- } | {
599
- readonly [detail: string]: unknown;
600
- readonly _tag: "port_rejected";
601
- }, unknown>, ctx: Readonly<Record<never, never>>) => Promise<FailMsg | SucceedMsg<R>>;
602
- };
601
+ succeed: (s: ResilientState<I, R>, key: string, msg: SucceedMsg<R, N>) => readonly [ResilientState<I, R>, readonly RunCmd<I, N>[]];
602
+ fail: (s: ResilientState<I, R>, key: string, msg: FailMsg<N>) => readonly [ResilientState<I, R>, readonly RunCmd<I, N>[]];
603
+ settleFailed: (s: ResilientState<I, R>, key: string, error: unknown) => readonly [ResilientState<I, R>, readonly RunCmd<I, N>[]];
604
+ onTimer: (s: ResilientState<I, R>, msg: ResilientTimerMsg) => readonly [ResilientState<I, R>, readonly RunCmd<I, N>[]];
605
+ subs: (s: ResilientState<I, R>) => readonly DeadlineSub<DeadlineNameOf<N>>[];
606
+ handlers: (ports: ResilientPorts<I, R>) => ResilientHandlers<I, R, N>;
603
607
  };
604
608
  /**
605
609
  * Lift a knob result `[slice, cmds]` into a host `[State, cmds]` where the
@@ -608,9 +612,195 @@ declare function createResilientCall<I, R>(config: ResilientConfig, rng?: () =>
608
612
  * record rebuild, no clock / RNG. Under `withResilience` the wrapper owns
609
613
  * `model.$resilience`, so there is nothing to lift; this is for the embedded
610
614
  * slice consumers only.
615
+ *
616
+ * The record rebuild itself is `liftSlice` from the root door (#231) — this
617
+ * stays as the named, pre-keyed convenience for the `state.resilience` field,
618
+ * unchanged in name, signature and subpath.
611
619
  */
612
620
  declare function liftResilience<S extends {
613
621
  resilience: ResilientState<I, R>;
614
- }, I, R, C extends Cmd>(state: S, [slice, cmds]: readonly [ResilientState<I, R>, readonly C[]]): readonly [S, readonly C[]];
622
+ }, I, R, C extends Cmd>(state: S, result: readonly [ResilientState<I, R>, readonly C[]]): readonly [S, readonly C[]];
623
+ /** What every verb of a knob in this family hands back. */
624
+ type Settle<I, R> = readonly [
625
+ ResilientState<I, R>,
626
+ readonly RunCmd<I>[]
627
+ ];
628
+ /**
629
+ * The part of a resilient-call knob {@link mountResilientCall} needs. This knob
630
+ * satisfies it, and so does every knob that delegates these verbs to it —
631
+ * `internal/jev/ask` and `internal/llm-call` both do, which is why the mount is
632
+ * written against the shape rather than against either door.
633
+ *
634
+ * `OkMsg` / `ErrMsg` are parameters rather than {@link SucceedMsg} /
635
+ * {@link FailMsg} because an inheriting knob narrows them: jev-ask's `fail`
636
+ * takes a `JevFailMsg` whose `error` is a typed `JevAskErr`, and a mount that
637
+ * fixed the supertype would hand that verb a widened Msg.
638
+ */
639
+ interface MountableKnob<I, R, OkMsg, ErrMsg, Handlers, N extends string = DefaultResilientName> {
640
+ /**
641
+ * The Msg-name family this knob settles into — `<name>_ok` / `<name>_err`
642
+ * (#229). The mount reads it rather than assuming `resilient_*`, so a named
643
+ * knob mounts into the cells it actually emits; an unnamed one is
644
+ * `resilient`, so nothing a machine already spread changes.
645
+ */
646
+ readonly name: N;
647
+ init(): ResilientState<I, R>;
648
+ succeed(s: ResilientState<I, R>, key: string, msg: OkMsg): Settle<I, R>;
649
+ fail(s: ResilientState<I, R>, key: string, msg: ErrMsg): Settle<I, R>;
650
+ onTimer(s: ResilientState<I, R>, msg: ResilientTimerMsg<N>): Settle<I, R>;
651
+ subs(s: ResilientState<I, R>): readonly DeadlineSub<DeadlineNameOf<N>>[];
652
+ handlers(): Handlers;
653
+ }
654
+ /**
655
+ * The consumer's half of a settle cell: fold the settled answer into the
656
+ * machine's own Model.
657
+ *
658
+ * It is handed the Model the inherited verb ALREADY settled — the slice at
659
+ * `slice` is the post-`succeed` / post-`fail` one — so the ordering that wedges
660
+ * a call at `running` is not something this callback can express. It returns
661
+ * the repo's universal cell shape so a fold that needs to chain an effect
662
+ * (book the answer, then write it somewhere) returns that Cmd like any other
663
+ * reducer cell would.
664
+ */
665
+ type SettleFold<Model, M, C extends Cmd> = (model: Model, msg: M) => readonly [Model, readonly C[]];
666
+ /** One cell of the update fragment {@link mountResilientCall} returns. */
667
+ type MountedCell<Model, M, I, C extends Cmd> = (model: Model, msg: M) => readonly [Model, readonly (RunCmd<I> | C)[]];
668
+ /**
669
+ * What to mount, and where. `slice` names the Model field the knob's state
670
+ * lives on — a plain, readable field, per
671
+ * [ADR 0015](../../../../.decisions/0015-hide-the-wiring-never-the-state.md):
672
+ * the mount absorbs the assembly and hides none of the durable state.
673
+ */
674
+ interface MountConfig<Model, Slice extends string, I, R, AttemptType extends string, AttemptMsg, OkMsg, ErrMsg, C extends Cmd, N extends string = DefaultResilientName> {
675
+ /** The Model field carrying the knob's slice. */
676
+ readonly slice: Slice;
677
+ /**
678
+ * The cell that starts a call. Its shape is the one wiring point the mount
679
+ * cannot supply: each door's `attempt` takes its own arguments (jev-ask reads
680
+ * a key, a state and an instant; llm-call reads a request), and only the
681
+ * consumer knows which Msg field carries each. `run` is that one line.
682
+ */
683
+ readonly attempt: {
684
+ /** The Msg type that starts a call — the key the cell lands on. */
685
+ readonly on: AttemptType;
686
+ readonly run: (slice: ResilientState<I, R>, msg: AttemptMsg) => Settle<I, R>;
687
+ };
688
+ /** Fold a settled success into the Model. Omit and only the slice advances. */
689
+ readonly onOk?: SettleFold<Model, OkMsg, C>;
690
+ /** Fold a settled failure into the Model. Omit and only the slice advances. */
691
+ readonly onErr?: SettleFold<Model, ErrMsg, C>;
692
+ /**
693
+ * Fold a call the TIMER settled into the Model. This is the third failure
694
+ * class, and it never reaches {@link MountConfig.onErr}: a deadline fire
695
+ * settles `failed` inside the slice and emits no settle Msg, so without this
696
+ * callback a call that dies on its budget advances the slice and folds
697
+ * nothing — the shape that used to be a documented caveat.
698
+ *
699
+ * It runs once per call the knob's deadline cell moved INTO `failed`:
700
+ * the deadline fire itself, and the resumed retry whose gate found the
701
+ * budget spent. A plain backoff tick, a stale fire and an already-`failed`
702
+ * call fold nothing. `error` is the slice's own settled error — a
703
+ * {@link DeadlineExceededError} on the deadline path.
704
+ *
705
+ * Omit and only the slice advances, exactly as the other two do.
706
+ */
707
+ readonly onDeadline?: SettleFold<Model, DeadlineSettled<N>, C>;
708
+ }
709
+ /**
710
+ * What {@link MountConfig.onDeadline} is handed: the one call the timer cell
711
+ * just settled `failed`, named by its `key`, carrying the error the slice
712
+ * settled with and the timer Msg that produced it. It is not a Msg the reducer
713
+ * ever sees — no settle Msg exists for this failure class, which is the whole
714
+ * reason the callback is here.
715
+ */
716
+ interface DeadlineSettled<N extends string = DefaultResilientName> {
717
+ /** The call key that settled. */
718
+ readonly key: string;
719
+ /** The error now on the slice — a {@link DeadlineExceededError} on the deadline path. */
720
+ readonly error: unknown;
721
+ /**
722
+ * The timer Msg whose fire settled it — this knob's own tag, so a fold on a
723
+ * knob named `jev` is handed a `jev_deadline` and one on an unnamed knob a
724
+ * `deadline_exceeded`.
725
+ */
726
+ readonly msg: ResilientTimerMsg<N>;
727
+ }
728
+ /**
729
+ * The four fragments a consumer spreads into `defineMachine`. Together with
730
+ * `init` they are the eight wiring points; none of them is optional at the type
731
+ * level, so a consumer that mounts cannot omit `subscribe` (a backed-off retry
732
+ * that never fires) or re-implement `interpret` as a dispatching handler.
733
+ */
734
+ interface MountedResilientCall<Model, Slice extends string, I, R, AttemptType extends string, AttemptMsg, OkMsg, ErrMsg, C extends Cmd, Handlers, N extends string = DefaultResilientName> {
735
+ /** The starting slice under its field name — spread into the machine's `init`. */
736
+ init(): {
737
+ readonly [K in Slice]: ResilientState<I, R>;
738
+ };
739
+ /**
740
+ * The three settle cells plus the attempt cell, to spread into `update`.
741
+ *
742
+ * The two settle keys are the knob's OWN Msg names (#229), so a knob built as
743
+ * `name: "jev"` mounts into `jev_ok` / `jev_err` and two named knobs in one
744
+ * machine spread into four distinct cells instead of colliding on one. An
745
+ * unnamed knob is `resilient`, so the keys read `resilient_ok` /
746
+ * `resilient_err` exactly as they always have.
747
+ *
748
+ * The deadline cell is keyed the same way (#238). A knob's deadline Sub
749
+ * carries its name, so a knob built as `name: "jev"` dispatches
750
+ * `jev_deadline` and mounts into a `jev_deadline` cell; an unnamed knob still
751
+ * dispatches and mounts `deadline_exceeded`. Before that, both mounts wrote
752
+ * the one unqualified `deadline_exceeded` key and the last spread silently
753
+ * dropped the other knob's deadline fold. The cell folds through
754
+ * {@link MountConfig.onDeadline}, since a call the timer settles emits no
755
+ * settle Msg and so reaches no `onErr`.
756
+ */
757
+ readonly update: Readonly<Record<AttemptType, MountedCell<Model, AttemptMsg, I, C>>> & {
758
+ readonly [K in ResilientOkType<N>]: MountedCell<Model, OkMsg, I, C>;
759
+ } & {
760
+ readonly [K in ResilientErrType<N>]: MountedCell<Model, ErrMsg, I, C>;
761
+ } & {
762
+ readonly [K in ResilientDeadlineType<N>]: MountedCell<Model, ResilientTimerMsg<N>, I, C>;
763
+ };
764
+ subscriptions(model: Model): readonly DeadlineSub<DeadlineNameOf<N>>[];
765
+ readonly subscribe: {
766
+ readonly deadline: typeof subscribeDeadline;
767
+ };
768
+ readonly interpret: Handlers;
769
+ }
770
+ /**
771
+ * Pre-assemble a resilient-call knob into the fragments a machine definition
772
+ * spreads, so mounting one is a spread instead of eight hand-spliced points.
773
+ *
774
+ * The three points that used to fail only at runtime are gone at the type
775
+ * level rather than documented:
776
+ *
777
+ * - The settle cells run the inherited `succeed` / `fail` verb and hand the
778
+ * already-settled Model to {@link SettleFold}. There is no cell for a
779
+ * consumer to write in the wrong order.
780
+ * - `interpret` is `knob.handlers()` — the form that RETURNS the settle Msg
781
+ * so it re-enters the reducer. A consumer that spreads the fragment cannot
782
+ * substitute a dispatching handler for it.
783
+ * - `subscribe` carries `subscribeDeadline`, so the retry timer is armed by
784
+ * construction rather than by remembering.
785
+ *
786
+ * A deadline-exceeded call settles inside the slice and emits no settle Msg, so
787
+ * it reaches no `onErr`. {@link MountConfig.onDeadline} is that failure class's
788
+ * fold — omit it and the slice still advances, exactly as omitting `onErr`
789
+ * does.
790
+ *
791
+ * Nothing is taken away. The slice stays a plain field at `slice` that the
792
+ * consumer reads, `replay` sees and the journal prints, and every verb the
793
+ * fragments call is still exported and callable by hand — a consumer that
794
+ * wants a settle cell this shape cannot express writes that one cell itself and
795
+ * spreads the rest. PURE: a record of closures over `knob` and `config`, no
796
+ * clock and no RNG.
797
+ */
798
+ declare function mountResilientCall<Slice extends string, I, R, Model extends {
799
+ readonly [K in Slice]: ResilientState<I, R>;
800
+ }, AttemptType extends string, AttemptMsg, OkMsg extends {
801
+ readonly key: string;
802
+ }, ErrMsg extends {
803
+ readonly key: string;
804
+ }, Handlers, C extends Cmd = never, N extends string = DefaultResilientName>(knob: MountableKnob<I, R, OkMsg, ErrMsg, Handlers, N>, config: MountConfig<Model, Slice, I, R, AttemptType, AttemptMsg, OkMsg, ErrMsg, C, N>): MountedResilientCall<Model, Slice, I, R, AttemptType, AttemptMsg, OkMsg, ErrMsg, C, Handlers, N>;
615
805
 
616
- export { runCmdDef as A, tryConsume as B, type CircuitConfig as C, type DeadlineConfig as D, type FailMsg as F, MsgType as M, type RunCmd as R, type SucceedMsg as S, type TokenBucket as T, type ResilientState as a, type MsgTypeValue as b, type RateLimitConfig as c, type ResilientPorts as d, type ResilientConfig as e, type ResilientTimerMsg as f, type CacheConfig as g, type CallBudget as h, type CallPhase as i, type CircuitPolicy as j, type CircuitState as k, type DeadlineExceededError as l, type RunCmdDef as m, type SlidingWindow as n, canPass as o, createResilientCall as p, defaultCircuitPolicy as q, initBucket as r, initCircuit as s, initWindow as t, liftResilience as u, onFailure as v, onSuccess as w, record as x, refill as y, remaining as z };
806
+ export { type SettleFold as A, type SlidingWindow as B, type CircuitConfig as C, type DeadlineConfig as D, canPass as E, type FailMsg as F, createResilientCall as G, defaultCircuitPolicy as H, initBucket as I, initCircuit as J, initWindow as K, liftResilience as L, type MountConfig as M, onFailure as N, onSuccess as O, record as P, refill as Q, type RunCmd as R, type SucceedMsg as S, type TokenBucket as T, remaining as U, runCmdDef as V, tryConsume as W, type ResilientState as a, type RateLimitConfig as b, type ResilientPorts as c, type ResilientHandlers as d, type ResilientConfig as e, type ResilientTimerMsg as f, type CacheConfig as g, type CallBudget as h, type CallPhase as i, type CircuitPolicy as j, type CircuitState as k, DEFAULT_RESILIENT_NAME as l, mountResilientCall as m, type DeadlineExceededError as n, type DeadlineNameOf as o, type DeadlineSettled as p, type DefaultResilientName as q, type MountableKnob as r, type MountedCell as s, type MountedResilientCall as t, type ResilientDeadlineType as u, type ResilientErrType as v, type ResilientOkType as w, type ResilientRunType as x, type RunCmdDef as y, type Settle as z };
@@ -1,4 +1,4 @@
1
- import { S as Store } from './runtime-types-LWDoi943.js';
1
+ import { S as Store } from './runtime-types-CMF13BBh.js';
2
2
 
3
3
  /**
4
4
  * internal/work-queue — substrate-agnostic work-queue lifecycle on `Store<S>`.
@@ -1,5 +1,5 @@
1
- import { C as Cmd, P as Port } from './core-CTzMJ82M.js';
2
- import { Q as QueueItem } from './index-DJWIER_3.js';
1
+ import { C as Cmd, P as Port } from './core-DnzqWy6u.js';
2
+ import { Q as QueueItem } from './index-CSyMYDAB.js';
3
3
 
4
4
  /**
5
5
  * internal/flow/fan-out — scatter-gather over a bounded-concurrency work list.
@@ -1,4 +1,4 @@
1
- import { B as BootingRuntime } from './runtime-types-LWDoi943.js';
1
+ import { B as BootingRuntime } from './runtime-types-CMF13BBh.js';
2
2
 
3
3
  /**
4
4
  * A recorded run, sufficient to reproduce it via `../trace-replay`.
@@ -1,5 +1,5 @@
1
- import { S as Sub, c as SubId } from './core-CTzMJ82M.js';
2
- import { S as SubscribeHandler } from './types-DP3f5NIl.js';
1
+ import { S as Sub, c as SubId } from './core-DnzqWy6u.js';
2
+ import { S as SubscribeHandler } from './types-BseNPIhr.js';
3
3
 
4
4
  /**
5
5
  * internal/resilience/cache — a TTL cache as pure state, PLUS a periodic eviction Sub.
@@ -208,9 +208,9 @@ declare const cacheEvictionSubscribe: SubscribeHandler<CacheEvictionSub, CacheEv
208
208
  * noun that doubles as the SubId family); same shape family as the
209
209
  * `TimeoutSubData` the `fromTimeout` factory consumes.
210
210
  */
211
- type DeadlineSub = Sub<"deadline"> & {
211
+ type DeadlineSub<N extends string | undefined = undefined> = Sub<"deadline"> & {
212
212
  readonly atMs: number;
213
- } & DeadlineOpts;
213
+ } & DeadlineOpts<N>;
214
214
  /**
215
215
  * Additive options the `deadlineSub` factory folds onto the Sub literal. This
216
216
  * is the extension seam (invariant 5 — composition by reduction): future fields
@@ -221,10 +221,24 @@ type DeadlineSub = Sub<"deadline"> & {
221
221
  * they ask for what they need by name, never positionally, so a shape extension
222
222
  * never rewrites the ~13 `deadlineSub(id, atMs)` call sites.
223
223
  *
224
- * Empty today on purpose — the seam exists before the first extension does, so
225
- * the first field is a one-line additive change, not a 13-site migration.
224
+ * The first field to land here is {@link DeadlineOpts.name} — the knob name the
225
+ * dispatched Msg tag is derived from — and it landed exactly that way: one
226
+ * optional member, zero rewritten call sites.
226
227
  */
227
- type DeadlineOpts = {};
228
+ type DeadlineOpts<N extends string | undefined = undefined> = {
229
+ /**
230
+ * The knob this deadline belongs to. Present → the dispatched Msg's tag is
231
+ * `` `${name}_deadline` ``; absent → the tag stays the bare
232
+ * `"deadline_exceeded"` every machine wired before this field is already
233
+ * handling. `N` is the name as a TYPE as well as a value, so a consumer's
234
+ * cell key and the Msg type are derived from one place and cannot drift.
235
+ *
236
+ * Name a deadline when a machine arms more than one family of them. The Sub
237
+ * *id* was already scoped (`` `${name}:deadline:${key}` ``); this scopes the
238
+ * Msg the Sub dispatches, which is what a reducer cell keys off.
239
+ */
240
+ readonly name?: N;
241
+ };
228
242
  /**
229
243
  * The Msg the deadline dispatches when the wall clock crosses `atMs`. Exported
230
244
  * as a tagged shape so consumers can union it into their machine's Msg type and
@@ -238,11 +252,19 @@ type DeadlineOpts = {};
238
252
  * they prefer — `deadlineExceeded(...)` only fixes the wire shape, not the
239
253
  * consumer's local dialect.
240
254
  */
241
- type DeadlineExceeded = {
242
- readonly type: "deadline_exceeded";
255
+ type DeadlineExceeded<N extends string | undefined = undefined> = {
256
+ readonly type: DeadlineMsgType<N>;
243
257
  readonly id: string;
244
258
  readonly atMs: number;
245
259
  };
260
+ /**
261
+ * The dispatched Msg's tag, derived from the deadline's optional name. A named
262
+ * deadline speaks `` `${N}_deadline` ``; an unnamed one speaks the bare
263
+ * `"deadline_exceeded"` literal, which is what `DeadlineExceeded` with no type
264
+ * argument still means — so every machine wired before the name existed keeps
265
+ * the exact type it had.
266
+ */
267
+ type DeadlineMsgType<N extends string | undefined> = N extends string ? `${N}_deadline` : "deadline_exceeded";
246
268
  /**
247
269
  * Build a deadline Sub literal. Pure data — no clock read, no timer; the timer
248
270
  * is armed later by the `subscribe` cell. `id` is branded via `subId(...)` so
@@ -265,7 +287,7 @@ type DeadlineExceeded = {
265
287
  * optionality is the future-proofing seam — extending the shape
266
288
  * never breaks an existing `deadlineSub(id, atMs)` call site.
267
289
  */
268
- declare function deadlineSub(id: string, atMs: number, opts?: DeadlineOpts): DeadlineSub;
290
+ declare function deadlineSub<N extends string | undefined = undefined>(id: string, atMs: number, opts?: DeadlineOpts<N>): DeadlineSub<N>;
269
291
  /**
270
292
  * The host-plugged timer backing. Given the deadline's stable `id`, its
271
293
  * absolute `atMs`, and the Msg to fire, arm the platform-appropriate timer
@@ -303,7 +325,7 @@ type ArmTimer<M> = (id: SubId, atMs: number, msg: M, dispatch: (msg: M) => void)
303
325
  * `subscribeWith(setTimeoutArmTimer())`, so there is one deadline surface and
304
326
  * one anchor, not a second one per host.
305
327
  */
306
- declare function subscribeWith(armTimer: ArmTimer<DeadlineExceeded>): SubscribeHandler<DeadlineSub, DeadlineExceeded, unknown>;
328
+ declare function subscribeWith<N extends string | undefined = undefined>(armTimer: ArmTimer<DeadlineExceeded<N>>): SubscribeHandler<DeadlineSub<N>, DeadlineExceeded<N>, unknown>;
307
329
  /**
308
330
  * The `setTimeout` timer backing — for node / browser / any host whose timer is
309
331
  * a plain `setTimeout`. Arms for the REMAINING time (`max(0, atMs - Date.now())`,
@@ -317,7 +339,7 @@ declare function subscribeWith(armTimer: ArmTimer<DeadlineExceeded>): SubscribeH
317
339
  * it plugs its own `armTimer` (a `do_alarm` registration) into
318
340
  * {@link subscribeWith}.
319
341
  */
320
- declare function setTimeoutArmTimer(): ArmTimer<DeadlineExceeded>;
342
+ declare function setTimeoutArmTimer<N extends string | undefined = undefined>(): ArmTimer<DeadlineExceeded<N>>;
321
343
  /**
322
344
  * The `subscribe["deadline"]` handler for the DEFAULT `setTimeout` backing. Arms a
323
345
  * one-shot timer for the remaining delay `max(0, atMs - Date.now())` and
@@ -333,13 +355,26 @@ declare function setTimeoutArmTimer(): ArmTimer<DeadlineExceeded>;
333
355
  * subscribe: {
334
356
  * deadline: subscribeDeadline,
335
357
  * }
358
+ *
359
+ * Generic in the deadline's name so ONE handler serves every knob in a machine:
360
+ * the tag it dispatches is read off the Sub's own `name`, so a machine mounting
361
+ * a named knob beside an unnamed one wires this same cell once and each Sub
362
+ * still dispatches its own tag.
336
363
  */
337
- declare const subscribeDeadline: SubscribeHandler<DeadlineSub, DeadlineExceeded, unknown>;
364
+ declare const subscribeDeadline: <N extends string | undefined = undefined>(sub: DeadlineSub<N>, ctx: unknown, dispatch: (msg: DeadlineExceeded<N>) => void) => () => void;
338
365
  /**
339
366
  * Construct the Msg the deadline dispatches. Exported so consumers can build /
340
367
  * assert the same shape (and so the subscribe cell and tests share one
341
368
  * constructor rather than two literals that can drift).
342
369
  */
343
- declare function deadlineExceeded(id: string, atMs: number): DeadlineExceeded;
370
+ declare function deadlineExceeded<N extends string | undefined = undefined>(id: string, atMs: number, name?: N): DeadlineExceeded<N>;
371
+ /**
372
+ * The one place the named tag is spelled. `undefined` → the bare
373
+ * `"deadline_exceeded"` literal; a name → `` `${name}_deadline` ``. Exported so
374
+ * a consumer keying a reducer cell off a named deadline derives the key from
375
+ * the same function the Sub dispatches through, instead of re-spelling the
376
+ * template and drifting.
377
+ */
378
+ declare function deadlineMsgType<N extends string | undefined>(name?: N): DeadlineMsgType<N>;
344
379
 
345
- export { type ArmTimer as A, type CacheEvictionSub as C, type DeadlineExceeded as D, type TtlCache as T, type DeadlineSub as a, deadlineSub as b, type CacheEvictMsg as c, deadlineExceeded as d, type CacheEntry as e, type DeadlineOpts as f, cacheEvictMsg as g, cacheEvictionSub as h, cacheEvictionSubscribe as i, evictExpired as j, get as k, has as l, initCache as m, set as n, setTimeoutArmTimer as o, subscribeWith as p, remove as r, subscribeDeadline as s };
380
+ export { type ArmTimer as A, type CacheEvictionSub as C, type DeadlineExceeded as D, type TtlCache as T, type DeadlineSub as a, deadlineSub as b, type CacheEvictMsg as c, deadlineExceeded as d, type CacheEntry as e, type DeadlineMsgType as f, type DeadlineOpts as g, cacheEvictMsg as h, cacheEvictionSub as i, cacheEvictionSubscribe as j, deadlineMsgType as k, evictExpired as l, get as m, has as n, initCache as o, set as p, setTimeoutArmTimer as q, remove as r, subscribeDeadline as s, subscribeWith as t };
@@ -1,7 +1,7 @@
1
- import { I as Interpret, C as Cmd } from './core-CTzMJ82M.js';
2
- import { S as SnapshotWriteCmd, a as SnapshotState, b as SnapshotStore, c as SnapshotSavedMsg, d as SnapshotFailedMsg, e as SnapshotLoadedMsg, f as SnapshotLoadFailedMsg, g as SnapshotLoadCmd } from './index-DMCeMPMJ.js';
3
- import { D as DeadlineExceeded, a as DeadlineSub } from './index-q0hXFeZ0.js';
4
- import { Q as QueueItem } from './index-DJWIER_3.js';
1
+ import { I as Interpret, C as Cmd } from './core-DnzqWy6u.js';
2
+ import { S as SnapshotWriteCmd, a as SnapshotState, b as SnapshotStore, c as SnapshotSavedMsg, d as SnapshotFailedMsg, e as SnapshotLoadedMsg, f as SnapshotLoadFailedMsg, g as SnapshotLoadCmd } from './index-ZCMhnVKN.js';
3
+ import { D as DeadlineExceeded, a as DeadlineSub } from './index-HSYgG2Yt.js';
4
+ import { Q as QueueItem } from './index-CSyMYDAB.js';
5
5
 
6
6
  /**
7
7
  * internal/flow/monitored-run — a long-running operation that is BOTH staged and
@@ -1,4 +1,4 @@
1
- import { a as CmdOf, b as CmdDef, C as Cmd, I as Interpret } from './core-CTzMJ82M.js';
1
+ import { a as CmdOf, b as CmdDef, C as Cmd, I as Interpret } from './core-DnzqWy6u.js';
2
2
 
3
3
  /**
4
4
  * The snapshot knob.