@agenticprimitives/fabric 0.0.0-alpha.4 → 0.0.0-alpha.8

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 (130) hide show
  1. package/CLAUDE.md +22 -2
  2. package/README.md +16 -16
  3. package/dist/case-emissions.d.ts +95 -0
  4. package/dist/case-emissions.d.ts.map +1 -0
  5. package/dist/case-emissions.js +208 -0
  6. package/dist/case-emissions.js.map +1 -0
  7. package/dist/case-machine.d.ts +28 -2
  8. package/dist/case-machine.d.ts.map +1 -1
  9. package/dist/case-machine.js +34 -7
  10. package/dist/case-machine.js.map +1 -1
  11. package/dist/cloudflare/index.d.ts +1 -0
  12. package/dist/cloudflare/index.d.ts.map +1 -1
  13. package/dist/cloudflare/index.js +4 -0
  14. package/dist/cloudflare/index.js.map +1 -1
  15. package/dist/cloudflare/interaction-store.d.ts +55 -0
  16. package/dist/cloudflare/interaction-store.d.ts.map +1 -0
  17. package/dist/cloudflare/interaction-store.js +230 -0
  18. package/dist/cloudflare/interaction-store.js.map +1 -0
  19. package/dist/cloudflare/principal-gateway-do.d.ts +118 -2
  20. package/dist/cloudflare/principal-gateway-do.d.ts.map +1 -1
  21. package/dist/cloudflare/principal-gateway-do.js +182 -7
  22. package/dist/cloudflare/principal-gateway-do.js.map +1 -1
  23. package/dist/communicative-act.d.ts +24 -1
  24. package/dist/communicative-act.d.ts.map +1 -1
  25. package/dist/communicative-act.js +28 -0
  26. package/dist/communicative-act.js.map +1 -1
  27. package/dist/delivery-envelope.d.ts.map +1 -1
  28. package/dist/delivery-envelope.js +0 -1
  29. package/dist/delivery-envelope.js.map +1 -1
  30. package/dist/enum-retirement.d.ts +43 -0
  31. package/dist/enum-retirement.d.ts.map +1 -0
  32. package/dist/enum-retirement.js +93 -0
  33. package/dist/enum-retirement.js.map +1 -0
  34. package/dist/exchange-record.d.ts +35 -4
  35. package/dist/exchange-record.d.ts.map +1 -1
  36. package/dist/exchange-record.js.map +1 -1
  37. package/dist/exchange-reducer.d.ts +32 -4
  38. package/dist/exchange-reducer.d.ts.map +1 -1
  39. package/dist/exchange-reducer.js +75 -1
  40. package/dist/exchange-reducer.js.map +1 -1
  41. package/dist/exchange-state.d.ts +30 -8
  42. package/dist/exchange-state.d.ts.map +1 -1
  43. package/dist/exchange-state.js +12 -10
  44. package/dist/exchange-state.js.map +1 -1
  45. package/dist/inbox-doc.d.ts +2 -2
  46. package/dist/inbox-doc.d.ts.map +1 -1
  47. package/dist/inbox-doc.js.map +1 -1
  48. package/dist/inbox-projection.d.ts +2 -2
  49. package/dist/inbox-projection.d.ts.map +1 -1
  50. package/dist/inbox-projection.js.map +1 -1
  51. package/dist/index.d.ts +21 -3
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +32 -2
  54. package/dist/index.js.map +1 -1
  55. package/dist/interaction-machines.d.ts +136 -0
  56. package/dist/interaction-machines.d.ts.map +1 -0
  57. package/dist/interaction-machines.js +174 -0
  58. package/dist/interaction-machines.js.map +1 -0
  59. package/dist/interaction-profile.d.ts +126 -0
  60. package/dist/interaction-profile.d.ts.map +1 -0
  61. package/dist/interaction-profile.js +192 -0
  62. package/dist/interaction-profile.js.map +1 -0
  63. package/dist/interaction-record.d.ts +168 -0
  64. package/dist/interaction-record.d.ts.map +1 -0
  65. package/dist/interaction-record.js +108 -0
  66. package/dist/interaction-record.js.map +1 -0
  67. package/dist/interactions/machine.d.ts +2 -2
  68. package/dist/interactions/machine.d.ts.map +1 -1
  69. package/dist/interactions/machine.js +2 -2
  70. package/dist/interactions/machine.js.map +1 -1
  71. package/dist/interactions/store.d.ts +9 -0
  72. package/dist/interactions/store.d.ts.map +1 -1
  73. package/dist/interactions/store.js +57 -2
  74. package/dist/interactions/store.js.map +1 -1
  75. package/dist/messaging/board.d.ts +3 -3
  76. package/dist/messaging/board.d.ts.map +1 -1
  77. package/dist/messaging/board.js +2 -2
  78. package/dist/messaging/board.js.map +1 -1
  79. package/dist/messaging/conversation-interaction.d.ts +66 -0
  80. package/dist/messaging/conversation-interaction.d.ts.map +1 -0
  81. package/dist/messaging/conversation-interaction.js +139 -0
  82. package/dist/messaging/conversation-interaction.js.map +1 -0
  83. package/dist/messaging/delivery.d.ts +2 -2
  84. package/dist/messaging/delivery.d.ts.map +1 -1
  85. package/dist/messaging/delivery.js +8 -1
  86. package/dist/messaging/delivery.js.map +1 -1
  87. package/dist/messaging/envelope.d.ts +7 -3
  88. package/dist/messaging/envelope.d.ts.map +1 -1
  89. package/dist/messaging/envelope.js +18 -1
  90. package/dist/messaging/envelope.js.map +1 -1
  91. package/dist/messaging/hash.d.ts +8 -2
  92. package/dist/messaging/hash.d.ts.map +1 -1
  93. package/dist/messaging/hash.js +6 -0
  94. package/dist/messaging/hash.js.map +1 -1
  95. package/dist/messaging/inbox-assistant.d.ts +16 -4
  96. package/dist/messaging/inbox-assistant.d.ts.map +1 -1
  97. package/dist/messaging/inbox-assistant.js +27 -4
  98. package/dist/messaging/inbox-assistant.js.map +1 -1
  99. package/dist/messaging/index.d.ts +4 -1
  100. package/dist/messaging/index.d.ts.map +1 -1
  101. package/dist/messaging/index.js +4 -0
  102. package/dist/messaging/index.js.map +1 -1
  103. package/dist/messaging/projector.d.ts +3 -3
  104. package/dist/messaging/projector.d.ts.map +1 -1
  105. package/dist/messaging/projector.js.map +1 -1
  106. package/dist/messaging/receipts.d.ts +3 -3
  107. package/dist/messaging/receipts.d.ts.map +1 -1
  108. package/dist/messaging/receipts.js.map +1 -1
  109. package/dist/messaging/rules.d.ts +10 -3
  110. package/dist/messaging/rules.d.ts.map +1 -1
  111. package/dist/messaging/rules.js +8 -1
  112. package/dist/messaging/rules.js.map +1 -1
  113. package/dist/messaging/store.d.ts +4 -4
  114. package/dist/messaging/store.d.ts.map +1 -1
  115. package/dist/messaging/store.js +5 -3
  116. package/dist/messaging/store.js.map +1 -1
  117. package/dist/messaging/types.d.ts +30 -0
  118. package/dist/messaging/types.d.ts.map +1 -1
  119. package/dist/messaging/types.js +3 -0
  120. package/dist/messaging/types.js.map +1 -1
  121. package/dist/messaging/vault-store.d.ts +2 -2
  122. package/dist/messaging/vault-store.d.ts.map +1 -1
  123. package/dist/protocol-binding.d.ts +71 -0
  124. package/dist/protocol-binding.d.ts.map +1 -0
  125. package/dist/protocol-binding.js +0 -0
  126. package/dist/protocol-binding.js.map +1 -0
  127. package/dist/record-catalog.d.ts.map +1 -1
  128. package/dist/record-catalog.js +7 -0
  129. package/dist/record-catalog.js.map +1 -1
  130. package/package.json +7 -7
@@ -0,0 +1,192 @@
1
+ // The profile mechanism (spec 340 W4) — what replaces the frozen `MessageKind`/`CaseState` enums.
2
+ //
3
+ // A profile declares what one KIND of interaction permits: its roles, its acts, the context every
4
+ // exchange in it must pin, which acts can create an obligation, and how it ends. A new interaction
5
+ // type is therefore a new profile — data — rather than a new enum member and a schema change. That is
6
+ // the whole extensibility story for anyone outside this repo.
7
+ //
8
+ // A PROFILE PERMITS NOTHING. `checkExchangeAgainstProfile` answers "is this move well-formed FOR THIS
9
+ // KIND of interaction", which is a shape question. Whether the actor was allowed to make it is
10
+ // `delegation` + `entitlements` + `tool-policy`, re-evaluated at the moment of acting (ADR-0041).
11
+ // The two are easy to conflate precisely because both can say no, so: a profile refusal means the
12
+ // record would be uninterpretable; an authority refusal means the party had no right. A profile
13
+ // saying yes has granted nothing.
14
+ //
15
+ // Versioning is the anti-downgrade control (spec 340 §6). `<name>/<semver>`, pinned onto every
16
+ // Exchange, and both halves required — a bare name would make the pin unfalsifiable.
17
+ import { isProfileVersion } from './interaction-record.js';
18
+ /**
19
+ * Every violation, not the first.
20
+ *
21
+ * A caller fixing one at a time needs N round trips to learn the exchange was never valid, and the
22
+ * usual outcome of that is a caller who stops checking.
23
+ */
24
+ export function checkExchangeAgainstProfile(profile, exchange) {
25
+ const violations = [];
26
+ if (!isProfileVersion(exchange.profileVersion)) {
27
+ violations.push({ reason: 'malformed-profile-version', value: exchange.profileVersion });
28
+ }
29
+ else if (exchange.profileVersion !== profile.profileVersion) {
30
+ // Not automatically an attack — an interaction whose profile versioned mid-flight legitimately
31
+ // contains exchanges under both. It IS the signal, and the only thing that disagrees afterwards.
32
+ violations.push({
33
+ reason: 'profile-version-mismatch',
34
+ pinned: exchange.profileVersion,
35
+ expected: profile.profileVersion,
36
+ });
37
+ }
38
+ for (const act of exchange.acts) {
39
+ if (!profile.permittedActs.includes(act))
40
+ violations.push({ reason: 'act-not-permitted', act });
41
+ }
42
+ for (const kind of profile.requiredContextKinds) {
43
+ if (!exchange.contextKinds.includes(kind))
44
+ violations.push({ reason: 'missing-required-context', kind });
45
+ }
46
+ if (exchange.createsCommitment) {
47
+ const creating = exchange.acts.filter((a) => profile.commitmentCreatingActs.includes(a));
48
+ if (creating.length === 0) {
49
+ // The structural half of "an Offer is not a Commitment": an exchange cannot claim to have
50
+ // created an obligation without realizing an act this profile says can create one.
51
+ violations.push({ reason: 'commitment-from-non-creating-act', act: exchange.acts[0] ?? 'INFORM' });
52
+ }
53
+ }
54
+ return violations;
55
+ }
56
+ // ─── The library ─────────────────────────────────────────────────────────────
57
+ /** Plain conversation. Creates no obligations, requires no context — and saying so explicitly is the
58
+ * point: the overwhelming majority of exchanges are this, and they should not carry ceremony. */
59
+ export const DIRECT_PROFILE = {
60
+ version: 'ap.interaction-profile.v1',
61
+ profileVersion: 'direct/1.0.0',
62
+ purpose: 'A conversation between two agents. Carries no obligation and evaluates no authority.',
63
+ roles: ['participant'],
64
+ permittedActs: ['INFORM', 'QUERY', 'NOTIFY', 'ACKNOWLEDGE'],
65
+ requiredContextKinds: [],
66
+ commitmentCreatingActs: [],
67
+ closeReasons: ['concluded', 'abandoned'],
68
+ };
69
+ /** Terms are proposed, countered and accepted. The only profile in this starter set where an ACCEPT
70
+ * can create an obligation, which is exactly why ACCEPT is not in the others. */
71
+ export const NEGOTIATION_PROFILE = {
72
+ version: 'ap.interaction-profile.v1',
73
+ profileVersion: 'negotiation/1.0.0',
74
+ purpose: 'Offer, counter-offer and acceptance over terms. A valid, authorized ACCEPT creates a Commitment.',
75
+ roles: ['proposer', 'counterparty'],
76
+ permittedActs: ['INFORM', 'QUERY', 'PROPOSE', 'COUNTER', 'ACCEPT', 'REJECT', 'RETRACT', 'ACKNOWLEDGE'],
77
+ requiredContextKinds: [],
78
+ commitmentCreatingActs: ['ACCEPT'],
79
+ closeReasons: ['agreed', 'declined', 'withdrawn', 'expired', 'abandoned'],
80
+ };
81
+ /** A question routed to a member and answered. `structured-only` by construction: the permitted acts
82
+ * contain no PROPOSE, so a consultation cannot quietly become a negotiation. */
83
+ export const CONSULTATION_PROFILE = {
84
+ version: 'ap.interaction-profile.v1',
85
+ profileVersion: 'consultation/1.0.0',
86
+ purpose: 'A routed question and its answers. Advice, never an offer — and structurally incapable of becoming one.',
87
+ roles: ['requester', 'router', 'consultant'],
88
+ permittedActs: ['QUERY', 'INFORM', 'ACKNOWLEDGE', 'REJECT'],
89
+ requiredContextKinds: ['delegation'],
90
+ commitmentCreatingActs: [],
91
+ closeReasons: ['answered', 'declined', 'expired', 'no-consultant-available'],
92
+ };
93
+ /**
94
+ * Spec 336's pre-task provider qualification, expressed as a profile of this model rather than as a
95
+ * parallel one. This is the profile mechanism's actual test: an existing, independently-designed
96
+ * chain either fits or it does not.
97
+ *
98
+ * IT MOSTLY FITS, AND WHERE IT DOES NOT, THE FINDING IS REAL — see `ENGAGEMENT_RESPONSE_KIND_AXES`
99
+ * below. `requiredContextKinds` is `['intent-projection']` because §3.1's rule is that an offer binds
100
+ * to the projection the provider REVIEWED, not to undisclosed facts in the intent; an engagement
101
+ * exchange that pins no projection cannot later be checked against what was actually disclosed.
102
+ *
103
+ * `commitmentCreatingActs` is EMPTY, and that is the load-bearing line. Nine of the chain's ten steps
104
+ * grant nothing; only the Mandate authorizes, and a Mandate is issued by `delegation`, not created by
105
+ * an act in this interaction. An engagement that could mint an obligation would be spec 336's central
106
+ * claim undone by its own profile.
107
+ */
108
+ export const ENGAGEMENT_PROFILE = {
109
+ version: 'ap.interaction-profile.v1',
110
+ profileVersion: 'engagement/1.0.0',
111
+ purpose: 'Pre-task provider qualification (spec 336): probe a candidate against a minimized intent projection and receive terms. Grants nothing — only the Mandate authorizes.',
112
+ roles: ['requester', 'candidate-provider'],
113
+ permittedActs: ['QUERY', 'INFORM', 'PROPOSE', 'COUNTER', 'REJECT', 'ACKNOWLEDGE', 'RETRACT'],
114
+ requiredContextKinds: ['intent-projection'],
115
+ commitmentCreatingActs: [],
116
+ closeReasons: [
117
+ 'offer-selected',
118
+ 'declined',
119
+ 'referred',
120
+ 'temporarily-unavailable',
121
+ 'not-selected',
122
+ 'expired',
123
+ 'cancelled',
124
+ ],
125
+ };
126
+ /**
127
+ * An org topic — the first profile that describes something already in production (spec 340 W11).
128
+ *
129
+ * Org topics were an Interaction in everything but name: the org SA owns the board, members join and
130
+ * leave, `facilitator`/`contributor` are its roles, and it opens and closes. This profile names that
131
+ * rather than building anything new.
132
+ *
133
+ * `commitmentCreatingActs` is empty and `PROPOSE`/`ACCEPT` are absent from the permitted set: a topic
134
+ * is a discussion board. If a negotiation happens in one, it belongs in its own Interaction under the
135
+ * negotiation profile — which is exactly ADR-0058 §14's rule that a thread is promoted only when it
136
+ * acquires an independent property, applied to the case that actually occurs.
137
+ */
138
+ export const TOPIC_PROFILE = {
139
+ version: 'ap.interaction-profile.v1',
140
+ profileVersion: 'topic/1.0.0',
141
+ purpose: 'An organization discussion board. Members post, facilitators manage. Carries no obligation and is structurally incapable of becoming a negotiation.',
142
+ roles: ['facilitator', 'contributor'],
143
+ permittedActs: ['INFORM', 'QUERY', 'NOTIFY', 'ACKNOWLEDGE'],
144
+ requiredContextKinds: [],
145
+ commitmentCreatingActs: [],
146
+ // `archived` is deliberately NOT here. Shelving a board is an inbox/display concern and already
147
+ // exists as `InboxState.archived`; an interaction that is archived has still concluded or not.
148
+ closeReasons: ['concluded', 'abandoned'],
149
+ };
150
+ export const PROFILE_LIBRARY = [
151
+ DIRECT_PROFILE,
152
+ NEGOTIATION_PROFILE,
153
+ CONSULTATION_PROFILE,
154
+ ENGAGEMENT_PROFILE,
155
+ TOPIC_PROFILE,
156
+ ];
157
+ export function profileFor(version) {
158
+ return PROFILE_LIBRARY.find((p) => p.profileVersion === version);
159
+ }
160
+ // ─── The finding W4 was run to produce ───────────────────────────────────────
161
+ /**
162
+ * Spec 336 §3.5's six "response kinds" are NOT one axis.
163
+ *
164
+ * Four are performatives — WHAT the act does, its illocutionary force. Two are classifications of the
165
+ * CONTENT an INFORM carries. Modelling all six as one enumeration is the same defect spec 336 itself
166
+ * diagnosed one level up, when it split probe "mode" into three orthogonal axes because one
167
+ * enumeration doing three jobs made ordinary positions unsayable.
168
+ *
169
+ * The consequence if left merged: `human-ux-required` would need a performative of its own, and the
170
+ * scheme would grow a concept per business outcome until it was a catalog — exactly what SKOS act
171
+ * kinds exist to prevent. Keeping the split means a provider saying "I need a human channel" is an
172
+ * INFORM whose content says so, which is what it actually is.
173
+ *
174
+ * This is a finding against spec 336 §3.5, recorded here because the profile is where it surfaced.
175
+ * It changes no wire format: the response kind stays on the content, where it already lives.
176
+ */
177
+ export const ENGAGEMENT_RESPONSE_KIND_AXES = {
178
+ offer: { axis: 'performative', performative: 'PROPOSE' },
179
+ decline: { axis: 'performative', performative: 'REJECT' },
180
+ 'needs-clarification': { axis: 'performative', performative: 'QUERY' },
181
+ acknowledgement: { axis: 'performative', performative: 'ACKNOWLEDGE' },
182
+ // A referral is not a distinct force — it is an INFORM whose content names another provider.
183
+ // Promoting it would make "who to ask instead" an act rather than a fact.
184
+ referral: { axis: 'content', carriedBy: 'INFORM' },
185
+ // A fact about TIME, and the one spec 336 is most careful about: it must never be cached as
186
+ // absence, because a resolver that can only handle "yes" reads "not right now" as "no such provider".
187
+ 'temporarily-unavailable': { axis: 'content', carriedBy: 'INFORM' },
188
+ // No performative, and it should not get one: needing a human channel is a property of HOW the
189
+ // answer must arrive, not of what was said.
190
+ 'human-ux-required': { axis: 'content', carriedBy: 'INFORM' },
191
+ };
192
+ //# sourceMappingURL=interaction-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction-profile.js","sourceRoot":"","sources":["../src/interaction-profile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,168 @@
1
+ import type { CanonicalAgentId } from '@agenticprimitives/types';
2
+ import type { Hex32 } from './messaging/index.js';
3
+ import type { ProtocolBindingV1 } from './protocol-binding.js';
4
+ import type { InteractionState } from './interaction-machines.js';
5
+ /** The interaction spine id. Ours, never a protocol's — an A2A `contextId` or a DIDComm `thid` is a
6
+ * foreign key into someone else's namespace and is carried alongside, never used as this (spec 340 §11). */
7
+ export type InteractionId = `ixn_${string}`;
8
+ /** Content address of a `ContextSnapshotV1`. A snapshot is identified BY its bytes. */
9
+ export type ContextDigest = Hex32;
10
+ /**
11
+ * The version of an `InteractionProfile`, pinned onto every Exchange.
12
+ *
13
+ * A profile declares its own roles, permitted acts, required contexts, state machine and authority
14
+ * requirements — so a new interaction type is a NEW PROFILE, not a new `MessageKind` member and not a
15
+ * schema change (spec 340 §6). That is the extensibility mechanism external adopters get.
16
+ *
17
+ * `<name>/<semver>` and both halves are required. A bare name would make the pin unfalsifiable, which
18
+ * is the whole reason the pin exists.
19
+ */
20
+ export type ProfileVersion = `${string}/${number}.${number}.${number}`;
21
+ export declare function isProfileVersion(value: string): value is ProfileVersion;
22
+ export declare function isFloatingVersion(value: string): boolean;
23
+ /**
24
+ * ONE reference inside a snapshot — a delegation, an entitlement, a policy, a credential status.
25
+ *
26
+ * All four fields are required, and that is the point. A reference carrying only an id resolves to
27
+ * whatever exists when someone later asks, which means a historical record describes the present
28
+ * instead of the past. The failure is quiet and forensic: nothing breaks at write time, and a year
29
+ * later nobody can say what the evaluator actually saw.
30
+ */
31
+ export interface ContextReferenceV1 {
32
+ /** What kind of thing this is — `delegation`, `entitlement`, `policy`, `status`, … */
33
+ kind: string;
34
+ /** Its canonical id in its OWN namespace. */
35
+ id: string;
36
+ /** The EXACT version. Never `current`/`latest` (see `assertReproducible`). */
37
+ version: string;
38
+ /** Digest of the referenced artifact as it stood. */
39
+ digest: Hex32;
40
+ /** When this reference was observed — not when the artifact was created. */
41
+ observedAt: string;
42
+ }
43
+ /**
44
+ * An immutable, digest-addressed bundle of exactly what was known and evaluated when an Exchange was
45
+ * made. Replaces `contextRefs[]`, which were floating pointers at live state.
46
+ */
47
+ export interface ContextSnapshotV1 {
48
+ version: 'ap.context-snapshot.v1';
49
+ /** sha256 over the canonical body (every field except `digest` itself). */
50
+ digest: ContextDigest;
51
+ /** The profile version in force when this was taken. */
52
+ profileVersion: ProfileVersion;
53
+ refs: readonly ContextReferenceV1[];
54
+ takenAt: string;
55
+ }
56
+ export type ContextReproducibilityFailure = {
57
+ reason: 'floating_version';
58
+ ref: ContextReferenceV1;
59
+ } | {
60
+ reason: 'floating_profile_version';
61
+ value: string;
62
+ } | {
63
+ reason: 'malformed_profile_version';
64
+ value: string;
65
+ } | {
66
+ reason: 'missing_field';
67
+ ref: ContextReferenceV1;
68
+ field: keyof ContextReferenceV1;
69
+ };
70
+ /**
71
+ * The reproducibility gate, as a TOTAL function over the failures rather than a boolean.
72
+ *
73
+ * Returns every problem, not the first: a caller fixing one floating ref at a time would otherwise
74
+ * need N round trips to learn the record was never reproducible.
75
+ */
76
+ export declare function checkReproducible(input: Pick<ContextSnapshotV1, 'profileVersion' | 'refs'>): readonly ContextReproducibilityFailure[];
77
+ /** Throwing form, for the write path. Fail-closed: an unreproducible snapshot is never stored. */
78
+ export declare function assertReproducible(input: Pick<ContextSnapshotV1, 'profileVersion' | 'refs'>): void;
79
+ /** Digest over the canonical body — every field except `digest`. */
80
+ export declare function hashContextSnapshot(snapshot: Omit<ContextSnapshotV1, 'digest'> | ContextSnapshotV1): Promise<ContextDigest>;
81
+ /** Build + seal. Refs are sorted so two callers observing the same context produce the same digest —
82
+ * a content address that depended on insertion order would not be one. */
83
+ export declare function buildContextSnapshot(input: {
84
+ profileVersion: ProfileVersion;
85
+ refs: readonly ContextReferenceV1[];
86
+ takenAt: string;
87
+ }): Promise<ContextSnapshotV1>;
88
+ /** Recompute and compare. A snapshot whose digest does not match its bytes is not evidence. */
89
+ export declare function verifyContextSnapshot(snapshot: ContextSnapshotV1): Promise<boolean>;
90
+ /**
91
+ * An agent's standing in an Interaction under a profile-defined role, over a time window.
92
+ *
93
+ * The role is a plain string BECAUSE the profile defines the role set. Enumerating roles here would
94
+ * reintroduce the frozen taxonomy profiles exist to replace — and a role, unlike a state, has no
95
+ * substrate-wide meaning to enumerate against.
96
+ */
97
+ export interface ParticipationV1 {
98
+ agent: CanonicalAgentId;
99
+ /** Defined by the interaction's profile, not by this package. */
100
+ role: string;
101
+ joinedAt: string;
102
+ /** Absent while participating. Set on leaving; the record is never deleted. */
103
+ leftAt?: string;
104
+ }
105
+ /** Participants at an instant — a projection over join/leave windows, never a stored second copy. */
106
+ export declare function participantsAt(participations: readonly ParticipationV1[], at: string): readonly ParticipationV1[];
107
+ /**
108
+ * The durable governed situation. Deliberately does NOT carry its exchanges: they live in their own
109
+ * records and point INWARD via `ExchangeRecordV1.interactionId`. An aggregate that inlined its
110
+ * exchanges would have to be rewritten on every message, which is how an "immutable signed unit"
111
+ * quietly becomes a mutable row.
112
+ */
113
+ export interface InteractionRecordV1 {
114
+ version: 'ap.interaction.v1';
115
+ interactionId: InteractionId;
116
+ /** The profile IN FORCE. Individual exchanges pin the version they were made under, which may be an
117
+ * older one — that difference is exactly what makes a downgrade detectable rather than invisible. */
118
+ profileVersion: ProfileVersion;
119
+ /** The gateway owner SA the interaction is custodied by. */
120
+ principal: CanonicalAgentId;
121
+ /** Where the interaction is in ITS OWN lifecycle — one of the six machines, and not the same
122
+ * question as any exchange's `exec`/`case`. Required rather than defaulted: a record that omitted
123
+ * it would be read as `forming` by whoever looked, including after it had concluded. */
124
+ lifecycleState: InteractionState;
125
+ /**
126
+ * HOW membership is determined — the distinction org topics forced into the model.
127
+ *
128
+ * `asserted`: the list below IS the membership. Someone joined, someone left, and the record says so.
129
+ *
130
+ * `derived`: membership is computed by the custodian from a source that already owns it — for an open
131
+ * org topic, the organization's own membership. `participations` MUST then stay EMPTY. Copying the
132
+ * member list per interaction is exactly the duplication `apmsg:openParticipation` forbids
133
+ * ("derived at read time — never stored per topic"), and a stale copy of a membership list is how a
134
+ * removed member keeps posting.
135
+ */
136
+ participationMode: 'asserted' | 'derived';
137
+ /** Empty when `participationMode` is `derived` — see above. */
138
+ participations: readonly ParticipationV1[];
139
+ /** Foreign keys into other protocols' namespaces (A2A contextId, DIDComm thid, Matrix event id).
140
+ * NEVER the canonical id — see `InteractionId` (spec 340 §11). A LIST of typed bindings rather
141
+ * than a `Record<protocol, value>`: one protocol contributes several distinct correlators
142
+ * (`a2a:contextId` and `a2a:taskId` are not the same key), and each is a claim about a moment, so
143
+ * it carries its own `observedAt` like every other reference in this model. */
144
+ protocolBindings?: readonly ProtocolBindingV1[];
145
+ createdAt: string;
146
+ updatedAt: string;
147
+ /** Monotonic revision, mirroring `ExchangeRecordV1.rev`. */
148
+ rev: number;
149
+ }
150
+ export type ProfileDowngrade = {
151
+ exchangeId: string;
152
+ pinned: ProfileVersion;
153
+ inForce: ProfileVersion;
154
+ };
155
+ /**
156
+ * Detect exchanges pinned to a profile version OLDER than the one now in force.
157
+ *
158
+ * This is not an error — an interaction whose profile versioned mid-flight legitimately contains
159
+ * exchanges under both. It is a REPORT, because the attack it surfaces has no network component: an
160
+ * adversary who can edit the interaction's `profileVersion` reinterprets a Negotiation as a generic
161
+ * Conversation and takes its acceptance semantics with it. The pin on each Exchange is what makes
162
+ * that visible, and this is the function that looks.
163
+ */
164
+ export declare function detectProfileDowngrades(interaction: Pick<InteractionRecordV1, 'profileVersion'>, exchanges: readonly {
165
+ exchangeId: string;
166
+ profileVersion?: ProfileVersion;
167
+ }[]): readonly ProfileDowngrade[];
168
+ //# sourceMappingURL=interaction-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction-record.d.ts","sourceRoot":"","sources":["../src/interaction-record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ // The durable governed situation (spec 340 W2; ADR-0058) — the aggregate `ExchangeRecordV1` has been
2
+ // living without.
3
+ //
4
+ // Today the model is Exchange-rooted: an exchange carries a `case?: CaseState` substate and there is no
5
+ // record of the interaction ITSELF. That holds exactly as long as an interaction is one request-shaped
6
+ // thing. It stops the moment participants join and leave, a profile versions, a context must be
7
+ // reproducible, or a commitment outlives any single exchange.
8
+ //
9
+ // Interaction the governed situation durable: participants, profile, state, commitments
10
+ // └── Exchange one immutable signed unit crossing its boundary
11
+ //
12
+ // An Exchange without an Interaction is a message. An Interaction without Exchanges is an empty room.
13
+ // Both are legitimate; neither is the other.
14
+ //
15
+ // WHAT THIS FILE CONFERS: nothing. An `InteractionRecordV1` records who is participating and under what
16
+ // profile; it never decides whether an act is permitted. Participation is not authority — a role
17
+ // explains WHY delegations were issued, it never substitutes for one (ADR-0048 §4). Authority stays in
18
+ // `delegation` + `entitlements` + `tool-policy`, re-evaluated at the moment of acting.
19
+ import { canonicalizeJson } from '@agenticprimitives/types';
20
+ import { sha256Hex32 } from './messaging/index.js';
21
+ const PROFILE_VERSION_RE = /^[a-z][a-z0-9-]*(?:\.[a-z0-9-]+)*\/\d+\.\d+\.\d+$/;
22
+ export function isProfileVersion(value) {
23
+ return PROFILE_VERSION_RE.test(value);
24
+ }
25
+ /** Values that name "whatever exists now". Forbidden inside any historical record (spec 340 §7). */
26
+ const FLOATING = new Set(['current', 'latest', 'head', 'main', 'tip', 'now']);
27
+ export function isFloatingVersion(value) {
28
+ return FLOATING.has(value.trim().toLowerCase());
29
+ }
30
+ /**
31
+ * The reproducibility gate, as a TOTAL function over the failures rather than a boolean.
32
+ *
33
+ * Returns every problem, not the first: a caller fixing one floating ref at a time would otherwise
34
+ * need N round trips to learn the record was never reproducible.
35
+ */
36
+ export function checkReproducible(input) {
37
+ const failures = [];
38
+ if (isFloatingVersion(input.profileVersion)) {
39
+ failures.push({ reason: 'floating_profile_version', value: input.profileVersion });
40
+ }
41
+ else if (!isProfileVersion(input.profileVersion)) {
42
+ failures.push({ reason: 'malformed_profile_version', value: input.profileVersion });
43
+ }
44
+ for (const ref of input.refs) {
45
+ for (const field of ['kind', 'id', 'version', 'digest', 'observedAt']) {
46
+ if (!ref[field])
47
+ failures.push({ reason: 'missing_field', ref, field });
48
+ }
49
+ if (ref.version && isFloatingVersion(ref.version)) {
50
+ failures.push({ reason: 'floating_version', ref });
51
+ }
52
+ }
53
+ return failures;
54
+ }
55
+ /** Throwing form, for the write path. Fail-closed: an unreproducible snapshot is never stored. */
56
+ export function assertReproducible(input) {
57
+ const failures = checkReproducible(input);
58
+ if (failures.length === 0)
59
+ return;
60
+ throw new Error(`ContextSnapshot is not reproducible: ${failures
61
+ .map((f) => f.reason === 'floating_version'
62
+ ? `${f.ref.kind}:${f.ref.id} pins "${f.ref.version}"`
63
+ : f.reason === 'missing_field'
64
+ ? `${f.ref.kind}:${f.ref.id} missing ${f.field}`
65
+ : `profileVersion "${f.value}" (${f.reason})`)
66
+ .join('; ')}`);
67
+ }
68
+ /** Digest over the canonical body — every field except `digest`. */
69
+ export async function hashContextSnapshot(snapshot) {
70
+ const { digest: _digest, ...body } = snapshot;
71
+ return sha256Hex32(canonicalizeJson(body));
72
+ }
73
+ /** Build + seal. Refs are sorted so two callers observing the same context produce the same digest —
74
+ * a content address that depended on insertion order would not be one. */
75
+ export async function buildContextSnapshot(input) {
76
+ assertReproducible(input);
77
+ const refs = [...input.refs].sort((a, b) => a.kind === b.kind ? (a.id === b.id ? a.digest.localeCompare(b.digest) : a.id.localeCompare(b.id)) : a.kind.localeCompare(b.kind));
78
+ const body = {
79
+ version: 'ap.context-snapshot.v1',
80
+ profileVersion: input.profileVersion,
81
+ refs,
82
+ takenAt: input.takenAt,
83
+ };
84
+ return { ...body, digest: await hashContextSnapshot(body) };
85
+ }
86
+ /** Recompute and compare. A snapshot whose digest does not match its bytes is not evidence. */
87
+ export async function verifyContextSnapshot(snapshot) {
88
+ return (await hashContextSnapshot(snapshot)) === snapshot.digest;
89
+ }
90
+ /** Participants at an instant — a projection over join/leave windows, never a stored second copy. */
91
+ export function participantsAt(participations, at) {
92
+ return participations.filter((p) => p.joinedAt <= at && (p.leftAt === undefined || p.leftAt > at));
93
+ }
94
+ /**
95
+ * Detect exchanges pinned to a profile version OLDER than the one now in force.
96
+ *
97
+ * This is not an error — an interaction whose profile versioned mid-flight legitimately contains
98
+ * exchanges under both. It is a REPORT, because the attack it surfaces has no network component: an
99
+ * adversary who can edit the interaction's `profileVersion` reinterprets a Negotiation as a generic
100
+ * Conversation and takes its acceptance semantics with it. The pin on each Exchange is what makes
101
+ * that visible, and this is the function that looks.
102
+ */
103
+ export function detectProfileDowngrades(interaction, exchanges) {
104
+ return exchanges.flatMap((x) => x.profileVersion && x.profileVersion !== interaction.profileVersion
105
+ ? [{ exchangeId: x.exchangeId, pinned: x.profileVersion, inForce: interaction.profileVersion }]
106
+ : []);
107
+ }
108
+ //# sourceMappingURL=interaction-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction-record.js","sourceRoot":"","sources":["../src/interaction-record.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { isTerminalCaseState, type CaseRejection } from '../case-machine.js';
1
+ import { isTerminalCaseState, type CaseRejection, type CaseTransitionContext } from '../case-machine.js';
2
2
  import type { InteractionCaseV1, InteractionState, InteractionTransitionEventV1 } from './types.js';
3
3
  export declare const TERMINAL_STATES: readonly InteractionState[];
4
4
  export declare const isTerminalState: typeof isTerminalCaseState;
@@ -15,5 +15,5 @@ export type TransitionResult = {
15
15
  * interactions `interactionId` onto the case `caseId` and delegates to `applyCaseTransition`. Pure,
16
16
  * fail-closed, role-checked — unchanged semantics for the surviving transitions.
17
17
  */
18
- export declare function applyInteractionTransition(current: InteractionCaseV1, event: InteractionTransitionEventV1): TransitionResult;
18
+ export declare function applyInteractionTransition(current: InteractionCaseV1, event: InteractionTransitionEventV1, ctx?: CaseTransitionContext): TransitionResult;
19
19
  //# sourceMappingURL=machine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../src/interactions/machine.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,mBAAmB,EAEnB,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAEpG,eAAO,MAAM,eAAe,EAAE,SAAS,gBAAgB,EAAyB,CAAC;AACjF,eAAO,MAAM,eAAe,4BAAsB,CAAC;AAEnD,MAAM,MAAM,mBAAmB,GAAG,aAAa,CAAC;AAChD,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,GACrC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAE/C;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,4BAA4B,GAClC,gBAAgB,CAclB"}
1
+ {"version":3,"file":"machine.d.ts","sourceRoot":"","sources":["../../src/interactions/machine.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,mBAAmB,EAEnB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAEpG,eAAO,MAAM,eAAe,EAAE,SAAS,gBAAgB,EAAyB,CAAC;AACjF,eAAO,MAAM,eAAe,4BAAsB,CAAC;AAEnD,MAAM,MAAM,mBAAmB,GAAG,aAAa,CAAC;AAChD,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,iBAAiB,CAAA;CAAE,GACrC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAE/C;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,4BAA4B,EACnC,GAAG,GAAE,qBAA0B,GAC9B,gBAAgB,CAclB"}
@@ -13,7 +13,7 @@ export const isTerminalState = isTerminalCaseState;
13
13
  * interactions `interactionId` onto the case `caseId` and delegates to `applyCaseTransition`. Pure,
14
14
  * fail-closed, role-checked — unchanged semantics for the surviving transitions.
15
15
  */
16
- export function applyInteractionTransition(current, event) {
16
+ export function applyInteractionTransition(current, event, ctx = {}) {
17
17
  return applyCaseTransition(current, {
18
18
  version: 'ap.case.event.v1',
19
19
  caseId: event.interactionId,
@@ -26,6 +26,6 @@ export function applyInteractionTransition(current, event) {
26
26
  evidenceRef: event.evidenceRef,
27
27
  authorityRef: event.authorityRef,
28
28
  signature: event.signature,
29
- });
29
+ }, ctx);
30
30
  }
31
31
  //# sourceMappingURL=machine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"machine.js","sourceRoot":"","sources":["../../src/interactions/machine.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,2GAA2G;AAC3G,2GAA2G;AAC3G,sGAAsG;AACtG,EAAE;AACF,iGAAiG;AACjG,6EAA6E;AAE7E,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,GAErB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,CAAC,MAAM,eAAe,GAAgC,oBAAoB,CAAC;AACjF,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAOnD;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAA0B,EAC1B,KAAmC;IAEnC,OAAO,mBAAmB,CAAC,OAAO,EAAE;QAClC,OAAO,EAAE,kBAAkB;QAC3B,MAAM,EAAE,KAAK,CAAC,aAAa;QAC3B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,SAAS,EAAE,KAAK,CAAC,SAAS;KAC3B,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"machine.js","sourceRoot":"","sources":["../../src/interactions/machine.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,2GAA2G;AAC3G,2GAA2G;AAC3G,sGAAsG;AACtG,EAAE;AACF,iGAAiG;AACjG,6EAA6E;AAE7E,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,GAGrB,MAAM,oBAAoB,CAAC;AAG5B,MAAM,CAAC,MAAM,eAAe,GAAgC,oBAAoB,CAAC;AACjF,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAOnD;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAA0B,EAC1B,KAAmC,EACnC,MAA6B,EAAE;IAE/B,OAAO,mBAAmB,CAAC,OAAO,EAAE;QAClC,OAAO,EAAE,kBAAkB;QAC3B,MAAM,EAAE,KAAK,CAAC,aAAa;QAC3B,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,SAAS,EAAE,KAAK,CAAC,SAAS;KAC3B,EAAE,GAAG,CAAC,CAAC;AACV,CAAC"}
@@ -1,9 +1,18 @@
1
1
  import { type TransitionResult } from './machine.js';
2
+ import type { CommitmentRecordV1, DecisionRecordV1 } from '../interaction-machines.js';
2
3
  import type { InteractionCaseV1, InteractionId, InteractionState, InteractionTransitionEventV1 } from './types.js';
3
4
  export interface InteractionStore {
4
5
  /** Register a new case. Fail-closed: only `draft` cases enter; duplicate ids throw. */
5
6
  putCase(c: InteractionCaseV1): void;
6
7
  getCase(id: InteractionId): InteractionCaseV1 | null;
8
+ /**
9
+ * The determination this case produced, if any (spec 340 W10). `null` until a transition emits one —
10
+ * `approve`/`deny`/`expire` are the three that do. Separate from the case's own state on purpose:
11
+ * a decision has its own lifecycle, its own signer, and outlives the transition that recorded it.
12
+ */
13
+ getDecision(id: InteractionId): DecisionRecordV1 | null;
14
+ /** The obligation this case gave rise to, if any. `null` until `issue-credential` creates one. */
15
+ getCommitment(id: InteractionId): CommitmentRecordV1 | null;
7
16
  /**
8
17
  * Apply a signed transition event. Idempotent: replaying an event whose
9
18
  * `idempotencyKey` was already applied returns the current case unchanged
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/interactions/store.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+C,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAClG,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAEnH,MAAM,WAAW,gBAAgB;IAC/B,uFAAuF;IACvF,OAAO,CAAC,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,EAAE,aAAa,GAAG,iBAAiB,GAAG,IAAI,CAAC;IACrD;;;;OAIG;IACH,UAAU,CAAC,KAAK,EAAE,4BAA4B,GAAG,gBAAgB,CAAC;IAClE,UAAU,CAAC,EAAE,EAAE,aAAa,GAAG,4BAA4B,EAAE,CAAC;IAC9D,SAAS,CAAC,KAAK,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,EAAE,CAAC;IACzD;iEAC6D;IAC7D,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAAC;CACjD;AAED,wBAAgB,8BAA8B,IAAI,gBAAgB,CA6DjE"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/interactions/store.ts"],"names":[],"mappings":"AAGA,OAAO,EAA+C,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAElG,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACvF,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAEnH,MAAM,WAAW,gBAAgB;IAC/B,uFAAuF;IACvF,OAAO,CAAC,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,EAAE,aAAa,GAAG,iBAAiB,GAAG,IAAI,CAAC;IACrD;;;;OAIG;IACH,WAAW,CAAC,EAAE,EAAE,aAAa,GAAG,gBAAgB,GAAG,IAAI,CAAC;IACxD,kGAAkG;IAClG,aAAa,CAAC,EAAE,EAAE,aAAa,GAAG,kBAAkB,GAAG,IAAI,CAAC;IAC5D;;;;OAIG;IACH,UAAU,CAAC,KAAK,EAAE,4BAA4B,GAAG,gBAAgB,CAAC;IAClE,UAAU,CAAC,EAAE,EAAE,aAAa,GAAG,4BAA4B,EAAE,CAAC;IAC9D,SAAS,CAAC,KAAK,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,EAAE,CAAC;IACzD;iEAC6D;IAC7D,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAAC;CACjD;AAED,wBAAgB,8BAA8B,IAAI,gBAAgB,CAyHjE"}