@agenticprimitives/fabric 0.0.0-alpha.3 → 0.0.0-alpha.30

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 (185) hide show
  1. package/CLAUDE.md +30 -29
  2. package/README.md +18 -16
  3. package/dist/adoption.d.ts +79 -0
  4. package/dist/adoption.d.ts.map +1 -0
  5. package/dist/adoption.js +95 -0
  6. package/dist/adoption.js.map +1 -0
  7. package/dist/case-emissions.d.ts +95 -0
  8. package/dist/case-emissions.d.ts.map +1 -0
  9. package/dist/case-emissions.js +208 -0
  10. package/dist/case-emissions.js.map +1 -0
  11. package/dist/case-machine.d.ts +28 -2
  12. package/dist/case-machine.d.ts.map +1 -1
  13. package/dist/case-machine.js +34 -7
  14. package/dist/case-machine.js.map +1 -1
  15. package/dist/cloudflare/authority-verdict-cache.d.ts +28 -1
  16. package/dist/cloudflare/authority-verdict-cache.d.ts.map +1 -1
  17. package/dist/cloudflare/authority-verdict-cache.js +32 -1
  18. package/dist/cloudflare/authority-verdict-cache.js.map +1 -1
  19. package/dist/cloudflare/index.d.ts +4 -1
  20. package/dist/cloudflare/index.d.ts.map +1 -1
  21. package/dist/cloudflare/index.js +7 -1
  22. package/dist/cloudflare/index.js.map +1 -1
  23. package/dist/cloudflare/interaction-store.d.ts +55 -0
  24. package/dist/cloudflare/interaction-store.d.ts.map +1 -0
  25. package/dist/cloudflare/interaction-store.js +230 -0
  26. package/dist/cloudflare/interaction-store.js.map +1 -0
  27. package/dist/cloudflare/principal-gateway-do.d.ts +136 -2
  28. package/dist/cloudflare/principal-gateway-do.d.ts.map +1 -1
  29. package/dist/cloudflare/principal-gateway-do.js +190 -8
  30. package/dist/cloudflare/principal-gateway-do.js.map +1 -1
  31. package/dist/cloudflare/sql-vault.d.ts.map +1 -1
  32. package/dist/cloudflare/sql-vault.js +56 -0
  33. package/dist/cloudflare/sql-vault.js.map +1 -1
  34. package/dist/cloudflare/vault-exchange-store.d.ts +47 -0
  35. package/dist/cloudflare/vault-exchange-store.d.ts.map +1 -0
  36. package/dist/cloudflare/vault-exchange-store.js +118 -0
  37. package/dist/cloudflare/vault-exchange-store.js.map +1 -0
  38. package/dist/cloudflare/vault-interaction-store.d.ts +44 -0
  39. package/dist/cloudflare/vault-interaction-store.d.ts.map +1 -0
  40. package/dist/cloudflare/vault-interaction-store.js +245 -0
  41. package/dist/cloudflare/vault-interaction-store.js.map +1 -0
  42. package/dist/communicative-act.d.ts +24 -1
  43. package/dist/communicative-act.d.ts.map +1 -1
  44. package/dist/communicative-act.js +28 -0
  45. package/dist/communicative-act.js.map +1 -1
  46. package/dist/delivery-envelope.d.ts.map +1 -1
  47. package/dist/delivery-envelope.js +0 -1
  48. package/dist/delivery-envelope.js.map +1 -1
  49. package/dist/email/index.d.ts +75 -0
  50. package/dist/email/index.d.ts.map +1 -0
  51. package/dist/email/index.js +77 -0
  52. package/dist/email/index.js.map +1 -0
  53. package/dist/enum-retirement.d.ts +43 -0
  54. package/dist/enum-retirement.d.ts.map +1 -0
  55. package/dist/enum-retirement.js +93 -0
  56. package/dist/enum-retirement.js.map +1 -0
  57. package/dist/exchange-record.d.ts +35 -4
  58. package/dist/exchange-record.d.ts.map +1 -1
  59. package/dist/exchange-record.js.map +1 -1
  60. package/dist/exchange-reducer.d.ts +32 -4
  61. package/dist/exchange-reducer.d.ts.map +1 -1
  62. package/dist/exchange-reducer.js +75 -1
  63. package/dist/exchange-reducer.js.map +1 -1
  64. package/dist/exchange-state.d.ts +30 -8
  65. package/dist/exchange-state.d.ts.map +1 -1
  66. package/dist/exchange-state.js +12 -10
  67. package/dist/exchange-state.js.map +1 -1
  68. package/dist/inbox-doc.d.ts +2 -2
  69. package/dist/inbox-doc.d.ts.map +1 -1
  70. package/dist/inbox-doc.js.map +1 -1
  71. package/dist/inbox-projection.d.ts +2 -2
  72. package/dist/inbox-projection.d.ts.map +1 -1
  73. package/dist/inbox-projection.js.map +1 -1
  74. package/dist/inbox-revision.d.ts +42 -0
  75. package/dist/inbox-revision.d.ts.map +1 -0
  76. package/dist/inbox-revision.js +57 -0
  77. package/dist/inbox-revision.js.map +1 -0
  78. package/dist/index.d.ts +26 -3
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +40 -2
  81. package/dist/index.js.map +1 -1
  82. package/dist/interaction-machines.d.ts +136 -0
  83. package/dist/interaction-machines.d.ts.map +1 -0
  84. package/dist/interaction-machines.js +174 -0
  85. package/dist/interaction-machines.js.map +1 -0
  86. package/dist/interaction-profile.d.ts +136 -0
  87. package/dist/interaction-profile.d.ts.map +1 -0
  88. package/dist/interaction-profile.js +212 -0
  89. package/dist/interaction-profile.js.map +1 -0
  90. package/dist/interaction-record.d.ts +168 -0
  91. package/dist/interaction-record.d.ts.map +1 -0
  92. package/dist/interaction-record.js +108 -0
  93. package/dist/interaction-record.js.map +1 -0
  94. package/dist/interactions/grant-scopes.d.ts +21 -0
  95. package/dist/interactions/grant-scopes.d.ts.map +1 -0
  96. package/dist/interactions/grant-scopes.js +88 -0
  97. package/dist/interactions/grant-scopes.js.map +1 -0
  98. package/dist/interactions/index.d.ts +1 -0
  99. package/dist/interactions/index.d.ts.map +1 -1
  100. package/dist/interactions/index.js +3 -0
  101. package/dist/interactions/index.js.map +1 -1
  102. package/dist/interactions/machine.d.ts +2 -2
  103. package/dist/interactions/machine.d.ts.map +1 -1
  104. package/dist/interactions/machine.js +2 -2
  105. package/dist/interactions/machine.js.map +1 -1
  106. package/dist/interactions/open-case.d.ts +60 -0
  107. package/dist/interactions/open-case.d.ts.map +1 -0
  108. package/dist/interactions/open-case.js +83 -0
  109. package/dist/interactions/open-case.js.map +1 -0
  110. package/dist/interactions/store.d.ts +9 -0
  111. package/dist/interactions/store.d.ts.map +1 -1
  112. package/dist/interactions/store.js +57 -2
  113. package/dist/interactions/store.js.map +1 -1
  114. package/dist/messaging/board.d.ts +3 -3
  115. package/dist/messaging/board.d.ts.map +1 -1
  116. package/dist/messaging/board.js +2 -2
  117. package/dist/messaging/board.js.map +1 -1
  118. package/dist/messaging/consult-routing.d.ts +21 -14
  119. package/dist/messaging/consult-routing.d.ts.map +1 -1
  120. package/dist/messaging/consult-routing.js +34 -25
  121. package/dist/messaging/consult-routing.js.map +1 -1
  122. package/dist/messaging/consult.d.ts +4 -0
  123. package/dist/messaging/consult.d.ts.map +1 -1
  124. package/dist/messaging/consult.js +3 -1
  125. package/dist/messaging/consult.js.map +1 -1
  126. package/dist/messaging/conversation-interaction.d.ts +66 -0
  127. package/dist/messaging/conversation-interaction.d.ts.map +1 -0
  128. package/dist/messaging/conversation-interaction.js +139 -0
  129. package/dist/messaging/conversation-interaction.js.map +1 -0
  130. package/dist/messaging/conversation.d.ts +69 -1
  131. package/dist/messaging/conversation.d.ts.map +1 -1
  132. package/dist/messaging/conversation.js +131 -0
  133. package/dist/messaging/conversation.js.map +1 -1
  134. package/dist/messaging/delivery.d.ts +2 -2
  135. package/dist/messaging/delivery.d.ts.map +1 -1
  136. package/dist/messaging/delivery.js +8 -1
  137. package/dist/messaging/delivery.js.map +1 -1
  138. package/dist/messaging/envelope.d.ts +7 -3
  139. package/dist/messaging/envelope.d.ts.map +1 -1
  140. package/dist/messaging/envelope.js +18 -1
  141. package/dist/messaging/envelope.js.map +1 -1
  142. package/dist/messaging/hash.d.ts +8 -2
  143. package/dist/messaging/hash.d.ts.map +1 -1
  144. package/dist/messaging/hash.js +6 -0
  145. package/dist/messaging/hash.js.map +1 -1
  146. package/dist/messaging/inbox-assistant.d.ts +16 -4
  147. package/dist/messaging/inbox-assistant.d.ts.map +1 -1
  148. package/dist/messaging/inbox-assistant.js +27 -4
  149. package/dist/messaging/inbox-assistant.js.map +1 -1
  150. package/dist/messaging/index.d.ts +6 -2
  151. package/dist/messaging/index.d.ts.map +1 -1
  152. package/dist/messaging/index.js +10 -1
  153. package/dist/messaging/index.js.map +1 -1
  154. package/dist/messaging/outbound-message.d.ts +42 -0
  155. package/dist/messaging/outbound-message.d.ts.map +1 -0
  156. package/dist/messaging/outbound-message.js +64 -0
  157. package/dist/messaging/outbound-message.js.map +1 -0
  158. package/dist/messaging/projector.d.ts +3 -3
  159. package/dist/messaging/projector.d.ts.map +1 -1
  160. package/dist/messaging/projector.js.map +1 -1
  161. package/dist/messaging/receipts.d.ts +3 -3
  162. package/dist/messaging/receipts.d.ts.map +1 -1
  163. package/dist/messaging/receipts.js.map +1 -1
  164. package/dist/messaging/rules.d.ts +10 -3
  165. package/dist/messaging/rules.d.ts.map +1 -1
  166. package/dist/messaging/rules.js +8 -1
  167. package/dist/messaging/rules.js.map +1 -1
  168. package/dist/messaging/store.d.ts +4 -4
  169. package/dist/messaging/store.d.ts.map +1 -1
  170. package/dist/messaging/store.js +5 -3
  171. package/dist/messaging/store.js.map +1 -1
  172. package/dist/messaging/types.d.ts +30 -0
  173. package/dist/messaging/types.d.ts.map +1 -1
  174. package/dist/messaging/types.js +3 -0
  175. package/dist/messaging/types.js.map +1 -1
  176. package/dist/messaging/vault-store.d.ts +2 -2
  177. package/dist/messaging/vault-store.d.ts.map +1 -1
  178. package/dist/protocol-binding.d.ts +71 -0
  179. package/dist/protocol-binding.d.ts.map +1 -0
  180. package/dist/protocol-binding.js +0 -0
  181. package/dist/protocol-binding.js.map +1 -0
  182. package/dist/record-catalog.d.ts.map +1 -1
  183. package/dist/record-catalog.js +12 -0
  184. package/dist/record-catalog.js.map +1 -1
  185. package/package.json +28 -15
@@ -52,9 +52,19 @@ export interface CaseTransitionEventV1 {
52
52
  authorityRef?: AuthorityRef;
53
53
  signature?: SignatureProof;
54
54
  }
55
+ /** W10b-3: `denied`/`expired`/`revoked` collapsed into `closed` — same terminality, and the verdict
56
+ * that distinguished them now lives in the decision and commitment records. */
55
57
  export declare const TERMINAL_CASE_STATES: readonly CaseState[];
56
58
  export declare function isTerminalCaseState(state: CaseState): boolean;
57
- export type CaseRejection = 'wrong-case' | 'invalid-transition' | 'unauthorized-actor' | 'case-expired' | 'not-yet-due';
59
+ /** The transitions that cannot land on the case machine alone. Exported so the set is a constant a
60
+ * caller can read rather than a rule buried in a branch. */
61
+ export declare const TRANSITIONS_REQUIRING_GRANTED_DECISION: readonly CaseTransition[];
62
+ export declare function requiresGrantedDecision(transition: CaseTransition): boolean;
63
+ export type CaseRejection = 'wrong-case' | 'invalid-transition' | 'unauthorized-actor' | 'case-expired' | 'not-yet-due'
64
+ /** W10b-3: the transition needs a granted decision and none was supplied. Its own reason rather than
65
+ * `invalid-transition`, because the case IS in a legal state — what is missing is the determination,
66
+ * and a caller that cannot tell those apart will "fix" the wrong one. */
67
+ | 'requires-granted-decision';
58
68
  export type CaseResult = {
59
69
  ok: true;
60
70
  case: FabricCaseV1;
@@ -62,11 +72,27 @@ export type CaseResult = {
62
72
  ok: false;
63
73
  reason: CaseRejection;
64
74
  };
75
+ /**
76
+ * What this machine cannot know on its own (spec 340 W10b-3).
77
+ *
78
+ * Until W10b-3, "you cannot issue before approving" was an FSM edge: `issue-credential` ran only
79
+ * `from: ['approved']`. With the determination moved to the decision machine, `triaged` is reachable by
80
+ * plain triage, so that ordering has to be re-established as a precondition or issuance could skip the
81
+ * determination entirely.
82
+ *
83
+ * Passed IN rather than looked up: this module is pure and has no store. The caller that holds the
84
+ * decision supplies it, and supplying nothing is a refusal, not a pass — a machine that treated
85
+ * "no decision provided" as "no decision required" would be exactly the fail-open this repo forbids.
86
+ */
87
+ export interface CaseTransitionContext {
88
+ /** The state of the decision for this case, or `null`/absent when there is none. */
89
+ decisionState?: 'pending' | 'granted' | 'refused' | 'withdrawn' | 'expired' | 'superseded' | null;
90
+ }
65
91
  /**
66
92
  * Pure, fail-closed (spec 316 §2). Generic over the concrete case type: preserves whatever extra fields
67
93
  * `T` carries beyond `CaseFsmFields`. Returns the next case or a typed rejection — never a silent no-op.
68
94
  */
69
- export declare function applyCaseTransition<T extends CaseFsmFields>(current: T, event: CaseTransitionEventV1): {
95
+ export declare function applyCaseTransition<T extends CaseFsmFields>(current: T, event: CaseTransitionEventV1, ctx?: CaseTransitionContext): {
70
96
  ok: true;
71
97
  case: T;
72
98
  } | {
@@ -1 +1 @@
1
- {"version":3,"file":"case-machine.d.ts","sourceRoot":"","sources":["../src/case-machine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"case-machine.d.ts","sourceRoot":"","sources":["../src/case-machine.ts"],"names":[],"mappings":"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"}
@@ -14,10 +14,24 @@
14
14
  // are inbox read-receipt facts. So `admit`(submitted→delivered)/`view`(delivered→seen) are DROPPED (they
15
15
  // become `ExchangeEventV1` `kind:'message'` events), and the moves that referenced `seen`/`delivered`
16
16
  // re-anchor on `submitted`/`triaged`.
17
- export const TERMINAL_CASE_STATES = ['denied', 'completed', 'expired', 'revoked', 'failed'];
17
+ /** W10b-3: `denied`/`expired`/`revoked` collapsed into `closed` — same terminality, and the verdict
18
+ * that distinguished them now lives in the decision and commitment records. */
19
+ export const TERMINAL_CASE_STATES = ['completed', 'closed', 'failed'];
18
20
  export function isTerminalCaseState(state) {
19
21
  return TERMINAL_CASE_STATES.includes(state);
20
22
  }
23
+ /**
24
+ * spec 340 W10b-3. The VERBS are unchanged — that is deliberate and load-bearing. A stored v1 case-event
25
+ * log names transitions, not states, so keeping every verb is what lets history replay with no
26
+ * migration (W10b-1). What changed is where four of them LAND, because `approved`/`denied`/`expired`/
27
+ * `revoked` were never execution states (§R.2):
28
+ *
29
+ * · `approve` now lands on `triaged` — the responder is working toward issuance. The DETERMINATION
30
+ * goes to the decision machine via `caseTransitionEmissions`. "Approved" was never a description
31
+ * of how far the work got; reading it as one is the "deciding is not doing" collapse.
32
+ * · `deny`/`expire`/`revoke` land on `closed` — taken up, ended without issuance. The verdict is in
33
+ * the decision record; the voided obligation is in the commitment record.
34
+ */
21
35
  const TRANSITIONS = {
22
36
  submit: { from: ['draft'], to: 'submitted', signers: ['requester'] },
23
37
  triage: { from: ['submitted'], to: 'triaged', signers: ['responder'] },
@@ -25,14 +39,24 @@ const TRANSITIONS = {
25
39
  // needs-info → triaged (NOT submitted): the requester supplied info, the responder RESUMES working
26
40
  // (couples to exec `working`), preserving the "responder engaged" phase across the info loop.
27
41
  'submit-info': { from: ['needs-info'], to: 'triaged', signers: ['requester'] },
28
- approve: { from: ['submitted', 'triaged'], to: 'approved', signers: ['responder', 'resource-owner'] },
29
- 'issue-credential': { from: ['approved'], to: 'issued', signers: ['resource-owner', 'responder'] },
42
+ approve: { from: ['submitted', 'triaged'], to: 'triaged', signers: ['responder', 'resource-owner'] },
43
+ // `from: ['triaged']` plus a REQUIRED granted decision — see `requiresGrantedDecision`. The ordering
44
+ // "you cannot issue before approving" used to be an FSM edge (`from: ['approved']`); with the
45
+ // decision out of this enum it becomes a cross-machine precondition instead, because `triaged` is
46
+ // reachable by plain triage and would otherwise let issuance skip the determination entirely.
47
+ 'issue-credential': { from: ['triaged'], to: 'issued', signers: ['resource-owner', 'responder'] },
30
48
  'deliver-credential': { from: ['issued'], to: 'completed', signers: ['resource-owner', 'responder'] },
31
- deny: { from: 'any-non-terminal', to: 'denied', signers: ['responder', 'resource-owner'] },
32
- expire: { from: 'any-non-terminal', to: 'expired', signers: ['any'] },
33
- revoke: { from: 'any-non-terminal', to: 'revoked', signers: ['responder', 'resource-owner'] },
49
+ deny: { from: 'any-non-terminal', to: 'closed', signers: ['responder', 'resource-owner'] },
50
+ expire: { from: 'any-non-terminal', to: 'closed', signers: ['any'] },
51
+ revoke: { from: 'any-non-terminal', to: 'closed', signers: ['responder', 'resource-owner'] },
34
52
  fail: { from: 'any-non-terminal', to: 'failed', signers: ['any'] },
35
53
  };
54
+ /** The transitions that cannot land on the case machine alone. Exported so the set is a constant a
55
+ * caller can read rather than a rule buried in a branch. */
56
+ export const TRANSITIONS_REQUIRING_GRANTED_DECISION = ['issue-credential'];
57
+ export function requiresGrantedDecision(transition) {
58
+ return TRANSITIONS_REQUIRING_GRANTED_DECISION.includes(transition);
59
+ }
36
60
  function actorRoles(c, actor) {
37
61
  const roles = new Set(['any']);
38
62
  if (actor === c.requester)
@@ -50,7 +74,7 @@ function isPastExpiry(c, atIso) {
50
74
  * Pure, fail-closed (spec 316 §2). Generic over the concrete case type: preserves whatever extra fields
51
75
  * `T` carries beyond `CaseFsmFields`. Returns the next case or a typed rejection — never a silent no-op.
52
76
  */
53
- export function applyCaseTransition(current, event) {
77
+ export function applyCaseTransition(current, event, ctx = {}) {
54
78
  if (event.caseId !== current.id)
55
79
  return { ok: false, reason: 'wrong-case' };
56
80
  const spec = TRANSITIONS[event.transition];
@@ -59,6 +83,9 @@ export function applyCaseTransition(current, event) {
59
83
  const fromOk = spec.from === 'any-non-terminal' ? !isTerminalCaseState(current.state) : spec.from.includes(current.state);
60
84
  if (!fromOk)
61
85
  return { ok: false, reason: 'invalid-transition' };
86
+ if (requiresGrantedDecision(event.transition) && ctx.decisionState !== 'granted') {
87
+ return { ok: false, reason: 'requires-granted-decision' };
88
+ }
62
89
  // `expire` only lands once the deadline passed; everything else (except `fail`) rejects on an expired case.
63
90
  if (event.transition === 'expire') {
64
91
  if (current.expiresAt === undefined || !isPastExpiry(current, event.at))
@@ -1 +1 @@
1
- {"version":3,"file":"case-machine.js","sourceRoot":"","sources":["../src/case-machine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"case-machine.js","sourceRoot":"","sources":["../src/case-machine.ts"],"names":[],"mappings":"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"}
@@ -23,5 +23,32 @@ export interface AuthorityVerdictCache {
23
23
  /** Deployment-epoch change (spec 311): drop every verdict NOT on `currentEpoch`. */
24
24
  sweepEpoch(currentEpoch: string): Promise<void>;
25
25
  }
26
- export declare function createDurableObjectAuthorityVerdictCache(sql: SqlStorage): AuthorityVerdictCache;
26
+ /**
27
+ * How long a cached verdict may be reused before the cold path must run again.
28
+ *
29
+ * 60s mirrors `InteractionsDO`'s existing positive-verdict cache (NEW-H4/FAB-A2A-1), which was sized as
30
+ * an RPC-429 mitigation for high-frequency non-sensitive reads. Matching it keeps ONE number in the
31
+ * deployment rather than two that drift.
32
+ */
33
+ export declare const VERDICT_TTL_MS = 60000;
34
+ export interface VerdictCacheOptions {
35
+ /** Bounded reuse window. `0` disables caching entirely (every get misses ⇒ cold path every call). */
36
+ ttlMs?: number;
37
+ now?: () => number;
38
+ }
39
+ /**
40
+ * BOUNDED REUSE IS PART OF THE VERDICT, NOT AN OPTIMISATION KNOB.
41
+ *
42
+ * Verdict (A) asserts "this delegation was valid AND UNREVOKED at `verifiedAt`". Serving it later without
43
+ * regard to age silently upgrades that into "is valid and unrevoked", which is a claim the cold path never
44
+ * made. Before this, `verified_at` was written and never read: a verdict cached once stayed warm forever,
45
+ * and a revoked delegation kept passing (A) until something called `invalidateDelegation` — a revocation
46
+ * NOTICE that has to be delivered by a second mechanism and may simply never arrive. Revocation that only
47
+ * works when someone remembers to push it is not revocation.
48
+ *
49
+ * Expiry is a MISS, not an error: `invokeFast` refuses on a miss and the caller re-runs `verifyAndCache`,
50
+ * which re-checks the signature and `isRevoked` on-chain. So the ceiling on serving a revoked delegation
51
+ * is `ttlMs`, and the mechanism is the same one throughout (ADR-0013) — the cold path, run again.
52
+ */
53
+ export declare function createDurableObjectAuthorityVerdictCache(sql: SqlStorage, opts?: VerdictCacheOptions): AuthorityVerdictCache;
27
54
  //# sourceMappingURL=authority-verdict-cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"authority-verdict-cache.d.ts","sourceRoot":"","sources":["../../src/cloudflare/authority-verdict-cache.ts"],"names":[],"mappings":"AA6BA;4GAC4G;AAC5G,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,kGAAkG;IAClG,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,gBAAgB,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;AAYhH,MAAM,WAAW,qBAAqB;IACpC,yDAAyD;IACzD,GAAG,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C;mGAC+F;IAC/F,GAAG,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAChE,uFAAuF;IACvF,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,oFAAoF;IACpF,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAKD,wBAAgB,wCAAwC,CAAC,GAAG,EAAE,UAAU,GAAG,qBAAqB,CA6C/F"}
1
+ {"version":3,"file":"authority-verdict-cache.d.ts","sourceRoot":"","sources":["../../src/cloudflare/authority-verdict-cache.ts"],"names":[],"mappings":"AA6BA;4GAC4G;AAC5G,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,kGAAkG;IAClG,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,gBAAgB,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;AAYhH,MAAM,WAAW,qBAAqB;IACpC,yDAAyD;IACzD,GAAG,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C;mGAC+F;IAC/F,GAAG,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;IAChE,uFAAuF;IACvF,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,oFAAoF;IACpF,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD;AAKD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,QAAS,CAAC;AAErC,MAAM,WAAW,mBAAmB;IAClC,qGAAqG;IACrG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wCAAwC,CACtD,GAAG,EAAE,UAAU,EACf,IAAI,CAAC,EAAE,mBAAmB,GACzB,qBAAqB,CAsDvB"}
@@ -26,10 +26,34 @@ const CREATE_TABLE = `CREATE TABLE IF NOT EXISTS authority_verdicts (
26
26
  const CREATE_IDX_DELEG = `CREATE INDEX IF NOT EXISTS idx_authority_verdicts_deleg ON authority_verdicts (delegation_hash)`;
27
27
  const CREATE_IDX_EPOCH = `CREATE INDEX IF NOT EXISTS idx_authority_verdicts_epoch ON authority_verdicts (epoch)`;
28
28
  const keyOf = (k) => `${k.sessionKey.toLowerCase()}|${k.delegationHash.toLowerCase()}|${k.epoch}|${k.manager.toLowerCase()}`;
29
- export function createDurableObjectAuthorityVerdictCache(sql) {
29
+ /**
30
+ * How long a cached verdict may be reused before the cold path must run again.
31
+ *
32
+ * 60s mirrors `InteractionsDO`'s existing positive-verdict cache (NEW-H4/FAB-A2A-1), which was sized as
33
+ * an RPC-429 mitigation for high-frequency non-sensitive reads. Matching it keeps ONE number in the
34
+ * deployment rather than two that drift.
35
+ */
36
+ export const VERDICT_TTL_MS = 60_000;
37
+ /**
38
+ * BOUNDED REUSE IS PART OF THE VERDICT, NOT AN OPTIMISATION KNOB.
39
+ *
40
+ * Verdict (A) asserts "this delegation was valid AND UNREVOKED at `verifiedAt`". Serving it later without
41
+ * regard to age silently upgrades that into "is valid and unrevoked", which is a claim the cold path never
42
+ * made. Before this, `verified_at` was written and never read: a verdict cached once stayed warm forever,
43
+ * and a revoked delegation kept passing (A) until something called `invalidateDelegation` — a revocation
44
+ * NOTICE that has to be delivered by a second mechanism and may simply never arrive. Revocation that only
45
+ * works when someone remembers to push it is not revocation.
46
+ *
47
+ * Expiry is a MISS, not an error: `invokeFast` refuses on a miss and the caller re-runs `verifyAndCache`,
48
+ * which re-checks the signature and `isRevoked` on-chain. So the ceiling on serving a revoked delegation
49
+ * is `ttlMs`, and the mechanism is the same one throughout (ADR-0013) — the cold path, run again.
50
+ */
51
+ export function createDurableObjectAuthorityVerdictCache(sql, opts) {
30
52
  sql.exec(CREATE_TABLE);
31
53
  sql.exec(CREATE_IDX_DELEG);
32
54
  sql.exec(CREATE_IDX_EPOCH);
55
+ const ttlMs = opts?.ttlMs ?? VERDICT_TTL_MS;
56
+ const now = opts?.now ?? (() => Date.now());
33
57
  return {
34
58
  async put(v) {
35
59
  sql.exec(`INSERT INTO authority_verdicts (cache_key, principal, session_key, delegation_hash, epoch, manager, verified_at)
@@ -46,6 +70,13 @@ export function createDurableObjectAuthorityVerdictCache(sql) {
46
70
  const r = rows[0];
47
71
  if (!r)
48
72
  return null;
73
+ // Age it out. An unparseable `verified_at` counts as EXPIRED: a row whose age cannot be established
74
+ // is one whose freshness cannot be established, and the safe reading of "I don't know" is a miss.
75
+ const verifiedAtMs = Date.parse(r.verified_at);
76
+ if (!Number.isFinite(verifiedAtMs) || now() - verifiedAtMs >= ttlMs) {
77
+ sql.exec('DELETE FROM authority_verdicts WHERE cache_key = ?', keyOf(key));
78
+ return null;
79
+ }
49
80
  return {
50
81
  principal: r.principal,
51
82
  sessionKey: r.session_key,
@@ -1 +1 @@
1
- {"version":3,"file":"authority-verdict-cache.js","sourceRoot":"","sources":["../../src/cloudflare/authority-verdict-cache.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,uEAAuE;AACvE,EAAE;AACF,0FAA0F;AAC1F,2GAA2G;AAC3G,oGAAoG;AACpG,iGAAiG;AACjG,4GAA4G;AAC5G,qDAAqD;AACrD,wGAAwG;AACxG,yGAAyG;AACzG,wGAAwG;AACxG,4GAA4G;AAC5G,oGAAoG;AACpG,EAAE;AACF,0GAA0G;AAE1G,MAAM,YAAY,GAAG;;;;;;;;EAQnB,CAAC;AACH,MAAM,gBAAgB,GAAG,iGAAiG,CAAC;AAC3H,MAAM,gBAAgB,GAAG,uFAAuF,CAAC;AAwCjH,MAAM,KAAK,GAAG,CAAC,CAAsB,EAAU,EAAE,CAC/C,GAAG,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;AAE1G,MAAM,UAAU,wCAAwC,CAAC,GAAe;IACtE,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACvB,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC3B,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAE3B,OAAO;QACL,KAAK,CAAC,GAAG,CAAC,CAAC;YACT,GAAG,CAAC,IAAI,CACN;;;;;0EAKkE,EAClE,KAAK,CAAC,CAAC,CAAC,EACR,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,EACzB,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE,EAC1B,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,EAC9B,CAAC,CAAC,KAAK,EACP,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,EACvB,CAAC,CAAC,UAAU,CACb,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,GAAG;YACX,MAAM,IAAI,GAAG,GAAG;iBACb,IAAI,CAAa,sDAAsD,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;iBACpF,OAAO,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,IAAI,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC;YACpB,OAAO;gBACL,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,UAAU,EAAE,CAAC,CAAC,WAAW;gBACzB,cAAc,EAAE,CAAC,CAAC,eAAe;gBACjC,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,UAAU,EAAE,CAAC,CAAC,WAAW;aAC1B,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,oBAAoB,CAAC,cAAc;YACvC,GAAG,CAAC,IAAI,CAAC,0DAA0D,EAAE,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC;QACrG,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,YAAY;YAC3B,GAAG,CAAC,IAAI,CAAC,iDAAiD,EAAE,YAAY,CAAC,CAAC;QAC5E,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"authority-verdict-cache.js","sourceRoot":"","sources":["../../src/cloudflare/authority-verdict-cache.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,16 @@
1
1
  export { createDurableObjectSqlVault } from './sql-vault.js';
2
2
  export { createDurableObjectExchangeStore, type ExchangeStore } from './exchange-store.js';
3
+ export { createDurableObjectInteractionStore, type InteractionStore, type SnapshotPutResult, } from './interaction-store.js';
3
4
  export { createDurableObjectOutboxStore, type OutboxStore, type OutboxEntry } from './outbox-store.js';
4
5
  export { createDurableObjectProvenanceStore, type ProvenanceStore } from './provenance-store.js';
5
6
  export { createDurableObjectChannelStore, projectionAuthorizes, type ChannelStore, type ChannelV1, type ConversationRoleProjection, type ConversationRoleAction, } from './channel-store.js';
6
- export { createDurableObjectAuthorityVerdictCache, type AuthorityVerdictCache, type AuthorityVerdict, type AuthorityVerdictKey, } from './authority-verdict-cache.js';
7
+ export { createDurableObjectAuthorityVerdictCache, VERDICT_TTL_MS, type VerdictCacheOptions, type AuthorityVerdictCache, type AuthorityVerdict, type AuthorityVerdictKey, } from './authority-verdict-cache.js';
7
8
  export { createDurableObjectRequestIdLedger, type RequestIdLedger, type RequestIdReservation } from './request-id-ledger.js';
8
9
  export { createDurableObjectReceiptSigner, verifyDeliveryReceipt, type DeliveryReceiptSigner, type DeliveryReceiptInput, type SignedDeliveryReceiptV1, } from './receipt-signer.js';
9
10
  export { PrincipalGatewayDO, type PrincipalGatewayEnv, type GatewayDeps } from './principal-gateway-do.js';
10
11
  export { buildVaultTools, createToolRegistry, type GatewayTool, type GatewayToolContext, type GatewayToolRegistry, } from './gateway-tools.js';
11
12
  export { runGatewayOrchestration, gatewayToolSpecs, bindGatewayToolInvoker } from './orchestration-runtime.js';
13
+ export { createVaultExchangeStore, exchangeResource, EXCHANGE_INDEX_RESOURCE, type VaultExchangeStore, type ExchangeIndexV1, } from './vault-exchange-store.js';
14
+ export { createVaultInteractionStore, interactionResource, decisionResource, commitmentResource, snapshotResource, inboxEntryResource, INTERACTION_INDEX_RESOURCE, type VaultInteractionStore, type InteractionIndexV1, } from './vault-interaction-store.js';
12
15
  export declare const FABRIC_CLOUDFLARE_ADAPTER_STATUS: "w2-coresident-mcp";
13
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,gCAAgC,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC3F,OAAO,EAAE,8BAA8B,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACvG,OAAO,EAAE,kCAAkC,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACjG,OAAO,EACL,+BAA+B,EAAE,oBAAoB,EACrD,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,KAAK,0BAA0B,EAAE,KAAK,sBAAsB,GAChG,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,wCAAwC,EACxC,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,kCAAkC,EAAE,KAAK,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC7H,OAAO,EACL,gCAAgC,EAChC,qBAAqB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC3G,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAE/G,eAAO,MAAM,gCAAgC,EAAG,mBAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,gCAAgC,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAI3F,OAAO,EACL,mCAAmC,EACnC,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,8BAA8B,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACvG,OAAO,EAAE,kCAAkC,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACjG,OAAO,EACL,+BAA+B,EAAE,oBAAoB,EACrD,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,KAAK,0BAA0B,EAAE,KAAK,sBAAsB,GAChG,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,wCAAwC,EACxC,cAAc,EACd,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,GACzB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,kCAAkC,EAAE,KAAK,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC7H,OAAO,EACL,gCAAgC,EAChC,qBAAqB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,KAAK,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC3G,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAC/G,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,kBAAkB,EACvB,KAAK,eAAe,GACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,0BAA0B,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,GACxB,MAAM,8BAA8B,CAAC;AAEtC,eAAO,MAAM,gCAAgC,EAAG,mBAA4B,CAAC"}
@@ -7,14 +7,20 @@
7
7
  // absorption follow in subsequent W2 steps.
8
8
  export { createDurableObjectSqlVault } from './sql-vault.js';
9
9
  export { createDurableObjectExchangeStore } from './exchange-store.js';
10
+ // The interaction spine's durable home (spec 340 W6) — interactions, context snapshots, decisions,
11
+ // commitments and per-viewer inbox state. Five tables, because the six machines answer to different
12
+ // parties at different times and one row would make them one write.
13
+ export { createDurableObjectInteractionStore, } from './interaction-store.js';
10
14
  export { createDurableObjectOutboxStore } from './outbox-store.js';
11
15
  export { createDurableObjectProvenanceStore } from './provenance-store.js';
12
16
  export { createDurableObjectChannelStore, projectionAuthorizes, } from './channel-store.js';
13
- export { createDurableObjectAuthorityVerdictCache, } from './authority-verdict-cache.js';
17
+ export { createDurableObjectAuthorityVerdictCache, VERDICT_TTL_MS, } from './authority-verdict-cache.js';
14
18
  export { createDurableObjectRequestIdLedger } from './request-id-ledger.js';
15
19
  export { createDurableObjectReceiptSigner, verifyDeliveryReceipt, } from './receipt-signer.js';
16
20
  export { PrincipalGatewayDO } from './principal-gateway-do.js';
17
21
  export { buildVaultTools, createToolRegistry, } from './gateway-tools.js';
18
22
  export { runGatewayOrchestration, gatewayToolSpecs, bindGatewayToolInvoker } from './orchestration-runtime.js';
23
+ export { createVaultExchangeStore, exchangeResource, EXCHANGE_INDEX_RESOURCE, } from './vault-exchange-store.js';
24
+ export { createVaultInteractionStore, interactionResource, decisionResource, commitmentResource, snapshotResource, inboxEntryResource, INTERACTION_INDEX_RESOURCE, } from './vault-interaction-store.js';
19
25
  export const FABRIC_CLOUDFLARE_ADAPTER_STATUS = 'w2-coresident-mcp';
20
26
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAAA,0GAA0G;AAC1G,EAAE;AACF,wGAAwG;AACxG,wGAAwG;AACxG,yGAAyG;AACzG,yGAAyG;AACzG,4CAA4C;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,gCAAgC,EAAsB,MAAM,qBAAqB,CAAC;AAC3F,OAAO,EAAE,8BAA8B,EAAsC,MAAM,mBAAmB,CAAC;AACvG,OAAO,EAAE,kCAAkC,EAAwB,MAAM,uBAAuB,CAAC;AACjG,OAAO,EACL,+BAA+B,EAAE,oBAAoB,GAEtD,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,wCAAwC,GAIzC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,kCAAkC,EAAmD,MAAM,wBAAwB,CAAC;AAC7H,OAAO,EACL,gCAAgC,EAChC,qBAAqB,GAItB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAA8C,MAAM,2BAA2B,CAAC;AAC3G,OAAO,EACL,eAAe,EACf,kBAAkB,GAInB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAE/G,MAAM,CAAC,MAAM,gCAAgC,GAAG,mBAA4B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAAA,0GAA0G;AAC1G,EAAE;AACF,wGAAwG;AACxG,wGAAwG;AACxG,yGAAyG;AACzG,yGAAyG;AACzG,4CAA4C;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,gCAAgC,EAAsB,MAAM,qBAAqB,CAAC;AAC3F,mGAAmG;AACnG,oGAAoG;AACpG,oEAAoE;AACpE,OAAO,EACL,mCAAmC,GAGpC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,8BAA8B,EAAsC,MAAM,mBAAmB,CAAC;AACvG,OAAO,EAAE,kCAAkC,EAAwB,MAAM,uBAAuB,CAAC;AACjG,OAAO,EACL,+BAA+B,EAAE,oBAAoB,GAEtD,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,wCAAwC,EACxC,cAAc,GAKf,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,kCAAkC,EAAmD,MAAM,wBAAwB,CAAC;AAC7H,OAAO,EACL,gCAAgC,EAChC,qBAAqB,GAItB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,kBAAkB,EAA8C,MAAM,2BAA2B,CAAC;AAC3G,OAAO,EACL,eAAe,EACf,kBAAkB,GAInB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAC/G,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,uBAAuB,GAGxB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,0BAA0B,GAG3B,MAAM,8BAA8B,CAAC;AAEtC,MAAM,CAAC,MAAM,gCAAgC,GAAG,mBAA4B,CAAC"}
@@ -0,0 +1,55 @@
1
+ import type { InteractionRecordV1, InteractionId, ContextSnapshotV1 } from '../interaction-record.js';
2
+ import { type InteractionLifecycleV1, type InteractionTransition, type DecisionRecordV1, type DecisionTransition, type CommitmentRecordV1, type CommitmentTransition, type InboxEntryV1, type InboxTransition, type MachineResult } from '../interaction-machines.js';
3
+ import { type ProtocolBindingV1, type BindingResolution } from '../protocol-binding.js';
4
+ import type { CanonicalAgentId } from '@agenticprimitives/types';
5
+ export type SnapshotPutResult = {
6
+ ok: true;
7
+ stored: 'new' | 'identical';
8
+ } | {
9
+ ok: false;
10
+ reason: 'digest-mismatch';
11
+ };
12
+ export interface InteractionStore {
13
+ putInteraction(record: InteractionRecordV1): Promise<void>;
14
+ getInteraction(id: InteractionId | string): Promise<InteractionRecordV1 | null>;
15
+ listInteractions(): Promise<InteractionRecordV1[]>;
16
+ /** Drive the interaction lifecycle THROUGH its machine. `null` when the interaction is unknown. */
17
+ transitionInteraction(id: InteractionId | string, event: {
18
+ transition: InteractionTransition;
19
+ actor: CanonicalAgentId;
20
+ at: string;
21
+ }): Promise<MachineResult<InteractionLifecycleV1> | null>;
22
+ /** Index a foreign correlator. Duplicates across interactions are KEPT — that is the ambiguity. */
23
+ bindProtocolTo(id: InteractionId, binding: ProtocolBindingV1): Promise<void>;
24
+ resolveByBinding(protocol: string, field: string, value: string): Promise<BindingResolution>;
25
+ /** Content-addressed. Verifies the digest against the bytes before storing — which IS the
26
+ * immutability guarantee: forged content cannot reach a digest it does not hash to. */
27
+ putContextSnapshot(snapshot: ContextSnapshotV1): Promise<SnapshotPutResult>;
28
+ getContextSnapshot(digest: string): Promise<ContextSnapshotV1 | null>;
29
+ putDecision(record: DecisionRecordV1): Promise<void>;
30
+ getDecision(id: string): Promise<DecisionRecordV1 | null>;
31
+ transitionDecision(id: string, event: {
32
+ transition: DecisionTransition;
33
+ actor: CanonicalAgentId;
34
+ at: string;
35
+ subject?: string;
36
+ }): Promise<MachineResult<DecisionRecordV1> | null>;
37
+ putCommitment(record: CommitmentRecordV1): Promise<void>;
38
+ getCommitment(id: string): Promise<CommitmentRecordV1 | null>;
39
+ /** Open obligations — the query "what is still owed" that a single `case` field could not answer. */
40
+ listOpenCommitments(): Promise<CommitmentRecordV1[]>;
41
+ transitionCommitment(id: string, event: {
42
+ transition: CommitmentTransition;
43
+ actor: CanonicalAgentId;
44
+ at: string;
45
+ }): Promise<MachineResult<CommitmentRecordV1> | null>;
46
+ putInboxEntry(entry: InboxEntryV1): Promise<void>;
47
+ getInboxEntry(viewer: CanonicalAgentId, exchangeId: string): Promise<InboxEntryV1 | null>;
48
+ transitionInbox(viewer: CanonicalAgentId, exchangeId: string, event: {
49
+ transition: InboxTransition;
50
+ actor: CanonicalAgentId;
51
+ at: string;
52
+ }): Promise<MachineResult<InboxEntryV1> | null>;
53
+ }
54
+ export declare function createDurableObjectInteractionStore(sql: SqlStorage): InteractionStore;
55
+ //# sourceMappingURL=interaction-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction-store.d.ts","sourceRoot":"","sources":["../../src/cloudflare/interaction-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,230 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+ // DO-local InteractionStore (spec 340 W6) — durable homes for the records W2–W5 defined and nothing
3
+ // wrote. The `PrincipalGatewayDO` is the single writer for its principal, so no cross-writer races.
4
+ //
5
+ // Five tables, and the reason they are five rather than one wide row is the reason there are six state
6
+ // machines: an interaction's lifecycle, a decision, a commitment and a viewer's inbox state are
7
+ // answered by different parties at different times, and one row would make them one write.
8
+ //
9
+ // TWO INVARIANTS THIS LAYER OWNS, both about immutability rather than authority:
10
+ //
11
+ // 1. A ContextSnapshot is CONTENT-ADDRESSED, and the digest check IS the immutability guarantee.
12
+ // `putContextSnapshot` verifies the digest against the bytes before storing, so a party cannot
13
+ // rewrite what an evaluator saw while every Exchange still pins the same hash — the forged
14
+ // snapshot is refused at the door, not detected later.
15
+ //
16
+ // There is deliberately no separate `immutable-conflict` outcome. It was written first and was
17
+ // BOTH dead and wrong: dead, because content that differs necessarily fails the digest check
18
+ // already; and wrong, because it compared `JSON.stringify` output, so the same snapshot re-put
19
+ // with a different key insertion order would have been rejected as a conflicting overwrite. A
20
+ // verified digest with a row already at it means the content is the same — that is what
21
+ // content-addressing means — so the re-put is a no-op.
22
+ // 2. Every transition goes through its machine. The store never sets a state directly, so "the
23
+ // creditor discharges, not the debtor" cannot be bypassed by writing the row.
24
+ //
25
+ // It confers nothing. Persisting a commitment does not make it owed; persisting a decision does not
26
+ // authorize anything. Authority is `delegation` + `entitlements` + `tool-policy` at the moment of
27
+ // acting (ADR-0041, ADR-0043).
28
+ import { verifyContextSnapshot } from '../interaction-record.js';
29
+ import { applyInteractionTransition, applyDecisionTransition, applyCommitmentTransition, applyInboxTransition, } from '../interaction-machines.js';
30
+ import { bindingKey, resolveInteractionByBinding, } from '../protocol-binding.js';
31
+ const CREATE_TABLES = [
32
+ `CREATE TABLE IF NOT EXISTS interaction_records (
33
+ interaction_id TEXT PRIMARY KEY,
34
+ record_json TEXT NOT NULL,
35
+ state TEXT NOT NULL,
36
+ rev INTEGER NOT NULL,
37
+ updated_at TEXT NOT NULL
38
+ )`,
39
+ // Keyed by the binding, not by the interaction: the lookup direction is foreign → ours, and a
40
+ // duplicate key across two interactions is the AMBIGUITY the resolver must be able to see. A UNIQUE
41
+ // constraint here would silently drop the second one and manufacture a confident wrong answer.
42
+ `CREATE TABLE IF NOT EXISTS interaction_bindings (
43
+ binding_key TEXT NOT NULL,
44
+ interaction_id TEXT NOT NULL,
45
+ binding_json TEXT NOT NULL,
46
+ PRIMARY KEY (binding_key, interaction_id)
47
+ )`,
48
+ `CREATE TABLE IF NOT EXISTS context_snapshots (
49
+ digest TEXT PRIMARY KEY,
50
+ snapshot_json TEXT NOT NULL
51
+ )`,
52
+ `CREATE TABLE IF NOT EXISTS decision_records (
53
+ decision_id TEXT PRIMARY KEY,
54
+ record_json TEXT NOT NULL,
55
+ updated_at TEXT NOT NULL
56
+ )`,
57
+ `CREATE TABLE IF NOT EXISTS commitment_records (
58
+ commitment_id TEXT PRIMARY KEY,
59
+ record_json TEXT NOT NULL,
60
+ state TEXT NOT NULL,
61
+ updated_at TEXT NOT NULL
62
+ )`,
63
+ `CREATE TABLE IF NOT EXISTS inbox_entries (
64
+ viewer TEXT NOT NULL,
65
+ exchange_id TEXT NOT NULL,
66
+ record_json TEXT NOT NULL,
67
+ PRIMARY KEY (viewer, exchange_id)
68
+ )`,
69
+ ];
70
+ /** States an obligation is still live in. `discharged`/`breached`/`void` are ended, differently. */
71
+ const OPEN_COMMITMENT_STATES = ['proposed', 'active', 'fulfilment-claimed'];
72
+ export function createDurableObjectInteractionStore(sql) {
73
+ for (const ddl of CREATE_TABLES)
74
+ sql.exec(ddl);
75
+ const one = (query, ...binds) => {
76
+ const rows = sql.exec(query, ...binds).toArray();
77
+ return rows[0] ? JSON.parse(rows[0].record_json) : null;
78
+ };
79
+ const saveInteraction = (record) => {
80
+ sql.exec(`INSERT INTO interaction_records (interaction_id, record_json, state, rev, updated_at)
81
+ VALUES (?, ?, ?, ?, ?)
82
+ ON CONFLICT(interaction_id) DO UPDATE SET
83
+ record_json = excluded.record_json, state = excluded.state,
84
+ rev = excluded.rev, updated_at = excluded.updated_at`, record.interactionId, JSON.stringify(record), lifecycleStateOf(record), record.rev, record.updatedAt);
85
+ };
86
+ const saveCommitment = (record) => {
87
+ sql.exec(`INSERT INTO commitment_records (commitment_id, record_json, state, updated_at)
88
+ VALUES (?, ?, ?, ?)
89
+ ON CONFLICT(commitment_id) DO UPDATE SET
90
+ record_json = excluded.record_json, state = excluded.state, updated_at = excluded.updated_at`, record.commitmentId, JSON.stringify(record), record.state, record.updatedAt);
91
+ };
92
+ const store = {
93
+ async putInteraction(record) {
94
+ saveInteraction(record);
95
+ for (const b of record.protocolBindings ?? []) {
96
+ sql.exec(`INSERT INTO interaction_bindings (binding_key, interaction_id, binding_json) VALUES (?, ?, ?)
97
+ ON CONFLICT(binding_key, interaction_id) DO UPDATE SET binding_json = excluded.binding_json`, bindingKey(b.protocol, b.field, b.value), record.interactionId, JSON.stringify(b));
98
+ }
99
+ },
100
+ async getInteraction(id) {
101
+ return one('SELECT record_json FROM interaction_records WHERE interaction_id = ?', String(id));
102
+ },
103
+ async listInteractions() {
104
+ return sql
105
+ .exec('SELECT record_json FROM interaction_records ORDER BY updated_at DESC')
106
+ .toArray()
107
+ .map((r) => JSON.parse(r.record_json));
108
+ },
109
+ async transitionInteraction(id, event) {
110
+ const record = await this.getInteraction(id);
111
+ if (!record)
112
+ return null;
113
+ const result = applyInteractionTransition(lifecycleOf(record), event);
114
+ // Fail-closed: a rejection leaves the row exactly as it was. The store never sets state itself,
115
+ // so "concluding is custodial" cannot be bypassed by writing the row directly.
116
+ if (result.ok) {
117
+ saveInteraction({
118
+ ...record,
119
+ lifecycleState: result.next.state,
120
+ updatedAt: event.at,
121
+ rev: record.rev + 1,
122
+ });
123
+ }
124
+ return result;
125
+ },
126
+ async bindProtocolTo(id, binding) {
127
+ sql.exec(`INSERT INTO interaction_bindings (binding_key, interaction_id, binding_json) VALUES (?, ?, ?)
128
+ ON CONFLICT(binding_key, interaction_id) DO UPDATE SET binding_json = excluded.binding_json`, bindingKey(binding.protocol, binding.field, binding.value), id, JSON.stringify(binding));
129
+ },
130
+ async resolveByBinding(protocol, field, value) {
131
+ const key = bindingKey(protocol, field, value);
132
+ const ids = sql
133
+ .exec('SELECT interaction_id FROM interaction_bindings WHERE binding_key = ?', key)
134
+ .toArray()
135
+ .map((r) => r.interaction_id);
136
+ // Reuses the in-memory resolver over a one-key index so SQL and non-SQL callers cannot disagree
137
+ // about what "ambiguous" means — one definition, two backing stores.
138
+ return resolveInteractionByBinding(new Map([[key, ids]]), protocol, field, value);
139
+ },
140
+ async putContextSnapshot(snapshot) {
141
+ // A snapshot whose digest does not match its bytes is not evidence, and storing it would let a
142
+ // later `verifyContextSnapshot` fail on a record that arrived corrupt rather than was tampered.
143
+ if (!(await verifyContextSnapshot(snapshot)))
144
+ return { ok: false, reason: 'digest-mismatch' };
145
+ const existing = sql
146
+ .exec('SELECT snapshot_json FROM context_snapshots WHERE digest = ?', snapshot.digest)
147
+ .toArray()[0];
148
+ // The digest verified and a row is already here, so the content is the same — two parties
149
+ // observing one context legitimately store it twice. A no-op, and the stored bytes win.
150
+ if (existing)
151
+ return { ok: true, stored: 'identical' };
152
+ sql.exec('INSERT INTO context_snapshots (digest, snapshot_json) VALUES (?, ?)', snapshot.digest, JSON.stringify(snapshot));
153
+ return { ok: true, stored: 'new' };
154
+ },
155
+ async getContextSnapshot(digest) {
156
+ const rows = sql
157
+ .exec('SELECT snapshot_json FROM context_snapshots WHERE digest = ?', digest)
158
+ .toArray();
159
+ return rows[0] ? JSON.parse(rows[0].snapshot_json) : null;
160
+ },
161
+ async putDecision(record) {
162
+ sql.exec(`INSERT INTO decision_records (decision_id, record_json, updated_at) VALUES (?, ?, ?)
163
+ ON CONFLICT(decision_id) DO UPDATE SET record_json = excluded.record_json, updated_at = excluded.updated_at`, record.decisionId, JSON.stringify(record), record.updatedAt);
164
+ },
165
+ async getDecision(id) {
166
+ return one('SELECT record_json FROM decision_records WHERE decision_id = ?', id);
167
+ },
168
+ async transitionDecision(id, event) {
169
+ const record = await this.getDecision(id);
170
+ if (!record)
171
+ return null;
172
+ const result = applyDecisionTransition(record, event);
173
+ if (result.ok)
174
+ await this.putDecision(result.next);
175
+ return result;
176
+ },
177
+ async putCommitment(record) {
178
+ saveCommitment(record);
179
+ },
180
+ async getCommitment(id) {
181
+ return one('SELECT record_json FROM commitment_records WHERE commitment_id = ?', id);
182
+ },
183
+ async listOpenCommitments() {
184
+ return sql
185
+ .exec(`SELECT record_json FROM commitment_records WHERE state IN (?, ?, ?) ORDER BY updated_at DESC`, ...OPEN_COMMITMENT_STATES)
186
+ .toArray()
187
+ .map((r) => JSON.parse(r.record_json));
188
+ },
189
+ async transitionCommitment(id, event) {
190
+ const record = await this.getCommitment(id);
191
+ if (!record)
192
+ return null;
193
+ const result = applyCommitmentTransition(record, event);
194
+ if (result.ok)
195
+ saveCommitment(result.next);
196
+ return result;
197
+ },
198
+ async putInboxEntry(entry) {
199
+ sql.exec(`INSERT INTO inbox_entries (viewer, exchange_id, record_json) VALUES (?, ?, ?)
200
+ ON CONFLICT(viewer, exchange_id) DO UPDATE SET record_json = excluded.record_json`, entry.viewer, entry.exchangeId, JSON.stringify(entry));
201
+ },
202
+ async getInboxEntry(viewer, exchangeId) {
203
+ return one('SELECT record_json FROM inbox_entries WHERE viewer = ? AND exchange_id = ?', viewer, exchangeId);
204
+ },
205
+ async transitionInbox(viewer, exchangeId, event) {
206
+ const entry = await this.getInboxEntry(viewer, exchangeId);
207
+ if (!entry)
208
+ return null;
209
+ const result = applyInboxTransition(entry, event);
210
+ if (result.ok)
211
+ await this.putInboxEntry(result.next);
212
+ return result;
213
+ },
214
+ };
215
+ return store;
216
+ }
217
+ /** The lifecycle facet of a stored interaction, for the machine to operate on. */
218
+ function lifecycleOf(record) {
219
+ return {
220
+ interactionId: record.interactionId,
221
+ state: lifecycleStateOf(record),
222
+ principal: record.principal,
223
+ participations: record.participations,
224
+ updatedAt: record.updatedAt,
225
+ };
226
+ }
227
+ function lifecycleStateOf(record) {
228
+ return record.lifecycleState;
229
+ }
230
+ //# sourceMappingURL=interaction-store.js.map