@workglow/test-contract 0.6.1

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 (149) hide show
  1. package/README.md +232 -0
  2. package/dist/ai-provider/assertions/capabilityHonesty.d.ts +7 -0
  3. package/dist/ai-provider/assertions/dispose.d.ts +7 -0
  4. package/dist/ai-provider/assertions/inferAdvertisesRegistered.d.ts +15 -0
  5. package/dist/ai-provider/assertions/inferServesInferred.d.ts +20 -0
  6. package/dist/ai-provider/assertions/pricingMatchesModality.d.ts +36 -0
  7. package/dist/ai-provider/assertions/registryCoverage.d.ts +13 -0
  8. package/dist/ai-provider/assertions/sessionReuse.d.ts +7 -0
  9. package/dist/ai-provider/assertions/signalHonoring.d.ts +7 -0
  10. package/dist/ai-provider/assertions/structuredGeneration.d.ts +7 -0
  11. package/dist/ai-provider/assertions/textGenerationSmoke.d.ts +7 -0
  12. package/dist/ai-provider/assertions/toolCallAccumulator.d.ts +7 -0
  13. package/dist/ai-provider/assertions/toolCallMultiTurn.d.ts +7 -0
  14. package/dist/ai-provider/assertions/usageNormalization.d.ts +61 -0
  15. package/dist/ai-provider/fixtures.d.ts +8 -0
  16. package/dist/ai-provider/runAiProviderConformance.d.ts +7 -0
  17. package/dist/ai-provider/types.d.ts +75 -0
  18. package/dist/ai-provider.d.ts +25 -0
  19. package/dist/ai-provider.js +876 -0
  20. package/dist/ai-provider.js.map +26 -0
  21. package/dist/browser-context/ConformanceMockContext.d.ts +54 -0
  22. package/dist/browser-context/assertions/ariaRoundTrip.d.ts +7 -0
  23. package/dist/browser-context/assertions/capabilityHonesty.d.ts +7 -0
  24. package/dist/browser-context/assertions/itExpectFail.d.ts +8 -0
  25. package/dist/browser-context/assertions/networkIntrospection.d.ts +7 -0
  26. package/dist/browser-context/assertions/tabsLifecycle.d.ts +7 -0
  27. package/dist/browser-context/fixtures.d.ts +8 -0
  28. package/dist/browser-context/runIBrowserContextConformance.d.ts +7 -0
  29. package/dist/browser-context/types.d.ts +48 -0
  30. package/dist/browser-context.d.ts +18 -0
  31. package/dist/browser-context.js +567 -0
  32. package/dist/browser-context.js.map +17 -0
  33. package/dist/creditExhaustedSkip.d.ts +39 -0
  34. package/dist/creditExhaustedSkip.js +163 -0
  35. package/dist/creditExhaustedSkip.js.map +10 -0
  36. package/dist/entitlement-profile/assertions/denialShape.d.ts +13 -0
  37. package/dist/entitlement-profile/assertions/dispose.d.ts +16 -0
  38. package/dist/entitlement-profile/assertions/hierarchyHonoring.d.ts +11 -0
  39. package/dist/entitlement-profile/assertions/optionalNeverDenied.d.ts +11 -0
  40. package/dist/entitlement-profile/assertions/requestEntitlementShape.d.ts +12 -0
  41. package/dist/entitlement-profile/assertions/resourceScoping.d.ts +16 -0
  42. package/dist/entitlement-profile/assertions/subscribeGrant.d.ts +11 -0
  43. package/dist/entitlement-profile/assertions/subscribeReload.d.ts +11 -0
  44. package/dist/entitlement-profile/assertions/subscribeRevocation.d.ts +12 -0
  45. package/dist/entitlement-profile/assertions/surfaceCoverage.d.ts +7 -0
  46. package/dist/entitlement-profile/assertions/unsubscribeIdempotent.d.ts +7 -0
  47. package/dist/entitlement-profile/fixtures.d.ts +21 -0
  48. package/dist/entitlement-profile/runEntitlementProfileConformance.d.ts +7 -0
  49. package/dist/entitlement-profile/types.d.ts +45 -0
  50. package/dist/entitlement-profile.d.ts +23 -0
  51. package/dist/entitlement-profile.js +436 -0
  52. package/dist/entitlement-profile.js.map +22 -0
  53. package/dist/human-connector/MockHumanConnector.d.ts +29 -0
  54. package/dist/human-connector/assertions/abort.d.ts +7 -0
  55. package/dist/human-connector/assertions/capabilityHonesty.d.ts +7 -0
  56. package/dist/human-connector/assertions/concurrentIsolation.d.ts +7 -0
  57. package/dist/human-connector/assertions/multiTurnFollowUp.d.ts +7 -0
  58. package/dist/human-connector/assertions/notifyDisplayFastResolve.d.ts +7 -0
  59. package/dist/human-connector/assertions/roundtrip.d.ts +7 -0
  60. package/dist/human-connector/fixtures.d.ts +8 -0
  61. package/dist/human-connector/runHumanConnectorConformance.d.ts +9 -0
  62. package/dist/human-connector/types.d.ts +91 -0
  63. package/dist/human-connector.d.ts +19 -0
  64. package/dist/human-connector.js +843 -0
  65. package/dist/human-connector.js.map +20 -0
  66. package/dist/itExpectFail.d.ts +15 -0
  67. package/dist/itExpectFail.js +180 -0
  68. package/dist/itExpectFail.js.map +11 -0
  69. package/dist/storage-migrations/assertions/appliesAndRecords.d.ts +7 -0
  70. package/dist/storage-migrations/assertions/concurrentRunsSerialize.d.ts +18 -0
  71. package/dist/storage-migrations/assertions/ensureBookkeepingIdempotent.d.ts +7 -0
  72. package/dist/storage-migrations/assertions/failedMigrationLeavesNoPartialSchema.d.ts +14 -0
  73. package/dist/storage-migrations/assertions/failedMigrationNotRecorded.d.ts +7 -0
  74. package/dist/storage-migrations/assertions/idempotentRun.d.ts +7 -0
  75. package/dist/storage-migrations/assertions/incrementalApplication.d.ts +7 -0
  76. package/dist/storage-migrations/runMigrationRunnerContract.d.ts +9 -0
  77. package/dist/storage-migrations/types.d.ts +78 -0
  78. package/dist/storage-migrations.d.ts +18 -0
  79. package/dist/storage-migrations.js +473 -0
  80. package/dist/storage-migrations.js.map +20 -0
  81. package/dist/tabular-migrations/assertions/addAndDropIndex.d.ts +7 -0
  82. package/dist/tabular-migrations/assertions/addColumn.d.ts +7 -0
  83. package/dist/tabular-migrations/assertions/backfill.d.ts +7 -0
  84. package/dist/tabular-migrations/assertions/dropColumn.d.ts +7 -0
  85. package/dist/tabular-migrations/assertions/failedMigrationNotRecorded.d.ts +7 -0
  86. package/dist/tabular-migrations/assertions/freshDbFastPath.d.ts +7 -0
  87. package/dist/tabular-migrations/assertions/incrementalApplication.d.ts +7 -0
  88. package/dist/tabular-migrations/assertions/renameColumn.d.ts +7 -0
  89. package/dist/tabular-migrations/runTabularMigrationContract.d.ts +8 -0
  90. package/dist/tabular-migrations/types.d.ts +28 -0
  91. package/dist/tabular-migrations.d.ts +19 -0
  92. package/dist/tabular-migrations.js +257 -0
  93. package/dist/tabular-migrations.js.map +18 -0
  94. package/dist/tabular-storage/assertions/countMatchesQuery.d.ts +7 -0
  95. package/dist/tabular-storage/assertions/guardParity.d.ts +25 -0
  96. package/dist/tabular-storage/assertions/inListCriterion.d.ts +14 -0
  97. package/dist/tabular-storage/assertions/joinBoundedLeftRead.d.ts +29 -0
  98. package/dist/tabular-storage/assertions/joinPushdown.d.ts +13 -0
  99. package/dist/tabular-storage/assertions/notInListCriterion.d.ts +15 -0
  100. package/dist/tabular-storage/assertions/strategyParity.d.ts +31 -0
  101. package/dist/tabular-storage/assertions/subscribeToChanges.d.ts +21 -0
  102. package/dist/tabular-storage/assertions/vectorColumnFormat.d.ts +7 -0
  103. package/dist/tabular-storage/assertions/withConnectionTransaction.d.ts +7 -0
  104. package/dist/tabular-storage/assertions/withTransactionRollback.d.ts +7 -0
  105. package/dist/tabular-storage/fixtures.d.ts +33 -0
  106. package/dist/tabular-storage/joinFixtures.d.ts +66 -0
  107. package/dist/tabular-storage/runTabularJoinContract.d.ts +24 -0
  108. package/dist/tabular-storage/runTabularStorageContract.d.ts +9 -0
  109. package/dist/tabular-storage/types.d.ts +102 -0
  110. package/dist/tabular-storage.d.ts +25 -0
  111. package/dist/tabular-storage.js +1477 -0
  112. package/dist/tabular-storage.js.map +27 -0
  113. package/dist/vector-storage/assertions/dimensionValidation.d.ts +17 -0
  114. package/dist/vector-storage/assertions/legacyEncoding.d.ts +16 -0
  115. package/dist/vector-storage/assertions/metadataFilter.d.ts +16 -0
  116. package/dist/vector-storage/assertions/searchOptions.d.ts +16 -0
  117. package/dist/vector-storage/assertions/shared.d.ts +23 -0
  118. package/dist/vector-storage/assertions/similarityRanking.d.ts +18 -0
  119. package/dist/vector-storage/assertions/similaritySearchEvent.d.ts +16 -0
  120. package/dist/vector-storage/assertions/vectorRoundTrip.d.ts +17 -0
  121. package/dist/vector-storage/runVectorStorageContract.d.ts +20 -0
  122. package/dist/vector-storage/types.d.ts +87 -0
  123. package/dist/vector-storage.d.ts +19 -0
  124. package/dist/vector-storage.js +412 -0
  125. package/dist/vector-storage.js.map +21 -0
  126. package/dist/web-search/assertions/capabilityAgreement.d.ts +23 -0
  127. package/dist/web-search/assertions/credentialNaming.d.ts +21 -0
  128. package/dist/web-search/assertions/dateFiltering.d.ts +22 -0
  129. package/dist/web-search/assertions/domainNormalization.d.ts +24 -0
  130. package/dist/web-search/assertions/maxResultsCeiling.d.ts +22 -0
  131. package/dist/web-search/assertions/reportedQuery.d.ts +18 -0
  132. package/dist/web-search/assertions/signalThreading.d.ts +20 -0
  133. package/dist/web-search/fixtures.d.ts +40 -0
  134. package/dist/web-search/runWebSearchProviderConformance.d.ts +24 -0
  135. package/dist/web-search/types.d.ts +79 -0
  136. package/dist/web-search.d.ts +19 -0
  137. package/dist/web-search.js +560 -0
  138. package/dist/web-search.js.map +18 -0
  139. package/dist/worker-proxy/assertions/backlogOrdering.d.ts +7 -0
  140. package/dist/worker-proxy/assertions/disposeTerminatesWorker.d.ts +8 -0
  141. package/dist/worker-proxy/assertions/errorPropagation.d.ts +7 -0
  142. package/dist/worker-proxy/assertions/providerCallHelpers.d.ts +23 -0
  143. package/dist/worker-proxy/browserOnlyStub.d.ts +7 -0
  144. package/dist/worker-proxy/runWorkerProxyBoundary.d.ts +7 -0
  145. package/dist/worker-proxy/types.d.ts +47 -0
  146. package/dist/worker-proxy.d.ts +16 -0
  147. package/dist/worker-proxy.js +389 -0
  148. package/dist/worker-proxy.js.map +17 -0
  149. package/package.json +120 -0
@@ -0,0 +1,436 @@
1
+ // src/entitlement-profile/fixtures.ts
2
+ import {
3
+ Entitlements
4
+ } from "@workglow/task-graph";
5
+ var NETWORK_HTTP_REQUIRED = {
6
+ id: Entitlements.NETWORK_HTTP,
7
+ reason: "Conformance fixture: HTTP request"
8
+ };
9
+ var FILESYSTEM_REQUIRED = {
10
+ id: Entitlements.FILESYSTEM,
11
+ reason: "Conformance fixture: filesystem access"
12
+ };
13
+ var OPTIONAL_CREDENTIAL = {
14
+ id: Entitlements.CREDENTIAL,
15
+ reason: "Conformance fixture: optional credential",
16
+ optional: true
17
+ };
18
+ var SCOPED_FILESYSTEM_TMP_OK = {
19
+ id: Entitlements.FILESYSTEM_READ,
20
+ reason: "Conformance fixture: scoped read of /tmp",
21
+ resources: ["/tmp/data.json"]
22
+ };
23
+ var SCOPED_FILESYSTEM_ETC_BAD = {
24
+ id: Entitlements.FILESYSTEM_READ,
25
+ reason: "Conformance fixture: scoped read of /etc",
26
+ resources: ["/etc/passwd"]
27
+ };
28
+ var UNCOVERED_FOO = {
29
+ id: "foo:bar",
30
+ reason: "Conformance fixture: uncovered entitlement"
31
+ };
32
+ function createControllableSignalSource() {
33
+ const listeners = new Set;
34
+ return {
35
+ subscribe(listener) {
36
+ listeners.add(listener);
37
+ let unsubbed = false;
38
+ return () => {
39
+ if (unsubbed)
40
+ return;
41
+ unsubbed = true;
42
+ listeners.delete(listener);
43
+ };
44
+ },
45
+ emit(signal) {
46
+ for (const l of listeners)
47
+ l(signal);
48
+ }
49
+ };
50
+ }
51
+ // src/entitlement-profile/runEntitlementProfileConformance.ts
52
+ import { afterAll, beforeAll, describe as describe12 } from "vitest";
53
+
54
+ // src/entitlement-profile/assertions/denialShape.ts
55
+ import { describe, expect, it } from "vitest";
56
+ function denialShapeBlock(_opts, getHandle) {
57
+ describe("Denial shape", () => {
58
+ it("denial.entitlement is reference-equal to the requested entitlement", async () => {
59
+ const profile = getHandle().profile;
60
+ const result = await profile.requestEntitlement(UNCOVERED_FOO);
61
+ expect(result.outcome).toBe("denied");
62
+ if (result.outcome === "denied") {
63
+ expect(result.denial.entitlement).toBe(UNCOVERED_FOO);
64
+ }
65
+ });
66
+ it("denial.reason matches the EntitlementDenialReason union", async () => {
67
+ const profile = getHandle().profile;
68
+ const result = await profile.requestEntitlement(UNCOVERED_FOO);
69
+ if (result.outcome === "denied") {
70
+ expect(["policy-deny", "default-deny", "user-deny"]).toContain(result.denial.reason);
71
+ }
72
+ });
73
+ it("policy-deny and user-deny carry matchedRule; default-deny does not", async () => {
74
+ const profile = getHandle().profile;
75
+ const result = await profile.requestEntitlement(UNCOVERED_FOO);
76
+ if (result.outcome === "denied") {
77
+ const d = result.denial;
78
+ if (d.reason === "default-deny") {
79
+ expect("matchedRule" in d).toBe(false);
80
+ } else {
81
+ expect(d.matchedRule).toBeDefined();
82
+ }
83
+ }
84
+ });
85
+ });
86
+ }
87
+
88
+ // src/entitlement-profile/assertions/dispose.ts
89
+ import { describe as describe2, expect as expect2, it as it2 } from "vitest";
90
+ function disposeBlock(opts, _getHandle) {
91
+ describe2("Dispose", () => {
92
+ it2("dispose is idempotent (two calls succeed)", async () => {
93
+ const local = await opts.factory();
94
+ try {
95
+ await local.profile.dispose();
96
+ await expect2(local.profile.dispose()).resolves.toBeUndefined();
97
+ } finally {
98
+ await local.dispose();
99
+ }
100
+ });
101
+ it2.skipIf(!opts.capabilities.mutableSignalSource)("after dispose, signal source no longer drives events", async () => {
102
+ const local = await opts.factory();
103
+ try {
104
+ if (!local.simulateSignal)
105
+ return;
106
+ const events = [];
107
+ local.profile.subscribe((e) => events.push(e));
108
+ await local.profile.requestEntitlement(NETWORK_HTTP_REQUIRED);
109
+ await local.profile.dispose();
110
+ local.simulateSignal({ kind: "revoke", entitlement: NETWORK_HTTP_REQUIRED });
111
+ await new Promise((r) => setTimeout(r, 0));
112
+ expect2(events).toEqual([]);
113
+ } finally {
114
+ await local.dispose();
115
+ }
116
+ });
117
+ });
118
+ }
119
+
120
+ // src/entitlement-profile/assertions/hierarchyHonoring.ts
121
+ import { describe as describe3, expect as expect3, it as it3 } from "vitest";
122
+ function hierarchyHonoringBlock(opts, getHandle) {
123
+ describe3.skipIf(!opts.capabilities.hierarchyHonoring)("Hierarchy honoring", () => {
124
+ it3("granting a parent ID covers child IDs in the namespace", async () => {
125
+ const profile = getHandle().profile;
126
+ const parentGrant = profile.surface().find((g) => !g.id.includes(":") && !g.resources);
127
+ if (!parentGrant) {
128
+ return;
129
+ }
130
+ const childId = `${parentGrant.id}:probe`;
131
+ const result = await profile.requestEntitlement({ id: childId });
132
+ expect3(result.outcome).toBe("granted");
133
+ });
134
+ });
135
+ }
136
+
137
+ // src/entitlement-profile/assertions/optionalNeverDenied.ts
138
+ import { describe as describe4, expect as expect4, it as it4 } from "vitest";
139
+ function optionalNeverDeniedBlock(_opts, getHandle) {
140
+ describe4("Optional entitlements never denied", () => {
141
+ it4("requestEntitlement returns granted for an optional entitlement", async () => {
142
+ const profile = getHandle().profile;
143
+ const result = await profile.requestEntitlement(OPTIONAL_CREDENTIAL);
144
+ expect4(result.outcome).toBe("granted");
145
+ });
146
+ it4("checkAll returns no denials for an optional entitlement even when uncovered", async () => {
147
+ const profile = getHandle().profile;
148
+ const denials = await profile.checkAll({
149
+ entitlements: [{ id: "uncovered:optional", optional: true }]
150
+ });
151
+ expect4(denials).toEqual([]);
152
+ });
153
+ });
154
+ }
155
+
156
+ // src/entitlement-profile/assertions/requestEntitlementShape.ts
157
+ import { describe as describe5, expect as expect5, it as it5 } from "vitest";
158
+ function requestEntitlementShapeBlock(_opts, getHandle) {
159
+ describe5("requestEntitlement shape parity with checkAll", () => {
160
+ it5("granted: requestEntitlement and checkAll agree", async () => {
161
+ const profile = getHandle().profile;
162
+ const isCovered = profile.surface().some((g) => g.id === NETWORK_HTTP_REQUIRED.id && !g.resources);
163
+ if (!isCovered)
164
+ return;
165
+ const single = await profile.requestEntitlement(NETWORK_HTTP_REQUIRED);
166
+ const all = await profile.checkAll({ entitlements: [NETWORK_HTTP_REQUIRED] });
167
+ expect5(single.outcome).toBe("granted");
168
+ expect5(all).toEqual([]);
169
+ });
170
+ it5("denied: requestEntitlement and checkAll agree on reason", async () => {
171
+ const profile = getHandle().profile;
172
+ const single = await profile.requestEntitlement(UNCOVERED_FOO);
173
+ const all = await profile.checkAll({ entitlements: [UNCOVERED_FOO] });
174
+ expect5(single.outcome).toBe("denied");
175
+ expect5(all).toHaveLength(1);
176
+ if (single.outcome === "denied") {
177
+ expect5(all[0].reason).toBe(single.denial.reason);
178
+ if (single.denial.reason !== "default-deny") {
179
+ expect5(all[0].matchedRule).toEqual(single.denial.matchedRule);
180
+ }
181
+ }
182
+ });
183
+ });
184
+ }
185
+
186
+ // src/entitlement-profile/assertions/resourceScoping.ts
187
+ import { describe as describe6, expect as expect6, it as it6 } from "vitest";
188
+ function resourceScopingBlock(opts, getHandle) {
189
+ describe6.skipIf(!opts.capabilities.resourceScoping)("Resource scoping", () => {
190
+ it6("scoped read succeeds when the profile broadly grants filesystem", async () => {
191
+ const profile = getHandle().profile;
192
+ const hasBroadFilesystem = profile.surface().some((g) => g.id === "filesystem" && !g.resources);
193
+ if (!hasBroadFilesystem) {
194
+ return;
195
+ }
196
+ const result = await profile.requestEntitlement(SCOPED_FILESYSTEM_TMP_OK);
197
+ expect6(result.outcome).toBe("granted");
198
+ });
199
+ it6("scoped read fails when the profile does not grant filesystem at all", async () => {
200
+ const profile = getHandle().profile;
201
+ const hasFilesystem = profile.surface().some((g) => g.id === "filesystem" || g.id === "filesystem:read");
202
+ if (hasFilesystem) {
203
+ return;
204
+ }
205
+ const result = await profile.requestEntitlement(SCOPED_FILESYSTEM_ETC_BAD);
206
+ expect6(result.outcome).toBe("denied");
207
+ });
208
+ });
209
+ }
210
+
211
+ // src/entitlement-profile/assertions/subscribeGrant.ts
212
+ import { describe as describe7, expect as expect7, it as it7 } from "vitest";
213
+ function subscribeGrantBlock(opts, getHandle) {
214
+ describe7.skipIf(!opts.capabilities.mutableSignalSource)("Subscribe grant", () => {
215
+ it7("emits granted when previously-denied entitlement becomes granted", async () => {
216
+ const handle = getHandle();
217
+ if (!handle.simulateSignal) {
218
+ throw new Error("simulateSignal must be present when mutableSignalSource is true");
219
+ }
220
+ const events = [];
221
+ const unsub = handle.profile.subscribe((e) => events.push(e));
222
+ try {
223
+ const before = await handle.profile.requestEntitlement(UNCOVERED_FOO);
224
+ if (before.outcome !== "denied")
225
+ return;
226
+ handle.simulateSignal({ kind: "grant", entitlement: UNCOVERED_FOO });
227
+ await new Promise((r) => setTimeout(r, 0));
228
+ const granted = events.find((e) => e.kind === "granted");
229
+ expect7(granted).toBeDefined();
230
+ expect7(granted?.entitlement.id).toBe(UNCOVERED_FOO.id);
231
+ } finally {
232
+ unsub();
233
+ }
234
+ });
235
+ it7("does not emit when grant signal arrives for already-granted entitlement", async () => {
236
+ const handle = getHandle();
237
+ if (!handle.simulateSignal)
238
+ return;
239
+ const events = [];
240
+ const unsub = handle.profile.subscribe((e) => events.push(e));
241
+ try {
242
+ const before = await handle.profile.requestEntitlement(NETWORK_HTTP_REQUIRED);
243
+ if (before.outcome !== "granted")
244
+ return;
245
+ handle.simulateSignal({ kind: "grant", entitlement: NETWORK_HTTP_REQUIRED });
246
+ await new Promise((r) => setTimeout(r, 0));
247
+ expect7(events).toEqual([]);
248
+ } finally {
249
+ unsub();
250
+ }
251
+ });
252
+ });
253
+ }
254
+
255
+ // src/entitlement-profile/assertions/subscribeReload.ts
256
+ import { describe as describe8, expect as expect8, it as it8 } from "vitest";
257
+ function subscribeReloadBlock(opts, getHandle) {
258
+ describe8.skipIf(!opts.capabilities.mutableSignalSource)("Subscribe reload", () => {
259
+ it8("reload fires events only for previously-queried entitlements that flipped", async () => {
260
+ const handle = getHandle();
261
+ if (!handle.simulateSignal)
262
+ return;
263
+ const events = [];
264
+ await handle.profile.requestEntitlement(NETWORK_HTTP_REQUIRED);
265
+ await handle.profile.requestEntitlement(UNCOVERED_FOO);
266
+ const unsub = handle.profile.subscribe((e) => events.push(e));
267
+ try {
268
+ handle.simulateSignal({ kind: "reload" });
269
+ await new Promise((r) => setTimeout(r, 0));
270
+ expect8(events.map((e) => e.entitlement.id)).toEqual([NETWORK_HTTP_REQUIRED.id]);
271
+ } finally {
272
+ unsub();
273
+ }
274
+ });
275
+ });
276
+ }
277
+
278
+ // src/entitlement-profile/assertions/subscribeRevocation.ts
279
+ import { describe as describe9, expect as expect9, it as it9 } from "vitest";
280
+ function subscribeRevocationBlock(opts, getHandle) {
281
+ describe9.skipIf(!opts.capabilities.mutableSignalSource)("Subscribe revocation", () => {
282
+ it9("emits revoked when previously-granted entitlement becomes denied", async () => {
283
+ const handle = getHandle();
284
+ if (!handle.simulateSignal) {
285
+ throw new Error("simulateSignal must be present when mutableSignalSource is true");
286
+ }
287
+ const events = [];
288
+ const unsub = handle.profile.subscribe((e) => events.push(e));
289
+ try {
290
+ const before = await handle.profile.requestEntitlement(NETWORK_HTTP_REQUIRED);
291
+ if (before.outcome !== "granted") {
292
+ return;
293
+ }
294
+ handle.simulateSignal({ kind: "revoke", entitlement: NETWORK_HTTP_REQUIRED });
295
+ await new Promise((r) => setTimeout(r, 0));
296
+ const revoked = events.find((e) => e.kind === "revoked");
297
+ expect9(revoked).toBeDefined();
298
+ expect9(revoked?.entitlement.id).toBe(NETWORK_HTTP_REQUIRED.id);
299
+ } finally {
300
+ unsub();
301
+ }
302
+ });
303
+ it9("does not emit when no flip occurs (revoke for never-granted entitlement)", async () => {
304
+ const handle = getHandle();
305
+ if (!handle.simulateSignal)
306
+ return;
307
+ const events = [];
308
+ const unsub = handle.profile.subscribe((e) => events.push(e));
309
+ try {
310
+ await handle.profile.requestEntitlement(UNCOVERED_FOO);
311
+ handle.simulateSignal({ kind: "revoke", entitlement: UNCOVERED_FOO });
312
+ await new Promise((r) => setTimeout(r, 0));
313
+ expect9(events).toEqual([]);
314
+ } finally {
315
+ unsub();
316
+ }
317
+ });
318
+ });
319
+ }
320
+
321
+ // src/entitlement-profile/assertions/surfaceCoverage.ts
322
+ import { describe as describe10, expect as expect10, it as it10 } from "vitest";
323
+ function surfaceCoverageBlock(opts, getHandle) {
324
+ describe10("Surface coverage", () => {
325
+ it10("surface() includes every entitlement listed in expected.surfaceIncludes", async () => {
326
+ const profile = getHandle().profile;
327
+ const surface = profile.surface().map((g) => g.id);
328
+ for (const id of opts.expected.surfaceIncludes) {
329
+ expect10(surface).toContain(id);
330
+ }
331
+ });
332
+ it10("surface() excludes every entitlement listed in expected.surfaceExcludes", async () => {
333
+ const profile = getHandle().profile;
334
+ const surface = profile.surface().map((g) => g.id);
335
+ for (const id of opts.expected.surfaceExcludes) {
336
+ expect10(surface).not.toContain(id);
337
+ }
338
+ });
339
+ it10("requestEntitlement returns granted for an entitlement covered by surface", async () => {
340
+ const profile = getHandle().profile;
341
+ const firstGrant = profile.surface()[0];
342
+ if (!firstGrant) {
343
+ return;
344
+ }
345
+ const result = await profile.requestEntitlement({ id: firstGrant.id });
346
+ expect10(result.outcome).toBe("granted");
347
+ });
348
+ it10("requestEntitlement returns denied with default-deny reason for an uncovered entitlement", async () => {
349
+ const profile = getHandle().profile;
350
+ const result = await profile.requestEntitlement(UNCOVERED_FOO);
351
+ expect10(result.outcome).toBe("denied");
352
+ if (result.outcome === "denied") {
353
+ expect10(result.denial.reason).toBe("default-deny");
354
+ expect10(result.denial.entitlement).toBe(UNCOVERED_FOO);
355
+ }
356
+ });
357
+ });
358
+ }
359
+
360
+ // src/entitlement-profile/assertions/unsubscribeIdempotent.ts
361
+ import { describe as describe11, expect as expect11, it as it11 } from "vitest";
362
+ function unsubscribeIdempotentBlock(opts, getHandle) {
363
+ describe11.skipIf(!opts.capabilities.mutableSignalSource)("Unsubscribe idempotent", () => {
364
+ it11("calling unsubscribe twice does not throw", () => {
365
+ const profile = getHandle().profile;
366
+ const unsub = profile.subscribe(() => {});
367
+ unsub();
368
+ expect11(() => unsub()).not.toThrow();
369
+ });
370
+ it11("after unsubscribe, no further events are delivered", async () => {
371
+ const handle = getHandle();
372
+ if (!handle.simulateSignal)
373
+ return;
374
+ const events = [];
375
+ const unsub = handle.profile.subscribe((e) => events.push(e));
376
+ await handle.profile.requestEntitlement(NETWORK_HTTP_REQUIRED);
377
+ unsub();
378
+ handle.simulateSignal({ kind: "revoke", entitlement: NETWORK_HTTP_REQUIRED });
379
+ await new Promise((r) => setTimeout(r, 0));
380
+ expect11(events).toEqual([]);
381
+ });
382
+ });
383
+ }
384
+
385
+ // src/entitlement-profile/runEntitlementProfileConformance.ts
386
+ function runEntitlementProfileConformance(opts) {
387
+ describe12.skipIf(opts.skip)(`EntitlementProfile conformance: ${opts.name}`, () => {
388
+ let handle;
389
+ const getHandle = () => {
390
+ if (!handle)
391
+ throw new Error("conformance handle not initialized");
392
+ return handle;
393
+ };
394
+ beforeAll(async () => {
395
+ handle = await opts.factory();
396
+ }, opts.timeout);
397
+ afterAll(async () => {
398
+ if (handle)
399
+ await handle.dispose();
400
+ });
401
+ surfaceCoverageBlock(opts, getHandle);
402
+ hierarchyHonoringBlock(opts, getHandle);
403
+ resourceScopingBlock(opts, getHandle);
404
+ optionalNeverDeniedBlock(opts, getHandle);
405
+ denialShapeBlock(opts, getHandle);
406
+ requestEntitlementShapeBlock(opts, getHandle);
407
+ subscribeRevocationBlock(opts, getHandle);
408
+ subscribeGrantBlock(opts, getHandle);
409
+ subscribeReloadBlock(opts, getHandle);
410
+ unsubscribeIdempotentBlock(opts, getHandle);
411
+ disposeBlock(opts, getHandle);
412
+ });
413
+ }
414
+ export {
415
+ FILESYSTEM_REQUIRED,
416
+ NETWORK_HTTP_REQUIRED,
417
+ OPTIONAL_CREDENTIAL,
418
+ SCOPED_FILESYSTEM_ETC_BAD,
419
+ SCOPED_FILESYSTEM_TMP_OK,
420
+ UNCOVERED_FOO,
421
+ createControllableSignalSource,
422
+ denialShapeBlock,
423
+ disposeBlock,
424
+ hierarchyHonoringBlock,
425
+ optionalNeverDeniedBlock,
426
+ requestEntitlementShapeBlock,
427
+ resourceScopingBlock,
428
+ runEntitlementProfileConformance,
429
+ subscribeGrantBlock,
430
+ subscribeReloadBlock,
431
+ subscribeRevocationBlock,
432
+ surfaceCoverageBlock,
433
+ unsubscribeIdempotentBlock
434
+ };
435
+
436
+ //# debugId=A4B432BFC9E613D164756E2164756E21
@@ -0,0 +1,22 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/entitlement-profile/fixtures.ts", "../src/entitlement-profile/runEntitlementProfileConformance.ts", "../src/entitlement-profile/assertions/denialShape.ts", "../src/entitlement-profile/assertions/dispose.ts", "../src/entitlement-profile/assertions/hierarchyHonoring.ts", "../src/entitlement-profile/assertions/optionalNeverDenied.ts", "../src/entitlement-profile/assertions/requestEntitlementShape.ts", "../src/entitlement-profile/assertions/resourceScoping.ts", "../src/entitlement-profile/assertions/subscribeGrant.ts", "../src/entitlement-profile/assertions/subscribeReload.ts", "../src/entitlement-profile/assertions/subscribeRevocation.ts", "../src/entitlement-profile/assertions/surfaceCoverage.ts", "../src/entitlement-profile/assertions/unsubscribeIdempotent.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n Entitlements,\n type EntitlementSignal,\n type IEntitlementSignalSource,\n type TaskEntitlement,\n} from \"@workglow/task-graph\";\n\nexport const NETWORK_HTTP_REQUIRED: TaskEntitlement = {\n id: Entitlements.NETWORK_HTTP,\n reason: \"Conformance fixture: HTTP request\",\n};\n\nexport const FILESYSTEM_REQUIRED: TaskEntitlement = {\n id: Entitlements.FILESYSTEM,\n reason: \"Conformance fixture: filesystem access\",\n};\n\nexport const OPTIONAL_CREDENTIAL: TaskEntitlement = {\n id: Entitlements.CREDENTIAL,\n reason: \"Conformance fixture: optional credential\",\n optional: true,\n};\n\nexport const SCOPED_FILESYSTEM_TMP_OK: TaskEntitlement = {\n id: Entitlements.FILESYSTEM_READ,\n reason: \"Conformance fixture: scoped read of /tmp\",\n resources: [\"/tmp/data.json\"],\n};\n\nexport const SCOPED_FILESYSTEM_ETC_BAD: TaskEntitlement = {\n id: Entitlements.FILESYSTEM_READ,\n reason: \"Conformance fixture: scoped read of /etc\",\n resources: [\"/etc/passwd\"],\n};\n\n/** Guaranteed not to appear in any built-in profile surface. */\nexport const UNCOVERED_FOO: TaskEntitlement = {\n id: \"foo:bar\",\n reason: \"Conformance fixture: uncovered entitlement\",\n};\n\n/**\n * In-memory signal source for the Custom_Profile shim. The returned source\n * exposes `emit` so the shim's `simulateSignal` can drive listeners.\n */\nexport interface ControllableSignalSource extends IEntitlementSignalSource {\n emit(signal: EntitlementSignal): void;\n}\n\nexport function createControllableSignalSource(): ControllableSignalSource {\n const listeners = new Set<(s: EntitlementSignal) => void>();\n return {\n subscribe(listener) {\n listeners.add(listener);\n let unsubbed = false;\n return () => {\n if (unsubbed) return;\n unsubbed = true;\n listeners.delete(listener);\n };\n },\n emit(signal) {\n for (const l of listeners) l(signal);\n },\n };\n}\n",
6
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { afterAll, beforeAll, describe } from \"vitest\";\n\nimport { denialShapeBlock } from \"./assertions/denialShape\";\nimport { disposeBlock } from \"./assertions/dispose\";\nimport { hierarchyHonoringBlock } from \"./assertions/hierarchyHonoring\";\nimport { optionalNeverDeniedBlock } from \"./assertions/optionalNeverDenied\";\nimport { requestEntitlementShapeBlock } from \"./assertions/requestEntitlementShape\";\nimport { resourceScopingBlock } from \"./assertions/resourceScoping\";\nimport { subscribeGrantBlock } from \"./assertions/subscribeGrant\";\nimport { subscribeReloadBlock } from \"./assertions/subscribeReload\";\nimport { subscribeRevocationBlock } from \"./assertions/subscribeRevocation\";\nimport { surfaceCoverageBlock } from \"./assertions/surfaceCoverage\";\nimport { unsubscribeIdempotentBlock } from \"./assertions/unsubscribeIdempotent\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"./types\";\n\nexport function runEntitlementProfileConformance(opts: EntitlementProfileConformanceOpts): void {\n describe.skipIf(opts.skip)(`EntitlementProfile conformance: ${opts.name}`, () => {\n let handle: EntitlementProfileConformanceHandle | undefined;\n const getHandle = (): EntitlementProfileConformanceHandle => {\n if (!handle) throw new Error(\"conformance handle not initialized\");\n return handle;\n };\n\n beforeAll(async () => {\n handle = await opts.factory();\n }, opts.timeout);\n\n afterAll(async () => {\n if (handle) await handle.dispose();\n });\n\n // Assertion blocks are imported and invoked here as they are added.\n surfaceCoverageBlock(opts, getHandle);\n hierarchyHonoringBlock(opts, getHandle);\n resourceScopingBlock(opts, getHandle);\n optionalNeverDeniedBlock(opts, getHandle);\n denialShapeBlock(opts, getHandle);\n requestEntitlementShapeBlock(opts, getHandle);\n subscribeRevocationBlock(opts, getHandle);\n subscribeGrantBlock(opts, getHandle);\n subscribeReloadBlock(opts, getHandle);\n unsubscribeIdempotentBlock(opts, getHandle);\n disposeBlock(opts, getHandle);\n });\n}\n",
7
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport { UNCOVERED_FOO } from \"../fixtures\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\n/**\n * The denial returned by requestEntitlement for an uncovered entitlement\n * must satisfy the EntitlementDenial discriminated union: a `reason` of\n * \"policy-deny\" / \"user-deny\" requires `matchedRule`; \"default-deny\"\n * forbids it.\n */\nexport function denialShapeBlock(\n _opts: EntitlementProfileConformanceOpts,\n getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe(\"Denial shape\", () => {\n it(\"denial.entitlement is reference-equal to the requested entitlement\", async () => {\n const profile = getHandle().profile;\n const result = await profile.requestEntitlement(UNCOVERED_FOO);\n expect(result.outcome).toBe(\"denied\");\n if (result.outcome === \"denied\") {\n expect(result.denial.entitlement).toBe(UNCOVERED_FOO);\n }\n });\n\n it(\"denial.reason matches the EntitlementDenialReason union\", async () => {\n const profile = getHandle().profile;\n const result = await profile.requestEntitlement(UNCOVERED_FOO);\n if (result.outcome === \"denied\") {\n expect([\"policy-deny\", \"default-deny\", \"user-deny\"]).toContain(result.denial.reason);\n }\n });\n\n it(\"policy-deny and user-deny carry matchedRule; default-deny does not\", async () => {\n const profile = getHandle().profile;\n const result = await profile.requestEntitlement(UNCOVERED_FOO);\n if (result.outcome === \"denied\") {\n const d = result.denial;\n if (d.reason === \"default-deny\") {\n // Discriminated union: default-deny variant has no matchedRule property.\n expect(\"matchedRule\" in d).toBe(false);\n } else {\n // policy-deny / user-deny carry matchedRule.\n expect(d.matchedRule).toBeDefined();\n }\n }\n });\n });\n}\n",
8
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport type { EntitlementChangeEvent } from \"@workglow/task-graph\";\nimport { NETWORK_HTTP_REQUIRED } from \"../fixtures\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\n/**\n * dispose() is idempotent. After dispose, a simulateSignal does not deliver\n * events to listeners that subscribed before dispose.\n *\n * NOTE: This block uses an isolated profile via the factory, not the shared\n * conformance handle, because disposing the shared handle would break later\n * blocks. The factory is invoked again here; afterAll on the shared handle\n * still runs against its own profile.\n */\nexport function disposeBlock(\n opts: EntitlementProfileConformanceOpts,\n _getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe(\"Dispose\", () => {\n it(\"dispose is idempotent (two calls succeed)\", async () => {\n const local = await opts.factory();\n try {\n await local.profile.dispose();\n await expect(local.profile.dispose()).resolves.toBeUndefined();\n } finally {\n // local.dispose() is itself idempotent and will exercise dispose() again.\n await local.dispose();\n }\n });\n\n it.skipIf(!opts.capabilities.mutableSignalSource)(\n \"after dispose, signal source no longer drives events\",\n async () => {\n const local = await opts.factory();\n try {\n if (!local.simulateSignal) return;\n const events: EntitlementChangeEvent[] = [];\n local.profile.subscribe((e) => events.push(e));\n await local.profile.requestEntitlement(NETWORK_HTTP_REQUIRED);\n await local.profile.dispose();\n local.simulateSignal({ kind: \"revoke\", entitlement: NETWORK_HTTP_REQUIRED });\n await new Promise((r) => setTimeout(r, 0));\n expect(events).toEqual([]);\n } finally {\n await local.dispose();\n }\n }\n );\n });\n}\n",
9
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\n/**\n * If the profile surface includes a parent entitlement (e.g. \"network\"),\n * requesting a child entitlement (e.g. \"network:http\") must be granted.\n */\nexport function hierarchyHonoringBlock(\n opts: EntitlementProfileConformanceOpts,\n getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe.skipIf(!opts.capabilities.hierarchyHonoring)(\"Hierarchy honoring\", () => {\n it(\"granting a parent ID covers child IDs in the namespace\", async () => {\n const profile = getHandle().profile;\n // Find a grant whose ID has no colon (a parent), then probe a child.\n const parentGrant = profile.surface().find((g) => !g.id.includes(\":\") && !g.resources);\n if (!parentGrant) {\n // No broad parent grant in this profile; assertion vacuous.\n return;\n }\n const childId = `${parentGrant.id}:probe`;\n const result = await profile.requestEntitlement({ id: childId });\n expect(result.outcome).toBe(\"granted\");\n });\n });\n}\n",
10
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport { OPTIONAL_CREDENTIAL } from \"../fixtures\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\n/**\n * Optional entitlements must never be reported as denied — neither by\n * `requestEntitlement` nor by `checkAll`.\n */\nexport function optionalNeverDeniedBlock(\n _opts: EntitlementProfileConformanceOpts,\n getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe(\"Optional entitlements never denied\", () => {\n it(\"requestEntitlement returns granted for an optional entitlement\", async () => {\n const profile = getHandle().profile;\n const result = await profile.requestEntitlement(OPTIONAL_CREDENTIAL);\n expect(result.outcome).toBe(\"granted\");\n });\n\n it(\"checkAll returns no denials for an optional entitlement even when uncovered\", async () => {\n const profile = getHandle().profile;\n const denials = await profile.checkAll({\n entitlements: [{ id: \"uncovered:optional\", optional: true }],\n });\n expect(denials).toEqual([]);\n });\n });\n}\n",
11
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport { NETWORK_HTTP_REQUIRED, UNCOVERED_FOO } from \"../fixtures\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\n/**\n * For the same input, `requestEntitlement` and `checkAll([input])` agree:\n * - granted ↔ empty denial array\n * - denied ↔ single-element denial array with matching reason\n */\nexport function requestEntitlementShapeBlock(\n _opts: EntitlementProfileConformanceOpts,\n getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe(\"requestEntitlement shape parity with checkAll\", () => {\n it(\"granted: requestEntitlement and checkAll agree\", async () => {\n const profile = getHandle().profile;\n const isCovered = profile\n .surface()\n .some((g) => g.id === NETWORK_HTTP_REQUIRED.id && !g.resources);\n if (!isCovered) return; // assertion vacuous if profile doesn't grant network:http\n const single = await profile.requestEntitlement(NETWORK_HTTP_REQUIRED);\n const all = await profile.checkAll({ entitlements: [NETWORK_HTTP_REQUIRED] });\n expect(single.outcome).toBe(\"granted\");\n expect(all).toEqual([]);\n });\n\n it(\"denied: requestEntitlement and checkAll agree on reason\", async () => {\n const profile = getHandle().profile;\n const single = await profile.requestEntitlement(UNCOVERED_FOO);\n const all = await profile.checkAll({ entitlements: [UNCOVERED_FOO] });\n expect(single.outcome).toBe(\"denied\");\n expect(all).toHaveLength(1);\n if (single.outcome === \"denied\") {\n expect(all[0]!.reason).toBe(single.denial.reason);\n // Spec parity: when reason is policy-deny / user-deny, both calls must\n // return the same matchedRule. default-deny carries no matchedRule.\n if (single.denial.reason !== \"default-deny\") {\n expect((all[0]! as { matchedRule?: unknown }).matchedRule).toEqual(\n (single.denial as { matchedRule?: unknown }).matchedRule\n );\n }\n }\n });\n });\n}\n",
12
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport { SCOPED_FILESYSTEM_ETC_BAD, SCOPED_FILESYSTEM_TMP_OK } from \"../fixtures\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\n/**\n * For a profile that supports resource scoping, build a temporary scoped\n * grant by augmenting the profile is out of scope here — instead we\n * exercise the policy with a known-scoped fixture only when the profile\n * already grants filesystem broadly. When `filesystem` is broadly granted,\n * a scoped read of any resource succeeds. This block additionally verifies\n * that profiles which DO NOT grant filesystem deny a scoped read of\n * `/etc/passwd`.\n */\nexport function resourceScopingBlock(\n opts: EntitlementProfileConformanceOpts,\n getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe.skipIf(!opts.capabilities.resourceScoping)(\"Resource scoping\", () => {\n it(\"scoped read succeeds when the profile broadly grants filesystem\", async () => {\n const profile = getHandle().profile;\n const hasBroadFilesystem = profile\n .surface()\n .some((g) => g.id === \"filesystem\" && !g.resources);\n if (!hasBroadFilesystem) {\n // Profile does not broadly grant filesystem; this assertion is vacuous.\n return;\n }\n const result = await profile.requestEntitlement(SCOPED_FILESYSTEM_TMP_OK);\n expect(result.outcome).toBe(\"granted\");\n });\n\n it(\"scoped read fails when the profile does not grant filesystem at all\", async () => {\n const profile = getHandle().profile;\n const hasFilesystem = profile\n .surface()\n .some((g) => g.id === \"filesystem\" || g.id === \"filesystem:read\");\n if (hasFilesystem) {\n return; // not the negative case\n }\n const result = await profile.requestEntitlement(SCOPED_FILESYSTEM_ETC_BAD);\n expect(result.outcome).toBe(\"denied\");\n });\n });\n}\n",
13
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport type { EntitlementChangeEvent } from \"@workglow/task-graph\";\nimport { NETWORK_HTTP_REQUIRED, UNCOVERED_FOO } from \"../fixtures\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\n/**\n * Verify that the profile emits a \"granted\" change event when the signal\n * source emits a grant for a previously-denied entitlement.\n */\nexport function subscribeGrantBlock(\n opts: EntitlementProfileConformanceOpts,\n getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe.skipIf(!opts.capabilities.mutableSignalSource)(\"Subscribe grant\", () => {\n it(\"emits granted when previously-denied entitlement becomes granted\", async () => {\n const handle = getHandle();\n if (!handle.simulateSignal) {\n throw new Error(\"simulateSignal must be present when mutableSignalSource is true\");\n }\n const events: EntitlementChangeEvent[] = [];\n const unsub = handle.profile.subscribe((e) => events.push(e));\n try {\n // Seed: query an entitlement that is currently denied. The Custom shim's\n // simulateSignal stages the policy flip before emitting the signal.\n const before = await handle.profile.requestEntitlement(UNCOVERED_FOO);\n if (before.outcome !== \"denied\") return; // not the case for this profile\n handle.simulateSignal({ kind: \"grant\", entitlement: UNCOVERED_FOO });\n await new Promise((r) => setTimeout(r, 0));\n const granted = events.find((e) => e.kind === \"granted\");\n expect(granted).toBeDefined();\n expect(granted?.entitlement.id).toBe(UNCOVERED_FOO.id);\n } finally {\n unsub();\n }\n });\n\n it(\"does not emit when grant signal arrives for already-granted entitlement\", async () => {\n const handle = getHandle();\n if (!handle.simulateSignal) return;\n const events: EntitlementChangeEvent[] = [];\n const unsub = handle.profile.subscribe((e) => events.push(e));\n try {\n // Seed: query an entitlement currently granted by the policy.\n const before = await handle.profile.requestEntitlement(NETWORK_HTTP_REQUIRED);\n if (before.outcome !== \"granted\") return; // not the case for this profile\n handle.simulateSignal({ kind: \"grant\", entitlement: NETWORK_HTTP_REQUIRED });\n await new Promise((r) => setTimeout(r, 0));\n expect(events).toEqual([]);\n } finally {\n unsub();\n }\n });\n });\n}\n",
14
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport type { EntitlementChangeEvent } from \"@workglow/task-graph\";\nimport { NETWORK_HTTP_REQUIRED, UNCOVERED_FOO } from \"../fixtures\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\n/**\n * After querying a set of entitlements then signalling reload, change events\n * fire only for entitlements whose verdict actually flipped.\n */\nexport function subscribeReloadBlock(\n opts: EntitlementProfileConformanceOpts,\n getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe.skipIf(!opts.capabilities.mutableSignalSource)(\"Subscribe reload\", () => {\n it(\"reload fires events only for previously-queried entitlements that flipped\", async () => {\n const handle = getHandle();\n if (!handle.simulateSignal) return;\n const events: EntitlementChangeEvent[] = [];\n // Pre-seed by querying two entitlements before subscribing.\n await handle.profile.requestEntitlement(NETWORK_HTTP_REQUIRED);\n await handle.profile.requestEntitlement(UNCOVERED_FOO);\n const unsub = handle.profile.subscribe((e) => events.push(e));\n try {\n // The shim's simulateSignal stages a policy mutation that flips\n // exactly one of the two seeded entitlements before emitting reload.\n handle.simulateSignal({ kind: \"reload\" });\n await new Promise((r) => setTimeout(r, 0));\n // The shim's simulateSignal stages a policy mutation that flips exactly\n // one of the two seeded entitlements (NETWORK_HTTP) before emitting reload.\n // A conforming profile emits change events ONLY for entitlements that\n // actually flipped — never for entitlements whose verdict is unchanged.\n expect(events.map((e) => e.entitlement.id)).toEqual([NETWORK_HTTP_REQUIRED.id]);\n } finally {\n unsub();\n }\n });\n });\n}\n",
15
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport type { EntitlementChangeEvent } from \"@workglow/task-graph\";\nimport { NETWORK_HTTP_REQUIRED, UNCOVERED_FOO } from \"../fixtures\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\n/**\n * Verify that the profile re-evaluates and emits a \"revoked\" change event\n * when the signal source emits a revoke for a previously-granted\n * entitlement, and emits nothing when no flip occurred.\n */\nexport function subscribeRevocationBlock(\n opts: EntitlementProfileConformanceOpts,\n getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe.skipIf(!opts.capabilities.mutableSignalSource)(\"Subscribe revocation\", () => {\n it(\"emits revoked when previously-granted entitlement becomes denied\", async () => {\n const handle = getHandle();\n if (!handle.simulateSignal) {\n throw new Error(\"simulateSignal must be present when mutableSignalSource is true\");\n }\n const events: EntitlementChangeEvent[] = [];\n const unsub = handle.profile.subscribe((e) => events.push(e));\n try {\n // Seed: query and confirm currently granted.\n const before = await handle.profile.requestEntitlement(NETWORK_HTTP_REQUIRED);\n if (before.outcome !== \"granted\") {\n // Profile does not grant this; this assertion is vacuous for it.\n return;\n }\n // The Custom_Profile shim's underlying policy mutates so that revoke\n // signals reflect a real flip; the simulateSignal hook on the shim\n // is responsible for staging that policy change before emitting.\n handle.simulateSignal({ kind: \"revoke\", entitlement: NETWORK_HTTP_REQUIRED });\n await new Promise((r) => setTimeout(r, 0));\n const revoked = events.find((e) => e.kind === \"revoked\");\n expect(revoked).toBeDefined();\n expect(revoked?.entitlement.id).toBe(NETWORK_HTTP_REQUIRED.id);\n } finally {\n unsub();\n }\n });\n\n it(\"does not emit when no flip occurs (revoke for never-granted entitlement)\", async () => {\n const handle = getHandle();\n if (!handle.simulateSignal) return;\n const events: EntitlementChangeEvent[] = [];\n const unsub = handle.profile.subscribe((e) => events.push(e));\n try {\n // Query an uncovered entitlement: it's already denied.\n await handle.profile.requestEntitlement(UNCOVERED_FOO);\n handle.simulateSignal({ kind: \"revoke\", entitlement: UNCOVERED_FOO });\n await new Promise((r) => setTimeout(r, 0));\n expect(events).toEqual([]);\n } finally {\n unsub();\n }\n });\n });\n}\n",
16
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport { UNCOVERED_FOO } from \"../fixtures\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\nexport function surfaceCoverageBlock(\n opts: EntitlementProfileConformanceOpts,\n getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe(\"Surface coverage\", () => {\n it(\"surface() includes every entitlement listed in expected.surfaceIncludes\", async () => {\n const profile = getHandle().profile;\n const surface = profile.surface().map((g) => g.id);\n for (const id of opts.expected.surfaceIncludes) {\n expect(surface).toContain(id);\n }\n });\n\n it(\"surface() excludes every entitlement listed in expected.surfaceExcludes\", async () => {\n const profile = getHandle().profile;\n const surface = profile.surface().map((g) => g.id);\n for (const id of opts.expected.surfaceExcludes) {\n expect(surface).not.toContain(id);\n }\n });\n\n it(\"requestEntitlement returns granted for an entitlement covered by surface\", async () => {\n const profile = getHandle().profile;\n const firstGrant = profile.surface()[0];\n if (!firstGrant) {\n // empty surface — assertion vacuous; opts.expected.surfaceIncludes\n // would have been empty too.\n return;\n }\n const result = await profile.requestEntitlement({ id: firstGrant.id });\n expect(result.outcome).toBe(\"granted\");\n });\n\n it(\"requestEntitlement returns denied with default-deny reason for an uncovered entitlement\", async () => {\n const profile = getHandle().profile;\n const result = await profile.requestEntitlement(UNCOVERED_FOO);\n expect(result.outcome).toBe(\"denied\");\n if (result.outcome === \"denied\") {\n expect(result.denial.reason).toBe(\"default-deny\");\n expect(result.denial.entitlement).toBe(UNCOVERED_FOO);\n }\n });\n });\n}\n",
17
+ "/**\n * @license\n * Copyright 2026 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { describe, expect, it } from \"vitest\";\n\nimport type { EntitlementChangeEvent } from \"@workglow/task-graph\";\nimport { NETWORK_HTTP_REQUIRED } from \"../fixtures\";\nimport type {\n EntitlementProfileConformanceHandle,\n EntitlementProfileConformanceOpts,\n} from \"../types\";\n\nexport function unsubscribeIdempotentBlock(\n opts: EntitlementProfileConformanceOpts,\n getHandle: () => EntitlementProfileConformanceHandle\n): void {\n describe.skipIf(!opts.capabilities.mutableSignalSource)(\"Unsubscribe idempotent\", () => {\n it(\"calling unsubscribe twice does not throw\", () => {\n const profile = getHandle().profile;\n const unsub = profile.subscribe(() => {});\n unsub();\n expect(() => unsub()).not.toThrow();\n });\n\n it(\"after unsubscribe, no further events are delivered\", async () => {\n const handle = getHandle();\n if (!handle.simulateSignal) return;\n const events: EntitlementChangeEvent[] = [];\n const unsub = handle.profile.subscribe((e) => events.push(e));\n // Seed and unsub before signalling.\n await handle.profile.requestEntitlement(NETWORK_HTTP_REQUIRED);\n unsub();\n handle.simulateSignal({ kind: \"revoke\", entitlement: NETWORK_HTTP_REQUIRED });\n await new Promise((r) => setTimeout(r, 0));\n expect(events).toEqual([]);\n });\n });\n}\n"
18
+ ],
19
+ "mappings": "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",
20
+ "debugId": "A4B432BFC9E613D164756E2164756E21",
21
+ "names": []
22
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { HumanResponseAction, IHumanConnector, IHumanRequest, IHumanResponse } from "@workglow/util";
7
+ import type { MockResponseScript } from "./types";
8
+ export interface MockHumanConnectorOpts {
9
+ /** Default action when no script entry is queued. Defaults to "accept". */
10
+ readonly defaultAction?: HumanResponseAction;
11
+ /** Whether `followUp` is implemented. Defaults to true. */
12
+ readonly supportsFollowUp?: boolean;
13
+ }
14
+ export declare class MockHumanConnector implements IHumanConnector {
15
+ private readonly defaultAction;
16
+ private readonly _script;
17
+ readonly followUp?: (request: IHumanRequest, previous: IHumanResponse, signal: AbortSignal) => Promise<IHumanResponse>;
18
+ constructor(opts?: MockHumanConnectorOpts);
19
+ get script(): MockResponseScript;
20
+ send(request: IHumanRequest, signal: AbortSignal): Promise<IHumanResponse>;
21
+ /**
22
+ * Content belongs to an accepted elicit and nothing else, whatever a script
23
+ * put beside the action — the reference connector holds the same contract
24
+ * every adapter is measured against. A confirm answers with the decision
25
+ * alone, and a refused elicit answers with no data, since `HumanInputTask`
26
+ * spreads `content` onto its output ports either way.
27
+ */
28
+ private shape;
29
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { ConformanceFixture, HumanConnectorConformanceHandle, HumanConnectorConformanceOpts } from "../types";
7
+ export declare function abortBlock(opts: HumanConnectorConformanceOpts, fixture: ConformanceFixture, getHandle: () => HumanConnectorConformanceHandle): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { ConformanceFixture, HumanConnectorConformanceHandle, HumanConnectorConformanceOpts } from "../types";
7
+ export declare function capabilityHonestyBlock(opts: HumanConnectorConformanceOpts, fixture: ConformanceFixture, getHandle: () => HumanConnectorConformanceHandle): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { ConformanceFixture, HumanConnectorConformanceHandle, HumanConnectorConformanceOpts } from "../types";
7
+ export declare function concurrentIsolationBlock(opts: HumanConnectorConformanceOpts, fixture: ConformanceFixture, getHandle: () => HumanConnectorConformanceHandle): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { ConformanceFixture, HumanConnectorConformanceHandle, HumanConnectorConformanceOpts } from "../types";
7
+ export declare function multiTurnFollowUpBlock(opts: HumanConnectorConformanceOpts, fixture: ConformanceFixture, getHandle: () => HumanConnectorConformanceHandle): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { ConformanceFixture, HumanConnectorConformanceHandle, HumanConnectorConformanceOpts } from "../types";
7
+ export declare function notifyDisplayFastResolveBlock(opts: HumanConnectorConformanceOpts, fixture: ConformanceFixture, getHandle: () => HumanConnectorConformanceHandle): void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { ConformanceFixture, HumanConnectorConformanceHandle, HumanConnectorConformanceOpts } from "../types";
7
+ export declare function roundtripBlock(opts: HumanConnectorConformanceOpts, fixture: ConformanceFixture, getHandle: () => HumanConnectorConformanceHandle): void;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { ConformanceFixture } from "./types";
7
+ export declare const DEFAULT_HUMAN_CONFORMANCE_FIXTURE: ConformanceFixture;
8
+ export declare function resolveHumanConformanceFixture(override: Partial<ConformanceFixture> | undefined): ConformanceFixture;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Steven Roussey <sroussey@gmail.com>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import type { HumanConnectorConformanceOpts } from "./types";
7
+ export { MockHumanConnector } from "./MockHumanConnector";
8
+ export type { HumanConnectorConformanceOpts } from "./types";
9
+ export declare function runHumanConnectorConformance(opts: HumanConnectorConformanceOpts): void;