@primust/artifact-core 1.0.0 → 1.3.0

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 (62) hide show
  1. package/LICENSE +93 -0
  2. package/dist/canonical.d.ts +11 -0
  3. package/dist/canonical.d.ts.map +1 -1
  4. package/dist/canonical.js +92 -0
  5. package/dist/canonical.js.map +1 -1
  6. package/dist/commitment.d.ts +56 -8
  7. package/dist/commitment.d.ts.map +1 -1
  8. package/dist/commitment.js +71 -26
  9. package/dist/commitment.js.map +1 -1
  10. package/dist/commitment.test.js +14 -3
  11. package/dist/commitment.test.js.map +1 -1
  12. package/dist/hierarchical_leaf.d.ts +72 -0
  13. package/dist/hierarchical_leaf.d.ts.map +1 -0
  14. package/dist/hierarchical_leaf.js +144 -0
  15. package/dist/hierarchical_leaf.js.map +1 -0
  16. package/dist/hierarchical_leaf.test.d.ts +15 -0
  17. package/dist/hierarchical_leaf.test.d.ts.map +1 -0
  18. package/dist/hierarchical_leaf.test.js +145 -0
  19. package/dist/hierarchical_leaf.test.js.map +1 -0
  20. package/dist/index.d.ts +9 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +5 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/metadata_source.d.ts +4 -0
  25. package/dist/metadata_source.d.ts.map +1 -0
  26. package/dist/metadata_source.js +54 -0
  27. package/dist/metadata_source.js.map +1 -0
  28. package/dist/metadata_source.test.d.ts +2 -0
  29. package/dist/metadata_source.test.d.ts.map +1 -0
  30. package/dist/metadata_source.test.js +29 -0
  31. package/dist/metadata_source.test.js.map +1 -0
  32. package/dist/reversibility_taxonomy.d.ts +23 -0
  33. package/dist/reversibility_taxonomy.d.ts.map +1 -0
  34. package/dist/reversibility_taxonomy.js +208 -0
  35. package/dist/reversibility_taxonomy.js.map +1 -0
  36. package/dist/reversibility_taxonomy.test.d.ts +2 -0
  37. package/dist/reversibility_taxonomy.test.d.ts.map +1 -0
  38. package/dist/reversibility_taxonomy.test.js +146 -0
  39. package/dist/reversibility_taxonomy.test.js.map +1 -0
  40. package/dist/signing.d.ts.map +1 -1
  41. package/dist/signing.js +30 -6
  42. package/dist/signing.js.map +1 -1
  43. package/dist/trust_edge_mapping.d.ts +12 -0
  44. package/dist/trust_edge_mapping.d.ts.map +1 -0
  45. package/dist/trust_edge_mapping.js +88 -0
  46. package/dist/trust_edge_mapping.js.map +1 -0
  47. package/dist/trust_edge_mapping.test.d.ts +2 -0
  48. package/dist/trust_edge_mapping.test.d.ts.map +1 -0
  49. package/dist/trust_edge_mapping.test.js +86 -0
  50. package/dist/trust_edge_mapping.test.js.map +1 -0
  51. package/dist/types/artifact.d.ts +65 -4
  52. package/dist/types/artifact.d.ts.map +1 -1
  53. package/dist/types/proof_artifact.d.ts +52 -0
  54. package/dist/types/proof_artifact.d.ts.map +1 -0
  55. package/dist/types/proof_artifact.js +12 -0
  56. package/dist/types/proof_artifact.js.map +1 -0
  57. package/dist/validate-artifact.d.ts.map +1 -1
  58. package/dist/validate-artifact.js +88 -10
  59. package/dist/validate-artifact.js.map +1 -1
  60. package/dist/validate-artifact.test.js +16 -2
  61. package/dist/validate-artifact.test.js.map +1 -1
  62. package/package.json +13 -7
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Primust Artifact Core — Hierarchical-ZK Canonical Encoder (L13 P3)
3
+ *
4
+ * Implements the leaf encoders specified in
5
+ * `followup/L13_STEP3_HIERARCHICAL_ZK_LEAF_DESIGN.md` §3.6.
6
+ *
7
+ * This module is the language-independent encoding contract: TS (SDK +
8
+ * verifier) and Python (`primust-verify`) MUST produce byte-identical
9
+ * `poseidon2:<hex>` output for the same logical input. The parity test at
10
+ * §13 T-7 exercises shared fixtures against both implementations.
11
+ *
12
+ * No new crypto primitive is introduced — every step is a composition of
13
+ * `_bytesToFieldElements` + `_parseHashToField` + `_poseidon2Sponge` +
14
+ * the `poseidon2:` hex-format helper.
15
+ *
16
+ * Three leaf shapes are exposed:
17
+ *
18
+ * 1. `poseidon2HexRecordLeaf` (§4) — the 4-tuple per-record leaf hash
19
+ * (commitment_hash, check_result_u8, manifest_hash, sequence_index).
20
+ * Fed into `buildCommitmentRoot(record_leaves, 'poseidon2')` to
21
+ * obtain an action-unit's `action_unit_merkle_root`.
22
+ *
23
+ * 2. `poseidon2HexL1ActionUnitLeaf` (§3.1) — the 3-tuple action-unit
24
+ * leaf (action_unit_id, aggregated_result_u8, action_unit_merkle_root).
25
+ * Used as a run leaf when action_unit_count ≤ 64.
26
+ *
27
+ * 3. `poseidon2HexL2SuperUnitLeaf` (§3.2) — the 3-tuple super-unit
28
+ * leaf (super_unit_id, super_unit_aggregated_result_u8,
29
+ * super_unit_action_unit_merkle_root). Used as a run leaf when
30
+ * action_unit_count > 64. Identical math to L1; the circuit cannot
31
+ * tell L1 and L2 leaves apart.
32
+ */
33
+ /**
34
+ * Per-record leaf hash (§4). The 4-tuple feeds the per-action-unit
35
+ * Merkle fold whose root is the `action_unit_merkle_root` consumed by
36
+ * the L1/L2 leaf encoders below.
37
+ *
38
+ * Encoding (§3.6):
39
+ * elements = [
40
+ * parseHashToField(commitment_hash),
41
+ * BigInt(check_result_u8),
42
+ * parseHashToField(manifest_hash),
43
+ * BigInt(sequence_index),
44
+ * ]
45
+ * return 'poseidon2:' + sponge(elements).hex64
46
+ *
47
+ * @param commitmentHash must match `^(sha256|poseidon2):[0-9a-f]{64}$`.
48
+ * @param checkResultU8 0..255 (codec spec lives outside this module).
49
+ * @param manifestHash same shape as commitmentHash.
50
+ * @param sequenceIndex 0..BN254_MODULUS-1; bigint or number.
51
+ */
52
+ export declare function poseidon2HexRecordLeaf(commitmentHash: string, checkResultU8: number, manifestHash: string, sequenceIndex: bigint | number): string;
53
+ /**
54
+ * L1 action-unit leaf (§3.1). Used as a run leaf when
55
+ * action_unit_count ≤ 64.
56
+ *
57
+ * Encoding (§3.6):
58
+ * elements = concat(
59
+ * bytesToFieldElements(utf8(action_unit_id)),
60
+ * [BigInt(aggregated_result_u8)],
61
+ * [parseHashToField(action_unit_merkle_root)],
62
+ * )
63
+ * return 'poseidon2:' + sponge(elements).hex64
64
+ */
65
+ export declare function poseidon2HexL1ActionUnitLeaf(actionUnitId: string, aggregatedResultU8: number, actionUnitMerkleRoot: string): string;
66
+ /**
67
+ * L2 super-unit leaf (§3.2). Used as a run leaf when
68
+ * action_unit_count > 64. Identical math to L1; the circuit cannot
69
+ * distinguish the two leaf shapes.
70
+ */
71
+ export declare function poseidon2HexL2SuperUnitLeaf(superUnitId: string, superUnitAggregatedResultU8: number, superUnitActionUnitMerkleRoot: string): string;
72
+ //# sourceMappingURL=hierarchical_leaf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hierarchical_leaf.d.ts","sourceRoot":"","sources":["../src/hierarchical_leaf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAqEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GAAG,MAAM,GAC7B,MAAM,CAQR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,MAAM,EACpB,kBAAkB,EAAE,MAAM,EAC1B,oBAAoB,EAAE,MAAM,GAC3B,MAAM,CAOR;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,MAAM,EACnB,2BAA2B,EAAE,MAAM,EACnC,6BAA6B,EAAE,MAAM,GACpC,MAAM,CAOR"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Primust Artifact Core — Hierarchical-ZK Canonical Encoder (L13 P3)
3
+ *
4
+ * Implements the leaf encoders specified in
5
+ * `followup/L13_STEP3_HIERARCHICAL_ZK_LEAF_DESIGN.md` §3.6.
6
+ *
7
+ * This module is the language-independent encoding contract: TS (SDK +
8
+ * verifier) and Python (`primust-verify`) MUST produce byte-identical
9
+ * `poseidon2:<hex>` output for the same logical input. The parity test at
10
+ * §13 T-7 exercises shared fixtures against both implementations.
11
+ *
12
+ * No new crypto primitive is introduced — every step is a composition of
13
+ * `_bytesToFieldElements` + `_parseHashToField` + `_poseidon2Sponge` +
14
+ * the `poseidon2:` hex-format helper.
15
+ *
16
+ * Three leaf shapes are exposed:
17
+ *
18
+ * 1. `poseidon2HexRecordLeaf` (§4) — the 4-tuple per-record leaf hash
19
+ * (commitment_hash, check_result_u8, manifest_hash, sequence_index).
20
+ * Fed into `buildCommitmentRoot(record_leaves, 'poseidon2')` to
21
+ * obtain an action-unit's `action_unit_merkle_root`.
22
+ *
23
+ * 2. `poseidon2HexL1ActionUnitLeaf` (§3.1) — the 3-tuple action-unit
24
+ * leaf (action_unit_id, aggregated_result_u8, action_unit_merkle_root).
25
+ * Used as a run leaf when action_unit_count ≤ 64.
26
+ *
27
+ * 3. `poseidon2HexL2SuperUnitLeaf` (§3.2) — the 3-tuple super-unit
28
+ * leaf (super_unit_id, super_unit_aggregated_result_u8,
29
+ * super_unit_action_unit_merkle_root). Used as a run leaf when
30
+ * action_unit_count > 64. Identical math to L1; the circuit cannot
31
+ * tell L1 and L2 leaves apart.
32
+ */
33
+ import { BN254_MODULUS, _bytesToFieldElements, _parseHashToField, _poseidon2Sponge, } from './commitment.js';
34
+ // ── Helpers ──────────────────────────────────────────────────────────
35
+ /** Format a BN254 field element as a poseidon2-prefixed 64-hex commitment. */
36
+ function _poseidon2Hex(field) {
37
+ return 'poseidon2:' + field.toString(16).padStart(64, '0');
38
+ }
39
+ /** UTF-8 encode a string to bytes — wrapped so behavior is one line per call. */
40
+ const _utf8Encoder = new TextEncoder();
41
+ function _utf8(value) {
42
+ return _utf8Encoder.encode(value);
43
+ }
44
+ /** Encode an unsigned 8-bit value as a single field element. */
45
+ function _encodeU8(value, fieldName) {
46
+ if (!Number.isInteger(value) || value < 0 || value > 255) {
47
+ throw new Error(`${fieldName} must be an integer in [0, 255]; got ${value}`);
48
+ }
49
+ return BigInt(value);
50
+ }
51
+ /**
52
+ * Encode a u64 sequence index as a single field element.
53
+ *
54
+ * Rejects JS `number` values that are not safe integers — per t_62bc
55
+ * correctness HOLD on PR #363: `BigInt(unsafeNumber)` silently rounds
56
+ * the value BEFORE conversion (`9007199254740993` → `9007199254740992`
57
+ * because JS already lost the bit), so a Python caller that passes the
58
+ * exact integer would produce a different field element than a JS
59
+ * caller passing the same numeric literal. To preserve TS↔Python
60
+ * parity, the encoder requires either a `bigint` or a safe-integer
61
+ * `number`.
62
+ */
63
+ function _encodeU64(value, fieldName) {
64
+ if (typeof value === 'number') {
65
+ if (!Number.isInteger(value)) {
66
+ throw new Error(`${fieldName} must be an integer; got ${value}`);
67
+ }
68
+ if (!Number.isSafeInteger(value)) {
69
+ throw new Error(`${fieldName} number ${value} exceeds Number.MAX_SAFE_INTEGER ` +
70
+ `(${Number.MAX_SAFE_INTEGER}); pass a bigint to avoid silent ` +
71
+ 'rounding (TS↔Python parity)');
72
+ }
73
+ }
74
+ const v = typeof value === 'bigint' ? value : BigInt(value);
75
+ if (v < 0n)
76
+ throw new Error(`${fieldName} must be non-negative; got ${v}`);
77
+ if (v >= BN254_MODULUS) {
78
+ throw new Error(`${fieldName} must be < BN254_MODULUS; got ${v} (exceeds field)`);
79
+ }
80
+ return v;
81
+ }
82
+ // ── Public API ───────────────────────────────────────────────────────
83
+ /**
84
+ * Per-record leaf hash (§4). The 4-tuple feeds the per-action-unit
85
+ * Merkle fold whose root is the `action_unit_merkle_root` consumed by
86
+ * the L1/L2 leaf encoders below.
87
+ *
88
+ * Encoding (§3.6):
89
+ * elements = [
90
+ * parseHashToField(commitment_hash),
91
+ * BigInt(check_result_u8),
92
+ * parseHashToField(manifest_hash),
93
+ * BigInt(sequence_index),
94
+ * ]
95
+ * return 'poseidon2:' + sponge(elements).hex64
96
+ *
97
+ * @param commitmentHash must match `^(sha256|poseidon2):[0-9a-f]{64}$`.
98
+ * @param checkResultU8 0..255 (codec spec lives outside this module).
99
+ * @param manifestHash same shape as commitmentHash.
100
+ * @param sequenceIndex 0..BN254_MODULUS-1; bigint or number.
101
+ */
102
+ export function poseidon2HexRecordLeaf(commitmentHash, checkResultU8, manifestHash, sequenceIndex) {
103
+ const elements = [
104
+ _parseHashToField(commitmentHash),
105
+ _encodeU8(checkResultU8, 'checkResultU8'),
106
+ _parseHashToField(manifestHash),
107
+ _encodeU64(sequenceIndex, 'sequenceIndex'),
108
+ ];
109
+ return _poseidon2Hex(_poseidon2Sponge(elements));
110
+ }
111
+ /**
112
+ * L1 action-unit leaf (§3.1). Used as a run leaf when
113
+ * action_unit_count ≤ 64.
114
+ *
115
+ * Encoding (§3.6):
116
+ * elements = concat(
117
+ * bytesToFieldElements(utf8(action_unit_id)),
118
+ * [BigInt(aggregated_result_u8)],
119
+ * [parseHashToField(action_unit_merkle_root)],
120
+ * )
121
+ * return 'poseidon2:' + sponge(elements).hex64
122
+ */
123
+ export function poseidon2HexL1ActionUnitLeaf(actionUnitId, aggregatedResultU8, actionUnitMerkleRoot) {
124
+ const elements = [
125
+ ..._bytesToFieldElements(_utf8(actionUnitId)),
126
+ _encodeU8(aggregatedResultU8, 'aggregatedResultU8'),
127
+ _parseHashToField(actionUnitMerkleRoot),
128
+ ];
129
+ return _poseidon2Hex(_poseidon2Sponge(elements));
130
+ }
131
+ /**
132
+ * L2 super-unit leaf (§3.2). Used as a run leaf when
133
+ * action_unit_count > 64. Identical math to L1; the circuit cannot
134
+ * distinguish the two leaf shapes.
135
+ */
136
+ export function poseidon2HexL2SuperUnitLeaf(superUnitId, superUnitAggregatedResultU8, superUnitActionUnitMerkleRoot) {
137
+ const elements = [
138
+ ..._bytesToFieldElements(_utf8(superUnitId)),
139
+ _encodeU8(superUnitAggregatedResultU8, 'superUnitAggregatedResultU8'),
140
+ _parseHashToField(superUnitActionUnitMerkleRoot),
141
+ ];
142
+ return _poseidon2Hex(_poseidon2Sponge(elements));
143
+ }
144
+ //# sourceMappingURL=hierarchical_leaf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hierarchical_leaf.js","sourceRoot":"","sources":["../src/hierarchical_leaf.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * T-7 cross-language parity tests for the L13 P3 canonical encoder.
3
+ *
4
+ * The golden fixtures at `schemas/golden/hierarchical_leaf_vectors.json`
5
+ * are produced by the Python encoder and asserted byte-for-byte by both
6
+ * Python and TS test suites. A drift between TS and Python on any fixture
7
+ * means a sealed VPEC's verifier-side root recompute will diverge from the
8
+ * SDK-side root emission — i.e. proofs that the SDK generates will not
9
+ * verify.
10
+ *
11
+ * Per merged design doc:
12
+ * followup/L13_STEP3_HIERARCHICAL_ZK_LEAF_DESIGN.md §13 T-7.
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=hierarchical_leaf.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hierarchical_leaf.test.d.ts","sourceRoot":"","sources":["../src/hierarchical_leaf.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * T-7 cross-language parity tests for the L13 P3 canonical encoder.
3
+ *
4
+ * The golden fixtures at `schemas/golden/hierarchical_leaf_vectors.json`
5
+ * are produced by the Python encoder and asserted byte-for-byte by both
6
+ * Python and TS test suites. A drift between TS and Python on any fixture
7
+ * means a sealed VPEC's verifier-side root recompute will diverge from the
8
+ * SDK-side root emission — i.e. proofs that the SDK generates will not
9
+ * verify.
10
+ *
11
+ * Per merged design doc:
12
+ * followup/L13_STEP3_HIERARCHICAL_ZK_LEAF_DESIGN.md §13 T-7.
13
+ */
14
+ import { readFileSync } from 'node:fs';
15
+ import { resolve } from 'node:path';
16
+ import { describe, expect, it } from 'vitest';
17
+ import { BN254_MODULUS } from './commitment.js';
18
+ import { poseidon2HexL1ActionUnitLeaf, poseidon2HexL2SuperUnitLeaf, poseidon2HexRecordLeaf, } from './hierarchical_leaf.js';
19
+ // ── Fixture loading ──────────────────────────────────────────────────
20
+ const vectorsPath = resolve(__dirname, '../../../schemas/golden/hierarchical_leaf_vectors.json');
21
+ const VECTORS = JSON.parse(readFileSync(vectorsPath, 'utf-8'));
22
+ // ── record-leaf (§4 / §3.6) ──────────────────────────────────────────
23
+ describe('hierarchical_leaf / record leaf (§4)', () => {
24
+ for (const v of VECTORS.record_leaves) {
25
+ it(`golden vector — ${v.name}`, () => {
26
+ const actual = poseidon2HexRecordLeaf(v.inputs.commitment_hash, v.inputs.check_result_u8, v.inputs.manifest_hash, BigInt(v.inputs.sequence_index));
27
+ expect(actual).toBe(v.expected);
28
+ });
29
+ }
30
+ });
31
+ // ── L1 action-unit leaf (§3.1 / §3.6) ────────────────────────────────
32
+ describe('hierarchical_leaf / L1 action-unit leaf (§3.1)', () => {
33
+ for (const v of VECTORS.l1_action_unit_leaves) {
34
+ it(`golden vector — ${v.name}`, () => {
35
+ const actual = poseidon2HexL1ActionUnitLeaf(v.inputs.action_unit_id, v.inputs.aggregated_result_u8, v.inputs.action_unit_merkle_root);
36
+ expect(actual).toBe(v.expected);
37
+ });
38
+ }
39
+ });
40
+ // ── L2 super-unit leaf (§3.2 / §3.6) ─────────────────────────────────
41
+ describe('hierarchical_leaf / L2 super-unit leaf (§3.2)', () => {
42
+ for (const v of VECTORS.l2_super_unit_leaves) {
43
+ it(`golden vector — ${v.name}`, () => {
44
+ const actual = poseidon2HexL2SuperUnitLeaf(v.inputs.super_unit_id, v.inputs.super_unit_aggregated_result_u8, v.inputs.super_unit_action_unit_merkle_root);
45
+ expect(actual).toBe(v.expected);
46
+ });
47
+ }
48
+ });
49
+ // ── L1 / L2 indistinguishability invariant ───────────────────────────
50
+ describe('hierarchical_leaf / L1 == L2 indistinguishability (§3.2)', () => {
51
+ for (const v of VECTORS.l1_l2_indistinguishability) {
52
+ it(`circuit cannot distinguish L1 vs L2 — ${v.name}`, () => {
53
+ const l1 = poseidon2HexL1ActionUnitLeaf(v.inputs.id, v.inputs.result_u8, v.inputs.sub_root);
54
+ const l2 = poseidon2HexL2SuperUnitLeaf(v.inputs.id, v.inputs.result_u8, v.inputs.sub_root);
55
+ expect(l1).toBe(v.expected_l1);
56
+ expect(l2).toBe(v.expected_l2);
57
+ expect(l1).toBe(l2);
58
+ });
59
+ }
60
+ });
61
+ // ── Negative paths — input validation ────────────────────────────────
62
+ describe('hierarchical_leaf / validation', () => {
63
+ const VALID = 'poseidon2:' + 'a'.repeat(64);
64
+ it('rejects negative u8 in record leaf', () => {
65
+ expect(() => poseidon2HexRecordLeaf(VALID, -1, VALID, 0n)).toThrow(/checkResultU8/);
66
+ });
67
+ it('rejects u8 > 255 in record leaf', () => {
68
+ expect(() => poseidon2HexRecordLeaf(VALID, 256, VALID, 0n)).toThrow(/checkResultU8/);
69
+ });
70
+ it('rejects non-integer u8', () => {
71
+ expect(() => poseidon2HexRecordLeaf(VALID, 1.5, VALID, 0n)).toThrow(/checkResultU8/);
72
+ });
73
+ it('rejects negative sequence_index', () => {
74
+ expect(() => poseidon2HexRecordLeaf(VALID, 0, VALID, -1n)).toThrow(/sequenceIndex/);
75
+ });
76
+ it('rejects sequence_index overflowing BN254', () => {
77
+ expect(() => poseidon2HexRecordLeaf(VALID, 0, VALID, BN254_MODULUS)).toThrow(/sequenceIndex/);
78
+ });
79
+ it('rejects prefixless hash in L1 leaf', () => {
80
+ expect(() => poseidon2HexL1ActionUnitLeaf('au_x', 0, 'a'.repeat(64))).toThrow(/Invalid hash format/);
81
+ });
82
+ // t_62bc HOLD #2898 — unsafe-integer numeric sequenceIndex parity gap.
83
+ // JS BigInt() silently rounds a number above Number.MAX_SAFE_INTEGER
84
+ // BEFORE conversion, so the TS encoder would hash a different field
85
+ // element than the Python encoder for the same integer literal. The
86
+ // encoder must reject such values, forcing callers to pass a bigint.
87
+ it('rejects numeric sequenceIndex above Number.MAX_SAFE_INTEGER (T-7 parity gap)', () => {
88
+ // Number.MAX_SAFE_INTEGER + 2 is 9007199254740993 mathematically,
89
+ // but JS already loses the bit and stores it as 9007199254740992.
90
+ // The encoder must reject the value rather than silently encode
91
+ // the rounded number — Python would encode the exact integer
92
+ // 9007199254740993, so the TS↔Python parity breaks. The test
93
+ // demonstrates the encoder's rejection on a non-safe-integer
94
+ // numeric input.
95
+ const unsafe = Number.MAX_SAFE_INTEGER + 2;
96
+ expect(Number.isSafeInteger(unsafe)).toBe(false);
97
+ expect(() => poseidon2HexRecordLeaf(VALID, 0, VALID, unsafe)).toThrow(/exceeds Number\.MAX_SAFE_INTEGER|pass a bigint/);
98
+ });
99
+ it('rejects non-integer numeric sequenceIndex (defensive)', () => {
100
+ expect(() => poseidon2HexRecordLeaf(VALID, 0, VALID, 1.5)).toThrow(/must be an integer/);
101
+ });
102
+ it('accepts bigint sequenceIndex above Number.MAX_SAFE_INTEGER (parity path)', () => {
103
+ // The bigint path is the parity-correct way to encode a sequence
104
+ // index above 2**53-1 — TS encodes the exact field element, no
105
+ // rounding. (BN254_MODULUS upper bound still applies.)
106
+ const aboveSafe = BigInt(Number.MAX_SAFE_INTEGER) + 2n;
107
+ expect(() => poseidon2HexRecordLeaf(VALID, 0, VALID, aboveSafe)).not.toThrow();
108
+ });
109
+ });
110
+ // ── Encoding invariants spot-checks ──────────────────────────────────
111
+ describe('hierarchical_leaf / encoding invariants', () => {
112
+ const ROOT = 'poseidon2:' + '0'.repeat(64);
113
+ it('record leaf produces poseidon2:hex64 shape', () => {
114
+ const r = poseidon2HexRecordLeaf(ROOT, 0, ROOT, 0n);
115
+ expect(r.startsWith('poseidon2:')).toBe(true);
116
+ expect(r.length).toBe('poseidon2:'.length + 64);
117
+ });
118
+ it('L1 leaf produces poseidon2:hex64 shape', () => {
119
+ const r = poseidon2HexL1ActionUnitLeaf('au_x', 0, ROOT);
120
+ expect(r.startsWith('poseidon2:')).toBe(true);
121
+ expect(r.length).toBe('poseidon2:'.length + 64);
122
+ });
123
+ it('L2 leaf produces poseidon2:hex64 shape', () => {
124
+ const r = poseidon2HexL2SuperUnitLeaf('su_x', 0, ROOT);
125
+ expect(r.startsWith('poseidon2:')).toBe(true);
126
+ expect(r.length).toBe('poseidon2:'.length + 64);
127
+ });
128
+ it('record leaf is deterministic', () => {
129
+ const a = poseidon2HexRecordLeaf(ROOT, 4, ROOT, 42n);
130
+ const b = poseidon2HexRecordLeaf(ROOT, 4, ROOT, 42n);
131
+ expect(a).toBe(b);
132
+ });
133
+ it('different commitment_hash produces different leaf', () => {
134
+ const a = poseidon2HexRecordLeaf('sha256:' + 'a'.repeat(64), 0, ROOT, 0n);
135
+ const b = poseidon2HexRecordLeaf('sha256:' + 'b'.repeat(64), 0, ROOT, 0n);
136
+ expect(a).not.toBe(b);
137
+ });
138
+ it('sha256:HEX and poseidon2:HEX produce identical leaf (algorithm-agnostic-after-parse, per ZK ruling §3.2)', () => {
139
+ const hex = 'a'.repeat(64);
140
+ const a = poseidon2HexRecordLeaf('sha256:' + hex, 0, ROOT, 0n);
141
+ const b = poseidon2HexRecordLeaf('poseidon2:' + hex, 0, ROOT, 0n);
142
+ expect(a).toBe(b);
143
+ });
144
+ });
145
+ //# sourceMappingURL=hierarchical_leaf.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hierarchical_leaf.test.js","sourceRoot":"","sources":["../src/hierarchical_leaf.test.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,9 +1,17 @@
1
1
  export { canonical } from './canonical.js';
2
2
  export { generateKeyPair, sign, verify, rotateKey, toBase64Url, fromBase64Url } from './signing.js';
3
- export { commit, commitOutput, buildCommitmentRoot, selectProofLevel, ZK_IS_BLOCKING, } from './commitment.js';
3
+ export { commit, commitOutput, buildCommitmentRoot, selectProofLevel, ZK_IS_BLOCKING, BN254_MODULUS, } from './commitment.js';
4
4
  export type { CommitmentResult } from './commitment.js';
5
+ export { poseidon2HexRecordLeaf, poseidon2HexL1ActionUnitLeaf, poseidon2HexL2SuperUnitLeaf, } from './hierarchical_leaf.js';
5
6
  export { validateArtifact } from './validate-artifact.js';
6
7
  export type { ValidationError, ValidationResult } from './validate-artifact.js';
7
8
  export type { SignerRecord, SignatureEnvelope, KeyStatus, RevocationReason, SignerType, } from './types.js';
8
9
  export type { VPECArtifact, ProofLevel, SurfaceEntry, ProofDistribution, Coverage, GapEntry, ZkProof, ArtifactIssuer, ArtifactSignature, TimestampAnchor, TransparencyLog, PendingFlags, GapType, GapSeverity, SurfaceType, ObservationMode, ScopeType, PolicyBasis, ArtifactState, CommitmentAlgorithm, Prover, ProverSystem, TsaProvider, OrgRegion, } from './types/artifact.js';
10
+ export type { ProofArtifact, VerificationStatus } from './types/proof_artifact.js';
11
+ export { TAXONOMY_VERSION, REVERSIBILITY_CLASSES, isReversibilityClass, classify as classifyReversibility, isWedgeSurfaceCovered, } from './reversibility_taxonomy.js';
12
+ export type { ReversibilityClass, ClassifyOptions } from './reversibility_taxonomy.js';
13
+ export { MAPPING_VERSION, TRUST_EDGES, classify as classifyTrustEdge, knownKinds as knownTrustEdgeKinds, } from './trust_edge_mapping.js';
14
+ export type { TrustEdge } from './trust_edge_mapping.js';
15
+ export { METADATA_SOURCE_VALUES, isMetadataSource } from './metadata_source.js';
16
+ export type { MetadataSource } from './metadata_source.js';
9
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACpG,OAAO,EACL,MAAM,EACN,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,GACf,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAChF,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,gBAAgB,EAChB,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,YAAY,EACZ,OAAO,EACP,WAAW,EACX,WAAW,EACX,eAAe,EACf,SAAS,EACT,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,MAAM,EACN,YAAY,EACZ,WAAW,EACX,SAAS,GACV,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACpG,OAAO,EACL,MAAM,EACN,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,aAAa,GACd,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAChF,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,gBAAgB,EAChB,UAAU,GACX,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,YAAY,EACZ,OAAO,EACP,WAAW,EACX,WAAW,EACX,eAAe,EACf,SAAS,EACT,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,MAAM,EACN,YAAY,EACZ,WAAW,EACX,SAAS,GACV,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACpB,QAAQ,IAAI,qBAAqB,EACjC,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACvF,OAAO,EACL,eAAe,EACf,WAAW,EACX,QAAQ,IAAI,iBAAiB,EAC7B,UAAU,IAAI,mBAAmB,GAClC,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAChF,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  // @primust/artifact-core — Canonical JSON, hashing, signing, commitments, artifact types
2
2
  export { canonical } from './canonical.js';
3
3
  export { generateKeyPair, sign, verify, rotateKey, toBase64Url, fromBase64Url } from './signing.js';
4
- export { commit, commitOutput, buildCommitmentRoot, selectProofLevel, ZK_IS_BLOCKING, } from './commitment.js';
4
+ export { commit, commitOutput, buildCommitmentRoot, selectProofLevel, ZK_IS_BLOCKING, BN254_MODULUS, } from './commitment.js';
5
+ export { poseidon2HexRecordLeaf, poseidon2HexL1ActionUnitLeaf, poseidon2HexL2SuperUnitLeaf, } from './hierarchical_leaf.js';
5
6
  export { validateArtifact } from './validate-artifact.js';
7
+ export { TAXONOMY_VERSION, REVERSIBILITY_CLASSES, isReversibilityClass, classify as classifyReversibility, isWedgeSurfaceCovered, } from './reversibility_taxonomy.js';
8
+ export { MAPPING_VERSION, TRUST_EDGES, classify as classifyTrustEdge, knownKinds as knownTrustEdgeKinds, } from './trust_edge_mapping.js';
9
+ export { METADATA_SOURCE_VALUES, isMetadataSource } from './metadata_source.js';
6
10
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACpG,OAAO,EACL,MAAM,EACN,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,GACf,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACpG,OAAO,EACL,MAAM,EACN,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,sBAAsB,EACtB,4BAA4B,EAC5B,2BAA2B,GAC5B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAoC1D,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACpB,QAAQ,IAAI,qBAAqB,EACjC,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,eAAe,EACf,WAAW,EACX,QAAQ,IAAI,iBAAiB,EAC7B,UAAU,IAAI,mBAAmB,GAClC,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const METADATA_SOURCE_VALUES: readonly ["hook_observed", "sdk_decomposed", "sdk_caller_supplied", "hook_and_sdk_concordant"];
2
+ export type MetadataSource = (typeof METADATA_SOURCE_VALUES)[number];
3
+ export declare function isMetadataSource(value: unknown): value is MetadataSource;
4
+ //# sourceMappingURL=metadata_source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata_source.d.ts","sourceRoot":"","sources":["../src/metadata_source.ts"],"names":[],"mappings":"AAkCA,eAAO,MAAM,sBAAsB,gGAmBzB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AAErE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAIxE"}
@@ -0,0 +1,54 @@
1
+ // metadata_source enum — TypeScript sibling of
2
+ // `packages/primust-checks/src/primust_checks/metadata_source.py`.
3
+ //
4
+ // Single source of truth for the metadata_source CHECK enum on
5
+ // check_execution_records (migration 179) on the TS side.
6
+ //
7
+ // Each of the four values is a PRECISE, NARROW provenance claim —
8
+ // not a fallback ladder. The values' trust meaning depends on staying
9
+ // narrow.
10
+ //
11
+ // - 'hook_observed' — A runtime intercept (CC / Cursor / Anthropic
12
+ // Agent SDK lifecycle hook) saw this at the framework boundary.
13
+ // Substrate witness; strongest non-repudiation.
14
+ //
15
+ // - 'sdk_decomposed' — An SDK adapter derived the bounded metadata
16
+ // in-process (LLM quadruple, enforcement attribution, redaction).
17
+ // Adapter composition — observed and shaped, not relayed.
18
+ //
19
+ // - 'sdk_caller_supplied' — App code passed metadata args to
20
+ // run.record() and the SDK relayed without deriving or
21
+ // independently observing. Caller-as-source-of-truth. Honest,
22
+ // narrow; weaker evidence than hook_observed (no substrate
23
+ // witness) or sdk_decomposed (no adapter composition).
24
+ //
25
+ // - 'hook_and_sdk_concordant' — Both layers independently confirmed
26
+ // the same fact via the trace_context join (Phase 3+). Cross-
27
+ // checked; highest trust. Back-filled server-side.
28
+ //
29
+ // - NULL — RESERVED for legacy pre-179 rows and aggregator-emitted
30
+ // records with no single per-record derivation. No new emitter
31
+ // should land NULL. A NULL on a fresh record is an emitter bug.
32
+ //
33
+ // SI-1: enum-constrained string, never content.
34
+ export const METADATA_SOURCE_VALUES = [
35
+ // Runtime intercept saw the event at the framework boundary.
36
+ // Substrate witness; strongest non-repudiation.
37
+ 'hook_observed',
38
+ // SDK adapter derived the bounded metadata in-process (LLM
39
+ // quadruple, enforcement attribution, redaction). Adapter
40
+ // composition — observed and shaped, not relayed.
41
+ 'sdk_decomposed',
42
+ // App code passed metadata args to run.record() and the SDK
43
+ // relayed without deriving or independently observing. Honest,
44
+ // narrow; weaker than hook_observed / sdk_decomposed.
45
+ 'sdk_caller_supplied',
46
+ // Both layers independently confirmed the same fact via the
47
+ // trace_context join (Phase 3+). Cross-checked; highest trust.
48
+ // Back-filled server-side; never emitted directly by a single layer.
49
+ 'hook_and_sdk_concordant',
50
+ ];
51
+ export function isMetadataSource(value) {
52
+ return (typeof value === 'string' && METADATA_SOURCE_VALUES.includes(value));
53
+ }
54
+ //# sourceMappingURL=metadata_source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata_source.js","sourceRoot":"","sources":["../src/metadata_source.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,mEAAmE;AACnE,EAAE;AACF,+DAA+D;AAC/D,0DAA0D;AAC1D,EAAE;AACF,kEAAkE;AAClE,sEAAsE;AACtE,UAAU;AACV,EAAE;AACF,qEAAqE;AACrE,oEAAoE;AACpE,oDAAoD;AACpD,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,8DAA8D;AAC9D,EAAE;AACF,+DAA+D;AAC/D,2DAA2D;AAC3D,kEAAkE;AAClE,+DAA+D;AAC/D,2DAA2D;AAC3D,EAAE;AACF,sEAAsE;AACtE,kEAAkE;AAClE,uDAAuD;AACvD,EAAE;AACF,qEAAqE;AACrE,mEAAmE;AACnE,oEAAoE;AACpE,EAAE;AACF,gDAAgD;AAEhD,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,6DAA6D;IAC7D,gDAAgD;IAChD,eAAe;IAEf,2DAA2D;IAC3D,0DAA0D;IAC1D,kDAAkD;IAClD,gBAAgB;IAEhB,4DAA4D;IAC5D,+DAA+D;IAC/D,sDAAsD;IACtD,qBAAqB;IAErB,4DAA4D;IAC5D,+DAA+D;IAC/D,qEAAqE;IACrE,yBAAyB;CACjB,CAAC;AAIX,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ,IAAK,sBAA4C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC3F,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=metadata_source.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata_source.test.d.ts","sourceRoot":"","sources":["../src/metadata_source.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { METADATA_SOURCE_VALUES, isMetadataSource } from './metadata_source.js';
3
+ describe('metadata_source', () => {
4
+ it('has exactly the four canonical values from migration 179', () => {
5
+ expect(new Set(METADATA_SOURCE_VALUES)).toEqual(new Set([
6
+ 'hook_observed',
7
+ 'sdk_decomposed',
8
+ 'sdk_caller_supplied',
9
+ 'hook_and_sdk_concordant',
10
+ ]));
11
+ });
12
+ it('isMetadataSource accepts all four enum strings', () => {
13
+ for (const v of METADATA_SOURCE_VALUES) {
14
+ expect(isMetadataSource(v)).toBe(true);
15
+ }
16
+ });
17
+ it('rejects unknown strings (including the distinct `source` enum)', () => {
18
+ expect(isMetadataSource('garbage')).toBe(false);
19
+ expect(isMetadataSource('hook')).toBe(false); // bare 'hook' is `source`, not metadata_source
20
+ expect(isMetadataSource('sdk')).toBe(false);
21
+ });
22
+ it('rejects non-strings', () => {
23
+ expect(isMetadataSource(null)).toBe(false);
24
+ expect(isMetadataSource(42)).toBe(false);
25
+ expect(isMetadataSource([])).toBe(false);
26
+ expect(isMetadataSource({ value: 'hook_observed' })).toBe(false);
27
+ });
28
+ });
29
+ //# sourceMappingURL=metadata_source.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata_source.test.js","sourceRoot":"","sources":["../src/metadata_source.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAEhF,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,IAAI,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAC7C,IAAI,GAAG,CAAC;YACN,eAAe;YACf,gBAAgB;YAChB,qBAAqB;YACrB,yBAAyB;SAC1B,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,KAAK,MAAM,CAAC,IAAI,sBAAsB,EAAE,CAAC;YACvC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,+CAA+C;QAC7F,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,gBAAgB,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ export declare const TAXONOMY_VERSION: "1.0.0";
2
+ export declare const REVERSIBILITY_CLASSES: readonly ["reversible", "append_only", "external_side_effect", "irreversible", "unknown"];
3
+ export type ReversibilityClass = (typeof REVERSIBILITY_CLASSES)[number];
4
+ export declare function isReversibilityClass(v: unknown): v is ReversibilityClass;
5
+ export interface ClassifyOptions {
6
+ overrides?: Record<string, string>;
7
+ }
8
+ /**
9
+ * Classify an outbound action by `(target_system_kind, operation)`.
10
+ *
11
+ * Lookup order:
12
+ * 1. Customer override for the exact (kind, op) pair.
13
+ * 2. System default for the exact (kind, op) pair.
14
+ * 3. Per-kind fallback.
15
+ * 4. `'unknown'`.
16
+ */
17
+ export declare function classify(target_system_kind: string, operation: string, options?: ClassifyOptions): ReversibilityClass;
18
+ /**
19
+ * True if this kind has real (non-`'unknown'`) classifications in the
20
+ * system defaults. Used by the Phase 1 acceptance gate.
21
+ */
22
+ export declare function isWedgeSurfaceCovered(target_system_kind: string): boolean;
23
+ //# sourceMappingURL=reversibility_taxonomy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversibility_taxonomy.d.ts","sourceRoot":"","sources":["../src/reversibility_taxonomy.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,gBAAgB,EAAG,OAAgB,CAAC;AAEjD,eAAO,MAAM,qBAAqB,2FAMxB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAGxE,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,kBAAkB,CAExE;AAgKD,MAAM,WAAW,eAAe;IAI9B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CACtB,kBAAkB,EAAE,MAAM,EAC1B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,eAAoB,GAC5B,kBAAkB,CAcpB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAMzE"}