@oxdeai/conformance 1.3.0 → 2.0.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 (51) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/LICENSE +213 -0
  3. package/README.md +217 -5
  4. package/dist/evidence-metadata.json +3489 -0
  5. package/dist/scripts/build-evidence-metadata.d.mts +1 -0
  6. package/dist/scripts/build-evidence-metadata.mjs +7 -0
  7. package/dist/scripts/build-evidence-metadata.mjs.map +1 -0
  8. package/dist/scripts/extract-vectors.js +228 -22
  9. package/dist/scripts/extract-vectors.js.map +1 -1
  10. package/dist/src/evidenceScope.d.mts +68 -0
  11. package/dist/src/evidenceScope.mjs +127 -0
  12. package/dist/src/evidenceScope.mjs.map +1 -0
  13. package/dist/src/fixtures/conformance-engine-secret.fixture.d.ts +5 -0
  14. package/dist/src/fixtures/conformance-engine-secret.fixture.js +7 -0
  15. package/dist/src/fixtures/conformance-engine-secret.fixture.js.map +1 -0
  16. package/dist/src/fixtures/ed25519.test-only.fixture.d.ts +1 -1
  17. package/dist/src/fixtures/ed25519.test-only.fixture.js +2 -1
  18. package/dist/src/fixtures/ed25519.test-only.fixture.js.map +1 -1
  19. package/dist/src/fixtures/krl-ed25519.test-only.fixture.d.ts +13 -0
  20. package/dist/src/fixtures/krl-ed25519.test-only.fixture.js +19 -0
  21. package/dist/src/fixtures/krl-ed25519.test-only.fixture.js.map +1 -0
  22. package/dist/src/trustedTimeConformance.d.ts +32 -0
  23. package/dist/src/trustedTimeConformance.js +484 -0
  24. package/dist/src/trustedTimeConformance.js.map +1 -0
  25. package/dist/src/validate-trusted-time.d.ts +1 -0
  26. package/dist/src/validate-trusted-time.js +14 -0
  27. package/dist/src/validate-trusted-time.js.map +1 -0
  28. package/dist/src/validate.d.ts +1 -0
  29. package/dist/src/validate.js +723 -31
  30. package/dist/src/validate.js.map +1 -1
  31. package/package.json +37 -12
  32. package/vectors/audit-chain.json +2 -2
  33. package/vectors/authorization-payload.json +46 -34
  34. package/vectors/authorization-signature-verification.json +39 -1
  35. package/vectors/authorization-verification.json +54 -1
  36. package/vectors/clock-semantics-verification.json +136 -0
  37. package/vectors/delegation-chain-verification.json +366 -0
  38. package/vectors/delegation-parent-hash.json +54 -0
  39. package/vectors/delegation-signature-verification.json +317 -0
  40. package/vectors/delegation-verification.json +252 -0
  41. package/vectors/envelope-verification.json +3 -3
  42. package/vectors/key-lifecycle-verification.json +131 -0
  43. package/vectors/profile-c-state-verification.json +217 -0
  44. package/vectors/signed-krl-verification.json +103 -0
  45. package/vectors/trusted-time.json +50 -0
  46. package/dist/extract-vectors.js +0 -416
  47. package/scripts/extract-vectors.ts +0 -466
  48. package/src/fixtures/README.md +0 -11
  49. package/src/fixtures/ed25519.test-only.fixture.ts +0 -14
  50. package/src/validate.ts +0 -828
  51. package/tsconfig.json +0 -14
@@ -0,0 +1,131 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "description": "Key lifecycle conformance vectors for AuthorizationV1. Exercises keyIsActiveAt, findKeyInKeySets, and AUTH_KEY_INACTIVE / AUTH_KID_UNKNOWN enforcement. Verification time is KL_VERIFY_NOW = 1730000010. Key windows use KL_PAST = 1729992800 (2h before) and KL_FUTURE = 1730007200 (2h after).",
4
+ "vectors": [
5
+ {
6
+ "id": "key-lifecycle-001",
7
+ "description": "Active key, no time constraints. Key found, keyIsActiveAt returns true. Signature verifies. Expected: ok.",
8
+ "mode": "key-active",
9
+ "expected": {
10
+ "status": "ok",
11
+ "violations": []
12
+ }
13
+ },
14
+ {
15
+ "id": "key-lifecycle-002",
16
+ "description": "Revoked key. status=revoked causes keyIsActiveAt to return false immediately, regardless of time window. Expected: AUTH_KEY_INACTIVE.",
17
+ "mode": "key-revoked",
18
+ "expected": {
19
+ "status": "invalid",
20
+ "violations": [
21
+ {
22
+ "code": "AUTH_KEY_INACTIVE",
23
+ "message": "key is not active at verification time"
24
+ }
25
+ ]
26
+ }
27
+ },
28
+ {
29
+ "id": "key-lifecycle-003",
30
+ "description": "Key not yet active: not_before is in the future (KL_FUTURE > KL_VERIFY_NOW). keyIsActiveAt returns false. Expected: AUTH_KEY_INACTIVE.",
31
+ "mode": "key-not-before-future",
32
+ "expected": {
33
+ "status": "invalid",
34
+ "violations": [
35
+ {
36
+ "code": "AUTH_KEY_INACTIVE",
37
+ "message": "key is not active at verification time"
38
+ }
39
+ ]
40
+ }
41
+ },
42
+ {
43
+ "id": "key-lifecycle-004",
44
+ "description": "Key validity window expired: not_after is in the past (KL_PAST < KL_VERIFY_NOW). keyIsActiveAt returns false. Expected: AUTH_KEY_INACTIVE.",
45
+ "mode": "key-not-after-past",
46
+ "expected": {
47
+ "status": "invalid",
48
+ "violations": [
49
+ {
50
+ "code": "AUTH_KEY_INACTIVE",
51
+ "message": "key is not active at verification time"
52
+ }
53
+ ]
54
+ }
55
+ },
56
+ {
57
+ "id": "key-lifecycle-005",
58
+ "description": "Key within valid time window: not_before=KL_PAST, not_after=KL_FUTURE. Both bounds satisfied at KL_VERIFY_NOW. keyIsActiveAt returns true. Expected: ok.",
59
+ "mode": "key-valid-window",
60
+ "expected": {
61
+ "status": "ok",
62
+ "violations": []
63
+ }
64
+ },
65
+ {
66
+ "id": "key-lifecycle-006",
67
+ "description": "Key window fully expired: not_before=KL_PAST-3600, not_after=KL_PAST. not_after < KL_VERIFY_NOW. keyIsActiveAt returns false. Expected: AUTH_KEY_INACTIVE.",
68
+ "mode": "key-expired-window",
69
+ "expected": {
70
+ "status": "invalid",
71
+ "violations": [
72
+ {
73
+ "code": "AUTH_KEY_INACTIVE",
74
+ "message": "key is not active at verification time"
75
+ }
76
+ ]
77
+ }
78
+ },
79
+ {
80
+ "id": "key-lifecycle-007",
81
+ "description": "Retired key within validity window: status=retired, not_before=KL_PAST, not_after=KL_FUTURE. Retired keys are accepted during dual-sign overlap window. keyIsActiveAt returns true. Expected: ok.",
82
+ "mode": "key-retired-within-window",
83
+ "expected": {
84
+ "status": "ok",
85
+ "violations": []
86
+ }
87
+ },
88
+ {
89
+ "id": "key-lifecycle-008",
90
+ "description": "Retired key past validity window: status=retired, not_after=KL_PAST. Retirement window has closed. keyIsActiveAt returns false. Expected: AUTH_KEY_INACTIVE.",
91
+ "mode": "key-retired-past-window",
92
+ "expected": {
93
+ "status": "invalid",
94
+ "violations": [
95
+ {
96
+ "code": "AUTH_KEY_INACTIVE",
97
+ "message": "key is not active at verification time"
98
+ }
99
+ ]
100
+ }
101
+ },
102
+ {
103
+ "id": "key-lifecycle-009",
104
+ "description": "Revoked key with otherwise-valid time window: status=revoked, not_before=KL_PAST, not_after=KL_FUTURE. Revocation takes precedence over time bounds. keyIsActiveAt returns false immediately. Expected: AUTH_KEY_INACTIVE.",
105
+ "mode": "key-revoked-valid-window",
106
+ "expected": {
107
+ "status": "invalid",
108
+ "violations": [
109
+ {
110
+ "code": "AUTH_KEY_INACTIVE",
111
+ "message": "key is not active at verification time"
112
+ }
113
+ ]
114
+ }
115
+ },
116
+ {
117
+ "id": "key-lifecycle-010",
118
+ "description": "Known issuer, wrong kid: trustedKeySets contains the correct issuer but a different kid. findKeyInKeySets returns undefined. Expected: AUTH_KID_UNKNOWN.",
119
+ "mode": "wrong-kid-known-issuer",
120
+ "expected": {
121
+ "status": "invalid",
122
+ "violations": [
123
+ {
124
+ "code": "AUTH_KID_UNKNOWN",
125
+ "message": "kid not found for issuer/alg"
126
+ }
127
+ ]
128
+ }
129
+ }
130
+ ]
131
+ }
@@ -0,0 +1,217 @@
1
+ {
2
+ "description": "Portable Profile C state-hash semantics vectors for cross-language conformance (Go, Python). Modes 001–005 require only canonicalization-v1 and SHA-256. Modes 006–008 additionally require AuthorizationV1 Encoding B signature verification (alg='ed25519', expires_at, base64url signature, no domain prefix). The authoritative source for this corpus is docs/spec/test-vectors/profile-c-state-verification.json; packages/conformance/vectors/profile-c-state-verification.json is its generated secondary projection for package consumers.",
3
+ "encoding_b_notes": {
4
+ "alg": "ed25519 (lowercase — Sift-compatible Encoding B)",
5
+ "expiry_field": "expires_at (not expiry — Encoding B wire format)",
6
+ "signature_encoding": "base64url (RFC 4648 §5, no padding)",
7
+ "signing_payload": "All auth fields except signature.sig. signature becomes { alg, kid } with sig excluded.",
8
+ "signing_preimage": "canonicalJson(signingPayload) — NO domain prefix. Different from SignedKRLV1 which uses 'OXDEAI_KRL_V1\\n' prefix."
9
+ },
10
+ "hash_strategies": {
11
+ "core": "SHA-256(canonicalJson(state)) — standard OxDeAI state hash",
12
+ "provider": "SHA-256('PROVIDER:' + canonicalJson(state)) — simulates external provider algorithm",
13
+ "throws": "Simulates a computeStateHash failure; harness must return outcome 'compute-error' without computing any hash"
14
+ },
15
+ "outcomes": {
16
+ "compute-error": "computeStateHash threw — execution blocked fail-closed",
17
+ "ok": "Committed hash equals live-state hash — Profile C step 10 passes",
18
+ "state-hash-mismatch": "Committed hash does not equal live-state hash — Profile C step 10 blocks execution"
19
+ },
20
+ "portable": true,
21
+ "profile": "C",
22
+ "vectors": [
23
+ {
24
+ "description": "Core strategy: same state at signing and verification — hashes are identical, outcome ok.",
25
+ "expected": {
26
+ "status": "ok"
27
+ },
28
+ "hash_strategy": "core",
29
+ "id": "profile-c-001",
30
+ "mode": "live-state-match",
31
+ "state_input": {
32
+ "period": "p1",
33
+ "spent": 0
34
+ }
35
+ },
36
+ {
37
+ "description": "Core strategy: live state has advanced since signing — hashes differ, outcome state-hash-mismatch.",
38
+ "expected": {
39
+ "reason": "computeStateHash(liveState) does not equal authorization.state_hash",
40
+ "status": "state-hash-mismatch"
41
+ },
42
+ "hash_strategy": "core",
43
+ "id": "profile-c-002",
44
+ "live_state_input": {
45
+ "period": "p1",
46
+ "spent": 500000
47
+ },
48
+ "mode": "live-state-mismatch",
49
+ "state_input": {
50
+ "period": "p1",
51
+ "spent": 0
52
+ }
53
+ },
54
+ {
55
+ "description": "Provider hash committed at signing; core hash used at verification. Even with the same state, hashes differ — outcome state-hash-mismatch. Models a missing or wrong computeStateHash configuration.",
56
+ "expected": {
57
+ "reason": "provider hash committed; Core strategy used at verification produces a different hash",
58
+ "status": "state-hash-mismatch"
59
+ },
60
+ "id": "profile-c-003",
61
+ "mode": "hash-strategy-mismatch",
62
+ "signing_strategy": "provider",
63
+ "state_input": {
64
+ "period": "p1",
65
+ "spent": 0
66
+ },
67
+ "verify_strategy": "core"
68
+ },
69
+ {
70
+ "description": "computeStateHash throws — execution blocked fail-closed. Harness must return compute-error without computing any hash.",
71
+ "expected": {
72
+ "reason": "computeStateHash threw; execution blocked fail-closed",
73
+ "status": "compute-error"
74
+ },
75
+ "hash_strategy": "throws",
76
+ "id": "profile-c-004",
77
+ "mode": "compute-throws"
78
+ },
79
+ {
80
+ "description": "TOCTOU / stale state: authorization issued against an earlier state; live state has advanced to a different period and higher spend. Core hash of live state does not match committed hash — outcome state-hash-mismatch.",
81
+ "expected": {
82
+ "reason": "TOCTOU: live state has advanced since authorization was issued",
83
+ "status": "state-hash-mismatch"
84
+ },
85
+ "hash_strategy": "core",
86
+ "id": "profile-c-005",
87
+ "live_state_input": {
88
+ "period": "p2",
89
+ "spent": 5000000
90
+ },
91
+ "mode": "toctou-stale-state",
92
+ "state_input": {
93
+ "period": "p1",
94
+ "spent": 0
95
+ }
96
+ },
97
+ {
98
+ "auth": {
99
+ "audience": "merchant-gateway",
100
+ "auth_id": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
101
+ "decision": "ALLOW",
102
+ "expires_at": 1730000060,
103
+ "intent_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
104
+ "issued_at": 1730000000,
105
+ "issuer": "oxdeai.policy-engine",
106
+ "policy_id": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
107
+ "signature": {
108
+ "alg": "ed25519",
109
+ "kid": "2026-01",
110
+ "sig": "jMyip7h-GMgl2nV_q8Cz-MuqbD4vgba6vseRejY13e-w8WZeW7UU7ft58JHJFJR0fyZ3NGXvjJBGeKSSJLThCA"
111
+ },
112
+ "state_hash": "6a3b184144ed303c66357aa212d7432be648b5a2b3b0d56974bc91ca7a6732c7"
113
+ },
114
+ "description": "Encoding B AuthorizationV1 (alg='ed25519', expires_at, base64url sig) + provider hash strategy, matching state. Harness: (1) verify Encoding B signature independently, (2) compute committedHash=providerHash(state_input), cross-check with auth.state_hash, (3) liveHash=providerHash(state_input) — same, outcome ok.",
115
+ "expected": {
116
+ "status": "ok"
117
+ },
118
+ "hash_strategy": "provider",
119
+ "id": "profile-c-006",
120
+ "mode": "encoding-b-live-state-match",
121
+ "opts": {
122
+ "now": 1730000010,
123
+ "trustedKey": {
124
+ "alg": "Ed25519",
125
+ "kid": "2026-01",
126
+ "public_key": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAWiMMGTYK7zzHwZXLzDpCshxAH6Lgx8gVsJaixePuY7g=\n-----END PUBLIC KEY-----"
127
+ }
128
+ },
129
+ "state_input": {
130
+ "period": "p1",
131
+ "spent": 0
132
+ }
133
+ },
134
+ {
135
+ "auth": {
136
+ "audience": "merchant-gateway",
137
+ "auth_id": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
138
+ "decision": "ALLOW",
139
+ "expires_at": 1730000060,
140
+ "intent_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
141
+ "issued_at": 1730000000,
142
+ "issuer": "oxdeai.policy-engine",
143
+ "policy_id": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
144
+ "signature": {
145
+ "alg": "ed25519",
146
+ "kid": "2026-01",
147
+ "sig": "jMyip7h-GMgl2nV_q8Cz-MuqbD4vgba6vseRejY13e-w8WZeW7UU7ft58JHJFJR0fyZ3NGXvjJBGeKSSJLThCA"
148
+ },
149
+ "state_hash": "6a3b184144ed303c66357aa212d7432be648b5a2b3b0d56974bc91ca7a6732c7"
150
+ },
151
+ "description": "Encoding B AuthorizationV1 + provider hash strategy, stale state. Signature verifies. committedHash=providerHash({period:p1,spent:0}), liveHash=providerHash({period:p1,spent:250000}) — mismatch, outcome state-hash-mismatch.",
152
+ "expected": {
153
+ "reason": "Encoding B auth: live state mismatch detected at Profile C step 10",
154
+ "status": "state-hash-mismatch"
155
+ },
156
+ "hash_strategy": "provider",
157
+ "id": "profile-c-007",
158
+ "live_state_input": {
159
+ "period": "p1",
160
+ "spent": 250000
161
+ },
162
+ "mode": "encoding-b-live-state-mismatch",
163
+ "opts": {
164
+ "now": 1730000010,
165
+ "trustedKey": {
166
+ "alg": "Ed25519",
167
+ "kid": "2026-01",
168
+ "public_key": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAWiMMGTYK7zzHwZXLzDpCshxAH6Lgx8gVsJaixePuY7g=\n-----END PUBLIC KEY-----"
169
+ }
170
+ },
171
+ "state_input": {
172
+ "period": "p1",
173
+ "spent": 0
174
+ }
175
+ },
176
+ {
177
+ "auth": {
178
+ "audience": "merchant-gateway",
179
+ "auth_id": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
180
+ "decision": "ALLOW",
181
+ "expires_at": 1730000060,
182
+ "intent_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
183
+ "issued_at": 1730000000,
184
+ "issuer": "oxdeai.policy-engine",
185
+ "policy_id": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
186
+ "signature": {
187
+ "alg": "ed25519",
188
+ "kid": "2026-01",
189
+ "sig": "jMyip7h-GMgl2nV_q8Cz-MuqbD4vgba6vseRejY13e-w8WZeW7UU7ft58JHJFJR0fyZ3NGXvjJBGeKSSJLThCA"
190
+ },
191
+ "state_hash": "6a3b184144ed303c66357aa212d7432be648b5a2b3b0d56974bc91ca7a6732c7"
192
+ },
193
+ "description": "Encoding B AuthorizationV1 + hash strategy mismatch: provider committed, core used for live verification. Signature verifies. committedHash=providerHash(state_input), liveHash=coreHash(state_input) — different algorithms, mismatch, outcome state-hash-mismatch.",
194
+ "expected": {
195
+ "reason": "Encoding B auth: computeStateHash strategy mismatch produces different hash",
196
+ "status": "state-hash-mismatch"
197
+ },
198
+ "id": "profile-c-008",
199
+ "mode": "encoding-b-hash-strategy-mismatch",
200
+ "opts": {
201
+ "now": 1730000010,
202
+ "trustedKey": {
203
+ "alg": "Ed25519",
204
+ "kid": "2026-01",
205
+ "public_key": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAWiMMGTYK7zzHwZXLzDpCshxAH6Lgx8gVsJaixePuY7g=\n-----END PUBLIC KEY-----"
206
+ }
207
+ },
208
+ "signing_strategy": "provider",
209
+ "state_input": {
210
+ "period": "p1",
211
+ "spent": 0
212
+ },
213
+ "verify_strategy": "core"
214
+ }
215
+ ],
216
+ "version": "1.1.0"
217
+ }
@@ -0,0 +1,103 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "description": "SignedKRLV1 verification conformance vectors. Artifacts are built dynamically by the validator using the KRL fixture key (krl-ed25519.test-only.fixture.ts, kid: krl-2026-01, issuer: krl.issuer). Fixed timestamps: KRL_T_ISSUED=1730000000, KRL_T_NOT_AFTER=1730003600, verify now=1730000010.",
4
+ "vectors": [
5
+ {
6
+ "id": "krl-001",
7
+ "mode": "valid",
8
+ "description": "Valid signed KRL — signature verifies, not expired, no regression",
9
+ "expected": {
10
+ "status": "ok",
11
+ "violations": []
12
+ }
13
+ },
14
+ {
15
+ "id": "krl-002",
16
+ "mode": "invalid-signature",
17
+ "description": "Tampered signature (last 4 bytes replaced) — Ed25519 verification fails",
18
+ "expected": {
19
+ "status": "invalid",
20
+ "violations": [
21
+ { "code": "KRL_SIG_INVALID", "message": "Ed25519 signature verification failed" }
22
+ ]
23
+ }
24
+ },
25
+ {
26
+ "id": "krl-003",
27
+ "mode": "expired",
28
+ "description": "Verification time is not_after + 1 — strict zero-tolerance expiry fires",
29
+ "expected": {
30
+ "status": "invalid",
31
+ "violations": [
32
+ { "code": "KRL_EXPIRED", "message": "KRL has expired" }
33
+ ]
34
+ }
35
+ },
36
+ {
37
+ "id": "krl-004",
38
+ "mode": "malformed-revoked-kids",
39
+ "description": "revoked_kids is a string, not an array — structural malformation",
40
+ "expected": {
41
+ "status": "invalid",
42
+ "violations": [
43
+ { "code": "KRL_MALFORMED", "message": "revoked_kids must be an array of strings" }
44
+ ]
45
+ }
46
+ },
47
+ {
48
+ "id": "krl-005",
49
+ "mode": "duplicate-revoked-kids",
50
+ "description": "revoked_kids contains [\"kid-1\", \"kid-1\"] — producers must deduplicate; verifier rejects",
51
+ "expected": {
52
+ "status": "invalid",
53
+ "violations": [
54
+ { "code": "KRL_MALFORMED", "message": "duplicate entry in revoked_kids" }
55
+ ]
56
+ }
57
+ },
58
+ {
59
+ "id": "krl-006",
60
+ "mode": "unknown-signing-kid",
61
+ "description": "signature.kid tampered to \"unknown-kid\" after signing — not found in trusted key sets",
62
+ "expected": {
63
+ "status": "invalid",
64
+ "violations": [
65
+ { "code": "KRL_UNKNOWN_SIGNING_KID", "message": "KRL signing kid not found in trusted key sets" }
66
+ ]
67
+ }
68
+ },
69
+ {
70
+ "id": "krl-007",
71
+ "mode": "signing-key-inactive",
72
+ "description": "Trusted key set contains the correct kid but with status: revoked — keyIsActiveAt returns false",
73
+ "expected": {
74
+ "status": "invalid",
75
+ "violations": [
76
+ { "code": "KRL_SIGNING_KEY_INACTIVE", "message": "KRL signing key is not active at verification time" }
77
+ ]
78
+ }
79
+ },
80
+ {
81
+ "id": "krl-008",
82
+ "mode": "unsupported-alg",
83
+ "description": "signature.alg is \"HMAC-SHA256\" — only Ed25519 is accepted for SignedKRLV1",
84
+ "expected": {
85
+ "status": "invalid",
86
+ "violations": [
87
+ { "code": "KRL_UNSUPPORTED_ALG", "message": "only Ed25519 is supported for SignedKRLV1 signing" }
88
+ ]
89
+ }
90
+ },
91
+ {
92
+ "id": "krl-009",
93
+ "mode": "version-regression",
94
+ "description": "krl_version=1 but previousKrlVersionByIssuer[krl.issuer]=5 — version went backwards",
95
+ "expected": {
96
+ "status": "invalid",
97
+ "violations": [
98
+ { "code": "KRL_VERSION_REGRESSION", "message": "krl_version 1 is less than the previously accepted version 5 for issuer \"krl.issuer\"" }
99
+ ]
100
+ }
101
+ }
102
+ ]
103
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "schema_version": "1.0.0",
3
+ "description": "Strict trusted-time conformance vectors. Every active vector is release-blocking. Pending vectors describe unsupported normative categories and never count as passing.",
4
+ "vectors": [
5
+ {"id":"tt-issuance-before","category":"authorization_issuance","status":"active","description":"Fresh intent before evaluation time.","input":{"intent_timestamp":1729999990,"evaluation_time":1730000000,"effective_ttl":60,"authorization_action":"EXECUTE"},"expected":{"decision":"ALLOW","reasons":[],"authorization_issued_at":1730000000,"authorization_expiry":1730000060}},
6
+ {"id":"tt-issuance-equal","category":"authorization_issuance","status":"active","description":"Intent and evaluation clocks equal.","input":{"intent_timestamp":1730000000,"evaluation_time":1730000000,"effective_ttl":60,"authorization_action":"EXECUTE"},"expected":{"decision":"ALLOW","reasons":[],"authorization_issued_at":1730000000,"authorization_expiry":1730000060}},
7
+ {"id":"tt-issuance-after","category":"authorization_issuance","status":"active","description":"Fresh intent after evaluation time.","input":{"intent_timestamp":1730000010,"evaluation_time":1730000000,"effective_ttl":60,"authorization_action":"EXECUTE"},"expected":{"decision":"ALLOW","reasons":[],"authorization_issued_at":1730000000,"authorization_expiry":1730000060}},
8
+ {"id":"tt-noninterference-earlier","category":"authorization_issuance","status":"active","description":"Earlier freshness-valid intent has the trusted issuance window.","comparison_group":"issuance-intent-noninterference","input":{"intent_timestamp":1729999980,"evaluation_time":1730000000,"effective_ttl":60,"authorization_action":"EXECUTE"},"expected":{"decision":"ALLOW","reasons":[],"authorization_issued_at":1730000000,"authorization_expiry":1730000060}},
9
+ {"id":"tt-noninterference-later","category":"authorization_issuance","status":"active","description":"Later freshness-valid intent has the trusted issuance window.","comparison_group":"issuance-intent-noninterference","input":{"intent_timestamp":1730000020,"evaluation_time":1730000000,"effective_ttl":60,"authorization_action":"EXECUTE"},"expected":{"decision":"ALLOW","reasons":[],"authorization_issued_at":1730000000,"authorization_expiry":1730000060}},
10
+ {"id":"tt-evaluation-sensitivity-first","category":"authorization_issuance","status":"active","description":"First trusted evaluation time.","comparison_group":"issuance-evaluation-sensitivity","input":{"intent_timestamp":1730000000,"evaluation_time":1730000000,"effective_ttl":60,"authorization_action":"EXECUTE"},"expected":{"decision":"ALLOW","reasons":[],"authorization_issued_at":1730000000,"authorization_expiry":1730000060}},
11
+ {"id":"tt-evaluation-sensitivity-second","category":"authorization_issuance","status":"active","description":"Advancing trusted time advances issuance.","comparison_group":"issuance-evaluation-sensitivity","input":{"intent_timestamp":1730000000,"evaluation_time":1730000010,"effective_ttl":60,"authorization_action":"EXECUTE"},"expected":{"decision":"ALLOW","reasons":[],"authorization_issued_at":1730000010,"authorization_expiry":1730000070}},
12
+ {"id":"tt-release-issuance","category":"authorization_issuance","status":"active","description":"RELEASE uses the shared trusted issuance block.","input":{"intent_timestamp":1730000001,"evaluation_time":1730000000,"effective_ttl":60,"authorization_action":"RELEASE"},"expected":{"decision":"ALLOW","reasons":[],"authorization_issued_at":1730000000,"authorization_expiry":1730000060}},
13
+ {"id":"tt-freshness-denial","category":"intent_freshness","status":"active","description":"Intent one second beyond future skew denies before issuance.","input":{"intent_timestamp":1730000301,"evaluation_time":1730000000,"max_clock_skew_seconds":300,"max_intent_age_seconds":300},"expected":{"decision":"DENY","reasons":["INTENT_FRESHNESS_FUTURE"]}},
14
+ {"id":"tt-deterministic","category":"determinism","status":"active","description":"Identical issuance inputs produce identical normalized output.","input":{"intent_timestamp":1730000005,"evaluation_time":1730000000,"effective_ttl":60,"repeat":2},"expected":{"decision":"ALLOW","reasons":[],"authorization_issued_at":1730000000,"authorization_expiry":1730000060,"identical_output":true}},
15
+ {"id":"tt-invalid-ttl-zero","category":"malformed_configuration","status":"active","description":"Zero fixed issuance TTL is rejected.","input":{"configuration_field":"authorization_ttl_seconds","configuration_value":0},"expected":{"throws":true,"error_includes":"authorization_ttl_seconds"}},
16
+ {"id":"tt-invalid-verifier-skew-fraction","category":"malformed_configuration","status":"active","description":"Fractional verifier future-issued skew is rejected.","input":{"configuration_field":"maxFutureIssuedAtSkewSeconds","configuration_value":1.5},"expected":{"throws":true,"error_includes":"maxFutureIssuedAtSkewSeconds"}},
17
+ {"id":"tt-expiry-overflow","category":"protocol_seconds_validation","status":"active","description":"Issuance refuses unsafe expiry arithmetic.","input":{"case":"issuance_expiry_overflow","intent_timestamp":9007199254740932,"evaluation_time":9007199254740932,"effective_ttl":60},"expected":{"throws":true,"error_includes":"safe integer"}},
18
+ {"id":"tt-protocol-negative-intent","category":"protocol_seconds_validation","status":"active","description":"Negative intent protocol seconds deny.","input":{"case":"intent_timestamp","intent_timestamp":-1,"evaluation_time":1730000000},"expected":{"decision":"DENY","reasons":["STATE_INVALID"]}},
19
+ {"id":"tt-protocol-fractional-intent","category":"protocol_seconds_validation","status":"active","description":"Fractional intent protocol seconds deny.","input":{"case":"intent_timestamp","intent_timestamp":1729999999.5,"evaluation_time":1730000000},"expected":{"decision":"DENY","reasons":["STATE_INVALID"]}},
20
+ {"id":"tt-protocol-negative-evaluation","category":"protocol_seconds_validation","status":"active","description":"Negative trusted evaluation time refuses evaluation.","input":{"case":"evaluation_time","intent_timestamp":1730000000,"evaluation_time":-1},"expected":{"throws":true,"error_includes":"evaluationTime"}},
21
+ {"id":"tt-neg-001","category":"intent_freshness","status":"active","description":"Grossly future-dated intent denies.","input":{"intent_timestamp":4883600000,"evaluation_time":1730000000,"max_clock_skew_seconds":300,"max_intent_age_seconds":300},"expected":{"decision":"DENY","reasons":["INTENT_FRESHNESS_FUTURE"]}},
22
+ {"id":"tt-neg-005","category":"intent_freshness","status":"active","description":"Stale intent denies.","input":{"intent_timestamp":1729999400,"evaluation_time":1730000000,"max_clock_skew_seconds":300,"max_intent_age_seconds":300},"expected":{"decision":"DENY","reasons":["INTENT_STALE"]}},
23
+ {"id":"tt-pos-001","category":"intent_freshness","status":"active","description":"Fresh future-side boundary intent passes.","input":{"intent_timestamp":1730000300,"evaluation_time":1730000000,"max_clock_skew_seconds":300,"max_intent_age_seconds":300},"expected":{"decision":"ALLOW","reasons":[]}},
24
+ {"id":"tt-pos-004","category":"intent_freshness","status":"active","description":"Fresh stale-side boundary intent passes.","input":{"intent_timestamp":1729999700,"evaluation_time":1730000000,"max_clock_skew_seconds":300,"max_intent_age_seconds":300},"expected":{"decision":"ALLOW","reasons":[]}},
25
+ {"id":"tt-neg-002","category":"replay","status":"active","description":"First use is allowed and immediate replay is denied using persisted nextState.","input":{"replay_window_seconds":600,"max_nonces_per_agent":256,"steps":[{"intent_timestamp":1730000000,"evaluation_time":1730000000,"nonce":"7"},{"intent_timestamp":1730000005,"evaluation_time":1730000005,"nonce":"7"}]},"expected":{"steps":[{"decision":"ALLOW","reasons":[],"nonce_state":[{"nonce":"7","nonce_first_seen_time":1730000000}]},{"decision":"DENY","reasons":["REPLAY_NONCE"],"nonce_state":[{"nonce":"7","nonce_first_seen_time":1730000000}]}]}},
26
+ {"id":"tt-pos-002","category":"replay","status":"active","description":"A distinct nonce inside retention is allowed and appended.","input":{"replay_window_seconds":600,"max_nonces_per_agent":256,"steps":[{"intent_timestamp":1730000000,"evaluation_time":1730000000,"nonce":"7"},{"intent_timestamp":1730000005,"evaluation_time":1730000005,"nonce":"8"}]},"expected":{"steps":[{"decision":"ALLOW","reasons":[],"nonce_state":[{"nonce":"7","nonce_first_seen_time":1730000000}]},{"decision":"ALLOW","reasons":[],"nonce_state":[{"nonce":"7","nonce_first_seen_time":1730000000},{"nonce":"8","nonce_first_seen_time":1730000005}]}]}},
27
+ {"id":"tt-neg-004","category":"replay","status":"active","description":"Future freshness denial precedes retained-nonce replay.","input":{"replay_window_seconds":600,"max_nonces_per_agent":256,"initial_nonce_state":[{"nonce":"n7","nonce_first_seen_time":1730000000}],"steps":[{"intent_timestamp":1730600010,"evaluation_time":1730000005,"nonce":"n7"}]},"expected":{"steps":[{"decision":"DENY","reasons":["INTENT_FRESHNESS_FUTURE"],"nonce_state":[{"nonce":"n7","nonce_first_seen_time":1730000000}]}]}},
28
+ {"id":"tt-neg-006","category":"replay","status":"active","description":"Stale freshness denial precedes retained-nonce replay.","input":{"replay_window_seconds":600,"max_nonces_per_agent":256,"initial_nonce_state":[{"nonce":"n7","nonce_first_seen_time":1730000000}],"steps":[{"intent_timestamp":1729999400,"evaluation_time":1730000005,"nonce":"n7"}]},"expected":{"steps":[{"decision":"DENY","reasons":["INTENT_STALE"],"nonce_state":[{"nonce":"n7","nonce_first_seen_time":1730000000}]}]}},
29
+ {"id":"tt-replay-future-within-band","category":"replay","status":"active","description":"Freshness-valid future intent cannot evict trusted replay state.","input":{"replay_window_seconds":600,"max_nonces_per_agent":256,"steps":[{"intent_timestamp":1730000000,"evaluation_time":1730000000,"nonce":"9"},{"intent_timestamp":1730000300,"evaluation_time":1730000000,"nonce":"9"}]},"expected":{"steps":[{"decision":"ALLOW","reasons":[],"nonce_state":[{"nonce":"9","nonce_first_seen_time":1730000000}]},{"decision":"DENY","reasons":["REPLAY_NONCE"],"nonce_state":[{"nonce":"9","nonce_first_seen_time":1730000000}]}]}},
30
+ {"id":"tt-velocity-first","category":"velocity","status":"active","description":"First action starts at trusted time.","input":{"window_seconds":60,"max_actions":1,"steps":[{"intent_timestamp":1730000010,"evaluation_time":1730000000,"nonce":"v1"}]},"expected":{"steps":[{"decision":"ALLOW","reasons":[],"velocity_window_start":1730000000,"velocity_count":1}]}},
31
+ {"id":"tt-velocity-limit-active","category":"velocity","status":"active","description":"Persisted first action followed by active-window denial.","input":{"window_seconds":60,"max_actions":1,"steps":[{"intent_timestamp":1730000000,"evaluation_time":1730000000,"nonce":"v1"},{"intent_timestamp":1730000001,"evaluation_time":1730000000,"nonce":"v2"}]},"expected":{"steps":[{"decision":"ALLOW","reasons":[],"velocity_window_start":1730000000,"velocity_count":1},{"decision":"DENY","reasons":["VELOCITY_EXCEEDED"],"velocity_window_start":1730000000,"velocity_count":1}]}},
32
+ {"id":"tt-velocity-future-intent-active","category":"velocity","status":"active","description":"Fresh future intent cannot reset the active window.","input":{"window_seconds":60,"max_actions":1,"initial_velocity":{"velocity_window_start":1730000000,"velocity_count":1},"steps":[{"intent_timestamp":1730000030,"evaluation_time":1730000010,"nonce":"v2"}]},"expected":{"steps":[{"decision":"DENY","reasons":["VELOCITY_EXCEEDED"],"velocity_window_start":1730000000,"velocity_count":1}]}},
33
+ {"id":"tt-velocity-stale-boundary-active","category":"velocity","status":"active","description":"Fresh stale-boundary intent cannot reset the active window.","input":{"window_seconds":60,"max_actions":1,"initial_velocity":{"velocity_window_start":1730000000,"velocity_count":1},"steps":[{"intent_timestamp":1729999710,"evaluation_time":1730000010,"nonce":"v2"}]},"expected":{"steps":[{"decision":"DENY","reasons":["VELOCITY_EXCEEDED"],"velocity_window_start":1730000000,"velocity_count":1}]}},
34
+ {"id":"tt-velocity-before-boundary","category":"velocity","status":"active","description":"Just before boundary remains exhausted.","input":{"window_seconds":60,"max_actions":1,"initial_velocity":{"velocity_window_start":1730000000,"velocity_count":1},"steps":[{"intent_timestamp":1730000059,"evaluation_time":1730000059,"nonce":"v2"}]},"expected":{"steps":[{"decision":"DENY","reasons":["VELOCITY_EXCEEDED"],"velocity_window_start":1730000000,"velocity_count":1}]}},
35
+ {"id":"tt-velocity-exact-boundary","category":"velocity","status":"active","description":"Exact boundary resets at trusted time.","input":{"window_seconds":60,"max_actions":1,"initial_velocity":{"velocity_window_start":1730000000,"velocity_count":1},"steps":[{"intent_timestamp":1730000030,"evaluation_time":1730000060,"nonce":"v2"}]},"expected":{"steps":[{"decision":"ALLOW","reasons":[],"velocity_window_start":1730000060,"velocity_count":1}]}},
36
+ {"id":"tt-velocity-after-boundary","category":"velocity","status":"active","description":"After boundary resets at trusted time.","input":{"window_seconds":60,"max_actions":1,"initial_velocity":{"velocity_window_start":1730000000,"velocity_count":1},"steps":[{"intent_timestamp":1730000061,"evaluation_time":1730000061,"nonce":"v2"}]},"expected":{"steps":[{"decision":"ALLOW","reasons":[],"velocity_window_start":1730000061,"velocity_count":1}]}},
37
+ {"id":"tt-velocity-backward-evaluation","category":"velocity","status":"active","description":"Backward trusted time fails closed.","input":{"window_seconds":60,"max_actions":1,"initial_velocity":{"velocity_window_start":1730000000,"velocity_count":0},"steps":[{"intent_timestamp":1729999999,"evaluation_time":1729999999,"nonce":"v2"}]},"expected":{"steps":[{"decision":"DENY","reasons":["STATE_INVALID"],"velocity_window_start":1730000000,"velocity_count":0}]}},
38
+ {"id":"tt-velocity-malformed-window-start","category":"velocity","status":"active","description":"Negative stored start fails closed.","input":{"window_seconds":60,"max_actions":1,"initial_velocity":{"velocity_window_start":-1,"velocity_count":0},"steps":[{"intent_timestamp":1730000000,"evaluation_time":1730000000,"nonce":"v2"}]},"expected":{"steps":[{"decision":"DENY","reasons":["STATE_INVALID"],"velocity_window_start":-1,"velocity_count":0}]}},
39
+ {"id":"tt-velocity-deterministic","category":"determinism","status":"active","description":"Repeated velocity sequence is deterministic.","input":{"kind":"velocity_sequence","repeat":2,"window_seconds":60,"max_actions":2,"initial_velocity":{"velocity_window_start":1729999990,"velocity_count":0},"steps":[{"intent_timestamp":1729999990,"evaluation_time":1730000000,"nonce":"vd1"}]},"expected":{"identical_output":true}},
40
+ {"id":"tt-neg-003","category":"velocity","status":"active","description":"Legacy active-window case is executable.","input":{"window_seconds":60,"max_actions":1,"initial_velocity":{"velocity_window_start":1730000000,"velocity_count":1},"steps":[{"intent_timestamp":1730000005,"evaluation_time":1730000005,"nonce":"v3"}]},"expected":{"steps":[{"decision":"DENY","reasons":["VELOCITY_EXCEEDED"],"velocity_window_start":1730000000,"velocity_count":1}]}},
41
+ {"id":"tt-pos-003","category":"velocity","status":"active","description":"Trusted time after expiry resets the window.","input":{"window_seconds":60,"max_actions":1,"initial_velocity":{"velocity_window_start":1730000000,"velocity_count":1},"steps":[{"intent_timestamp":1730000065,"evaluation_time":1730000065,"nonce":"v4"}]},"expected":{"steps":[{"decision":"ALLOW","reasons":[],"velocity_window_start":1730000065,"velocity_count":1}]}},
42
+ {"id":"tt-auth-verify-future-boundary","category":"authorization_verification","status":"active","description":"Issued-at exactly at verifier skew boundary is accepted.","input":{"authorization_issued_at":1730000300,"authorization_expiry":1730000360,"verifier_time":1730000000,"max_future_issued_at_skew_seconds":300},"expected":{"status":"ok","violation_codes":[]}},
43
+ {"id":"tt-auth-verify-future-implausible","category":"authorization_verification","status":"active","description":"Issued-at beyond verifier skew is rejected.","input":{"authorization_issued_at":1730000301,"authorization_expiry":1730000361,"verifier_time":1730000000,"max_future_issued_at_skew_seconds":300},"expected":{"status":"invalid","violation_codes":["AUTH_ISSUED_AT_IMPLAUSIBLE"]}},
44
+ {"id":"tt-auth-verify-expiry-boundary","category":"authorization_verification","status":"active","description":"Verifier time at expiry rejects.","input":{"authorization_issued_at":1729999940,"authorization_expiry":1730000000,"verifier_time":1730000000,"max_future_issued_at_skew_seconds":300},"expected":{"status":"invalid","violation_codes":["AUTH_EXPIRED"]}},
45
+ {"id":"tt-tool-window-trusted-time","category":"tool_window","status":"active","description":"A stateful tool-call sequence uses only trusted evaluation time for creation, active-limit denial, timestamp noninterference, and the exact-boundary reset.","input":{"window_seconds":60,"max_calls":1,"steps":[{"intent_timestamp":1730000000,"evaluation_time":1730000000,"nonce":"tw1"},{"intent_timestamp":1730000300,"evaluation_time":1730000000,"nonce":"tw2"},{"intent_timestamp":1729999700,"evaluation_time":1730000000,"nonce":"tw3"},{"intent_timestamp":1730000059,"evaluation_time":1730000059,"nonce":"tw4"},{"intent_timestamp":1730000030,"evaluation_time":1730000060,"nonce":"tw5"} ]},"expected":{"steps":[{"decision":"ALLOW","reasons":[],"tool_calls":[{"tool_call_time":1730000000,"tool":"search"}]},{"decision":"DENY","reasons":["TOOL_CALL_LIMIT_EXCEEDED"],"tool_calls":[{"tool_call_time":1730000000,"tool":"search"}]},{"decision":"DENY","reasons":["TOOL_CALL_LIMIT_EXCEEDED"],"tool_calls":[{"tool_call_time":1730000000,"tool":"search"}]},{"decision":"DENY","reasons":["TOOL_CALL_LIMIT_EXCEEDED"],"tool_calls":[{"tool_call_time":1730000000,"tool":"search"}]},{"decision":"ALLOW","reasons":[],"tool_calls":[{"tool_call_time":1730000060,"tool":"search"}]}]}},
46
+ {"id":"tt-tool-window-after-boundary","category":"tool_window","status":"active","description":"Trusted time after the exact boundary expires the prior call and stamps the replacement with evaluation time.","input":{"window_seconds":60,"max_calls":1,"initial_tool_calls":[{"tool_call_time":1730000000,"tool":"search"}],"steps":[{"intent_timestamp":1730000030,"evaluation_time":1730000061,"nonce":"twa1"}]},"expected":{"steps":[{"decision":"ALLOW","reasons":[],"tool_calls":[{"tool_call_time":1730000061,"tool":"search"}]}]}},
47
+ {"id":"tt-tool-window-backward-evaluation","category":"tool_window","status":"active","description":"Trusted time behind persisted tool-call state fails closed and preserves the state.","input":{"window_seconds":60,"max_calls":1,"initial_tool_calls":[{"tool_call_time":1730000000,"tool":"search"}],"steps":[{"intent_timestamp":1729999999,"evaluation_time":1729999999,"nonce":"twb1"}]},"expected":{"steps":[{"decision":"DENY","reasons":["STATE_INVALID"],"tool_calls":[{"tool_call_time":1730000000,"tool":"search"}]}]}},
48
+ {"id":"tt-tool-window-malformed-state","category":"tool_window","status":"active","description":"A negative persisted tool-call timestamp fails closed and remains unchanged.","input":{"window_seconds":60,"max_calls":1,"initial_tool_calls":[{"tool_call_time":-1,"tool":"search"}],"steps":[{"intent_timestamp":1730000000,"evaluation_time":1730000000,"nonce":"twm1"}]},"expected":{"steps":[{"decision":"DENY","reasons":["STATE_INVALID"],"tool_calls":[{"tool_call_time":-1,"tool":"search"}]}]}}
49
+ ]
50
+ }