@atcn/subledger 1.3.2 → 1.4.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.
- package/dist/documents.d.ts +206 -8
- package/dist/documents.js +18 -4
- package/dist/projection.d.ts +5 -0
- package/dist/projection.js +29 -2
- package/dist/response.d.ts +6 -0
- package/dist/response.js +4 -0
- package/dist/types.d.ts +25 -1
- package/dist/types.js +7 -0
- package/dist/verify.d.ts +2 -0
- package/dist/verify.js +80 -8
- package/package.json +3 -3
- package/test-vectors/vectors.json +85 -0
package/dist/documents.d.ts
CHANGED
|
@@ -2,12 +2,14 @@ import { z } from "zod";
|
|
|
2
2
|
/**
|
|
3
3
|
* Signed documents of the Agent Work Subledger (PRD v1.2 §6, §16).
|
|
4
4
|
* Schema 1.3 adds closure `obligation_links`, the clearing-network claim asserters, and the `network_recorded` assurance label;
|
|
5
|
-
* 1.2 documents must use neither
|
|
5
|
+
* 1.2 documents must use neither. Schema 1.4 adds delegation `execution`, the response statement fields `execution`,
|
|
6
|
+
* `issued_at`, `expires_at` and `refs`, and the `expired` and `revoked` labels; 1.2 and 1.3 documents must use none
|
|
7
|
+
* of them (see packages/schema/COMPATIBILITY.md).
|
|
6
8
|
*/
|
|
7
|
-
export declare const SUBLEDGER_SCHEMA_VERSION: "1.
|
|
8
|
-
export declare const SUPPORTED_SUBLEDGER_SCHEMA_VERSIONS: readonly ["1.2", "1.3"];
|
|
9
|
+
export declare const SUBLEDGER_SCHEMA_VERSION: "1.4";
|
|
10
|
+
export declare const SUPPORTED_SUBLEDGER_SCHEMA_VERSIONS: readonly ["1.2", "1.3", "1.4"];
|
|
9
11
|
/** Must equal this package's version in package.json (checked by a test). */
|
|
10
|
-
export declare const SUBLEDGER_VERIFIER_VERSION: "1.
|
|
12
|
+
export declare const SUBLEDGER_VERIFIER_VERSION: "1.4.1";
|
|
11
13
|
export declare const RECEIPT_DOCUMENT_TYPE: "atcn.subledger.receipt";
|
|
12
14
|
export declare const CLOSURE_DOCUMENT_TYPE: "atcn.subledger.closure";
|
|
13
15
|
export declare const RESPONSE_STATEMENT_TYPE: "atcn.subledger.receipt_response";
|
|
@@ -180,6 +182,8 @@ export declare const DeliveryClaimSchema: z.ZodObject<{
|
|
|
180
182
|
provider_key_signed: "provider_key_signed";
|
|
181
183
|
contested: "contested";
|
|
182
184
|
superseded: "superseded";
|
|
185
|
+
expired: "expired";
|
|
186
|
+
revoked: "revoked";
|
|
183
187
|
}>>;
|
|
184
188
|
note: z.ZodNullable<z.ZodString>;
|
|
185
189
|
evidence: z.ZodArray<z.ZodObject<{
|
|
@@ -259,6 +263,20 @@ export declare const ResponseStatementSchema: z.ZodObject<{
|
|
|
259
263
|
proposed_value: z.ZodString;
|
|
260
264
|
reason: z.ZodString;
|
|
261
265
|
}, z.core.$strip>>;
|
|
266
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
267
|
+
execution_id: z.ZodString;
|
|
268
|
+
execution_digest: z.ZodString;
|
|
269
|
+
}, z.core.$strip>>;
|
|
270
|
+
issued_at: z.ZodOptional<z.ZodString>;
|
|
271
|
+
expires_at: z.ZodOptional<z.ZodString>;
|
|
272
|
+
refs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
273
|
+
relation: z.ZodEnum<{
|
|
274
|
+
revokes: "revokes";
|
|
275
|
+
disputes: "disputes";
|
|
276
|
+
}>;
|
|
277
|
+
attestation_digest: z.ZodString;
|
|
278
|
+
reason: z.ZodString;
|
|
279
|
+
}, z.core.$strip>>>;
|
|
262
280
|
}, z.core.$strip>;
|
|
263
281
|
export type ResponseStatement = z.infer<typeof ResponseStatementSchema>;
|
|
264
282
|
export declare const ResponseRecordSchema: z.ZodObject<{
|
|
@@ -303,6 +321,20 @@ export declare const ResponseRecordSchema: z.ZodObject<{
|
|
|
303
321
|
proposed_value: z.ZodString;
|
|
304
322
|
reason: z.ZodString;
|
|
305
323
|
}, z.core.$strip>>;
|
|
324
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
325
|
+
execution_id: z.ZodString;
|
|
326
|
+
execution_digest: z.ZodString;
|
|
327
|
+
}, z.core.$strip>>;
|
|
328
|
+
issued_at: z.ZodOptional<z.ZodString>;
|
|
329
|
+
expires_at: z.ZodOptional<z.ZodString>;
|
|
330
|
+
refs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
331
|
+
relation: z.ZodEnum<{
|
|
332
|
+
revokes: "revokes";
|
|
333
|
+
disputes: "disputes";
|
|
334
|
+
}>;
|
|
335
|
+
attestation_digest: z.ZodString;
|
|
336
|
+
reason: z.ZodString;
|
|
337
|
+
}, z.core.$strip>>>;
|
|
306
338
|
}, z.core.$strip>;
|
|
307
339
|
statement_digest: z.ZodString;
|
|
308
340
|
provider_signature: z.ZodNullable<z.ZodObject<{
|
|
@@ -320,6 +352,8 @@ export declare const ResponseRecordSchema: z.ZodObject<{
|
|
|
320
352
|
provider_key_signed: "provider_key_signed";
|
|
321
353
|
contested: "contested";
|
|
322
354
|
superseded: "superseded";
|
|
355
|
+
expired: "expired";
|
|
356
|
+
revoked: "revoked";
|
|
323
357
|
}>>;
|
|
324
358
|
decision: z.ZodNullable<z.ZodObject<{
|
|
325
359
|
status: z.ZodEnum<{
|
|
@@ -410,8 +444,9 @@ export declare const ReceiptFinancialEventSchema: z.ZodObject<{
|
|
|
410
444
|
export declare const ReceiptPayloadSchema: z.ZodObject<{
|
|
411
445
|
document_type: z.ZodLiteral<"atcn.subledger.receipt">;
|
|
412
446
|
schema_version: z.ZodEnum<{
|
|
413
|
-
1.
|
|
447
|
+
1.4: "1.4";
|
|
414
448
|
1.2: "1.2";
|
|
449
|
+
1.3: "1.3";
|
|
415
450
|
}>;
|
|
416
451
|
receipt_id: z.ZodString;
|
|
417
452
|
revision: z.ZodNumber;
|
|
@@ -445,6 +480,30 @@ export declare const ReceiptPayloadSchema: z.ZodObject<{
|
|
|
445
480
|
disclosed: "disclosed";
|
|
446
481
|
none: "none";
|
|
447
482
|
}>;
|
|
483
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
484
|
+
execution_id: z.ZodString;
|
|
485
|
+
protocol: z.ZodOptional<z.ZodObject<{
|
|
486
|
+
name: z.ZodLiteral<"a2a">;
|
|
487
|
+
task_id: z.ZodString;
|
|
488
|
+
context_id: z.ZodOptional<z.ZodString>;
|
|
489
|
+
}, z.core.$strip>>;
|
|
490
|
+
agent: z.ZodObject<{
|
|
491
|
+
agent_id: z.ZodString;
|
|
492
|
+
agent_version: z.ZodString;
|
|
493
|
+
card_digest: z.ZodOptional<z.ZodString>;
|
|
494
|
+
model: z.ZodOptional<z.ZodObject<{
|
|
495
|
+
provider: z.ZodString;
|
|
496
|
+
name: z.ZodString;
|
|
497
|
+
version: z.ZodString;
|
|
498
|
+
}, z.core.$strip>>;
|
|
499
|
+
config_digest: z.ZodOptional<z.ZodString>;
|
|
500
|
+
}, z.core.$strip>;
|
|
501
|
+
skill: z.ZodOptional<z.ZodObject<{
|
|
502
|
+
namespace: z.ZodString;
|
|
503
|
+
skill_id: z.ZodString;
|
|
504
|
+
agent_card_url: z.ZodOptional<z.ZodURL>;
|
|
505
|
+
}, z.core.$strip>>;
|
|
506
|
+
}, z.core.$strip>>;
|
|
448
507
|
}, z.core.$strip>;
|
|
449
508
|
provider: z.ZodObject<{
|
|
450
509
|
provider_id: z.ZodNullable<z.ZodString>;
|
|
@@ -493,6 +552,8 @@ export declare const ReceiptPayloadSchema: z.ZodObject<{
|
|
|
493
552
|
provider_key_signed: "provider_key_signed";
|
|
494
553
|
contested: "contested";
|
|
495
554
|
superseded: "superseded";
|
|
555
|
+
expired: "expired";
|
|
556
|
+
revoked: "revoked";
|
|
496
557
|
}>>;
|
|
497
558
|
recorded_at: z.ZodString;
|
|
498
559
|
}, z.core.$strip>>;
|
|
@@ -612,8 +673,9 @@ export declare const SignedReceiptSchema: z.ZodObject<{
|
|
|
612
673
|
payload: z.ZodObject<{
|
|
613
674
|
document_type: z.ZodLiteral<"atcn.subledger.receipt">;
|
|
614
675
|
schema_version: z.ZodEnum<{
|
|
615
|
-
1.
|
|
676
|
+
1.4: "1.4";
|
|
616
677
|
1.2: "1.2";
|
|
678
|
+
1.3: "1.3";
|
|
617
679
|
}>;
|
|
618
680
|
receipt_id: z.ZodString;
|
|
619
681
|
revision: z.ZodNumber;
|
|
@@ -647,6 +709,30 @@ export declare const SignedReceiptSchema: z.ZodObject<{
|
|
|
647
709
|
disclosed: "disclosed";
|
|
648
710
|
none: "none";
|
|
649
711
|
}>;
|
|
712
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
713
|
+
execution_id: z.ZodString;
|
|
714
|
+
protocol: z.ZodOptional<z.ZodObject<{
|
|
715
|
+
name: z.ZodLiteral<"a2a">;
|
|
716
|
+
task_id: z.ZodString;
|
|
717
|
+
context_id: z.ZodOptional<z.ZodString>;
|
|
718
|
+
}, z.core.$strip>>;
|
|
719
|
+
agent: z.ZodObject<{
|
|
720
|
+
agent_id: z.ZodString;
|
|
721
|
+
agent_version: z.ZodString;
|
|
722
|
+
card_digest: z.ZodOptional<z.ZodString>;
|
|
723
|
+
model: z.ZodOptional<z.ZodObject<{
|
|
724
|
+
provider: z.ZodString;
|
|
725
|
+
name: z.ZodString;
|
|
726
|
+
version: z.ZodString;
|
|
727
|
+
}, z.core.$strip>>;
|
|
728
|
+
config_digest: z.ZodOptional<z.ZodString>;
|
|
729
|
+
}, z.core.$strip>;
|
|
730
|
+
skill: z.ZodOptional<z.ZodObject<{
|
|
731
|
+
namespace: z.ZodString;
|
|
732
|
+
skill_id: z.ZodString;
|
|
733
|
+
agent_card_url: z.ZodOptional<z.ZodURL>;
|
|
734
|
+
}, z.core.$strip>>;
|
|
735
|
+
}, z.core.$strip>>;
|
|
650
736
|
}, z.core.$strip>;
|
|
651
737
|
provider: z.ZodObject<{
|
|
652
738
|
provider_id: z.ZodNullable<z.ZodString>;
|
|
@@ -695,6 +781,8 @@ export declare const SignedReceiptSchema: z.ZodObject<{
|
|
|
695
781
|
provider_key_signed: "provider_key_signed";
|
|
696
782
|
contested: "contested";
|
|
697
783
|
superseded: "superseded";
|
|
784
|
+
expired: "expired";
|
|
785
|
+
revoked: "revoked";
|
|
698
786
|
}>>;
|
|
699
787
|
recorded_at: z.ZodString;
|
|
700
788
|
}, z.core.$strip>>;
|
|
@@ -848,6 +936,30 @@ export declare const ClosureDelegationSchema: z.ZodObject<{
|
|
|
848
936
|
delivery_status: z.ZodString;
|
|
849
937
|
retrospective: z.ZodBoolean;
|
|
850
938
|
created_at: z.ZodString;
|
|
939
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
940
|
+
execution_id: z.ZodString;
|
|
941
|
+
protocol: z.ZodOptional<z.ZodObject<{
|
|
942
|
+
name: z.ZodLiteral<"a2a">;
|
|
943
|
+
task_id: z.ZodString;
|
|
944
|
+
context_id: z.ZodOptional<z.ZodString>;
|
|
945
|
+
}, z.core.$strip>>;
|
|
946
|
+
agent: z.ZodObject<{
|
|
947
|
+
agent_id: z.ZodString;
|
|
948
|
+
agent_version: z.ZodString;
|
|
949
|
+
card_digest: z.ZodOptional<z.ZodString>;
|
|
950
|
+
model: z.ZodOptional<z.ZodObject<{
|
|
951
|
+
provider: z.ZodString;
|
|
952
|
+
name: z.ZodString;
|
|
953
|
+
version: z.ZodString;
|
|
954
|
+
}, z.core.$strip>>;
|
|
955
|
+
config_digest: z.ZodOptional<z.ZodString>;
|
|
956
|
+
}, z.core.$strip>;
|
|
957
|
+
skill: z.ZodOptional<z.ZodObject<{
|
|
958
|
+
namespace: z.ZodString;
|
|
959
|
+
skill_id: z.ZodString;
|
|
960
|
+
agent_card_url: z.ZodOptional<z.ZodURL>;
|
|
961
|
+
}, z.core.$strip>>;
|
|
962
|
+
}, z.core.$strip>>;
|
|
851
963
|
}, z.core.$strip>;
|
|
852
964
|
export type ClosureDelegation = z.infer<typeof ClosureDelegationSchema>;
|
|
853
965
|
export declare const AllocationRecordSchema: z.ZodObject<{
|
|
@@ -1052,8 +1164,9 @@ export type ObligationLink = z.infer<typeof ObligationLinkSchema>;
|
|
|
1052
1164
|
export declare const ClosurePayloadSchema: z.ZodObject<{
|
|
1053
1165
|
document_type: z.ZodLiteral<"atcn.subledger.closure">;
|
|
1054
1166
|
schema_version: z.ZodEnum<{
|
|
1055
|
-
1.
|
|
1167
|
+
1.4: "1.4";
|
|
1056
1168
|
1.2: "1.2";
|
|
1169
|
+
1.3: "1.3";
|
|
1057
1170
|
}>;
|
|
1058
1171
|
closure_id: z.ZodString;
|
|
1059
1172
|
version: z.ZodNumber;
|
|
@@ -1105,6 +1218,30 @@ export declare const ClosurePayloadSchema: z.ZodObject<{
|
|
|
1105
1218
|
delivery_status: z.ZodString;
|
|
1106
1219
|
retrospective: z.ZodBoolean;
|
|
1107
1220
|
created_at: z.ZodString;
|
|
1221
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
1222
|
+
execution_id: z.ZodString;
|
|
1223
|
+
protocol: z.ZodOptional<z.ZodObject<{
|
|
1224
|
+
name: z.ZodLiteral<"a2a">;
|
|
1225
|
+
task_id: z.ZodString;
|
|
1226
|
+
context_id: z.ZodOptional<z.ZodString>;
|
|
1227
|
+
}, z.core.$strip>>;
|
|
1228
|
+
agent: z.ZodObject<{
|
|
1229
|
+
agent_id: z.ZodString;
|
|
1230
|
+
agent_version: z.ZodString;
|
|
1231
|
+
card_digest: z.ZodOptional<z.ZodString>;
|
|
1232
|
+
model: z.ZodOptional<z.ZodObject<{
|
|
1233
|
+
provider: z.ZodString;
|
|
1234
|
+
name: z.ZodString;
|
|
1235
|
+
version: z.ZodString;
|
|
1236
|
+
}, z.core.$strip>>;
|
|
1237
|
+
config_digest: z.ZodOptional<z.ZodString>;
|
|
1238
|
+
}, z.core.$strip>;
|
|
1239
|
+
skill: z.ZodOptional<z.ZodObject<{
|
|
1240
|
+
namespace: z.ZodString;
|
|
1241
|
+
skill_id: z.ZodString;
|
|
1242
|
+
agent_card_url: z.ZodOptional<z.ZodURL>;
|
|
1243
|
+
}, z.core.$strip>>;
|
|
1244
|
+
}, z.core.$strip>>;
|
|
1108
1245
|
}, z.core.$strip>>;
|
|
1109
1246
|
delivery_claims: z.ZodArray<z.ZodObject<{
|
|
1110
1247
|
event_id: z.ZodString;
|
|
@@ -1135,6 +1272,8 @@ export declare const ClosurePayloadSchema: z.ZodObject<{
|
|
|
1135
1272
|
provider_key_signed: "provider_key_signed";
|
|
1136
1273
|
contested: "contested";
|
|
1137
1274
|
superseded: "superseded";
|
|
1275
|
+
expired: "expired";
|
|
1276
|
+
revoked: "revoked";
|
|
1138
1277
|
}>>;
|
|
1139
1278
|
note: z.ZodNullable<z.ZodString>;
|
|
1140
1279
|
evidence: z.ZodArray<z.ZodObject<{
|
|
@@ -1386,6 +1525,20 @@ export declare const ClosurePayloadSchema: z.ZodObject<{
|
|
|
1386
1525
|
proposed_value: z.ZodString;
|
|
1387
1526
|
reason: z.ZodString;
|
|
1388
1527
|
}, z.core.$strip>>;
|
|
1528
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
1529
|
+
execution_id: z.ZodString;
|
|
1530
|
+
execution_digest: z.ZodString;
|
|
1531
|
+
}, z.core.$strip>>;
|
|
1532
|
+
issued_at: z.ZodOptional<z.ZodString>;
|
|
1533
|
+
expires_at: z.ZodOptional<z.ZodString>;
|
|
1534
|
+
refs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1535
|
+
relation: z.ZodEnum<{
|
|
1536
|
+
revokes: "revokes";
|
|
1537
|
+
disputes: "disputes";
|
|
1538
|
+
}>;
|
|
1539
|
+
attestation_digest: z.ZodString;
|
|
1540
|
+
reason: z.ZodString;
|
|
1541
|
+
}, z.core.$strip>>>;
|
|
1389
1542
|
}, z.core.$strip>;
|
|
1390
1543
|
statement_digest: z.ZodString;
|
|
1391
1544
|
provider_signature: z.ZodNullable<z.ZodObject<{
|
|
@@ -1403,6 +1556,8 @@ export declare const ClosurePayloadSchema: z.ZodObject<{
|
|
|
1403
1556
|
provider_key_signed: "provider_key_signed";
|
|
1404
1557
|
contested: "contested";
|
|
1405
1558
|
superseded: "superseded";
|
|
1559
|
+
expired: "expired";
|
|
1560
|
+
revoked: "revoked";
|
|
1406
1561
|
}>>;
|
|
1407
1562
|
decision: z.ZodNullable<z.ZodObject<{
|
|
1408
1563
|
status: z.ZodEnum<{
|
|
@@ -1459,8 +1614,9 @@ export declare const SignedClosureSchema: z.ZodObject<{
|
|
|
1459
1614
|
payload: z.ZodObject<{
|
|
1460
1615
|
document_type: z.ZodLiteral<"atcn.subledger.closure">;
|
|
1461
1616
|
schema_version: z.ZodEnum<{
|
|
1462
|
-
1.
|
|
1617
|
+
1.4: "1.4";
|
|
1463
1618
|
1.2: "1.2";
|
|
1619
|
+
1.3: "1.3";
|
|
1464
1620
|
}>;
|
|
1465
1621
|
closure_id: z.ZodString;
|
|
1466
1622
|
version: z.ZodNumber;
|
|
@@ -1512,6 +1668,30 @@ export declare const SignedClosureSchema: z.ZodObject<{
|
|
|
1512
1668
|
delivery_status: z.ZodString;
|
|
1513
1669
|
retrospective: z.ZodBoolean;
|
|
1514
1670
|
created_at: z.ZodString;
|
|
1671
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
1672
|
+
execution_id: z.ZodString;
|
|
1673
|
+
protocol: z.ZodOptional<z.ZodObject<{
|
|
1674
|
+
name: z.ZodLiteral<"a2a">;
|
|
1675
|
+
task_id: z.ZodString;
|
|
1676
|
+
context_id: z.ZodOptional<z.ZodString>;
|
|
1677
|
+
}, z.core.$strip>>;
|
|
1678
|
+
agent: z.ZodObject<{
|
|
1679
|
+
agent_id: z.ZodString;
|
|
1680
|
+
agent_version: z.ZodString;
|
|
1681
|
+
card_digest: z.ZodOptional<z.ZodString>;
|
|
1682
|
+
model: z.ZodOptional<z.ZodObject<{
|
|
1683
|
+
provider: z.ZodString;
|
|
1684
|
+
name: z.ZodString;
|
|
1685
|
+
version: z.ZodString;
|
|
1686
|
+
}, z.core.$strip>>;
|
|
1687
|
+
config_digest: z.ZodOptional<z.ZodString>;
|
|
1688
|
+
}, z.core.$strip>;
|
|
1689
|
+
skill: z.ZodOptional<z.ZodObject<{
|
|
1690
|
+
namespace: z.ZodString;
|
|
1691
|
+
skill_id: z.ZodString;
|
|
1692
|
+
agent_card_url: z.ZodOptional<z.ZodURL>;
|
|
1693
|
+
}, z.core.$strip>>;
|
|
1694
|
+
}, z.core.$strip>>;
|
|
1515
1695
|
}, z.core.$strip>>;
|
|
1516
1696
|
delivery_claims: z.ZodArray<z.ZodObject<{
|
|
1517
1697
|
event_id: z.ZodString;
|
|
@@ -1542,6 +1722,8 @@ export declare const SignedClosureSchema: z.ZodObject<{
|
|
|
1542
1722
|
provider_key_signed: "provider_key_signed";
|
|
1543
1723
|
contested: "contested";
|
|
1544
1724
|
superseded: "superseded";
|
|
1725
|
+
expired: "expired";
|
|
1726
|
+
revoked: "revoked";
|
|
1545
1727
|
}>>;
|
|
1546
1728
|
note: z.ZodNullable<z.ZodString>;
|
|
1547
1729
|
evidence: z.ZodArray<z.ZodObject<{
|
|
@@ -1793,6 +1975,20 @@ export declare const SignedClosureSchema: z.ZodObject<{
|
|
|
1793
1975
|
proposed_value: z.ZodString;
|
|
1794
1976
|
reason: z.ZodString;
|
|
1795
1977
|
}, z.core.$strip>>;
|
|
1978
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
1979
|
+
execution_id: z.ZodString;
|
|
1980
|
+
execution_digest: z.ZodString;
|
|
1981
|
+
}, z.core.$strip>>;
|
|
1982
|
+
issued_at: z.ZodOptional<z.ZodString>;
|
|
1983
|
+
expires_at: z.ZodOptional<z.ZodString>;
|
|
1984
|
+
refs: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1985
|
+
relation: z.ZodEnum<{
|
|
1986
|
+
revokes: "revokes";
|
|
1987
|
+
disputes: "disputes";
|
|
1988
|
+
}>;
|
|
1989
|
+
attestation_digest: z.ZodString;
|
|
1990
|
+
reason: z.ZodString;
|
|
1991
|
+
}, z.core.$strip>>>;
|
|
1796
1992
|
}, z.core.$strip>;
|
|
1797
1993
|
statement_digest: z.ZodString;
|
|
1798
1994
|
provider_signature: z.ZodNullable<z.ZodObject<{
|
|
@@ -1810,6 +2006,8 @@ export declare const SignedClosureSchema: z.ZodObject<{
|
|
|
1810
2006
|
provider_key_signed: "provider_key_signed";
|
|
1811
2007
|
contested: "contested";
|
|
1812
2008
|
superseded: "superseded";
|
|
2009
|
+
expired: "expired";
|
|
2010
|
+
revoked: "revoked";
|
|
1813
2011
|
}>>;
|
|
1814
2012
|
decision: z.ZodNullable<z.ZodObject<{
|
|
1815
2013
|
status: z.ZodEnum<{
|
package/dist/documents.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
import { AttestationRefSchema, ExecutionBindingSchema, ExecutionDescriptorSchema } from "@atcn/schema";
|
|
1
2
|
import { z } from "zod";
|
|
2
3
|
import { ASSURANCE_LABELS, ATTESTABLE_FIELDS, CLAIM_ASSERTERS, Currency, DELIVERY_EVENT_TYPES, EvidenceRefSchema, FINANCIAL_EVENT_TYPES, FxSchema, Minor, NORMALIZED_STATUSES, PAYERS, RESPONSE_TYPES } from "./types.js";
|
|
3
4
|
/**
|
|
4
5
|
* Signed documents of the Agent Work Subledger (PRD v1.2 §6, §16).
|
|
5
6
|
* Schema 1.3 adds closure `obligation_links`, the clearing-network claim asserters, and the `network_recorded` assurance label;
|
|
6
|
-
* 1.2 documents must use neither
|
|
7
|
+
* 1.2 documents must use neither. Schema 1.4 adds delegation `execution`, the response statement fields `execution`,
|
|
8
|
+
* `issued_at`, `expires_at` and `refs`, and the `expired` and `revoked` labels; 1.2 and 1.3 documents must use none
|
|
9
|
+
* of them (see packages/schema/COMPATIBILITY.md).
|
|
7
10
|
*/
|
|
8
|
-
export const SUBLEDGER_SCHEMA_VERSION = "1.
|
|
9
|
-
export const SUPPORTED_SUBLEDGER_SCHEMA_VERSIONS = ["1.2", "1.3"];
|
|
11
|
+
export const SUBLEDGER_SCHEMA_VERSION = "1.4";
|
|
12
|
+
export const SUPPORTED_SUBLEDGER_SCHEMA_VERSIONS = ["1.2", "1.3", "1.4"];
|
|
10
13
|
/** Must equal this package's version in package.json (checked by a test). */
|
|
11
|
-
export const SUBLEDGER_VERIFIER_VERSION = "1.
|
|
14
|
+
export const SUBLEDGER_VERIFIER_VERSION = "1.4.1";
|
|
12
15
|
export const RECEIPT_DOCUMENT_TYPE = "atcn.subledger.receipt";
|
|
13
16
|
export const CLOSURE_DOCUMENT_TYPE = "atcn.subledger.closure";
|
|
14
17
|
export const RESPONSE_STATEMENT_TYPE = "atcn.subledger.receipt_response";
|
|
@@ -120,6 +123,13 @@ export const ResponseStatementSchema = z.object({
|
|
|
120
123
|
note: z.string().max(2000).nullable(),
|
|
121
124
|
evidence: z.array(EvidenceRefSchema).max(20),
|
|
122
125
|
corrections: z.array(CorrectionSchema).max(20),
|
|
126
|
+
/** Schema 1.4: the run the statement is about; must match the delegation's recorded execution. */
|
|
127
|
+
execution: ExecutionBindingSchema.optional(),
|
|
128
|
+
/** Schema 1.4: when the provider signed. Required with expires_at or refs. */
|
|
129
|
+
issued_at: Iso.optional(),
|
|
130
|
+
expires_at: Iso.optional(),
|
|
131
|
+
/** Schema 1.4: earlier statements this one revokes (same provider only) or disputes, by statement digest. */
|
|
132
|
+
refs: z.array(AttestationRefSchema).max(20).optional(),
|
|
123
133
|
});
|
|
124
134
|
export const ResponseRecordSchema = z.object({
|
|
125
135
|
response_id: z.string(),
|
|
@@ -180,6 +190,8 @@ export const ReceiptPayloadSchema = z.object({
|
|
|
180
190
|
expected_delivery: Iso.nullable(),
|
|
181
191
|
retrospective: z.boolean(),
|
|
182
192
|
downstream_visibility: z.enum(["unknown", "disclosed", "none"]),
|
|
193
|
+
/** Schema 1.4, present only when recorded: the run a provider statement can cite. */
|
|
194
|
+
execution: ExecutionDescriptorSchema.optional(),
|
|
183
195
|
}),
|
|
184
196
|
provider: z.object({
|
|
185
197
|
provider_id: z.string().nullable(),
|
|
@@ -219,6 +231,8 @@ export const ClosureDelegationSchema = z.object({
|
|
|
219
231
|
delivery_status: z.string(),
|
|
220
232
|
retrospective: z.boolean(),
|
|
221
233
|
created_at: Iso,
|
|
234
|
+
/** Schema 1.4, present only when recorded, so older closures keep their bytes. */
|
|
235
|
+
execution: ExecutionDescriptorSchema.optional(),
|
|
222
236
|
});
|
|
223
237
|
export const AllocationRecordSchema = z.object({
|
|
224
238
|
allocation_id: z.string(),
|
package/dist/projection.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AttestationItem } from "@atcn/schema";
|
|
1
2
|
import { type Rollup } from "./rollup.js";
|
|
2
3
|
import { type AllocationRecord, type CaptureGap, type ClosureDelegation, type ClosurePayload, type DeliveryClaim, type Disclosure, type ExceptionRecord, type FieldState, type Issuer, type KeyBindingRecord, type ObligationLink, type ReceiptPayload, type ReceiptTotals, type ResponseRecord } from "./documents.js";
|
|
3
4
|
import { type AttestableField, type FinancialEventRecord } from "./types.js";
|
|
@@ -23,6 +24,10 @@ export type DelegationRecord = ClosureDelegation & {
|
|
|
23
24
|
};
|
|
24
25
|
/** Claims superseded by a later correction stay visible and gain the "superseded" label. */
|
|
25
26
|
export declare function labelClaims(claims: DeliveryClaim[]): DeliveryClaim[];
|
|
27
|
+
/** A response as an attestation. Only a key-signed statement has a signer, so only it can revoke or be revoked. */
|
|
28
|
+
export declare function responseAttestation(response: ResponseRecord): AttestationItem;
|
|
29
|
+
/** Recomputes the "expired" and "revoked" labels as of `at`. Revoked and expired responses stay visible. */
|
|
30
|
+
export declare function labelResponses(responses: ResponseRecord[], at: string): ResponseRecord[];
|
|
26
31
|
/** Delivery status is the latest non-superseded status claim. It is a recorded claim, not an adjudicated truth. */
|
|
27
32
|
export declare function deliveryStatus(claims: DeliveryClaim[]): string;
|
|
28
33
|
/** Totals for a single delegation's own events (no allocation detail, which may name other cost centers). */
|
package/dist/projection.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { digestOf } from "@atcn/schema";
|
|
1
|
+
import { digestOf, resolveAttestations } from "@atcn/schema";
|
|
2
2
|
import { computeRollup, costSign } from "./rollup.js";
|
|
3
3
|
import { CLOSURE_DOCUMENT_TYPE, RECEIPT_DOCUMENT_TYPE, SUBLEDGER_SCHEMA_VERSION, } from "./documents.js";
|
|
4
4
|
import { ATTESTABLE_FIELDS } from "./types.js";
|
|
@@ -7,6 +7,32 @@ export function labelClaims(claims) {
|
|
|
7
7
|
const superseded = new Set(claims.map((c) => c.supersedes_event_id).filter((id) => id !== null));
|
|
8
8
|
return claims.map((c) => (superseded.has(c.event_id) && !c.assurance.includes("superseded") ? { ...c, assurance: [...c.assurance, "superseded"] } : c));
|
|
9
9
|
}
|
|
10
|
+
/** A response as an attestation. Only a key-signed statement has a signer, so only it can revoke or be revoked. */
|
|
11
|
+
export function responseAttestation(response) {
|
|
12
|
+
const s = response.statement;
|
|
13
|
+
return {
|
|
14
|
+
digest: response.statement_digest,
|
|
15
|
+
signer: response.assurance.includes("provider_key_signed") ? response.provider_id : null,
|
|
16
|
+
issued_at: s.issued_at,
|
|
17
|
+
expires_at: s.expires_at,
|
|
18
|
+
refs: s.refs,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const TIME_LABELS = ["expired", "revoked"];
|
|
22
|
+
/** Recomputes the "expired" and "revoked" labels as of `at`. Revoked and expired responses stay visible. */
|
|
23
|
+
export function labelResponses(responses, at) {
|
|
24
|
+
const { status } = resolveAttestations(responses.map(responseAttestation), at);
|
|
25
|
+
return responses.map((r) => {
|
|
26
|
+
const kept = r.assurance.filter((label) => !TIME_LABELS.includes(label));
|
|
27
|
+
const added = [];
|
|
28
|
+
if (status[r.statement_digest].time === "expired")
|
|
29
|
+
added.push("expired");
|
|
30
|
+
if (status[r.statement_digest].revoked_by !== null)
|
|
31
|
+
added.push("revoked");
|
|
32
|
+
const assurance = [...kept, ...added];
|
|
33
|
+
return assurance.length === r.assurance.length && assurance.every((label, i) => label === r.assurance[i]) ? r : { ...r, assurance };
|
|
34
|
+
});
|
|
35
|
+
}
|
|
10
36
|
const STATUS_BY_CLAIM = {
|
|
11
37
|
acceptance: "accepted",
|
|
12
38
|
completion: "completed",
|
|
@@ -103,6 +129,7 @@ export function buildReceiptPayload(input) {
|
|
|
103
129
|
expected_delivery: d.expected_delivery,
|
|
104
130
|
retrospective: d.retrospective,
|
|
105
131
|
downstream_visibility: d.downstream_visibility,
|
|
132
|
+
...(d.execution ? { execution: d.execution } : {}),
|
|
106
133
|
},
|
|
107
134
|
provider: {
|
|
108
135
|
provider_id: input.provider?.provider_id ?? null,
|
|
@@ -205,7 +232,7 @@ export function buildClosurePayload(input) {
|
|
|
205
232
|
rollup: rollupFor(input.task, input.delegations, input.events, input.allocations),
|
|
206
233
|
open_exceptions: input.open_exceptions,
|
|
207
234
|
receipts: input.receipts,
|
|
208
|
-
responses: input.responses,
|
|
235
|
+
responses: labelResponses(input.responses, input.generated_at),
|
|
209
236
|
key_bindings: input.key_bindings,
|
|
210
237
|
lineage: {
|
|
211
238
|
complete: input.capture_gaps.length === 0,
|
package/dist/response.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AttestationRef, type ExecutionBinding } from "@atcn/schema";
|
|
1
2
|
import { type Correction, type ResponseStatement } from "./documents.js";
|
|
2
3
|
import type { AttestableField, EvidenceRef, ResponseType } from "./types.js";
|
|
3
4
|
export interface StatementInput {
|
|
@@ -12,6 +13,11 @@ export interface StatementInput {
|
|
|
12
13
|
note?: string | null;
|
|
13
14
|
evidence?: EvidenceRef[];
|
|
14
15
|
corrections?: Correction[];
|
|
16
|
+
/** Schema 1.4 fields. Each is left out of the statement when not given, so older statements keep their bytes. */
|
|
17
|
+
execution?: ExecutionBinding;
|
|
18
|
+
issued_at?: string;
|
|
19
|
+
expires_at?: string;
|
|
20
|
+
refs?: AttestationRef[];
|
|
15
21
|
}
|
|
16
22
|
/** Builds the statement a provider responds with. Field order is irrelevant: the signature covers canonical JSON. */
|
|
17
23
|
export declare function buildResponseStatement(input: StatementInput): ResponseStatement;
|
package/dist/response.js
CHANGED
|
@@ -13,6 +13,10 @@ export function buildResponseStatement(input) {
|
|
|
13
13
|
note: input.note ?? null,
|
|
14
14
|
evidence: input.evidence ?? [],
|
|
15
15
|
corrections: input.corrections ?? [],
|
|
16
|
+
...(input.execution !== undefined ? { execution: input.execution } : {}),
|
|
17
|
+
...(input.issued_at !== undefined ? { issued_at: input.issued_at } : {}),
|
|
18
|
+
...(input.expires_at !== undefined ? { expires_at: input.expires_at } : {}),
|
|
19
|
+
...(input.refs !== undefined ? { refs: input.refs } : {}),
|
|
16
20
|
};
|
|
17
21
|
}
|
|
18
22
|
export function statementDigest(statement) {
|
package/dist/types.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type ClaimAsserter = (typeof CLAIM_ASSERTERS)[number];
|
|
|
20
20
|
export declare const EXCEPTION_KINDS: readonly ["budget_overrun", "unmatched_charge", "ambiguous_match", "missing_receipt", "duplicate_event", "amount_mismatch", "currency_mismatch", "stale_quote", "refund_after_close", "allocation_changed_after_close", "incomplete_lineage"];
|
|
21
21
|
export type ExceptionKind = (typeof EXCEPTION_KINDS)[number];
|
|
22
22
|
/** Trust labels kept separate on every screen and export (PRD §16 "Identity assurance"). Never collapsed into "verified". */
|
|
23
|
-
export declare const ASSURANCE_LABELS: readonly ["issuer_signed", "buyer_recorded", "network_recorded", "recipient_viewed", "link_authenticated_response", "provider_identity_bound", "provider_key_signed", "contested", "superseded"];
|
|
23
|
+
export declare const ASSURANCE_LABELS: readonly ["issuer_signed", "buyer_recorded", "network_recorded", "recipient_viewed", "link_authenticated_response", "provider_identity_bound", "provider_key_signed", "contested", "superseded", "expired", "revoked"];
|
|
24
24
|
export type AssuranceLabel = (typeof ASSURANCE_LABELS)[number];
|
|
25
25
|
export declare const RESPONSE_TYPES: readonly ["acknowledge_view", "acknowledge_delivery", "submit_evidence", "propose_correction", "signed_attestation"];
|
|
26
26
|
export type ResponseType = (typeof RESPONSE_TYPES)[number];
|
|
@@ -76,6 +76,30 @@ export declare const DelegationInputSchema: z.ZodObject<{
|
|
|
76
76
|
none: "none";
|
|
77
77
|
}>>;
|
|
78
78
|
retrospective: z.ZodDefault<z.ZodBoolean>;
|
|
79
|
+
execution: z.ZodOptional<z.ZodObject<{
|
|
80
|
+
execution_id: z.ZodString;
|
|
81
|
+
protocol: z.ZodOptional<z.ZodObject<{
|
|
82
|
+
name: z.ZodLiteral<"a2a">;
|
|
83
|
+
task_id: z.ZodString;
|
|
84
|
+
context_id: z.ZodOptional<z.ZodString>;
|
|
85
|
+
}, z.core.$strip>>;
|
|
86
|
+
agent: z.ZodObject<{
|
|
87
|
+
agent_id: z.ZodString;
|
|
88
|
+
agent_version: z.ZodString;
|
|
89
|
+
card_digest: z.ZodOptional<z.ZodString>;
|
|
90
|
+
model: z.ZodOptional<z.ZodObject<{
|
|
91
|
+
provider: z.ZodString;
|
|
92
|
+
name: z.ZodString;
|
|
93
|
+
version: z.ZodString;
|
|
94
|
+
}, z.core.$strip>>;
|
|
95
|
+
config_digest: z.ZodOptional<z.ZodString>;
|
|
96
|
+
}, z.core.$strip>;
|
|
97
|
+
skill: z.ZodOptional<z.ZodObject<{
|
|
98
|
+
namespace: z.ZodString;
|
|
99
|
+
skill_id: z.ZodString;
|
|
100
|
+
agent_card_url: z.ZodOptional<z.ZodURL>;
|
|
101
|
+
}, z.core.$strip>>;
|
|
102
|
+
}, z.core.$strip>>;
|
|
79
103
|
}, z.core.$strip>;
|
|
80
104
|
export type DelegationInput = z.infer<typeof DelegationInputSchema>;
|
|
81
105
|
export declare const DelegationEventInputSchema: z.ZodObject<{
|
package/dist/types.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ExecutionDescriptorSchema } from "@atcn/schema";
|
|
1
2
|
import { z } from "zod";
|
|
2
3
|
/** Agent Work Subledger record shapes (PRD v1.2 §6-§7). Amounts are integer minor units; currencies are ISO 4217. */
|
|
3
4
|
export const Currency = z.string().regex(/^[A-Z]{3}$/, "ISO 4217 currency code");
|
|
@@ -41,6 +42,10 @@ export const ASSURANCE_LABELS = [
|
|
|
41
42
|
"provider_key_signed",
|
|
42
43
|
"contested",
|
|
43
44
|
"superseded",
|
|
45
|
+
/** A response statement past its signed expires_at at the document's time (schema 1.4). */
|
|
46
|
+
"expired",
|
|
47
|
+
/** A response statement revoked by a later statement from the same provider (schema 1.4). */
|
|
48
|
+
"revoked",
|
|
44
49
|
];
|
|
45
50
|
export const RESPONSE_TYPES = ["acknowledge_view", "acknowledge_delivery", "submit_evidence", "propose_correction", "signed_attestation"];
|
|
46
51
|
export const SHARE_ACTIONS = ["view", "acknowledge_delivery", "submit_evidence", "propose_correction", "signed_attestation"];
|
|
@@ -93,6 +98,8 @@ export const DelegationInputSchema = z.object({
|
|
|
93
98
|
/** Whether the provider disclosed its own subdelegations. Absent data stays "unknown" (acceptance 24). */
|
|
94
99
|
downstream_visibility: z.enum(["unknown", "disclosed", "none"]).default("unknown"),
|
|
95
100
|
retrospective: z.boolean().default(false),
|
|
101
|
+
/** The provider's run as the buyer recorded it (for A2A, from the task and agent card). Provider statements can cite it. */
|
|
102
|
+
execution: ExecutionDescriptorSchema.optional(),
|
|
96
103
|
});
|
|
97
104
|
export const DelegationEventInputSchema = z.object({
|
|
98
105
|
type: z.enum(DELIVERY_EVENT_TYPES),
|
package/dist/verify.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface SubledgerVerifyOptions {
|
|
|
23
23
|
requireOperatorSignature?: boolean;
|
|
24
24
|
/** Closure packages (GET /v1/exports/{obligation_id}) of the obligations backing linked delegations, to cross-check them. */
|
|
25
25
|
obligationPackages?: unknown[];
|
|
26
|
+
/** Time to check a receipt's expires_at against (ISO 8601). Defaults to now. */
|
|
27
|
+
at?: string;
|
|
26
28
|
}
|
|
27
29
|
/** Detects the document type and verifies it offline: no network calls, no service access (acceptance 9). */
|
|
28
30
|
export declare function verifySubledgerDocument(input: unknown, options: SubledgerVerifyOptions): SubledgerVerificationReport;
|
package/dist/verify.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { verifyClosurePackage } from "@atcn/core";
|
|
2
|
-
import { ClosurePackageSchema, digestOf, verifyPayload } from "@atcn/schema";
|
|
2
|
+
import { ClosurePackageSchema, digestOf, executionBinding, resolveAttestations, verifyPayload } from "@atcn/schema";
|
|
3
3
|
import { CLEARING_SOURCE, clearingFacts, settlementEvidence, undoneBatch } from "./bridge.js";
|
|
4
4
|
import { CLOSURE_DOCUMENT_TYPE, RECEIPT_DOCUMENT_TYPE, SignedClosureSchema, SignedReceiptSchema, SIGNED_BY_HOSTED_SERVICE, SUBLEDGER_VERIFIER_VERSION, SUPPORTED_SUBLEDGER_SCHEMA_VERSIONS, } from "./documents.js";
|
|
5
|
-
import { receiptTotals, rollupFor } from "./projection.js";
|
|
5
|
+
import { labelResponses, receiptTotals, responseAttestation, rollupFor } from "./projection.js";
|
|
6
6
|
import { verifyCountersignature, verifyStatementSignature } from "./response.js";
|
|
7
7
|
import { ATTESTABLE_FIELDS } from "./types.js";
|
|
8
8
|
const SERVICE_ACTOR = "svc_atcn";
|
|
@@ -65,8 +65,9 @@ function unsupportedVersion(documentType, input) {
|
|
|
65
65
|
const supported = SUPPORTED_SUBLEDGER_SCHEMA_VERSIONS;
|
|
66
66
|
if (supported.includes(version))
|
|
67
67
|
return null;
|
|
68
|
+
const versions = [...SUPPORTED_SUBLEDGER_SCHEMA_VERSIONS];
|
|
68
69
|
const detail = `unsupported schema_version ${String(version)}: this verifier (@atcn/subledger ${SUBLEDGER_VERIFIER_VERSION}) supports ` +
|
|
69
|
-
`${
|
|
70
|
+
`${versions.slice(0, -1).join(", ")} and ${versions.at(-1)}. Upgrade @atcn/verify-cli (or @atcn/subledger) to the minimum ` +
|
|
70
71
|
"version listed for this schema in packages/schema/COMPATIBILITY.md.";
|
|
71
72
|
return { valid: false, document_type: documentType, unsupported_schema_version: String(version), checks: [check("schema_version", [detail])] };
|
|
72
73
|
}
|
|
@@ -84,6 +85,24 @@ function versionFeatureProblems(version, signedBy, claims, hasObligationLinks) {
|
|
|
84
85
|
problems.push(`schema 1.2 does not allow signed_by ${signedBy}`);
|
|
85
86
|
return problems;
|
|
86
87
|
}
|
|
88
|
+
const SCHEMA_1_4_STATEMENT_FIELDS = ["execution", "issued_at", "expires_at", "refs"];
|
|
89
|
+
const SCHEMA_1_4_LABELS = ["expired", "revoked"];
|
|
90
|
+
/** A document that declares 1.2 or 1.3 must not carry 1.4 fields, which those verifiers would drop before checking signatures. */
|
|
91
|
+
function schema14Problems(version, delegations, responses, claims) {
|
|
92
|
+
if (version !== "1.2" && version !== "1.3")
|
|
93
|
+
return [];
|
|
94
|
+
const problems = delegations.filter((d) => d.execution !== undefined).map((d) => `schema ${version} does not allow execution on delegation ${d.delegation_id}`);
|
|
95
|
+
for (const r of responses) {
|
|
96
|
+
for (const field of SCHEMA_1_4_STATEMENT_FIELDS)
|
|
97
|
+
if (r.statement[field] !== undefined)
|
|
98
|
+
problems.push(`schema ${version} does not allow statement ${field} (response ${r.response_id})`);
|
|
99
|
+
}
|
|
100
|
+
for (const item of [...responses, ...claims]) {
|
|
101
|
+
for (const label of item.assurance.filter((l) => SCHEMA_1_4_LABELS.includes(l)))
|
|
102
|
+
problems.push(`schema ${version} does not allow assurance ${label}`);
|
|
103
|
+
}
|
|
104
|
+
return problems;
|
|
105
|
+
}
|
|
87
106
|
function reversalProblems(events) {
|
|
88
107
|
const byId = new Map(events.map((e) => [e.financial_event_id, e]));
|
|
89
108
|
const problems = [];
|
|
@@ -105,7 +124,10 @@ export function verifyReceipt(input, options) {
|
|
|
105
124
|
return schemaFailure(RECEIPT_DOCUMENT_TYPE, parsed.error.issues);
|
|
106
125
|
const doc = parsed.data;
|
|
107
126
|
const r = doc.payload;
|
|
108
|
-
const schemaProblems =
|
|
127
|
+
const schemaProblems = [
|
|
128
|
+
...versionFeatureProblems(r.schema_version, r.issuer.signed_by, r.delivery_claims, false),
|
|
129
|
+
...schema14Problems(r.schema_version, [r.delegation], [], r.delivery_claims),
|
|
130
|
+
];
|
|
109
131
|
const checks = [check("schema", schemaProblems), signatureCheck(doc, r.issued_at, options.trustedKeys), operatorSignatureCheck(r, r.issuer.operator_id, doc.operator_signatures, options)];
|
|
110
132
|
const events = r.financial_events.map(({ allocation_version: _version, ...e }) => ({ ...e, liability_owner: null, economic_event_id: null, fx: null }));
|
|
111
133
|
checks.push(check("reversals", reversalProblems(events)));
|
|
@@ -120,8 +142,17 @@ export function verifyReceipt(input, options) {
|
|
|
120
142
|
fieldProblems.push(`field_status is missing ${f}`);
|
|
121
143
|
checks.push(check("field_disclosure", fieldProblems));
|
|
122
144
|
checks.push(receiptChainCheck(r, options));
|
|
145
|
+
checks.push(receiptExpiryCheck(r, options.at ?? new Date().toISOString()));
|
|
123
146
|
return finish(RECEIPT_DOCUMENT_TYPE, checks);
|
|
124
147
|
}
|
|
148
|
+
/** The issuer signed expires_at, so a receipt past it no longer stands, even though its signature still verifies. */
|
|
149
|
+
function receiptExpiryCheck(r, at) {
|
|
150
|
+
if (r.expires_at === null)
|
|
151
|
+
return { name: "expiry", ok: true, details: ["no expiry"] };
|
|
152
|
+
if (Date.parse(at) >= Date.parse(r.expires_at))
|
|
153
|
+
return check("expiry", [`receipt expired at ${r.expires_at} (checked at ${at})`]);
|
|
154
|
+
return { name: "expiry", ok: true, details: [`valid until ${r.expires_at} (checked at ${at})`] };
|
|
155
|
+
}
|
|
125
156
|
function receiptChainCheck(r, options) {
|
|
126
157
|
if (r.revision === 1)
|
|
127
158
|
return check("revision_chain", r.previous_receipt_digest === null && r.previous_receipt_id === null ? [] : ["revision 1 must not reference a previous receipt"]);
|
|
@@ -155,7 +186,10 @@ export function verifyClosure(input, options) {
|
|
|
155
186
|
return schemaFailure(CLOSURE_DOCUMENT_TYPE, parsed.error.issues);
|
|
156
187
|
const doc = parsed.data;
|
|
157
188
|
const c = doc.payload;
|
|
158
|
-
const schemaProblems =
|
|
189
|
+
const schemaProblems = [
|
|
190
|
+
...versionFeatureProblems(c.schema_version, c.issuer.signed_by, c.delivery_claims, c.obligation_links !== undefined),
|
|
191
|
+
...schema14Problems(c.schema_version, c.delegations, c.responses, c.delivery_claims),
|
|
192
|
+
];
|
|
159
193
|
const checks = [check("schema", schemaProblems), signatureCheck(doc, c.generated_at, options.trustedKeys), operatorSignatureCheck(c, c.issuer.operator_id, doc.operator_signatures, options)];
|
|
160
194
|
const digestProblems = c.financial_events.filter((e) => digestOf(e.record) !== e.event_digest).map((e) => `event ${e.record.financial_event_id} digest mismatch`);
|
|
161
195
|
const ids = c.financial_events.map((e) => e.record.financial_event_id);
|
|
@@ -167,7 +201,7 @@ export function verifyClosure(input, options) {
|
|
|
167
201
|
checks.push(check("allocations", allocationProblems(c)));
|
|
168
202
|
const recomputed = rollupFor(c.task, c.delegations, c.financial_events, c.allocations);
|
|
169
203
|
checks.push(check("totals", digestOf(recomputed) === digestOf(c.rollup) ? [] : ["roll-up does not match events, attribution, and allocations"]));
|
|
170
|
-
checks.push(
|
|
204
|
+
checks.push(providerResponsesCheck(c));
|
|
171
205
|
checks.push(closureChainCheck(c, options));
|
|
172
206
|
checks.push(obligationLinkCheck(c, options));
|
|
173
207
|
return finish(CLOSURE_DOCUMENT_TYPE, checks);
|
|
@@ -309,12 +343,39 @@ function allocationProblems(c) {
|
|
|
309
343
|
}
|
|
310
344
|
return problems;
|
|
311
345
|
}
|
|
346
|
+
function providerResponsesCheck(c) {
|
|
347
|
+
const problems = responseProblems(c);
|
|
348
|
+
const notes = [];
|
|
349
|
+
const resolution = resolveAttestations(c.responses.map(responseAttestation), c.generated_at);
|
|
350
|
+
const responseIdOf = new Map(c.responses.map((r) => [r.statement_digest, r.response_id]));
|
|
351
|
+
for (const p of resolution.problems) {
|
|
352
|
+
const id = responseIdOf.get(p.digest);
|
|
353
|
+
if (p.code === "revocation_not_by_signer")
|
|
354
|
+
problems.push(`response ${id} revokes ${p.target}, which its provider key did not sign`);
|
|
355
|
+
else
|
|
356
|
+
notes.push(`response ${id} references ${p.target}, which is not in this closure`);
|
|
357
|
+
}
|
|
358
|
+
for (const r of c.responses) {
|
|
359
|
+
if (resolution.status[r.statement_digest].time === "not_yet_valid")
|
|
360
|
+
problems.push(`response ${r.response_id} was issued after the closure was generated`);
|
|
361
|
+
}
|
|
362
|
+
const expected = new Map(labelResponses(c.responses, c.generated_at).map((r) => [r.response_id, r.assurance]));
|
|
363
|
+
for (const r of c.responses) {
|
|
364
|
+
for (const label of SCHEMA_1_4_LABELS) {
|
|
365
|
+
const shouldHave = expected.get(r.response_id).includes(label);
|
|
366
|
+
if (shouldHave !== r.assurance.includes(label)) {
|
|
367
|
+
problems.push(`response ${r.response_id} ${shouldHave ? "lacks" : "carries"} assurance ${label}, which does not match its expiry and revocations at ${c.generated_at}`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return problems.length > 0 ? check("provider_responses", problems) : { name: "provider_responses", ok: true, details: notes };
|
|
372
|
+
}
|
|
312
373
|
function responseProblems(c) {
|
|
313
374
|
const problems = [];
|
|
314
375
|
const receipts = new Map(c.receipts.map((r) => [r.receipt_id, r]));
|
|
315
|
-
const
|
|
376
|
+
const delegations = new Map(c.delegations.map((d) => [d.delegation_id, d]));
|
|
316
377
|
for (const r of c.receipts)
|
|
317
|
-
if (!
|
|
378
|
+
if (!delegations.has(r.delegation_id))
|
|
318
379
|
problems.push(`receipt ${r.receipt_id} covers a delegation outside the task`);
|
|
319
380
|
for (const response of c.responses) {
|
|
320
381
|
const receipt = receipts.get(response.receipt_id);
|
|
@@ -330,6 +391,17 @@ function responseProblems(c) {
|
|
|
330
391
|
}
|
|
331
392
|
if (s.issuer_operator_id !== c.issuer.operator_id)
|
|
332
393
|
problems.push(`response ${response.response_id} names another issuer`);
|
|
394
|
+
if (s.issued_at === undefined && (s.expires_at !== undefined || s.refs !== undefined))
|
|
395
|
+
problems.push(`response ${response.response_id} needs issued_at with expires_at or refs`);
|
|
396
|
+
if (s.issued_at !== undefined && s.expires_at !== undefined && Date.parse(s.expires_at) <= Date.parse(s.issued_at))
|
|
397
|
+
problems.push(`response ${response.response_id} expires before it was issued`);
|
|
398
|
+
if (s.execution) {
|
|
399
|
+
const declared = delegations.get(receipt.delegation_id)?.execution;
|
|
400
|
+
if (!declared)
|
|
401
|
+
problems.push(`response ${response.response_id} cites run ${s.execution.execution_id}, but delegation ${receipt.delegation_id} records none`);
|
|
402
|
+
else if (digestOf(executionBinding(declared)) !== digestOf(s.execution))
|
|
403
|
+
problems.push(`response ${response.response_id} cites run ${s.execution.execution_id}, which is not the run recorded on delegation ${receipt.delegation_id}`);
|
|
404
|
+
}
|
|
333
405
|
const claimsKeySigned = response.assurance.includes("provider_key_signed");
|
|
334
406
|
if (!claimsKeySigned)
|
|
335
407
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atcn/subledger",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Agent Work Subledger: deterministic attribution, roll-up, exceptions, signed receipts and closures, and offline verification",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"build": "tsc -p tsconfig.build.json"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@atcn/core": "1.
|
|
37
|
-
"@atcn/schema": "1.
|
|
36
|
+
"@atcn/core": "1.4.1",
|
|
37
|
+
"@atcn/schema": "1.4.1",
|
|
38
38
|
"zod": "^4.1.0"
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -90,6 +90,63 @@
|
|
|
90
90
|
"canonical": "{\"corrections\":[{\"field\":\"delivery.status\",\"proposed_value\":\"partial_completion\",\"reason\":\"file 3 missing\"}],\"document_type\":\"atcn.subledger.receipt_response\",\"evidence\":[{\"digest\":null,\"evidence_type\":\"delivery_log\",\"uri\":\"https://provider.example/delivery/7\"}],\"fields\":[],\"issuer_operator_id\":\"ten_01J00000000000000000000001\",\"note\":\"café: two of three files\",\"receipt_digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"receipt_id\":\"rcp_01J00000000000000000000002\",\"receipt_revision\":1,\"response_type\":\"propose_correction\"}",
|
|
91
91
|
"digest": "sha256:633530c26ed9133457be0a7d4a1417f24c73dc17fcbd20f58901cfb462390e15",
|
|
92
92
|
"signature": "XKtJa41QABDVCDvyKIGqNejsQAvqHaKqh_yanIrNWPcehrnLCNW28L621ar__eHdqP2-64yvZnwbuJD0efi4Aw"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"input": {
|
|
96
|
+
"receipt": {
|
|
97
|
+
"receipt_id": "rcp_01J00000000000000000000003",
|
|
98
|
+
"digest": "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
|
99
|
+
"revision": 1,
|
|
100
|
+
"issuer_operator_id": "ten_01J00000000000000000000001"
|
|
101
|
+
},
|
|
102
|
+
"response_type": "signed_attestation",
|
|
103
|
+
"fields": [
|
|
104
|
+
"delivery.status"
|
|
105
|
+
],
|
|
106
|
+
"execution": {
|
|
107
|
+
"execution_id": "run_01J00000000000000000000001",
|
|
108
|
+
"execution_digest": "sha256:9e282402ebfefeb4924e034733742b7cd346b022313e3e7f5b77d93651d11952"
|
|
109
|
+
},
|
|
110
|
+
"issued_at": "2026-10-01T00:00:00.000Z",
|
|
111
|
+
"expires_at": "2026-11-01T00:00:00.000Z",
|
|
112
|
+
"refs": [
|
|
113
|
+
{
|
|
114
|
+
"relation": "revokes",
|
|
115
|
+
"attestation_digest": "sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
|
116
|
+
"reason": "attested the wrong run"
|
|
117
|
+
}
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
"statement": {
|
|
121
|
+
"document_type": "atcn.subledger.receipt_response",
|
|
122
|
+
"receipt_id": "rcp_01J00000000000000000000003",
|
|
123
|
+
"receipt_digest": "sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
|
124
|
+
"receipt_revision": 1,
|
|
125
|
+
"issuer_operator_id": "ten_01J00000000000000000000001",
|
|
126
|
+
"response_type": "signed_attestation",
|
|
127
|
+
"fields": [
|
|
128
|
+
"delivery.status"
|
|
129
|
+
],
|
|
130
|
+
"note": null,
|
|
131
|
+
"evidence": [],
|
|
132
|
+
"corrections": [],
|
|
133
|
+
"execution": {
|
|
134
|
+
"execution_id": "run_01J00000000000000000000001",
|
|
135
|
+
"execution_digest": "sha256:9e282402ebfefeb4924e034733742b7cd346b022313e3e7f5b77d93651d11952"
|
|
136
|
+
},
|
|
137
|
+
"issued_at": "2026-10-01T00:00:00.000Z",
|
|
138
|
+
"expires_at": "2026-11-01T00:00:00.000Z",
|
|
139
|
+
"refs": [
|
|
140
|
+
{
|
|
141
|
+
"relation": "revokes",
|
|
142
|
+
"attestation_digest": "sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
|
143
|
+
"reason": "attested the wrong run"
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
},
|
|
147
|
+
"canonical": "{\"corrections\":[],\"document_type\":\"atcn.subledger.receipt_response\",\"evidence\":[],\"execution\":{\"execution_digest\":\"sha256:9e282402ebfefeb4924e034733742b7cd346b022313e3e7f5b77d93651d11952\",\"execution_id\":\"run_01J00000000000000000000001\"},\"expires_at\":\"2026-11-01T00:00:00.000Z\",\"fields\":[\"delivery.status\"],\"issued_at\":\"2026-10-01T00:00:00.000Z\",\"issuer_operator_id\":\"ten_01J00000000000000000000001\",\"note\":null,\"receipt_digest\":\"sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd\",\"receipt_id\":\"rcp_01J00000000000000000000003\",\"receipt_revision\":1,\"refs\":[{\"attestation_digest\":\"sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\",\"reason\":\"attested the wrong run\",\"relation\":\"revokes\"}],\"response_type\":\"signed_attestation\"}",
|
|
148
|
+
"digest": "sha256:f4839d189a371531782b945d494462c209b57a9988344b149315d61772b3c81d",
|
|
149
|
+
"signature": "TgkbCF-2xoTAWDQJqGtiMMvQ26nliShYzU6mJbJhWD6Q-y35FlwNA9L4ijdne9whcouQCTxlI8sZIsR_KpJBCQ"
|
|
93
150
|
}
|
|
94
151
|
],
|
|
95
152
|
"countersignature": {
|
|
@@ -104,5 +161,33 @@
|
|
|
104
161
|
}
|
|
105
162
|
},
|
|
106
163
|
"signature": "jUnhhTUE28I9wdyO15cFLm1aB9Lo-3r6d1cif7HPFLDIvLr8GngoKNCYtlTftNwxP1b7ARBUkwLga-PywmFtBA"
|
|
164
|
+
},
|
|
165
|
+
"execution_binding": {
|
|
166
|
+
"descriptor": {
|
|
167
|
+
"execution_id": "run_01J00000000000000000000001",
|
|
168
|
+
"protocol": {
|
|
169
|
+
"name": "a2a",
|
|
170
|
+
"task_id": "task-7",
|
|
171
|
+
"context_id": "ctx-7"
|
|
172
|
+
},
|
|
173
|
+
"agent": {
|
|
174
|
+
"agent_id": "agt_01J00000000000000000000002",
|
|
175
|
+
"agent_version": "2.1.0",
|
|
176
|
+
"card_digest": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
|
|
177
|
+
"model": {
|
|
178
|
+
"provider": "example",
|
|
179
|
+
"name": "coder",
|
|
180
|
+
"version": "2026-09"
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"skill": {
|
|
184
|
+
"namespace": "a2a",
|
|
185
|
+
"skill_id": "code-fix"
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
"binding": {
|
|
189
|
+
"execution_id": "run_01J00000000000000000000001",
|
|
190
|
+
"execution_digest": "sha256:9e282402ebfefeb4924e034733742b7cd346b022313e3e7f5b77d93651d11952"
|
|
191
|
+
}
|
|
107
192
|
}
|
|
108
193
|
}
|