agent-passport-system 1.28.0 → 1.29.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 (36) hide show
  1. package/README.md +4 -4
  2. package/dist/src/core/anchor-state.d.ts +46 -0
  3. package/dist/src/core/anchor-state.d.ts.map +1 -0
  4. package/dist/src/core/anchor-state.js +80 -0
  5. package/dist/src/core/anchor-state.js.map +1 -0
  6. package/dist/src/core/canonical-jcs.d.ts +23 -0
  7. package/dist/src/core/canonical-jcs.d.ts.map +1 -0
  8. package/dist/src/core/canonical-jcs.js +125 -0
  9. package/dist/src/core/canonical-jcs.js.map +1 -0
  10. package/dist/src/core/data-narrowing.d.ts +43 -0
  11. package/dist/src/core/data-narrowing.d.ts.map +1 -0
  12. package/dist/src/core/data-narrowing.js +97 -0
  13. package/dist/src/core/data-narrowing.js.map +1 -0
  14. package/dist/src/core/denial-domains.d.ts +43 -0
  15. package/dist/src/core/denial-domains.d.ts.map +1 -0
  16. package/dist/src/core/denial-domains.js +153 -0
  17. package/dist/src/core/denial-domains.js.map +1 -0
  18. package/dist/src/core/fidelity-probe.d.ts +45 -0
  19. package/dist/src/core/fidelity-probe.d.ts.map +1 -1
  20. package/dist/src/core/fidelity-probe.js +39 -1
  21. package/dist/src/core/fidelity-probe.js.map +1 -1
  22. package/dist/src/core/governance-posture.d.ts +72 -0
  23. package/dist/src/core/governance-posture.d.ts.map +1 -0
  24. package/dist/src/core/governance-posture.js +173 -0
  25. package/dist/src/core/governance-posture.js.map +1 -0
  26. package/dist/src/core/reputation-authority.d.ts +13 -4
  27. package/dist/src/core/reputation-authority.d.ts.map +1 -1
  28. package/dist/src/core/reputation-authority.js +29 -5
  29. package/dist/src/core/reputation-authority.js.map +1 -1
  30. package/dist/src/index.d.ts +11 -1
  31. package/dist/src/index.d.ts.map +1 -1
  32. package/dist/src/index.js +10 -0
  33. package/dist/src/index.js.map +1 -1
  34. package/dist/src/types/reputation-authority.d.ts +4 -0
  35. package/dist/src/types/reputation-authority.d.ts.map +1 -1
  36. package/package.json +2 -2
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/agent-passport-system)](https://www.npmjs.com/package/agent-passport-system)
4
4
  [![license](https://img.shields.io/npm/l/agent-passport-system)](https://github.com/aeoess/agent-passport-system/blob/main/LICENSE)
5
- [![tests](https://img.shields.io/badge/tests-1656%20passing-brightgreen)](https://github.com/aeoess/agent-passport-system)
5
+ [![tests](https://img.shields.io/badge/tests-1715%20passing-brightgreen)](https://github.com/aeoess/agent-passport-system)
6
6
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.18749779.svg)](https://doi.org/10.5281/zenodo.18749779)
7
7
 
8
8
  > **For AI agents:** visit [aeoess.com/llms.txt](https://aeoess.com/llms.txt) for machine-readable docs or [llms-full.txt](https://aeoess.com/llms-full.txt) for the complete reference.
@@ -124,7 +124,7 @@ const agent = joinSocialContract({ name: 'my-agent', owner: 'alice', floor: floo
124
124
 
125
125
  ## The Stack
126
126
 
127
- 56 core modules + 32 v2 constitutional modules. 1707 tests. Zero heavy dependencies.
127
+ 62 core modules + 32 v2 constitutional modules. 1715 tests. Zero heavy dependencies.
128
128
 
129
129
  | Layer | What it does | Key primitive |
130
130
  |-------|-------------|---------------|
@@ -178,7 +178,7 @@ npx agent-passport audit --floor values/floor.yaml
178
178
 
179
179
  ```bash
180
180
  npm test
181
- # 1707 tests across 86 files, 443 suites, 0 failures
181
+ # 1715 tests across 93 files, 446 suites, 0 failures
182
182
  ```
183
183
 
184
184
  50 adversarial tests: Merkle tampering, attribution gaming, compliance violations, floor negotiation attacks, cross-chain confused deputy, taint laundering, authority probing.
@@ -196,7 +196,7 @@ npm test
196
196
  | Signed receipts | 3-sig chain | Proposed | Logs | General | — |
197
197
  | Values enforcement | 8 principles, graduated | — | Rules | — | — |
198
198
  | Coordination | Task lifecycle + MCP | — | — | — | — |
199
- | Tests | 1656 (50 adversarial) | None | Limited | None | None |
199
+ | Tests | 1715 (50 adversarial) | None | Limited | None | None |
200
200
 
201
201
  ## Recognition
202
202
 
@@ -0,0 +1,46 @@
1
+ /** External anchor state for a receipt or batch.
2
+ * unanchored: exists only in gateway memory
3
+ * batched_pending: included in a Merkle batch, root not yet anchored externally
4
+ * anchored: Merkle root published to external log (Rekor, Solana, etc.)
5
+ * critical_direct_anchor: individual receipt anchored directly (bypass batching) */
6
+ export type AnchorState = 'unanchored' | 'batched_pending' | 'anchored' | 'critical_direct_anchor';
7
+ /** Anchor metadata on a receipt */
8
+ export interface AnchorMetadata {
9
+ state: AnchorState;
10
+ /** Batch ID if batched_pending or anchored */
11
+ batchId?: string;
12
+ /** External anchor reference (URL, transaction ID, etc.) */
13
+ anchorRef?: string;
14
+ /** When the anchor was confirmed */
15
+ anchoredAt?: string;
16
+ /** Which anchor backend was used */
17
+ anchorBackend?: string;
18
+ }
19
+ /** Auto-batch configuration */
20
+ export interface AutoBatchConfig {
21
+ /** Maximum seconds between batch commits (0 = disabled) */
22
+ maxIntervalSeconds: number;
23
+ /** Maximum receipts before auto-commit (0 = disabled) */
24
+ maxReceiptsPerBatch: number;
25
+ /** Whether critical/irreversible actions get direct anchor */
26
+ directAnchorCritical: boolean;
27
+ }
28
+ export declare const DEFAULT_AUTO_BATCH_CONFIG: AutoBatchConfig;
29
+ /** Create initial anchor metadata for a new receipt */
30
+ export declare function createAnchorMetadata(critical?: boolean): AnchorMetadata;
31
+ /** Transition anchor state when receipt is added to a batch */
32
+ export declare function markBatched(anchor: AnchorMetadata, batchId: string): AnchorMetadata;
33
+ /** Transition anchor state when batch root is externally anchored */
34
+ export declare function markAnchored(anchor: AnchorMetadata, anchorRef: string, anchorBackend: string): AnchorMetadata;
35
+ /** Check if auto-batch should fire based on config and current state */
36
+ export declare function shouldAutoBatch(pendingCount: number, lastBatchTime: string | null, config?: AutoBatchConfig): {
37
+ trigger: boolean;
38
+ reason: 'max_receipts' | 'max_interval' | null;
39
+ };
40
+ /** Check if an anchor state meets a minimum requirement */
41
+ export declare function meetsAnchorRequirement(current: AnchorState, minimum: AnchorState): boolean;
42
+ /** Check if anchor state transition is valid (can only move forward) */
43
+ export declare function isValidAnchorTransition(from: AnchorState, to: AnchorState): boolean;
44
+ /** Exported ordering for cross-language verification */
45
+ export declare const ANCHOR_STATE_ORDER: Record<AnchorState, number>;
46
+ //# sourceMappingURL=anchor-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchor-state.d.ts","sourceRoot":"","sources":["../../../src/core/anchor-state.ts"],"names":[],"mappings":"AAYA;;;;qFAIqF;AACrF,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,iBAAiB,GAAG,UAAU,GAAG,wBAAwB,CAAA;AAElG,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,WAAW,CAAA;IAClB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,oCAAoC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,+BAA+B;AAC/B,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,kBAAkB,EAAE,MAAM,CAAA;IAC1B,yDAAyD;IACzD,mBAAmB,EAAE,MAAM,CAAA;IAC3B,8DAA8D;IAC9D,oBAAoB,EAAE,OAAO,CAAA;CAC9B;AAED,eAAO,MAAM,yBAAyB,EAAE,eAIvC,CAAA;AAED,uDAAuD;AACvD,wBAAgB,oBAAoB,CAAC,QAAQ,GAAE,OAAe,GAAG,cAAc,CAI9E;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,cAAc,CAInF;AAED,qEAAqE;AACrE,wBAAgB,YAAY,CAC1B,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,cAAc,CAQhB;AAED,wEAAwE;AACxE,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,MAAM,GAAE,eAA2C,GAClD;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,cAAc,GAAG,cAAc,GAAG,IAAI,CAAA;CAAE,CAsBtE;AAUD,2DAA2D;AAC3D,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,WAAW,GACnB,OAAO,CAET;AAED,wEAAwE;AACxE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,GAAG,OAAO,CAEnF;AAED,wDAAwD;AACxD,eAAO,MAAM,kBAAkB,6BAAe,CAAA"}
@@ -0,0 +1,80 @@
1
+ // ══════════════════════════════════════════════════════════════════
2
+ // Anchor States — External verifiability tracking for receipts
3
+ // ══════════════════════════════════════════════════════════════════
4
+ // Consilium Priority 6. Gemini: "explicit receipt anchor states."
5
+ // desiorac (A2A #1672): batch commitment lags individual receipts.
6
+ //
7
+ // Every receipt and batch carries an anchor state:
8
+ // unanchored → batched_pending → anchored → critical_direct_anchor
9
+ //
10
+ // Auto-batching: configurable window (N seconds or N receipts).
11
+ // ══════════════════════════════════════════════════════════════════
12
+ export const DEFAULT_AUTO_BATCH_CONFIG = {
13
+ maxIntervalSeconds: 300, // 5 minutes
14
+ maxReceiptsPerBatch: 100,
15
+ directAnchorCritical: true,
16
+ };
17
+ /** Create initial anchor metadata for a new receipt */
18
+ export function createAnchorMetadata(critical = false) {
19
+ return {
20
+ state: critical ? 'critical_direct_anchor' : 'unanchored',
21
+ };
22
+ }
23
+ /** Transition anchor state when receipt is added to a batch */
24
+ export function markBatched(anchor, batchId) {
25
+ if (anchor.state === 'critical_direct_anchor')
26
+ return anchor; // already anchored
27
+ if (anchor.state === 'anchored')
28
+ return anchor; // already anchored
29
+ return { ...anchor, state: 'batched_pending', batchId };
30
+ }
31
+ /** Transition anchor state when batch root is externally anchored */
32
+ export function markAnchored(anchor, anchorRef, anchorBackend) {
33
+ if (anchor.state === 'critical_direct_anchor')
34
+ return anchor;
35
+ return {
36
+ ...anchor,
37
+ state: 'anchored',
38
+ anchorRef, anchorBackend,
39
+ anchoredAt: new Date().toISOString(),
40
+ };
41
+ }
42
+ /** Check if auto-batch should fire based on config and current state */
43
+ export function shouldAutoBatch(pendingCount, lastBatchTime, config = DEFAULT_AUTO_BATCH_CONFIG) {
44
+ if (pendingCount === 0)
45
+ return { trigger: false, reason: null };
46
+ // Receipt count trigger
47
+ if (config.maxReceiptsPerBatch > 0 && pendingCount >= config.maxReceiptsPerBatch) {
48
+ return { trigger: true, reason: 'max_receipts' };
49
+ }
50
+ // Time interval trigger
51
+ if (config.maxIntervalSeconds > 0 && lastBatchTime) {
52
+ const elapsed = (Date.now() - new Date(lastBatchTime).getTime()) / 1000;
53
+ if (elapsed >= config.maxIntervalSeconds) {
54
+ return { trigger: true, reason: 'max_interval' };
55
+ }
56
+ }
57
+ // First batch ever — trigger on interval if no previous batch
58
+ if (config.maxIntervalSeconds > 0 && !lastBatchTime && pendingCount > 0) {
59
+ return { trigger: true, reason: 'max_interval' };
60
+ }
61
+ return { trigger: false, reason: null };
62
+ }
63
+ /** Anchor state ordering — higher number = more externally verifiable */
64
+ const ANCHOR_ORDER = {
65
+ unanchored: 0,
66
+ batched_pending: 1,
67
+ anchored: 2,
68
+ critical_direct_anchor: 3,
69
+ };
70
+ /** Check if an anchor state meets a minimum requirement */
71
+ export function meetsAnchorRequirement(current, minimum) {
72
+ return ANCHOR_ORDER[current] >= ANCHOR_ORDER[minimum];
73
+ }
74
+ /** Check if anchor state transition is valid (can only move forward) */
75
+ export function isValidAnchorTransition(from, to) {
76
+ return ANCHOR_ORDER[to] >= ANCHOR_ORDER[from];
77
+ }
78
+ /** Exported ordering for cross-language verification */
79
+ export const ANCHOR_STATE_ORDER = ANCHOR_ORDER;
80
+ //# sourceMappingURL=anchor-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchor-state.js","sourceRoot":"","sources":["../../../src/core/anchor-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /** RFC 8785 JSON Canonicalization Scheme.
2
+ * Differences from legacy canonicalize():
3
+ * - null values ARE preserved (not filtered)
4
+ * - undefined object values become null
5
+ * - Number serialization follows ES2015 spec
6
+ * - All other behavior is identical (sorted keys, no whitespace) */
7
+ export declare function canonicalizeJCS(value: unknown): string;
8
+ /** Detect which canonicalization variant was likely used.
9
+ * Checks if null values are present — JCS preserves them, legacy strips them. */
10
+ export declare function detectCanonicalVariant(obj: unknown, canonicalString: string): 'jcs' | 'legacy' | 'ambiguous';
11
+ /** Cross-language test vector for canonicalization verification */
12
+ export interface CanonicalizationTestVector {
13
+ id: string;
14
+ description: string;
15
+ input: unknown;
16
+ expected_jcs: string;
17
+ expected_legacy: string;
18
+ sha256_jcs: string;
19
+ sha256_legacy: string;
20
+ }
21
+ /** Built-in test vectors for cross-language verification */
22
+ export declare function getTestVectors(): CanonicalizationTestVector[];
23
+ //# sourceMappingURL=canonical-jcs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical-jcs.d.ts","sourceRoot":"","sources":["../../../src/core/canonical-jcs.ts"],"names":[],"mappings":"AAcA;;;;;qEAKqE;AACrE,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAiCtD;AAED;kFACkF;AAClF,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,eAAe,EAAE,MAAM,GACtB,KAAK,GAAG,QAAQ,GAAG,WAAW,CAMhC;AAYD,mEAAmE;AACnE,MAAM,WAAW,0BAA0B;IACzC,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,OAAO,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;CACtB;AAOD,4DAA4D;AAC5D,wBAAgB,cAAc,IAAI,0BAA0B,EAAE,CAoF7D"}
@@ -0,0 +1,125 @@
1
+ // ══════════════════════════════════════════════════════════════════
2
+ // JCS Canonicalization — RFC 8785 compliant JSON Canonicalization
3
+ // ══════════════════════════════════════════════════════════════════
4
+ // The original canonicalize() filters null values — a deviation from
5
+ // RFC 8785 that cannot be changed without breaking existing signatures.
6
+ //
7
+ // This module provides:
8
+ // canonicalizeJCS() — strict RFC 8785 compliance
9
+ // verifyCanonical() — detect which variant was used
10
+ //
11
+ // Migration: new signatures should use JCS. Old signatures keep
12
+ // working with the legacy function. Verification tries both.
13
+ // ══════════════════════════════════════════════════════════════════
14
+ /** RFC 8785 JSON Canonicalization Scheme.
15
+ * Differences from legacy canonicalize():
16
+ * - null values ARE preserved (not filtered)
17
+ * - undefined object values become null
18
+ * - Number serialization follows ES2015 spec
19
+ * - All other behavior is identical (sorted keys, no whitespace) */
20
+ export function canonicalizeJCS(value) {
21
+ if (value === null || value === undefined)
22
+ return 'null';
23
+ switch (typeof value) {
24
+ case 'boolean':
25
+ return value ? 'true' : 'false';
26
+ case 'number': {
27
+ if (!isFinite(value))
28
+ throw new Error('JCS does not support Infinity or NaN');
29
+ // ES2015 number serialization — JSON.stringify handles this correctly
30
+ return JSON.stringify(value);
31
+ }
32
+ case 'string':
33
+ return JSON.stringify(value);
34
+ case 'object': {
35
+ if (value instanceof Date)
36
+ return JSON.stringify(value);
37
+ if (Array.isArray(value)) {
38
+ return '[' + value.map(item => canonicalizeJCS(item)).join(',') + ']';
39
+ }
40
+ // Object: sort keys by Unicode code point, preserve null values
41
+ const obj = value;
42
+ const keys = Object.keys(obj).sort();
43
+ const pairs = [];
44
+ for (const key of keys) {
45
+ const v = obj[key];
46
+ // RFC 8785: undefined becomes null, null is preserved
47
+ // Only skip if the key was never set (shouldn't happen with Object.keys)
48
+ pairs.push(`${JSON.stringify(key)}:${canonicalizeJCS(v)}`);
49
+ }
50
+ return '{' + pairs.join(',') + '}';
51
+ }
52
+ default:
53
+ throw new Error(`JCS: unsupported type ${typeof value}`);
54
+ }
55
+ }
56
+ /** Detect which canonicalization variant was likely used.
57
+ * Checks if null values are present — JCS preserves them, legacy strips them. */
58
+ export function detectCanonicalVariant(obj, canonicalString) {
59
+ // If the object has no null values, both variants produce identical output
60
+ if (!hasNullValues(obj))
61
+ return 'ambiguous';
62
+ // If canonical string contains `:null`, it's JCS (legacy strips nulls)
63
+ if (canonicalString.includes(':null'))
64
+ return 'jcs';
65
+ return 'legacy';
66
+ }
67
+ function hasNullValues(obj) {
68
+ if (obj === null)
69
+ return true;
70
+ if (typeof obj !== 'object' || obj === undefined)
71
+ return false;
72
+ if (Array.isArray(obj))
73
+ return obj.some(hasNullValues);
74
+ return Object.values(obj).some(v => v === null || v === undefined || hasNullValues(v));
75
+ }
76
+ import { createHash } from 'crypto';
77
+ /** Generate SHA-256 hex digest of a string */
78
+ function sha256hex(input) {
79
+ return createHash('sha256').update(input, 'utf-8').digest('hex');
80
+ }
81
+ /** Built-in test vectors for cross-language verification */
82
+ export function getTestVectors() {
83
+ const vectors = [];
84
+ function addVector(id, desc, input, jcs, legacy) {
85
+ vectors.push({
86
+ id, description: desc, input,
87
+ expected_jcs: jcs, expected_legacy: legacy,
88
+ sha256_jcs: sha256hex(jcs), sha256_legacy: sha256hex(legacy),
89
+ });
90
+ }
91
+ // V1: Simple object — both variants identical
92
+ addVector('cv-001', 'Simple object, no nulls — variants identical', { agentId: 'agent-001', scope: 'read' }, '{"agentId":"agent-001","scope":"read"}', '{"agentId":"agent-001","scope":"read"}');
93
+ // V2: Object with null — variants diverge
94
+ addVector('cv-002', 'Null value — JCS preserves, legacy strips', { agentId: 'agent-001', metadata: null, scope: 'read' }, '{"agentId":"agent-001","metadata":null,"scope":"read"}', '{"agentId":"agent-001","scope":"read"}');
95
+ // V3: Key ordering
96
+ addVector('cv-003', 'Keys sorted by Unicode code point', { zebra: 1, alpha: 2, middle: 3 }, '{"alpha":2,"middle":3,"zebra":1}', '{"alpha":2,"middle":3,"zebra":1}');
97
+ // V4: Nested objects with null
98
+ addVector('cv-004', 'Nested object with null at depth', { outer: { inner: null, value: 42 }, top: 'ok' }, '{"outer":{"inner":null,"value":42},"top":"ok"}', '{"outer":{"value":42},"top":"ok"}');
99
+ // V5: Arrays with null elements
100
+ addVector('cv-005', 'Array with null elements — both preserve array nulls', { items: [1, null, 3] }, '{"items":[1,null,3]}', '{"items":[1,null,3]}');
101
+ // V6: Number edge cases
102
+ addVector('cv-006', 'Number formatting — integers and floats', { integer: 42, negative: -7, float: 3.14, zero: 0 }, '{"float":3.14,"integer":42,"negative":-7,"zero":0}', '{"float":3.14,"integer":42,"negative":-7,"zero":0}');
103
+ // V7: Empty structures
104
+ addVector('cv-007', 'Empty object and empty array', { emptyArr: [], emptyObj: {} }, '{"emptyArr":[],"emptyObj":{}}', '{"emptyArr":[],"emptyObj":{}}');
105
+ // V8: Unicode
106
+ addVector('cv-008', 'Unicode string content', { name: 'Тимофій', emoji: '🔐' }, '{"emoji":"🔐","name":"Тимофій"}', '{"emoji":"🔐","name":"Тимофій"}');
107
+ // V9: Realistic APS object — delegation-like structure
108
+ addVector('cv-009', 'Realistic delegation object with mixed null/present fields', {
109
+ delegationId: 'del_abc123',
110
+ delegatedBy: 'did:aps:principal001',
111
+ delegatedTo: 'did:aps:agent002',
112
+ scope: ['data:read', 'commerce:checkout'],
113
+ spendLimit: 500,
114
+ obligationBundleHash: null,
115
+ expiresAt: '2026-04-01T00:00:00Z',
116
+ notBefore: null,
117
+ maxDepth: 3,
118
+ currentDepth: 1,
119
+ createdAt: '2026-03-29T00:00:00Z',
120
+ }, '{"createdAt":"2026-03-29T00:00:00Z","currentDepth":1,"delegatedBy":"did:aps:principal001","delegatedTo":"did:aps:agent002","delegationId":"del_abc123","expiresAt":"2026-04-01T00:00:00Z","maxDepth":3,"notBefore":null,"obligationBundleHash":null,"scope":["data:read","commerce:checkout"],"spendLimit":500}', '{"createdAt":"2026-03-29T00:00:00Z","currentDepth":1,"delegatedBy":"did:aps:principal001","delegatedTo":"did:aps:agent002","delegationId":"del_abc123","expiresAt":"2026-04-01T00:00:00Z","maxDepth":3,"scope":["data:read","commerce:checkout"],"spendLimit":500}');
121
+ // V10: Boolean values
122
+ addVector('cv-010', 'Boolean values', { active: true, revoked: false }, '{"active":true,"revoked":false}', '{"active":true,"revoked":false}');
123
+ return vectors;
124
+ }
125
+ //# sourceMappingURL=canonical-jcs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical-jcs.js","sourceRoot":"","sources":["../../../src/core/canonical-jcs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { ConstraintFacet, ConstraintStatus } from '../types/gateway.js';
2
+ /** A facet evaluation snapshot — facet name + its status */
3
+ export interface FacetSnapshot {
4
+ facet: ConstraintFacet;
5
+ status: ConstraintStatus;
6
+ }
7
+ /** Result of a narrowing check */
8
+ export interface NarrowingCheckResult {
9
+ valid: boolean;
10
+ /** Facets where data attempted to widen authority */
11
+ violations: Array<{
12
+ facet: ConstraintFacet;
13
+ before: ConstraintStatus;
14
+ after: ConstraintStatus;
15
+ message: string;
16
+ }>;
17
+ }
18
+ /** Assert that data influence only narrows authority.
19
+ * Compares constraint evaluations BEFORE and AFTER data is considered.
20
+ * Any facet that moves from a more restrictive status to a more
21
+ * permissive one is a violation — data attempted to widen authority.
22
+ *
23
+ * @param before - Facet evaluations before data influence
24
+ * @param after - Facet evaluations after data influence
25
+ * @returns NarrowingCheckResult with any violations */
26
+ export declare function assertDataNarrowsOnly(before: FacetSnapshot[], after: FacetSnapshot[]): NarrowingCheckResult;
27
+ /** Apply data-sourced constraint modifications safely.
28
+ * Only allows narrowing (making more restrictive).
29
+ * Returns the narrowed snapshots with any widening attempts rejected.
30
+ *
31
+ * Use case: a data source declares "this data requires scope:read_only"
32
+ * → the constraint is narrowed. But if data declares "grant scope:admin"
33
+ * → the widening is rejected and the original constraint stands. */
34
+ export declare function applyDataConstraints(current: FacetSnapshot[], dataInfluence: FacetSnapshot[]): {
35
+ result: FacetSnapshot[];
36
+ rejected: NarrowingCheckResult['violations'];
37
+ };
38
+ /** Check if a status transition is valid narrowing (same or more restrictive) */
39
+ export declare function isValidNarrowing(before: ConstraintStatus, after: ConstraintStatus): boolean;
40
+ /** The status ordering: fail < unknown < not_applicable < pass.
41
+ * Exported for test vectors and cross-language verification. */
42
+ export declare const NARROWING_ORDER: Record<ConstraintStatus, number>;
43
+ //# sourceMappingURL=data-narrowing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-narrowing.d.ts","sourceRoot":"","sources":["../../../src/core/data-narrowing.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAE5E,4DAA4D;AAC5D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,eAAe,CAAA;IACtB,MAAM,EAAE,gBAAgB,CAAA;CACzB;AAED,kCAAkC;AAClC,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAA;IACd,qDAAqD;IACrD,UAAU,EAAE,KAAK,CAAC;QAChB,KAAK,EAAE,eAAe,CAAA;QACtB,MAAM,EAAE,gBAAgB,CAAA;QACxB,KAAK,EAAE,gBAAgB,CAAA;QACvB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAC,CAAA;CACH;AAWD;;;;;;;wDAOwD;AACxD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,aAAa,EAAE,EACvB,KAAK,EAAE,aAAa,EAAE,GACrB,oBAAoB,CAwBtB;AAED;;;;;;qEAMqE;AACrE,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,aAAa,EAAE,EACxB,aAAa,EAAE,aAAa,EAAE,GAC7B;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,QAAQ,EAAE,oBAAoB,CAAC,YAAY,CAAC,CAAA;CAAE,CAkC3E;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAE3F;AAED;iEACiE;AACjE,eAAO,MAAM,eAAe,kCAAe,CAAA"}
@@ -0,0 +1,97 @@
1
+ // ══════════════════════════════════════════════════════════════════
2
+ // Data Narrowing Invariant — Data Can Only Narrow Authority
3
+ // ══════════════════════════════════════════════════════════════════
4
+ // GPT's "Context-Bypass Attack" (consilium March 2026):
5
+ // An agent reads a data source containing authority-widening
6
+ // instructions. The gateway must ensure data inputs can ONLY narrow
7
+ // the ConstraintVector, never widen it.
8
+ //
9
+ // Same as monotonic narrowing for delegation — monotonic narrowing
10
+ // for data influence. Only signed delegations from a higher-tier
11
+ // principal can widen authority.
12
+ // ══════════════════════════════════════════════════════════════════
13
+ /** Status ordering for monotonic narrowing check.
14
+ * Lower number = more restrictive. Authority can only move DOWN. */
15
+ const STATUS_ORDER = {
16
+ 'fail': 0,
17
+ 'unknown': 1,
18
+ 'not_applicable': 2,
19
+ 'pass': 3,
20
+ };
21
+ /** Assert that data influence only narrows authority.
22
+ * Compares constraint evaluations BEFORE and AFTER data is considered.
23
+ * Any facet that moves from a more restrictive status to a more
24
+ * permissive one is a violation — data attempted to widen authority.
25
+ *
26
+ * @param before - Facet evaluations before data influence
27
+ * @param after - Facet evaluations after data influence
28
+ * @returns NarrowingCheckResult with any violations */
29
+ export function assertDataNarrowsOnly(before, after) {
30
+ const violations = [];
31
+ const beforeMap = new Map(before.map(f => [f.facet, f.status]));
32
+ for (const a of after) {
33
+ const beforeStatus = beforeMap.get(a.facet);
34
+ if (beforeStatus === undefined)
35
+ continue; // new facet, no comparison
36
+ const beforeOrder = STATUS_ORDER[beforeStatus];
37
+ const afterOrder = STATUS_ORDER[a.status];
38
+ // If after is MORE permissive (higher order) than before → violation
39
+ if (afterOrder > beforeOrder) {
40
+ violations.push({
41
+ facet: a.facet,
42
+ before: beforeStatus,
43
+ after: a.status,
44
+ message: `Data attempted to widen ${a.facet}: ${beforeStatus} → ${a.status}`,
45
+ });
46
+ }
47
+ }
48
+ return { valid: violations.length === 0, violations };
49
+ }
50
+ /** Apply data-sourced constraint modifications safely.
51
+ * Only allows narrowing (making more restrictive).
52
+ * Returns the narrowed snapshots with any widening attempts rejected.
53
+ *
54
+ * Use case: a data source declares "this data requires scope:read_only"
55
+ * → the constraint is narrowed. But if data declares "grant scope:admin"
56
+ * → the widening is rejected and the original constraint stands. */
57
+ export function applyDataConstraints(current, dataInfluence) {
58
+ const currentMap = new Map(current.map(f => [f.facet, f]));
59
+ const result = [...current];
60
+ const rejected = [];
61
+ for (const influence of dataInfluence) {
62
+ const existing = currentMap.get(influence.facet);
63
+ if (!existing) {
64
+ // New facet from data — only accept if restrictive (fail or unknown)
65
+ if (STATUS_ORDER[influence.status] <= STATUS_ORDER['unknown']) {
66
+ result.push(influence);
67
+ }
68
+ continue;
69
+ }
70
+ const existingOrder = STATUS_ORDER[existing.status];
71
+ const influenceOrder = STATUS_ORDER[influence.status];
72
+ if (influenceOrder <= existingOrder) {
73
+ // More restrictive or equal — allowed (narrowing)
74
+ const idx = result.findIndex(f => f.facet === influence.facet);
75
+ if (idx >= 0)
76
+ result[idx] = influence;
77
+ }
78
+ else {
79
+ // Less restrictive — rejected (widening attempt)
80
+ rejected.push({
81
+ facet: influence.facet,
82
+ before: existing.status,
83
+ after: influence.status,
84
+ message: `Rejected: data tried to widen ${influence.facet} from ${existing.status} to ${influence.status}`,
85
+ });
86
+ }
87
+ }
88
+ return { result, rejected };
89
+ }
90
+ /** Check if a status transition is valid narrowing (same or more restrictive) */
91
+ export function isValidNarrowing(before, after) {
92
+ return STATUS_ORDER[after] <= STATUS_ORDER[before];
93
+ }
94
+ /** The status ordering: fail < unknown < not_applicable < pass.
95
+ * Exported for test vectors and cross-language verification. */
96
+ export const NARROWING_ORDER = STATUS_ORDER;
97
+ //# sourceMappingURL=data-narrowing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-narrowing.js","sourceRoot":"","sources":["../../../src/core/data-narrowing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { ConstraintFacet, ConstraintFailure } from '../types/gateway.js';
2
+ /** Five operator-facing denial domains.
3
+ * Each groups 2-4 ConstraintVector facets. */
4
+ export type DenialDomain = 'identity_trust' | 'authority_scope' | 'economic' | 'temporal_integrity' | 'safety_values';
5
+ /** Structured denial summary for operators and dashboards.
6
+ * Primary reason + contributing factors + remediation hint. */
7
+ export interface DenialSummary {
8
+ /** The single most important reason the action was denied */
9
+ primary: {
10
+ domain: DenialDomain;
11
+ domainLabel: string;
12
+ facet: ConstraintFacet;
13
+ code: string;
14
+ message: string;
15
+ };
16
+ /** Additional failures beyond the primary */
17
+ contributing: Array<{
18
+ domain: DenialDomain;
19
+ facet: ConstraintFacet;
20
+ code: string;
21
+ }>;
22
+ /** Total number of failed facets */
23
+ totalFailures: number;
24
+ /** The nearest condition that would have satisfied the primary failure */
25
+ nearestSatisfiable?: string;
26
+ /** One-line remediation hint */
27
+ remediationHint?: string;
28
+ }
29
+ /** Get the denial domain for a constraint facet */
30
+ export declare function getDomain(facet: ConstraintFacet): DenialDomain;
31
+ /** Get the human-readable label for a domain */
32
+ export declare function getDomainLabel(domain: DenialDomain): string;
33
+ /** Evaluation order: cheapest checks first.
34
+ * Gateway should evaluate in this order for deny-fast optimization.
35
+ * This also determines which failure is "primary" — first to fail wins. */
36
+ export declare const EVALUATION_ORDER: ConstraintFacet[];
37
+ /** Create a structured denial summary from constraint failures.
38
+ * The primary failure is the FIRST in evaluation order (cheapest check
39
+ * that failed), which is also the most actionable for the operator. */
40
+ export declare function summarizeDenial(failures: ConstraintFailure[]): DenialSummary | null;
41
+ /** Group failures by domain for dashboard display */
42
+ export declare function groupByDomain(failures: ConstraintFailure[]): Record<DenialDomain, ConstraintFailure[]>;
43
+ //# sourceMappingURL=denial-domains.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"denial-domains.d.ts","sourceRoot":"","sources":["../../../src/core/denial-domains.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAoB,MAAM,qBAAqB,CAAA;AAE/F;+CAC+C;AAC/C,MAAM,MAAM,YAAY,GACpB,gBAAgB,GAChB,iBAAiB,GACjB,UAAU,GACV,oBAAoB,GACpB,eAAe,CAAA;AA6BnB;gEACgE;AAChE,MAAM,WAAW,aAAa;IAC5B,6DAA6D;IAC7D,OAAO,EAAE;QACP,MAAM,EAAE,YAAY,CAAA;QACpB,WAAW,EAAE,MAAM,CAAA;QACnB,KAAK,EAAE,eAAe,CAAA;QACtB,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;IACD,6CAA6C;IAC7C,YAAY,EAAE,KAAK,CAAC;QAClB,MAAM,EAAE,YAAY,CAAA;QACpB,KAAK,EAAE,eAAe,CAAA;QACtB,IAAI,EAAE,MAAM,CAAA;KACb,CAAC,CAAA;IACF,oCAAoC;IACpC,aAAa,EAAE,MAAM,CAAA;IACrB,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,gCAAgC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAE9D;AAED,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAE3D;AAED;;4EAE4E;AAC5E,eAAO,MAAM,gBAAgB,EAAE,eAAe,EAe7C,CAAA;AAED;;wEAEwE;AACxE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,aAAa,GAAG,IAAI,CA8BnF;AAgDD,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAAC,YAAY,EAAE,iBAAiB,EAAE,CAAC,CAStG"}