@agentplat/mesh-conformance 0.3.0-beta.1 → 0.3.0-beta.4

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../src/planning.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,656 @@
1
+ import { canonicalizePlanningJsonV1, deepFreezePlanning, sha256HexPlanningV1, } from "@agentplat/collective-planning";
2
+ import { awaitConformanceOperation, MeshConformanceCleanupError, runConformanceCleanup, } from "./runner.js";
3
+ /** Version of the portable planning conformance contract. */
4
+ export const PLANNING_CONFORMANCE_VERSION_V1 = 1;
5
+ /**
6
+ * Closed declarations. A declaration states which public case groups were
7
+ * executed; it never grants authority to a planner or its runner.
8
+ */
9
+ export const PLANNING_CONFORMANCE_CAPABILITIES_V1 = Object.freeze([
10
+ "planning.portable",
11
+ "planning.reducer",
12
+ "planning.snapshot",
13
+ "planning.replanning",
14
+ "planning.fencing",
15
+ "planning.mesh-projection",
16
+ "planning.evaluation",
17
+ "planning.durable",
18
+ ]);
19
+ export const PLANNING_REQUIRED_CONFORMANCE_CAPABILITIES_V1 = Object.freeze([
20
+ "planning.portable",
21
+ "planning.reducer",
22
+ ]);
23
+ /** The complete public suite. Case identifiers and capability membership are closed. */
24
+ export const PLANNING_CONFORMANCE_CASES_V1 = Object.freeze([
25
+ define("planning.intent.closed-record", "planning.portable", "rejected", "unknown_field"),
26
+ define("planning.proposal.scope-widening", "planning.portable", "rejected", "scope_widening"),
27
+ define("planning.reducer.dependency-cycle", "planning.reducer", "rejected", "dependency_cycle"),
28
+ define("planning.reducer.exact-replay", "planning.reducer", "accepted", null),
29
+ define("planning.snapshot.cross-scope", "planning.snapshot", "rejected", "snapshot_scope_mismatch"),
30
+ define("planning.snapshot.rollback", "planning.snapshot", "rejected", "snapshot_rollback"),
31
+ define("planning.replanning.causal-predecessor", "planning.replanning", "rejected", "causal_predecessor_missing"),
32
+ define("planning.fencing.stale-result", "planning.fencing", "rejected", "stale_fence"),
33
+ define("planning.mesh-projection.assignment-bound", "planning.mesh-projection", "rejected", "assignment_binding_mismatch"),
34
+ define("planning.evaluation.public-artifact", "planning.evaluation", "rejected", "private_evidence_disclosed"),
35
+ define("planning.durable.restart-high-water", "planning.durable", "accepted", null),
36
+ ]);
37
+ /** Stable commitment to the public case definitions. */
38
+ export const PLANNING_CONFORMANCE_SUITE_DIGEST_V1 = commitment({
39
+ schemaVersion: 1,
40
+ cases: PLANNING_CONFORMANCE_CASES_V1.map((entry) => ({ ...entry })),
41
+ });
42
+ /**
43
+ * Runs every case against a fresh caller-supplied adapter. No adapter is
44
+ * allowed to share implicit state between cases, and undeclared groups are
45
+ * recorded instead of silently omitted.
46
+ */
47
+ export async function runPlanningConformanceV1(options) {
48
+ const normalizedOptions = normalizePlanningOptions(options);
49
+ const context = planningRunnerContext(normalizedOptions);
50
+ const capabilities = normalizeCapabilities(normalizedOptions.declaredCapabilities);
51
+ for (const capability of PLANNING_REQUIRED_CONFORMANCE_CAPABILITIES_V1) {
52
+ if (!capabilities.has(capability)) {
53
+ throw new TypeError("Required planning conformance capability is missing");
54
+ }
55
+ }
56
+ const fixtures = createPlanningConformanceFixturesV1();
57
+ return Object.freeze(await Promise.all(PLANNING_CONFORMANCE_CASES_V1.map(async (definition) => {
58
+ const challenge = fixtures.get(definition.caseId);
59
+ if (!capabilities.has(definition.capability)) {
60
+ return result(definition, "not_declared", null, 0, challenge.fixtureDigest, null);
61
+ }
62
+ let assessment;
63
+ const bounded = await runPlanningBoundedCase({
64
+ context,
65
+ run: async (signal) => {
66
+ const adapter = await awaitConformanceOperation(normalizedOptions.factory(Object.freeze({ seed: context.seed, signal })), signal);
67
+ assertAdapter(adapter);
68
+ let failure;
69
+ try {
70
+ assessment = validatePlanningConformanceAssessmentV1(await awaitConformanceOperation(adapter.assess(challenge, signal), signal));
71
+ assertAssessment(definition, challenge, assessment);
72
+ }
73
+ catch (error) {
74
+ failure = error;
75
+ }
76
+ await runConformanceCleanup(adapter.cleanup?.bind(adapter), context.cleanupTimeoutMs, failure);
77
+ if (failure !== undefined)
78
+ throw failure;
79
+ },
80
+ });
81
+ return result(definition, bounded.outcome === "passed" ? "passed" : "failed", bounded.outcome === "passed"
82
+ ? null
83
+ : (bounded.reasonCode ?? "assertion_failed"), bounded.durationMs, challenge.fixtureDigest, bounded.outcome === "passed"
84
+ ? (assessment?.evidenceDigest ?? null)
85
+ : null);
86
+ })));
87
+ }
88
+ function normalizePlanningOptions(input) {
89
+ const value = exactOptionRecord(input);
90
+ if (typeof value.factory !== "function") {
91
+ throw new TypeError("Planning conformance factory is required");
92
+ }
93
+ return Object.freeze({
94
+ factory: value.factory,
95
+ declaredCapabilities: value.declaredCapabilities,
96
+ ...(value.seed === undefined ? {} : { seed: value.seed }),
97
+ ...(value.timeoutMs === undefined
98
+ ? {}
99
+ : { timeoutMs: value.timeoutMs }),
100
+ ...(value.totalTimeoutMs === undefined
101
+ ? {}
102
+ : { totalTimeoutMs: value.totalTimeoutMs }),
103
+ ...(value.cleanupTimeoutMs === undefined
104
+ ? {}
105
+ : { cleanupTimeoutMs: value.cleanupTimeoutMs }),
106
+ ...(value.signal === undefined
107
+ ? {}
108
+ : { signal: value.signal }),
109
+ ...(value.clock === undefined
110
+ ? {}
111
+ : { clock: value.clock }),
112
+ });
113
+ }
114
+ function exactOptionRecord(input) {
115
+ if (!input ||
116
+ typeof input !== "object" ||
117
+ Array.isArray(input) ||
118
+ (Object.getPrototypeOf(input) !== Object.prototype &&
119
+ Object.getPrototypeOf(input) !== null) ||
120
+ Object.getOwnPropertySymbols(input).length !== 0)
121
+ throw new TypeError("Planning conformance options are invalid");
122
+ const required = ["declaredCapabilities", "factory"];
123
+ const permitted = [
124
+ ...required,
125
+ "cleanupTimeoutMs",
126
+ "clock",
127
+ "seed",
128
+ "signal",
129
+ "timeoutMs",
130
+ "totalTimeoutMs",
131
+ ];
132
+ const names = Object.getOwnPropertyNames(input);
133
+ if (names.some((name) => !permitted.includes(name)) ||
134
+ required.some((name) => !names.includes(name)))
135
+ throw new TypeError("Planning conformance options have unknown fields");
136
+ const result = Object.create(null);
137
+ for (const name of names) {
138
+ const descriptor = Object.getOwnPropertyDescriptor(input, name);
139
+ if (!descriptor || !descriptor.enumerable || !("value" in descriptor)) {
140
+ throw new TypeError("Planning conformance options have accessors");
141
+ }
142
+ result[name] = descriptor.value;
143
+ }
144
+ return Object.freeze(result);
145
+ }
146
+ function planningRunnerContext(options) {
147
+ const seed = integer(options.seed ?? 0, "seed", 0, 0xffff_ffff);
148
+ const timeoutMs = integer(options.timeoutMs ?? 5_000, "timeout", 10, 60_000);
149
+ const totalTimeoutMs = integer(options.totalTimeoutMs ?? 60_000, "suite timeout", 10, 300_000);
150
+ const cleanupTimeoutMs = integer(options.cleanupTimeoutMs ?? 2_000, "cleanup timeout", 10, 30_000);
151
+ if (options.signal !== undefined &&
152
+ !(options.signal instanceof AbortSignal)) {
153
+ throw new TypeError("Planning conformance abort signal is invalid");
154
+ }
155
+ if (options.clock !== undefined && typeof options.clock !== "function") {
156
+ throw new TypeError("Planning conformance clock is invalid");
157
+ }
158
+ return Object.freeze({
159
+ seed,
160
+ timeoutMs,
161
+ cleanupTimeoutMs,
162
+ deadline: monotonicNow() + totalTimeoutMs,
163
+ signal: options.signal,
164
+ clock: options.clock ?? Date.now,
165
+ });
166
+ }
167
+ async function runPlanningBoundedCase(input) {
168
+ const started = input.context.clock();
169
+ const remaining = Math.trunc(input.context.deadline - monotonicNow());
170
+ if (remaining <= 0)
171
+ return Object.freeze({
172
+ outcome: "failed",
173
+ reasonCode: "suite_timeout",
174
+ durationMs: 0,
175
+ });
176
+ const controller = new AbortController();
177
+ const relay = () => controller.abort(new PlanningConformanceAbort("aborted"));
178
+ input.context.signal?.addEventListener("abort", relay, { once: true });
179
+ let timer;
180
+ try {
181
+ if (input.context.signal?.aborted)
182
+ throw new PlanningConformanceAbort("aborted");
183
+ const timeoutReason = remaining <= input.context.timeoutMs ? "suite_timeout" : "timeout";
184
+ timer = setTimeout(() => controller.abort(new PlanningConformanceAbort(timeoutReason)), Math.min(remaining, input.context.timeoutMs));
185
+ await input.run(controller.signal);
186
+ if (controller.signal.aborted)
187
+ throw controller.signal.reason;
188
+ return Object.freeze({
189
+ outcome: "passed",
190
+ reasonCode: null,
191
+ durationMs: duration(started, input.context.clock()),
192
+ });
193
+ }
194
+ catch (error) {
195
+ return Object.freeze({
196
+ outcome: "failed",
197
+ reasonCode: planningFailureCode(error),
198
+ durationMs: duration(started, input.context.clock()),
199
+ });
200
+ }
201
+ finally {
202
+ if (timer !== undefined)
203
+ clearTimeout(timer);
204
+ input.context.signal?.removeEventListener("abort", relay);
205
+ }
206
+ }
207
+ class PlanningConformanceAbort extends Error {
208
+ code;
209
+ constructor(code) {
210
+ super(code);
211
+ this.code = code;
212
+ }
213
+ }
214
+ function planningFailureCode(error) {
215
+ if (error instanceof PlanningConformanceAbort)
216
+ return error.code;
217
+ if (error instanceof MeshConformanceCleanupError) {
218
+ return error.previousFailure instanceof PlanningConformanceAbort
219
+ ? `${error.previousFailure.code}_cleanup_failed`
220
+ : "cleanup_failed";
221
+ }
222
+ return "assertion_failed";
223
+ }
224
+ function duration(started, ended) {
225
+ const value = Math.max(0, Math.trunc(ended - started));
226
+ return Number.isSafeInteger(value) ? Math.min(value, 60_000) : 60_000;
227
+ }
228
+ function monotonicNow() {
229
+ return globalThis.performance?.now() ?? Date.now();
230
+ }
231
+ /** Builds a sealed, canonical public report from a complete suite execution. */
232
+ export function createPlanningConformanceReportV1(input) {
233
+ exactRecord(input, [
234
+ "cases",
235
+ "declaredCapabilities",
236
+ "implementation",
237
+ "seed",
238
+ ]);
239
+ const capabilities = [
240
+ ...normalizeCapabilities(input.declaredCapabilities),
241
+ ].sort(compareAscii);
242
+ for (const capability of PLANNING_REQUIRED_CONFORMANCE_CAPABILITIES_V1) {
243
+ if (!capabilities.includes(capability))
244
+ throw new TypeError("Required planning conformance capability is missing");
245
+ }
246
+ const implementation = normalizeImplementation(input.implementation);
247
+ const seed = integer(input.seed, "seed", 0, 0xffff_ffff);
248
+ const cases = normalizeResults(input.cases, new Set(capabilities));
249
+ const counts = Object.freeze({
250
+ passed: cases.filter((entry) => entry.outcome === "passed").length,
251
+ failed: cases.filter((entry) => entry.outcome === "failed").length,
252
+ notDeclared: cases.filter((entry) => entry.outcome === "not_declared")
253
+ .length,
254
+ total: cases.length,
255
+ });
256
+ return Object.freeze({
257
+ schemaVersion: 1,
258
+ conformanceVersion: PLANNING_CONFORMANCE_VERSION_V1,
259
+ suiteDigest: PLANNING_CONFORMANCE_SUITE_DIGEST_V1,
260
+ fixtureManifestDigest: planningConformanceFixtureManifestDigestV1(),
261
+ implementation,
262
+ declaredCapabilities: Object.freeze(capabilities),
263
+ seed,
264
+ cases,
265
+ counts,
266
+ verdict: counts.failed === 0 ? "passed" : "failed",
267
+ });
268
+ }
269
+ /** Rejects a tampered, incomplete, undisclosed-capability or aggregate-inconsistent report. */
270
+ export function validatePlanningConformanceReportV1(value) {
271
+ exactRecord(value, [
272
+ "cases",
273
+ "conformanceVersion",
274
+ "counts",
275
+ "declaredCapabilities",
276
+ "fixtureManifestDigest",
277
+ "implementation",
278
+ "schemaVersion",
279
+ "seed",
280
+ "suiteDigest",
281
+ "verdict",
282
+ ]);
283
+ const report = value;
284
+ if (report.schemaVersion !== 1 ||
285
+ report.conformanceVersion !== PLANNING_CONFORMANCE_VERSION_V1 ||
286
+ report.suiteDigest !== PLANNING_CONFORMANCE_SUITE_DIGEST_V1 ||
287
+ report.fixtureManifestDigest !==
288
+ planningConformanceFixtureManifestDigestV1())
289
+ throw new TypeError("Planning conformance report binding is invalid");
290
+ const normalized = createPlanningConformanceReportV1({
291
+ implementation: report.implementation,
292
+ declaredCapabilities: report.declaredCapabilities,
293
+ seed: report.seed,
294
+ cases: report.cases,
295
+ });
296
+ exactRecord(report.counts, ["failed", "notDeclared", "passed", "total"]);
297
+ if (report.counts.passed !== normalized.counts.passed ||
298
+ report.counts.failed !== normalized.counts.failed ||
299
+ report.counts.notDeclared !== normalized.counts.notDeclared ||
300
+ report.counts.total !== normalized.counts.total ||
301
+ report.verdict !== normalized.verdict)
302
+ throw new TypeError("Planning conformance report aggregate is inconsistent");
303
+ return normalized;
304
+ }
305
+ /** Public deterministic fixtures; each one is a bounded, redacted challenge. */
306
+ export function createPlanningConformanceFixturesV1() {
307
+ const fixtures = PLANNING_CONFORMANCE_CASES_V1.map((definition) => {
308
+ const input = deepFreezePlanning(fixtureInput(definition.caseId));
309
+ return deepFreezePlanning({
310
+ schemaVersion: 1,
311
+ caseId: definition.caseId,
312
+ fixtureDigest: commitment({
313
+ schemaVersion: 1,
314
+ caseId: definition.caseId,
315
+ input,
316
+ }),
317
+ input,
318
+ });
319
+ });
320
+ return new Map(fixtures.map((fixture) => [fixture.caseId, fixture]));
321
+ }
322
+ export function planningConformanceFixtureManifestDigestV1() {
323
+ const fixtures = createPlanningConformanceFixturesV1();
324
+ return commitment({
325
+ schemaVersion: 1,
326
+ fixtures: PLANNING_CONFORMANCE_CASES_V1.map((definition) => ({
327
+ caseId: definition.caseId,
328
+ fixtureDigest: fixtures.get(definition.caseId).fixtureDigest,
329
+ })),
330
+ });
331
+ }
332
+ function fixtureInput(caseId) {
333
+ const common = { schemaVersion: 1, fixtureVersion: 1 };
334
+ switch (caseId) {
335
+ case "planning.intent.closed-record":
336
+ return Object.freeze({
337
+ ...common,
338
+ operation: "intent.validate",
339
+ intent: {
340
+ missionIntentId: "mission:planning-conformance",
341
+ revision: 1,
342
+ },
343
+ injectedAuthority: "must-not-be-accepted",
344
+ });
345
+ case "planning.proposal.scope-widening":
346
+ return Object.freeze({
347
+ ...common,
348
+ operation: "proposal.validate",
349
+ permittedCapabilityKeys: ["documents.write"],
350
+ proposalCapabilityKeys: ["documents.write", "root.admin"],
351
+ });
352
+ case "planning.reducer.dependency-cycle":
353
+ return Object.freeze({
354
+ ...common,
355
+ operation: "reducer.apply",
356
+ fragments: [
357
+ { fragmentId: "fragment:a", dependencies: ["fragment:b"] },
358
+ { fragmentId: "fragment:b", dependencies: ["fragment:a"] },
359
+ ],
360
+ });
361
+ case "planning.reducer.exact-replay":
362
+ return Object.freeze({
363
+ ...common,
364
+ operation: "reducer.replay",
365
+ commands: [
366
+ {
367
+ commandId: "command:1",
368
+ logicalTimeMs: 1,
369
+ kind: "observation.record",
370
+ },
371
+ {
372
+ commandId: "command:1",
373
+ logicalTimeMs: 1,
374
+ kind: "observation.record",
375
+ },
376
+ ],
377
+ });
378
+ case "planning.snapshot.cross-scope":
379
+ return Object.freeze({
380
+ ...common,
381
+ operation: "snapshot.restore",
382
+ snapshotScope: "tenant:one/policy:a/mission:one",
383
+ targetScope: "tenant:two/policy:a/mission:one",
384
+ snapshotGeneration: 4,
385
+ targetHighWater: 4,
386
+ });
387
+ case "planning.snapshot.rollback":
388
+ return Object.freeze({
389
+ ...common,
390
+ operation: "snapshot.restore",
391
+ snapshotScope: "tenant:one/policy:a/mission:one",
392
+ targetScope: "tenant:one/policy:a/mission:one",
393
+ snapshotGeneration: 3,
394
+ targetHighWater: 4,
395
+ });
396
+ case "planning.replanning.causal-predecessor":
397
+ return Object.freeze({
398
+ ...common,
399
+ operation: "replanning.apply",
400
+ triggerObservationDigest: null,
401
+ predecessorPlanDigest: null,
402
+ revisedPlanDigest: "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
403
+ });
404
+ case "planning.fencing.stale-result":
405
+ return Object.freeze({
406
+ ...common,
407
+ operation: "effect.apply",
408
+ currentFence: "fence:2",
409
+ resultFence: "fence:1",
410
+ workId: "work:planning-conformance",
411
+ });
412
+ case "planning.mesh-projection.assignment-bound":
413
+ return Object.freeze({
414
+ ...common,
415
+ operation: "mesh-projection.validate",
416
+ assignmentDigest: "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
417
+ extensionAssignmentDigest: "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789",
418
+ });
419
+ case "planning.evaluation.public-artifact":
420
+ return Object.freeze({
421
+ ...common,
422
+ operation: "evaluation.artifact.validate",
423
+ artifact: {
424
+ traceDigest: "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
425
+ },
426
+ privateEvidence: "must-not-be-disclosed",
427
+ });
428
+ case "planning.durable.restart-high-water":
429
+ return Object.freeze({
430
+ ...common,
431
+ operation: "durability.reopen",
432
+ scope: "tenant:one/policy:a/mission:one",
433
+ expectedStateDigest: "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
434
+ expectedFenceHighWater: 2,
435
+ });
436
+ }
437
+ }
438
+ export function validatePlanningConformanceAssessmentV1(value) {
439
+ exactRecord(value, [
440
+ "caseId",
441
+ "evidenceDigest",
442
+ "fixtureDigest",
443
+ "reasonCode",
444
+ "schemaVersion",
445
+ "verdict",
446
+ ]);
447
+ const assessment = value;
448
+ if (assessment.schemaVersion !== 1 ||
449
+ !caseDefinition(assessment.caseId) ||
450
+ !isDigest(assessment.fixtureDigest) ||
451
+ !isDigest(assessment.evidenceDigest) ||
452
+ !["accepted", "rejected"].includes(assessment.verdict) ||
453
+ (assessment.reasonCode !== null && !isReason(assessment.reasonCode)))
454
+ throw new TypeError("Planning conformance assessment is invalid");
455
+ return Object.freeze({ ...assessment });
456
+ }
457
+ function assertAssessment(definition, challenge, assessment) {
458
+ if (assessment.caseId !== definition.caseId ||
459
+ assessment.fixtureDigest !== challenge.fixtureDigest ||
460
+ assessment.verdict !== definition.expectedVerdict ||
461
+ assessment.reasonCode !== definition.expectedReasonCode)
462
+ throw new TypeError("Planning conformance assessment does not match public fixture");
463
+ }
464
+ function normalizeResults(values, capabilities) {
465
+ const candidates = ownArrayValues(values, PLANNING_CONFORMANCE_CASES_V1.length, "case results");
466
+ if (candidates.length !== PLANNING_CONFORMANCE_CASES_V1.length) {
467
+ throw new TypeError("Planning conformance case coverage is incomplete");
468
+ }
469
+ const fixtures = createPlanningConformanceFixturesV1();
470
+ const byId = new Map();
471
+ for (const candidate of candidates) {
472
+ exactRecord(candidate, [
473
+ "capability",
474
+ "caseId",
475
+ "durationMs",
476
+ "evidenceDigest",
477
+ "fixtureDigest",
478
+ "outcome",
479
+ "reasonCode",
480
+ ]);
481
+ const result = candidate;
482
+ if (byId.has(result.caseId))
483
+ throw new TypeError("Planning conformance case is duplicated");
484
+ byId.set(result.caseId, result);
485
+ }
486
+ return Object.freeze(PLANNING_CONFORMANCE_CASES_V1.map((definition) => {
487
+ const value = byId.get(definition.caseId);
488
+ if (!value)
489
+ throw new TypeError("Planning conformance case is missing");
490
+ const declared = capabilities.has(definition.capability);
491
+ if (value.caseId !== definition.caseId ||
492
+ value.capability !== definition.capability ||
493
+ !["passed", "failed", "not_declared"].includes(value.outcome) ||
494
+ !Number.isSafeInteger(value.durationMs) ||
495
+ value.durationMs < 0 ||
496
+ value.durationMs > 60_000 ||
497
+ value.fixtureDigest !==
498
+ fixtures.get(definition.caseId).fixtureDigest ||
499
+ (value.reasonCode !== null && !isReason(value.reasonCode)) ||
500
+ (value.evidenceDigest !== null && !isDigest(value.evidenceDigest)) ||
501
+ (!declared &&
502
+ (value.outcome !== "not_declared" ||
503
+ value.reasonCode !== null ||
504
+ value.evidenceDigest !== null)) ||
505
+ (declared && value.outcome === "not_declared") ||
506
+ (value.outcome === "passed" &&
507
+ (value.reasonCode !== null || value.evidenceDigest === null)) ||
508
+ (value.outcome === "failed" &&
509
+ (value.reasonCode === null || value.evidenceDigest !== null)))
510
+ throw new TypeError("Planning conformance case result is invalid");
511
+ return Object.freeze({ ...value });
512
+ }));
513
+ }
514
+ function result(definition, outcome, reasonCode, durationMs, fixtureDigest, evidenceDigest) {
515
+ return Object.freeze({
516
+ caseId: definition.caseId,
517
+ capability: definition.capability,
518
+ outcome,
519
+ reasonCode,
520
+ durationMs,
521
+ fixtureDigest,
522
+ evidenceDigest,
523
+ });
524
+ }
525
+ function normalizeCapabilities(values) {
526
+ const candidateValues = ownArrayValues(values, PLANNING_CONFORMANCE_CAPABILITIES_V1.length, "capabilities");
527
+ if (candidateValues.length > PLANNING_CONFORMANCE_CAPABILITIES_V1.length) {
528
+ throw new RangeError("Planning conformance capability count is invalid");
529
+ }
530
+ const result = new Set();
531
+ for (const candidate of candidateValues) {
532
+ if (typeof candidate !== "string") {
533
+ throw new TypeError("Planning conformance capability is invalid");
534
+ }
535
+ const value = candidate;
536
+ if (!PLANNING_CONFORMANCE_CAPABILITIES_V1.includes(value) ||
537
+ result.has(value)) {
538
+ throw new TypeError("Planning conformance capability is invalid");
539
+ }
540
+ result.add(value);
541
+ }
542
+ return result;
543
+ }
544
+ function normalizeImplementation(value) {
545
+ exactRecord(value, ["name", "version"]);
546
+ if (!isText(value.name, 128) ||
547
+ !/^[0-9A-Za-z][0-9A-Za-z.+-]{0,63}$/u.test(value.version)) {
548
+ throw new TypeError("Planning conformance implementation is invalid");
549
+ }
550
+ return Object.freeze({ name: value.name, version: value.version });
551
+ }
552
+ function assertAdapter(value) {
553
+ if (!value ||
554
+ typeof value !== "object" ||
555
+ (Object.getPrototypeOf(value) !== Object.prototype &&
556
+ Object.getPrototypeOf(value) !== null) ||
557
+ Object.getOwnPropertySymbols(value).length !== 0)
558
+ throw new TypeError("Planning conformance factory is invalid");
559
+ const names = Object.getOwnPropertyNames(value).sort(compareAscii);
560
+ if (names.length < 1 ||
561
+ names.length > 2 ||
562
+ names[0] !== "assess" ||
563
+ (names.length === 2 && names[1] !== "cleanup"))
564
+ throw new TypeError("Planning conformance factory is invalid");
565
+ const assess = Object.getOwnPropertyDescriptor(value, "assess");
566
+ const cleanup = Object.getOwnPropertyDescriptor(value, "cleanup");
567
+ if (!assess ||
568
+ !assess.enumerable ||
569
+ !("value" in assess) ||
570
+ typeof assess.value !== "function" ||
571
+ (cleanup !== undefined &&
572
+ (!cleanup.enumerable ||
573
+ !("value" in cleanup) ||
574
+ (cleanup.value !== undefined && typeof cleanup.value !== "function"))))
575
+ throw new TypeError("Planning conformance factory is invalid");
576
+ }
577
+ function define(caseId, capability, expectedVerdict, expectedReasonCode) {
578
+ return Object.freeze({
579
+ caseId,
580
+ capability,
581
+ expectedVerdict,
582
+ expectedReasonCode,
583
+ });
584
+ }
585
+ function caseDefinition(value) {
586
+ return PLANNING_CONFORMANCE_CASES_V1.find((definition) => definition.caseId === value);
587
+ }
588
+ function commitment(value) {
589
+ const encoded = new TextEncoder().encode(`agentplat.mesh-conformance/planning/v1\0${canonicalizePlanningJsonV1(value)}`);
590
+ return `sha256:${sha256HexPlanningV1(encoded)}`;
591
+ }
592
+ function exactRecord(value, keys) {
593
+ if (!value ||
594
+ typeof value !== "object" ||
595
+ Array.isArray(value) ||
596
+ (Object.getPrototypeOf(value) !== Object.prototype &&
597
+ Object.getPrototypeOf(value) !== null) ||
598
+ Object.getOwnPropertySymbols(value).length !== 0)
599
+ throw new TypeError("Planning conformance record is invalid");
600
+ const actual = Object.getOwnPropertyNames(value).sort(compareAscii);
601
+ const expected = [...keys].sort(compareAscii);
602
+ if (actual.length !== expected.length ||
603
+ actual.some((key, index) => key !== expected[index])) {
604
+ throw new TypeError("Planning conformance record has unknown fields");
605
+ }
606
+ for (const key of actual) {
607
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
608
+ if (!descriptor || !descriptor.enumerable || !("value" in descriptor)) {
609
+ throw new TypeError("Planning conformance record has accessors");
610
+ }
611
+ }
612
+ }
613
+ function ownArrayValues(value, maximum, label) {
614
+ if (!Array.isArray(value) ||
615
+ Object.getPrototypeOf(value) !== Array.prototype ||
616
+ value.length > maximum ||
617
+ Object.getOwnPropertySymbols(value).length !== 0)
618
+ throw new TypeError(`Planning conformance ${label} are invalid`);
619
+ const result = [];
620
+ const names = Object.getOwnPropertyNames(value);
621
+ if (names.length !== value.length + 1 || !names.includes("length")) {
622
+ throw new TypeError(`Planning conformance ${label} are sparse`);
623
+ }
624
+ for (let index = 0; index < value.length; index += 1) {
625
+ const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
626
+ if (!descriptor || !descriptor.enumerable || !("value" in descriptor)) {
627
+ throw new TypeError(`Planning conformance ${label} have accessors`);
628
+ }
629
+ result.push(descriptor.value);
630
+ }
631
+ return Object.freeze(result);
632
+ }
633
+ function integer(value, label, minimum, maximum) {
634
+ if (!Number.isSafeInteger(value) ||
635
+ value < minimum ||
636
+ value > maximum) {
637
+ throw new RangeError(`Planning conformance ${label} is invalid`);
638
+ }
639
+ return value;
640
+ }
641
+ function isDigest(value) {
642
+ return typeof value === "string" && /^sha256:[a-f0-9]{64}$/u.test(value);
643
+ }
644
+ function isReason(value) {
645
+ return typeof value === "string" && /^[a-z][a-z0-9._:-]{0,63}$/u.test(value);
646
+ }
647
+ function isText(value, maximum) {
648
+ return (typeof value === "string" &&
649
+ value.length > 0 &&
650
+ new TextEncoder().encode(value).byteLength <= maximum &&
651
+ !/[\u0000-\u001f\u007f]/u.test(value));
652
+ }
653
+ function compareAscii(left, right) {
654
+ return left < right ? -1 : left > right ? 1 : 0;
655
+ }
656
+ //# sourceMappingURL=planning.js.map