agent-passport-system 1.40.0 → 1.41.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.
package/README.md CHANGED
@@ -7,9 +7,9 @@
7
7
 
8
8
  > **For AI agents:** visit [aeoess.com/llms.txt](https://aeoess.com/llms.txt) for machine-readable docs.
9
9
 
10
- **Governance infrastructure for AI agents. Gateway evaluation under 2ms.**
10
+ **Enforcement and accountability layer for AI agents. Bring your own identity.**
11
11
 
12
- Authority can only decrease at each transfer point. The gateway is both judge and executor. Every action produces a signed receipt.
12
+ Accepts did:key, did:web, SPIFFE SVIDs, OAuth tokens, and native did:aps. Authority can only decrease at each transfer point. The gateway is both judge and executor. Every action produces a signed receipt. Gateway evaluation under 2ms.
13
13
 
14
14
  ```bash
15
15
  npm install agent-passport-system
@@ -17,10 +17,16 @@ npm install agent-passport-system
17
17
 
18
18
  ## Quick Start
19
19
 
20
+ Lead with the curated essentials. `agent-passport-system/core` exposes the ~25 functions that 90% of integrations need — identity, delegation, enforcement, commerce, reputation, key management. The full `agent-passport-system` root import is unchanged and backward compatible: pull from it when Core does not cover your case.
21
+
20
22
  ```typescript
21
23
  import {
22
- createPassport, createDelegation, evaluateIntent, commercePreflight
24
+ createPassport, createDelegation,
25
+ evaluateIntent, commercePreflight, generateKeyPair
23
26
  } from 'agent-passport-system/core'
27
+
28
+ // Full 936-export API still available — use when Core does not cover your case.
29
+ // import { ... } from 'agent-passport-system'
24
30
  ```
25
31
 
26
32
  ## Core Protocol
@@ -0,0 +1,186 @@
1
+ import type { FidelityAttestation } from '../types/gateway.js';
2
+ /** Reference to a PDR (Probabilistic Delegation Reliability) score event,
3
+ * as defined in Nanook PDR v2.19 §6.3. The pdr.score.v1 wire format is
4
+ * not yet a published spec; this interface mirrors the field set the paper
5
+ * attributes to NexusGuard's AIP implementation (aip_identity/pdr.py).
6
+ *
7
+ * This is an EXTERNAL reference — the SDK does not produce these scores,
8
+ * it only carries them inside a fingerprint envelope. The optional
9
+ * signature field is the score's own external signature (e.g. from the
10
+ * NexusGuard issuer); verifyBehavioralFingerprint does NOT validate it. */
11
+ export interface PDRScoreRef {
12
+ source: 'pdr.score.v1';
13
+ /** Composite PDR score in [0, 1]. Per Nanook §6.3: weighted combination of
14
+ * Calibration (0.5), Adaptation (0.2), Robustness (0.3). */
15
+ scoreOverall: number;
16
+ /** Calibration sub-score in [0, 1]. Jaccard similarity of claimed vs delivered. */
17
+ scoreCalibration: number;
18
+ /** Adaptation sub-score in [0, 1]. Temporal improvement slope. */
19
+ scoreAdaptation: number;
20
+ /** Robustness sub-score in [0, 1]. Condition-based variance. */
21
+ scoreRobustness: number;
22
+ /** Number of behavioral observations the score is computed over. */
23
+ observationCount: number;
24
+ /** Temporal spread of those observations, in days. */
25
+ windowDays: number;
26
+ /** Identifier of the issuing PDR scorer (e.g. 'nexusguard-aip-0.5.48'). */
27
+ issuer: string;
28
+ /** ISO 8601 timestamp of score issuance. */
29
+ issuedAt: string;
30
+ /** Optional external signature from the PDR issuer. NOT validated by
31
+ * verifyBehavioralFingerprint — see JSDoc on that function. */
32
+ signature?: string;
33
+ }
34
+ /** Reference to a within-session constraint compliance score, in the style
35
+ * of Saebo et al. arXiv:2603.03456 ("Asymmetric Goal Drift in Coding Agents
36
+ * Under Value Conflict"). Measures whether the agent maintained its
37
+ * declared value hierarchy under context pressure across a session.
38
+ *
39
+ * Like PDRScoreRef, this is an external reference. The SDK does not
40
+ * produce Saebo scores; it carries them inside the envelope so consumers
41
+ * that want all three axes have one signed artifact to verify. */
42
+ export interface SaeboScoreRef {
43
+ source: 'saebo.constraint.v1';
44
+ /** Compliance score in [0, 1]: 1.0 = no violations across session,
45
+ * 0.0 = constraint violated on every turn. */
46
+ complianceScore: number;
47
+ /** Number of constraint violations observed in the session. */
48
+ violationCount: number;
49
+ /** Total turn count of the session being scored. */
50
+ sessionTurnCount: number;
51
+ /** Identifier of the issuing constraint scorer. */
52
+ issuer: string;
53
+ /** ISO 8601 timestamp of score issuance. */
54
+ issuedAt: string;
55
+ /** Optional external signature from the issuer. NOT validated by
56
+ * verifyBehavioralFingerprint. */
57
+ signature?: string;
58
+ }
59
+ /** Three-axis behavioral measurement envelope. Always carries at least one
60
+ * HBB FidelityAttestation (axis 1). PDR and Saebo references are optional
61
+ * axes — a fingerprint with only fidelity is still well-formed. */
62
+ export interface BehavioralFingerprint {
63
+ subject: {
64
+ /** DID of the subject agent being measured (not the measurer). */
65
+ did: string;
66
+ /** LLM substrate identifier the subject was running on at measurement
67
+ * time (e.g. 'claude-sonnet-4', 'gpt-5-turbo'). */
68
+ substrate: string;
69
+ };
70
+ /** One or more HBB attestations. Multiple attestations are common when
71
+ * the substrate-swap protocol from Nanook §8.10 takes pre/post probes. */
72
+ fidelity: FidelityAttestation[];
73
+ /** Optional axis 2: PDR cross-session reliability reference. */
74
+ pdr_ref?: PDRScoreRef;
75
+ /** Optional axis 3: Saebo within-session constraint compliance reference. */
76
+ constraint_ref?: SaeboScoreRef;
77
+ /** Identifier of the party that composed and signed this envelope.
78
+ * May or may not be the same party that produced the inner
79
+ * FidelityAttestations (which carry their own measuredBy). */
80
+ measurerId: string;
81
+ /** Hex-encoded Ed25519 public key of the envelope signer. Embedded so
82
+ * third parties can verify offline given only the envelope. */
83
+ measurerPublicKey: string;
84
+ /** ISO 8601 timestamp of envelope signing. */
85
+ signedAt: string;
86
+ /** Hex-encoded Ed25519 signature over canonicalize({ subject, fidelity,
87
+ * pdr_ref, constraint_ref, measurerId, signedAt }). */
88
+ signature: string;
89
+ }
90
+ /** Result of verifyBehavioralFingerprint. All-or-nothing validity flag plus
91
+ * per-field breakdown for diagnostic visibility. */
92
+ export interface FingerprintVerificationResult {
93
+ /** True iff the envelope signature verifies AND every inner fidelity
94
+ * attestation signature verifies under the same public key. */
95
+ valid: boolean;
96
+ /** Whether the envelope-level signature verified against measurerPublicKey. */
97
+ envelopeSignatureValid: boolean;
98
+ /** One boolean per inner FidelityAttestation, in the same order as
99
+ * fp.fidelity. Each entry is the result of verifyFidelityAttestation
100
+ * against the provided measurerPublicKey. */
101
+ innerFidelitySignaturesValid: boolean[];
102
+ /** Human-readable diagnostic messages. Empty array on success. */
103
+ errors: string[];
104
+ }
105
+ /** Compose and sign a BehavioralFingerprint envelope.
106
+ *
107
+ * Requires at least one FidelityAttestation. The envelope carries pre-built
108
+ * fidelity attestations as-is — they retain their own measuredBy/signature
109
+ * fields and stay independently verifiable.
110
+ *
111
+ * The signing key is used for the envelope signature only. Inner fidelity
112
+ * attestations were signed earlier by their own measurers; this function
113
+ * does not re-sign them.
114
+ *
115
+ * @throws if fidelity is empty.
116
+ *
117
+ * Reference: Nanook PDR v2.19 §2.2, §8.10. Gap audit §5 rank 2.
118
+ */
119
+ export declare function createBehavioralFingerprint(subject: {
120
+ did: string;
121
+ substrate: string;
122
+ }, fidelity: FidelityAttestation[], opts: {
123
+ pdr?: PDRScoreRef;
124
+ constraint?: SaeboScoreRef;
125
+ measurerId: string;
126
+ measurerPublicKey: string;
127
+ signingKey: string;
128
+ /** Override the signing timestamp. Test fixtures only. */
129
+ signedAt?: string;
130
+ }): BehavioralFingerprint;
131
+ /** Verify a BehavioralFingerprint envelope.
132
+ *
133
+ * Performs two checks:
134
+ * 1. Envelope signature: verify the envelope's own Ed25519 signature
135
+ * against the provided measurerPublicKey.
136
+ * 2. Inner fidelity signatures: for each FidelityAttestation in
137
+ * fp.fidelity, run verifyFidelityAttestation against the SAME
138
+ * measurerPublicKey. The per-attestation result is reported in
139
+ * innerFidelitySignaturesValid.
140
+ *
141
+ * Limitation by design: this function does NOT verify pdr_ref.signature or
142
+ * constraint_ref.signature. Those are external axes whose issuers may use
143
+ * different key schemes, signature formats, or canonicalization rules. If
144
+ * those fields carry signatures, callers must verify them out-of-band with
145
+ * the appropriate issuer's verification logic. The fingerprint envelope's
146
+ * own signature still covers the entire pdr_ref / constraint_ref content
147
+ * as JSON, so tampering with their fields will fail envelope verification.
148
+ *
149
+ * Limitation on multi-measurer fidelity attestations: if the inner
150
+ * attestations were signed by different keys than the envelope, their per-
151
+ * attestation entries in innerFidelitySignaturesValid will be false. The
152
+ * envelope itself is still validly signed; callers can re-verify failed
153
+ * inner attestations against the correct keys via verifyFidelityAttestation.
154
+ *
155
+ * The all-or-nothing valid flag is true iff envelope signature is valid
156
+ * AND every inner fidelity signature is valid under the same key.
157
+ */
158
+ export declare function verifyBehavioralFingerprint(fp: BehavioralFingerprint, measurerPublicKey: string): FingerprintVerificationResult;
159
+ /** Pure projection helper for a BehavioralFingerprint. Surfaces the top-
160
+ * level scalar from each axis without combining them into a single number.
161
+ *
162
+ * The paper's three-axis orthogonality claim (Nanook PDR v2.19 §2.2) is
163
+ * untested. This SDK deliberately does NOT bake a combinator policy into
164
+ * the projection: callers that want a composite score must compute it
165
+ * themselves with their own weighting choices. The function returns the
166
+ * raw axis scalars and lets the consumer decide.
167
+ *
168
+ * - fidelityMean: arithmetic mean of fp.fidelity[*].fidelity.score.
169
+ * A simple mean is the right default because each FidelityAttestation
170
+ * represents one HBB probe under different conditions (e.g. pre vs
171
+ * post substrate swap). Confidence-weighting is available inside the
172
+ * individual SubstrateFidelity scoring path; the envelope projection
173
+ * treats each attestation as one observation.
174
+ *
175
+ * - pdrOverall: scoreOverall from the optional PDR reference, or undefined
176
+ * if no PDR axis is present.
177
+ *
178
+ * - constraintCompliance: complianceScore from the optional Saebo
179
+ * reference, or undefined if no constraint axis is present.
180
+ */
181
+ export declare function composeFingerprintAxes(fp: BehavioralFingerprint): {
182
+ fidelityMean: number;
183
+ pdrOverall?: number;
184
+ constraintCompliance?: number;
185
+ };
186
+ //# sourceMappingURL=behavioral-fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"behavioral-fingerprint.d.ts","sourceRoot":"","sources":["../../../src/core/behavioral-fingerprint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,214 @@
1
+ // ══════════════════════════════════════════════════════════════════
2
+ // Behavioral Fingerprint — Three-Axis Joint Measurement Envelope
3
+ // ══════════════════════════════════════════════════════════════════
4
+ // Composes three independent behavioral measurement axes into one signed
5
+ // artifact:
6
+ //
7
+ // Axis 1 (within-session authority-pressure fidelity):
8
+ // AEOESS Hold/Bend/Break — src/core/fidelity-probe.ts
9
+ //
10
+ // Axis 2 (cross-session output reliability):
11
+ // PDR score reference — produced by NexusGuard or any pdr.score.v1 issuer
12
+ //
13
+ // Axis 3 (within-session constraint compliance under value pressure):
14
+ // Saebo et al. constraint score reference — produced by an external scorer
15
+ //
16
+ // The envelope does NOT combine the three axes into a single composite
17
+ // score. The orthogonality claim from Nanook PDR v2.19 §2.2 is untested,
18
+ // and baking a combinator policy into the SDK would prejudge that result.
19
+ // composeFingerprintAxes() is a pure projection helper, nothing more.
20
+ //
21
+ // Signing: Ed25519. The envelope signature covers the canonical JSON of
22
+ // {subject, fidelity, pdr_ref, constraint_ref, measurerId, signedAt} —
23
+ // every field except the signature itself. Inner FidelityAttestation
24
+ // objects retain their own signatures (signed by their own measurer); the
25
+ // envelope signature covers them as JSON content but does not replace
26
+ // their independent verifiability.
27
+ //
28
+ // Reference: Nanook PDR v2.19 §2.2 (three-axis framework), §8.10 (joint
29
+ // experiment design), gap audit §3 row 10, gap audit §5 rank 2.
30
+ // ══════════════════════════════════════════════════════════════════
31
+ import { sign, verify } from '../crypto/keys.js';
32
+ import { canonicalize } from './canonical.js';
33
+ import { verifyFidelityAttestation } from './fidelity-probe.js';
34
+ // ── Create ──
35
+ /** Compose and sign a BehavioralFingerprint envelope.
36
+ *
37
+ * Requires at least one FidelityAttestation. The envelope carries pre-built
38
+ * fidelity attestations as-is — they retain their own measuredBy/signature
39
+ * fields and stay independently verifiable.
40
+ *
41
+ * The signing key is used for the envelope signature only. Inner fidelity
42
+ * attestations were signed earlier by their own measurers; this function
43
+ * does not re-sign them.
44
+ *
45
+ * @throws if fidelity is empty.
46
+ *
47
+ * Reference: Nanook PDR v2.19 §2.2, §8.10. Gap audit §5 rank 2.
48
+ */
49
+ export function createBehavioralFingerprint(subject, fidelity, opts) {
50
+ if (!Array.isArray(fidelity) || fidelity.length === 0) {
51
+ throw new Error('createBehavioralFingerprint: at least one fidelity attestation is required');
52
+ }
53
+ if (!opts.measurerId || typeof opts.measurerId !== 'string') {
54
+ throw new Error('createBehavioralFingerprint: measurerId must be a non-empty string');
55
+ }
56
+ if (!opts.measurerPublicKey || typeof opts.measurerPublicKey !== 'string') {
57
+ throw new Error('createBehavioralFingerprint: measurerPublicKey must be a non-empty string');
58
+ }
59
+ if (!opts.signingKey || typeof opts.signingKey !== 'string') {
60
+ throw new Error('createBehavioralFingerprint: signingKey must be a non-empty string');
61
+ }
62
+ const signedAt = opts.signedAt ?? new Date().toISOString();
63
+ // Build the unsigned envelope. Canonicalize will sort keys alphabetically
64
+ // and strip null/undefined, so PDR/constraint absence produces the same
65
+ // bytes regardless of property declaration order.
66
+ const unsigned = {
67
+ subject,
68
+ fidelity,
69
+ ...(opts.pdr ? { pdr_ref: opts.pdr } : {}),
70
+ ...(opts.constraint ? { constraint_ref: opts.constraint } : {}),
71
+ measurerId: opts.measurerId,
72
+ measurerPublicKey: opts.measurerPublicKey,
73
+ signedAt,
74
+ };
75
+ const payload = canonicalize(unsigned);
76
+ const signature = sign(payload, opts.signingKey);
77
+ return {
78
+ ...unsigned,
79
+ signature,
80
+ };
81
+ }
82
+ // ── Verify ──
83
+ /** Verify a BehavioralFingerprint envelope.
84
+ *
85
+ * Performs two checks:
86
+ * 1. Envelope signature: verify the envelope's own Ed25519 signature
87
+ * against the provided measurerPublicKey.
88
+ * 2. Inner fidelity signatures: for each FidelityAttestation in
89
+ * fp.fidelity, run verifyFidelityAttestation against the SAME
90
+ * measurerPublicKey. The per-attestation result is reported in
91
+ * innerFidelitySignaturesValid.
92
+ *
93
+ * Limitation by design: this function does NOT verify pdr_ref.signature or
94
+ * constraint_ref.signature. Those are external axes whose issuers may use
95
+ * different key schemes, signature formats, or canonicalization rules. If
96
+ * those fields carry signatures, callers must verify them out-of-band with
97
+ * the appropriate issuer's verification logic. The fingerprint envelope's
98
+ * own signature still covers the entire pdr_ref / constraint_ref content
99
+ * as JSON, so tampering with their fields will fail envelope verification.
100
+ *
101
+ * Limitation on multi-measurer fidelity attestations: if the inner
102
+ * attestations were signed by different keys than the envelope, their per-
103
+ * attestation entries in innerFidelitySignaturesValid will be false. The
104
+ * envelope itself is still validly signed; callers can re-verify failed
105
+ * inner attestations against the correct keys via verifyFidelityAttestation.
106
+ *
107
+ * The all-or-nothing valid flag is true iff envelope signature is valid
108
+ * AND every inner fidelity signature is valid under the same key.
109
+ */
110
+ export function verifyBehavioralFingerprint(fp, measurerPublicKey) {
111
+ const errors = [];
112
+ // Validate input shape
113
+ if (!fp || typeof fp !== 'object') {
114
+ return {
115
+ valid: false,
116
+ envelopeSignatureValid: false,
117
+ innerFidelitySignaturesValid: [],
118
+ errors: ['fingerprint is not an object'],
119
+ };
120
+ }
121
+ if (!Array.isArray(fp.fidelity) || fp.fidelity.length === 0) {
122
+ return {
123
+ valid: false,
124
+ envelopeSignatureValid: false,
125
+ innerFidelitySignaturesValid: [],
126
+ errors: ['fingerprint must carry at least one fidelity attestation'],
127
+ };
128
+ }
129
+ // Step 1: envelope signature.
130
+ // Reconstruct the canonical payload exactly as createBehavioralFingerprint
131
+ // produced it: every field except `signature`. Note that the spread-with-
132
+ // conditional pattern in create produces no key for absent optional fields,
133
+ // and canonicalize() strips null/undefined, so the two paths agree.
134
+ const unsigned = {
135
+ subject: fp.subject,
136
+ fidelity: fp.fidelity,
137
+ ...(fp.pdr_ref !== undefined ? { pdr_ref: fp.pdr_ref } : {}),
138
+ ...(fp.constraint_ref !== undefined ? { constraint_ref: fp.constraint_ref } : {}),
139
+ measurerId: fp.measurerId,
140
+ measurerPublicKey: fp.measurerPublicKey,
141
+ signedAt: fp.signedAt,
142
+ };
143
+ const payload = canonicalize(unsigned);
144
+ let envelopeSignatureValid = false;
145
+ try {
146
+ envelopeSignatureValid = verify(payload, fp.signature, measurerPublicKey);
147
+ }
148
+ catch {
149
+ envelopeSignatureValid = false;
150
+ }
151
+ if (!envelopeSignatureValid) {
152
+ errors.push('envelope signature failed verification');
153
+ }
154
+ // Step 2: each inner fidelity attestation under the SAME public key.
155
+ const innerFidelitySignaturesValid = fp.fidelity.map((att, i) => {
156
+ let ok = false;
157
+ try {
158
+ ok = verifyFidelityAttestation(att, measurerPublicKey);
159
+ }
160
+ catch {
161
+ ok = false;
162
+ }
163
+ if (!ok) {
164
+ errors.push(`inner fidelity attestation ${i} (${att.attestationId ?? 'unknown'}) failed verification`);
165
+ }
166
+ return ok;
167
+ });
168
+ const allInnerValid = innerFidelitySignaturesValid.every(Boolean);
169
+ return {
170
+ valid: envelopeSignatureValid && allInnerValid,
171
+ envelopeSignatureValid,
172
+ innerFidelitySignaturesValid,
173
+ errors,
174
+ };
175
+ }
176
+ // ── Compose / Project ──
177
+ /** Pure projection helper for a BehavioralFingerprint. Surfaces the top-
178
+ * level scalar from each axis without combining them into a single number.
179
+ *
180
+ * The paper's three-axis orthogonality claim (Nanook PDR v2.19 §2.2) is
181
+ * untested. This SDK deliberately does NOT bake a combinator policy into
182
+ * the projection: callers that want a composite score must compute it
183
+ * themselves with their own weighting choices. The function returns the
184
+ * raw axis scalars and lets the consumer decide.
185
+ *
186
+ * - fidelityMean: arithmetic mean of fp.fidelity[*].fidelity.score.
187
+ * A simple mean is the right default because each FidelityAttestation
188
+ * represents one HBB probe under different conditions (e.g. pre vs
189
+ * post substrate swap). Confidence-weighting is available inside the
190
+ * individual SubstrateFidelity scoring path; the envelope projection
191
+ * treats each attestation as one observation.
192
+ *
193
+ * - pdrOverall: scoreOverall from the optional PDR reference, or undefined
194
+ * if no PDR axis is present.
195
+ *
196
+ * - constraintCompliance: complianceScore from the optional Saebo
197
+ * reference, or undefined if no constraint axis is present.
198
+ */
199
+ export function composeFingerprintAxes(fp) {
200
+ if (!fp.fidelity || fp.fidelity.length === 0) {
201
+ throw new Error('composeFingerprintAxes: fingerprint has no fidelity attestations');
202
+ }
203
+ const sum = fp.fidelity.reduce((acc, att) => acc + att.fidelity.score, 0);
204
+ const fidelityMean = sum / fp.fidelity.length;
205
+ const result = {
206
+ fidelityMean,
207
+ };
208
+ if (fp.pdr_ref)
209
+ result.pdrOverall = fp.pdr_ref.scoreOverall;
210
+ if (fp.constraint_ref)
211
+ result.constraintCompliance = fp.constraint_ref.complianceScore;
212
+ return result;
213
+ }
214
+ //# sourceMappingURL=behavioral-fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"behavioral-fingerprint.js","sourceRoot":"","sources":["../../../src/core/behavioral-fingerprint.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  // ══════════════════════════════════════════════════════════════════
2
2
  // Denial Domains — Operator-Facing Constraint Grouping
3
3
  // ══════════════════════════════════════════════════════════════════
4
- // The ConstraintVector has 15 facets. That's correct for the machine.
4
+ // The ConstraintVector has 14 facets. That's correct for the machine.
5
5
  // For humans it's unusable. This module groups facets into 5 domains
6
6
  // and provides a primary + contributing denial format.
7
7
  //
8
- // Consilium Priority 4 — unanimous that 15 facets need grouping.
8
+ // Consilium Priority 4 — unanimous that 14 facets need grouping.
9
9
  // Claude: "primary denial reason + count"
10
10
  // GPT: "4 master tiers"
11
11
  // Gemini: "5 operator-facing domains"
@@ -0,0 +1,77 @@
1
+ /** A content-addressable identifier for an evaluation probe. The hash
2
+ * is the canonical JSON of the probe digested with the named algorithm.
3
+ * Two probes with the same content (regardless of property declaration
4
+ * order in the source) produce the same hash. */
5
+ export interface ProbeIdentity {
6
+ /** Hex-encoded digest. Length depends on algorithm: 64 for sha256, 32 for md5. */
7
+ hash: string;
8
+ /** Hash algorithm used. SHA-256 by default; MD5 for Nanook interop. */
9
+ algorithm: 'sha256' | 'md5';
10
+ /** ISO 8601 timestamp of when the hash was computed. The only clock read in this module. */
11
+ computedAt: string;
12
+ }
13
+ /** Result of verifying a probe against an expected hash. The function
14
+ * does NOT throw on mismatch; the caller decides what to do. */
15
+ export interface ProbeIdentityVerification {
16
+ /** True iff computedHash === expectedHash. */
17
+ match: boolean;
18
+ /** The hash the caller said the probe should have. */
19
+ expectedHash: string;
20
+ /** The hash actually computed from the probe. */
21
+ computedHash: string;
22
+ /** Algorithm used for the recomputation. */
23
+ algorithm: 'sha256' | 'md5';
24
+ }
25
+ /**
26
+ * Compute a content-addressable identity for an evaluation probe.
27
+ *
28
+ * The probe is canonicalized via canonicalize() from canonical.ts (RFC
29
+ * 8785 JCS) before hashing. This means two probes with the same content
30
+ * but different property declaration order produce identical hashes,
31
+ * which is the entire point of the utility — it lets a downstream
32
+ * scoring system prove that the probe it scored is byte-identical to the
33
+ * probe the issuer published, even after a JSON round-trip that may have
34
+ * reordered keys.
35
+ *
36
+ * Pure in algorithmic terms: same input + same algorithm always
37
+ * produces the same hash. The only side effect is the ISO timestamp
38
+ * captured in computedAt, which is set from new Date(). Callers that
39
+ * need fully deterministic output (e.g. test fixtures) should compare
40
+ * the hash field directly and ignore computedAt.
41
+ *
42
+ * @param probe Any JSON-serializable value. Typically a FidelityChallenge
43
+ * or similar evaluation probe object.
44
+ * @param opts.algorithm 'sha256' (default) or 'md5' for Nanook interop.
45
+ *
46
+ * Reference: Nanook PDR v2.19 §5.9, gap audit §3 row 16 / §5 rank 7.
47
+ */
48
+ export declare function computeProbeIdentity(probe: unknown, opts?: {
49
+ algorithm?: 'sha256' | 'md5';
50
+ }): ProbeIdentity;
51
+ /**
52
+ * Verify that a probe matches an expected hash.
53
+ *
54
+ * Recomputes the hash from the probe via canonicalize() + the chosen
55
+ * algorithm and compares to the expected hash. Returns a verification
56
+ * result with both hashes exposed for diagnostic visibility.
57
+ *
58
+ * Does NOT throw on mismatch. Callers decide what to do with a false
59
+ * match: log it, deny the action, fall back to a different probe, etc.
60
+ * The function is purely informational.
61
+ *
62
+ * Algorithm mismatch case: if the caller passes an expectedHash that was
63
+ * produced under a different algorithm than the one passed via opts
64
+ * (e.g. expectedHash is a SHA-256 digest but opts.algorithm is 'md5'),
65
+ * the function recomputes under the requested algorithm and reports
66
+ * match: false. The function does not try to detect the mismatch
67
+ * automatically — the algorithm is a caller-provided assertion about how
68
+ * the expectedHash was originally computed.
69
+ *
70
+ * @param probe Any JSON-serializable value.
71
+ * @param expectedHash Hex-encoded digest the caller asserts the probe should produce.
72
+ * @param opts.algorithm Algorithm to use for the recomputation. Default 'sha256'.
73
+ */
74
+ export declare function verifyProbeIdentity(probe: unknown, expectedHash: string, opts?: {
75
+ algorithm?: 'sha256' | 'md5';
76
+ }): ProbeIdentityVerification;
77
+ //# sourceMappingURL=probe-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe-identity.d.ts","sourceRoot":"","sources":["../../../src/core/probe-identity.ts"],"names":[],"mappings":"AAoCA;;;kDAGkD;AAClD,MAAM,WAAW,aAAa;IAC5B,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAA;IACZ,uEAAuE;IACvE,SAAS,EAAE,QAAQ,GAAG,KAAK,CAAA;IAC3B,4FAA4F;IAC5F,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;iEACiE;AACjE,MAAM,WAAW,yBAAyB;IACxC,8CAA8C;IAC9C,KAAK,EAAE,OAAO,CAAA;IACd,sDAAsD;IACtD,YAAY,EAAE,MAAM,CAAA;IACpB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAA;IACpB,4CAA4C;IAC5C,SAAS,EAAE,QAAQ,GAAG,KAAK,CAAA;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;CAAE,GACtC,aAAa,CASf;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;CAAE,GACtC,yBAAyB,CAU3B"}
@@ -0,0 +1,102 @@
1
+ // Copyright 2024-2026 Tymofii Pidlisnyi. Apache-2.0 license. See LICENSE.
2
+ // ══════════════════════════════════════════════════════════════════
3
+ // Probe Identity — Content-Addressable Hashing for Evaluation Probes
4
+ // ══════════════════════════════════════════════════════════════════
5
+ // Reference: Nanook PDR v2.19 §5.9 (MD5 hash prompt identity verification),
6
+ // gap audit §3 row 16 / §5 rank 7.
7
+ //
8
+ // Nanook §5.9 uses an MD5 hash of the evaluation probe prompt to
9
+ // eliminate input variation as a confound: every scoring run can prove
10
+ // it used byte-identical input. APS has canonical JSON serialization in
11
+ // canonical.ts but no probe-prompt identity verification protocol. This
12
+ // utility ships that protocol.
13
+ //
14
+ // Algorithm choice:
15
+ // APS defaults to SHA-256 because the rest of the SDK uses it
16
+ // (canonical.ts, signatures, content hashing). MD5 is available as an
17
+ // opt-in for interop with Nanook's existing probe bank. Callers pick
18
+ // via opts.algorithm. Both produce hex strings.
19
+ //
20
+ // Canonicalization:
21
+ // The point of this utility is that two JSON objects with the same
22
+ // content but different key declaration order produce the same hash.
23
+ // canonicalize() from canonical.ts (RFC 8785 JCS) guarantees this by
24
+ // sorting keys alphabetically and stripping null/undefined. Do NOT use
25
+ // JSON.stringify() directly — declaration order would leak through.
26
+ //
27
+ // Array semantics:
28
+ // canonicalize() preserves array order because array order is semantic
29
+ // in JSON. [1, 2, 3] and [3, 2, 1] produce different hashes. This is
30
+ // correct: a probe that asks the agent to compute things in a specific
31
+ // sequence should be a different probe if the sequence changes.
32
+ // ══════════════════════════════════════════════════════════════════
33
+ import { createHash } from 'node:crypto';
34
+ import { canonicalize } from './canonical.js';
35
+ /**
36
+ * Compute a content-addressable identity for an evaluation probe.
37
+ *
38
+ * The probe is canonicalized via canonicalize() from canonical.ts (RFC
39
+ * 8785 JCS) before hashing. This means two probes with the same content
40
+ * but different property declaration order produce identical hashes,
41
+ * which is the entire point of the utility — it lets a downstream
42
+ * scoring system prove that the probe it scored is byte-identical to the
43
+ * probe the issuer published, even after a JSON round-trip that may have
44
+ * reordered keys.
45
+ *
46
+ * Pure in algorithmic terms: same input + same algorithm always
47
+ * produces the same hash. The only side effect is the ISO timestamp
48
+ * captured in computedAt, which is set from new Date(). Callers that
49
+ * need fully deterministic output (e.g. test fixtures) should compare
50
+ * the hash field directly and ignore computedAt.
51
+ *
52
+ * @param probe Any JSON-serializable value. Typically a FidelityChallenge
53
+ * or similar evaluation probe object.
54
+ * @param opts.algorithm 'sha256' (default) or 'md5' for Nanook interop.
55
+ *
56
+ * Reference: Nanook PDR v2.19 §5.9, gap audit §3 row 16 / §5 rank 7.
57
+ */
58
+ export function computeProbeIdentity(probe, opts) {
59
+ const algorithm = opts?.algorithm ?? 'sha256';
60
+ const canonical = canonicalize(probe);
61
+ const hash = createHash(algorithm).update(canonical).digest('hex');
62
+ return {
63
+ hash,
64
+ algorithm,
65
+ computedAt: new Date().toISOString(),
66
+ };
67
+ }
68
+ /**
69
+ * Verify that a probe matches an expected hash.
70
+ *
71
+ * Recomputes the hash from the probe via canonicalize() + the chosen
72
+ * algorithm and compares to the expected hash. Returns a verification
73
+ * result with both hashes exposed for diagnostic visibility.
74
+ *
75
+ * Does NOT throw on mismatch. Callers decide what to do with a false
76
+ * match: log it, deny the action, fall back to a different probe, etc.
77
+ * The function is purely informational.
78
+ *
79
+ * Algorithm mismatch case: if the caller passes an expectedHash that was
80
+ * produced under a different algorithm than the one passed via opts
81
+ * (e.g. expectedHash is a SHA-256 digest but opts.algorithm is 'md5'),
82
+ * the function recomputes under the requested algorithm and reports
83
+ * match: false. The function does not try to detect the mismatch
84
+ * automatically — the algorithm is a caller-provided assertion about how
85
+ * the expectedHash was originally computed.
86
+ *
87
+ * @param probe Any JSON-serializable value.
88
+ * @param expectedHash Hex-encoded digest the caller asserts the probe should produce.
89
+ * @param opts.algorithm Algorithm to use for the recomputation. Default 'sha256'.
90
+ */
91
+ export function verifyProbeIdentity(probe, expectedHash, opts) {
92
+ const algorithm = opts?.algorithm ?? 'sha256';
93
+ const canonical = canonicalize(probe);
94
+ const computedHash = createHash(algorithm).update(canonical).digest('hex');
95
+ return {
96
+ match: computedHash === expectedHash,
97
+ expectedHash,
98
+ computedHash,
99
+ algorithm,
100
+ };
101
+ }
102
+ //# sourceMappingURL=probe-identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe-identity.js","sourceRoot":"","sources":["../../../src/core/probe-identity.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,qEAAqE;AACrE,qEAAqE;AACrE,qEAAqE;AACrE,4EAA4E;AAC5E,mCAAmC;AACnC,EAAE;AACF,iEAAiE;AACjE,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,+BAA+B;AAC/B,EAAE;AACF,oBAAoB;AACpB,gEAAgE;AAChE,wEAAwE;AACxE,uEAAuE;AACvE,kDAAkD;AAClD,EAAE;AACF,oBAAoB;AACpB,qEAAqE;AACrE,uEAAuE;AACvE,uEAAuE;AACvE,yEAAyE;AACzE,sEAAsE;AACtE,EAAE;AACF,mBAAmB;AACnB,yEAAyE;AACzE,uEAAuE;AACvE,yEAAyE;AACzE,kEAAkE;AAClE,qEAAqE;AAErE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AA4B7C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAc,EACd,IAAuC;IAEvC,MAAM,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,QAAQ,CAAA;IAC7C,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;IACrC,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAClE,OAAO;QACL,IAAI;QACJ,SAAS;QACT,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAAc,EACd,YAAoB,EACpB,IAAuC;IAEvC,MAAM,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,QAAQ,CAAA;IAC7C,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;IACrC,MAAM,YAAY,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC1E,OAAO;QACL,KAAK,EAAE,YAAY,KAAK,YAAY;QACpC,YAAY;QACZ,YAAY;QACZ,SAAS;KACV,CAAA;AACH,CAAC"}