hachure 0.6.0 → 0.8.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.
@@ -0,0 +1,149 @@
1
+ {
2
+ "$comment": "Hand-derivation (merge.md §7c; status-function.md Steps 1-4). Both claims share subjectType/subjectId ('resource'/'svc-1') and fieldOrBehavior ('granted') -> same canonical claim (§4). Both bundles carry the identical policy 'policy.access-check.basic' (byte-identical in both -> unioning it is not a collision), which additionally declares incompatibleStatuses covering ['verified','disputed'] purely as an illustration that this does NOT by itself flip either claim's status (§7c) -- neither this vector's expect block nor status-function.md's fold reads incompatibleStatuses at all; it only affects the report layer, out of scope here (§9). No ids collide across the two bundles -> collisions is empty. Fold for producer-a's claim: latestEvent is 'producer-a.event.access.verified' (status 'verified', not terminal, skip Steps 2-3) -> Step 4 applies. 4a: claim has no expiresAt/ttlSeconds, policy validityRule.kind='duration', durationDays=30, verifiedAt=2026-06-01T00:00:00Z, now=2026-06-10T00:00:00Z -> 9 days elapsed < 30 -> not stale. 4b: entailing evidence (supportStrength defaults to 'entails' on both evidence items) = [producer-a.evidence.access.pass, producer-a.evidence.access.fail]; their evidenceType set {source_excerpt} and method set {observation} both satisfy policy.requiredEvidence=['source_excerpt']/requiredMethods=['observation']; requiresCorroboration=false -> no gap. 4c: 'producer-a.evidence.access.fail' has passing=false and blocking=true, observedAt=2026-06-05 (after the verified event) -> blocking failure found -> return 'disputed'. Fold for producer-b's claim: latestEvent is 'producer-b.event.access.verified' (status 'verified') -> Step 4. 4a: verifiedAt=2026-06-02T00:00:00Z, now=2026-06-10T00:00:00Z -> 8 days < 30 -> not stale. 4b: entailing evidence = [producer-b.evidence.access.pass], evidenceType {source_excerpt}, method {observation} -> satisfies policy -> no gap. 4c: the one evidence item has no 'passing:false' entry (passing is absent) -> no blocking failure -> 4d: return 'verified'. This demonstrates merge does not let producer-b's 'verified' overwrite or suppress producer-a's independently-derived 'disputed', and vice versa.",
3
+ "now": "2026-06-10T00:00:00.000Z",
4
+ "inputs": [
5
+ {
6
+ "schemaVersion": 4,
7
+ "source": "producer-a:run-3",
8
+ "producerId": "producer-a",
9
+ "claims": [
10
+ {
11
+ "id": "producer-a.claim.access.grant",
12
+ "subjectType": "resource",
13
+ "subjectId": "svc-1",
14
+ "surface": "access",
15
+ "claimType": "access-check",
16
+ "fieldOrBehavior": "granted",
17
+ "value": true,
18
+ "createdAt": "2026-06-01T00:00:00.000Z",
19
+ "updatedAt": "2026-06-01T00:00:00.000Z"
20
+ }
21
+ ],
22
+ "evidence": [
23
+ {
24
+ "id": "producer-a.evidence.access.pass",
25
+ "claimId": "producer-a.claim.access.grant",
26
+ "evidenceType": "source_excerpt",
27
+ "method": "observation",
28
+ "sourceRef": "source A: access log",
29
+ "excerptOrSummary": "Access granted.",
30
+ "observedAt": "2026-06-01T00:00:00.000Z",
31
+ "collectedBy": "agent-a"
32
+ },
33
+ {
34
+ "id": "producer-a.evidence.access.fail",
35
+ "claimId": "producer-a.claim.access.grant",
36
+ "evidenceType": "source_excerpt",
37
+ "method": "observation",
38
+ "sourceRef": "source A2: revocation log",
39
+ "excerptOrSummary": "Access revocation observed after original grant.",
40
+ "observedAt": "2026-06-05T00:00:00.000Z",
41
+ "collectedBy": "agent-a",
42
+ "passing": false,
43
+ "blocking": true
44
+ }
45
+ ],
46
+ "policies": [
47
+ {
48
+ "id": "policy.access-check.basic",
49
+ "claimType": "access-check",
50
+ "requiredEvidence": ["source_excerpt"],
51
+ "requiredMethods": ["observation"],
52
+ "requiresCorroboration": false,
53
+ "acceptanceCriteria": ["access confirmed from source"],
54
+ "reviewAuthority": "operator",
55
+ "validityRule": { "kind": "duration", "durationDays": 30 },
56
+ "stalenessTriggers": [],
57
+ "conflictRules": [],
58
+ "impactLevel": "medium",
59
+ "incompatibleStatuses": [
60
+ { "statuses": ["verified", "disputed"], "message": "conflicting access status across producers" }
61
+ ]
62
+ }
63
+ ],
64
+ "events": [
65
+ {
66
+ "id": "producer-a.event.access.verified",
67
+ "claimId": "producer-a.claim.access.grant",
68
+ "status": "verified",
69
+ "actor": "operator-a",
70
+ "method": "attestation",
71
+ "evidenceIds": ["producer-a.evidence.access.pass"],
72
+ "createdAt": "2026-06-01T00:00:00.000Z",
73
+ "verifiedAt": "2026-06-01T00:00:00.000Z"
74
+ }
75
+ ]
76
+ },
77
+ {
78
+ "schemaVersion": 4,
79
+ "source": "producer-b:run-4",
80
+ "producerId": "producer-b",
81
+ "claims": [
82
+ {
83
+ "id": "producer-b.claim.access.grant",
84
+ "subjectType": "resource",
85
+ "subjectId": "svc-1",
86
+ "surface": "access",
87
+ "claimType": "access-check",
88
+ "fieldOrBehavior": "granted",
89
+ "value": true,
90
+ "createdAt": "2026-06-02T00:00:00.000Z",
91
+ "updatedAt": "2026-06-02T00:00:00.000Z"
92
+ }
93
+ ],
94
+ "evidence": [
95
+ {
96
+ "id": "producer-b.evidence.access.pass",
97
+ "claimId": "producer-b.claim.access.grant",
98
+ "evidenceType": "source_excerpt",
99
+ "method": "observation",
100
+ "sourceRef": "source B: access log",
101
+ "excerptOrSummary": "Access granted, confirmed.",
102
+ "observedAt": "2026-06-02T00:00:00.000Z",
103
+ "collectedBy": "agent-b"
104
+ }
105
+ ],
106
+ "policies": [
107
+ {
108
+ "id": "policy.access-check.basic",
109
+ "claimType": "access-check",
110
+ "requiredEvidence": ["source_excerpt"],
111
+ "requiredMethods": ["observation"],
112
+ "requiresCorroboration": false,
113
+ "acceptanceCriteria": ["access confirmed from source"],
114
+ "reviewAuthority": "operator",
115
+ "validityRule": { "kind": "duration", "durationDays": 30 },
116
+ "stalenessTriggers": [],
117
+ "conflictRules": [],
118
+ "impactLevel": "medium",
119
+ "incompatibleStatuses": [
120
+ { "statuses": ["verified", "disputed"], "message": "conflicting access status across producers" }
121
+ ]
122
+ }
123
+ ],
124
+ "events": [
125
+ {
126
+ "id": "producer-b.event.access.verified",
127
+ "claimId": "producer-b.claim.access.grant",
128
+ "status": "verified",
129
+ "actor": "operator-b",
130
+ "method": "attestation",
131
+ "evidenceIds": ["producer-b.evidence.access.pass"],
132
+ "createdAt": "2026-06-02T00:00:00.000Z",
133
+ "verifiedAt": "2026-06-02T00:00:00.000Z"
134
+ }
135
+ ]
136
+ }
137
+ ],
138
+ "expect": {
139
+ "mergedClaimIds": [
140
+ "producer-a.claim.access.grant",
141
+ "producer-b.claim.access.grant"
142
+ ],
143
+ "collisions": [],
144
+ "statusByClaimId": {
145
+ "producer-a.claim.access.grant": "disputed",
146
+ "producer-b.claim.access.grant": "verified"
147
+ }
148
+ }
149
+ }
@@ -0,0 +1,100 @@
1
+ {
2
+ "$comment": "Hand-derivation (merge.md §4/§5/§7b; status-function.md Step 7). Both claims share subjectType/subjectId ('repo'/'repo-2') and fieldOrBehavior ('tier'), no qualifiers -> same canonical claim key (§4). Values 'gold' (producer-a) and 'silver' (producer-b) are not deep-equal, and both bundles reference the identical policy 'policy.pricing-field.tier-conflict', which declares incompatibleValues covering ['gold','silver'] -> this is a value conflict (§7b): both claims MUST be retained (mergedClaimIds has both distinct ids); the conflict itself surfaces only as a report-layer contradiction transparency gap, which is out of this vector format's scope (merge.md §9) and does NOT affect either claim's own status computation. The policy object is byte-identical in both bundles under the same id, so unioning it is not a collision (merge.md §5 rule 2) -> collisions is empty. Status-function.md fold, per claim: no verification event in either bundle (skip Steps 1-5); a policy IS resolved (claimType 'pricing-field' matches) so Step 6 ('no policy') does not apply; Step 7 applies ('policy present, no verification event'): producer-a's claim has one entailing evidence item with evidenceType 'source_excerpt', so its evidence-type set is {source_excerpt}, which is a superset of policy.requiredEvidence=['source_excerpt'] -> 'proposed'. producer-b's claim has no evidence at all, so its evidence-type set is {} which does NOT contain 'source_excerpt' -> 'unknown'. The two claims resolve to different statuses purely from their own attached evidence, independent of the value conflict between them.",
3
+ "now": "2026-06-10T00:00:00.000Z",
4
+ "inputs": [
5
+ {
6
+ "schemaVersion": 4,
7
+ "source": "producer-a:run-2",
8
+ "producerId": "producer-a",
9
+ "claims": [
10
+ {
11
+ "id": "producer-a.claim.pricing.tier",
12
+ "subjectType": "repo",
13
+ "subjectId": "repo-2",
14
+ "surface": "pricing",
15
+ "claimType": "pricing-field",
16
+ "fieldOrBehavior": "tier",
17
+ "value": "gold",
18
+ "createdAt": "2026-06-01T00:00:00.000Z",
19
+ "updatedAt": "2026-06-01T00:00:00.000Z"
20
+ }
21
+ ],
22
+ "evidence": [
23
+ {
24
+ "id": "producer-a.evidence.tier.source",
25
+ "claimId": "producer-a.claim.pricing.tier",
26
+ "evidenceType": "source_excerpt",
27
+ "method": "observation",
28
+ "sourceRef": "source A: internal pricing sheet",
29
+ "excerptOrSummary": "Tier is gold.",
30
+ "observedAt": "2026-06-01T00:00:00.000Z",
31
+ "collectedBy": "crawler-a"
32
+ }
33
+ ],
34
+ "policies": [
35
+ {
36
+ "id": "policy.pricing-field.tier-conflict",
37
+ "claimType": "pricing-field",
38
+ "requiredEvidence": ["source_excerpt"],
39
+ "acceptanceCriteria": ["tier confirmed by source"],
40
+ "reviewAuthority": "operator",
41
+ "validityRule": { "kind": "historical" },
42
+ "stalenessTriggers": [],
43
+ "conflictRules": [],
44
+ "impactLevel": "medium",
45
+ "incompatibleValues": [
46
+ { "values": ["gold", "silver"], "message": "tier values conflict across producers" }
47
+ ]
48
+ }
49
+ ],
50
+ "events": []
51
+ },
52
+ {
53
+ "schemaVersion": 4,
54
+ "source": "producer-b:run-9",
55
+ "producerId": "producer-b",
56
+ "claims": [
57
+ {
58
+ "id": "producer-b.claim.pricing.tier",
59
+ "subjectType": "repo",
60
+ "subjectId": "repo-2",
61
+ "surface": "pricing",
62
+ "claimType": "pricing-field",
63
+ "fieldOrBehavior": "tier",
64
+ "value": "silver",
65
+ "createdAt": "2026-06-02T00:00:00.000Z",
66
+ "updatedAt": "2026-06-02T00:00:00.000Z"
67
+ }
68
+ ],
69
+ "evidence": [],
70
+ "policies": [
71
+ {
72
+ "id": "policy.pricing-field.tier-conflict",
73
+ "claimType": "pricing-field",
74
+ "requiredEvidence": ["source_excerpt"],
75
+ "acceptanceCriteria": ["tier confirmed by source"],
76
+ "reviewAuthority": "operator",
77
+ "validityRule": { "kind": "historical" },
78
+ "stalenessTriggers": [],
79
+ "conflictRules": [],
80
+ "impactLevel": "medium",
81
+ "incompatibleValues": [
82
+ { "values": ["gold", "silver"], "message": "tier values conflict across producers" }
83
+ ]
84
+ }
85
+ ],
86
+ "events": []
87
+ }
88
+ ],
89
+ "expect": {
90
+ "mergedClaimIds": [
91
+ "producer-a.claim.pricing.tier",
92
+ "producer-b.claim.pricing.tier"
93
+ ],
94
+ "collisions": [],
95
+ "statusByClaimId": {
96
+ "producer-a.claim.pricing.tier": "proposed",
97
+ "producer-b.claim.pricing.tier": "unknown"
98
+ }
99
+ }
100
+ }
package/index.mjs CHANGED
@@ -11,6 +11,13 @@
11
11
  * vectors. Each vector has `input`, `expect`, and
12
12
  * `now` fields; run them against your implementation
13
13
  * to claim conformance.
14
+ * conformanceManifest — structured object describing conformance levels
15
+ * (L1 schema-valid, L2 status vectors, L3 merge
16
+ * vectors), which files satisfy each, and the
17
+ * schemaVersion/statusFunctionVersion it applies
18
+ * to. Parsed from conformance/manifest.json.
19
+ * Distinct from testVectors: this describes what
20
+ * passing means, testVectors is the raw fixtures.
14
21
  */
15
22
 
16
23
  import { readFileSync, readdirSync } from 'node:fs';
@@ -50,7 +57,9 @@ function loadTestVectors() {
50
57
  const conformanceDir = join(__dirname, 'conformance');
51
58
  const vectors = [];
52
59
  for (const file of readdirSync(conformanceDir).sort()) {
53
- if (!file.endsWith('.json')) continue;
60
+ // manifest.json is structured metadata (see conformanceManifest below),
61
+ // not a { now, input, expect } test vector — excluded here.
62
+ if (!file.endsWith('.json') || file === 'manifest.json') continue;
54
63
  const name = basename(file, '.json');
55
64
  const vector = JSON.parse(readFileSync(join(conformanceDir, file), 'utf8'));
56
65
  vectors.push({ name, vector });
@@ -59,3 +68,15 @@ function loadTestVectors() {
59
68
  }
60
69
 
61
70
  export const testVectors = loadTestVectors();
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // Conformance manifest — structured levels/requirements, distinct from the
74
+ // raw testVectors list above. See conformance/manifest.json and
75
+ // conformance/README.md for the human-readable pointer.
76
+ // ---------------------------------------------------------------------------
77
+ function loadConformanceManifest() {
78
+ const manifestPath = join(__dirname, 'conformance', 'manifest.json');
79
+ return JSON.parse(readFileSync(manifestPath, 'utf8'));
80
+ }
81
+
82
+ export const conformanceManifest = loadConformanceManifest();
@@ -2,6 +2,7 @@
2
2
 
3
3
  **Module:** `@kontourai/surface` — `src/interop/in-toto.ts`
4
4
  **Public exports:** `toInTotoStatement`, `toDsseEnvelope`, `buildPaeBytes`, `parseDssePayload`
5
+ **Conformance language:** MUST/SHOULD/MAY keywords in this document are to be interpreted per RFC 2119/BCP 14, as defined in [README.md's Conformance language section](README.md#conformance-language).
5
6
 
6
7
  ---
7
8