@onchaindiligence/agent-evidence 0.1.0 → 0.2.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
@@ -5,17 +5,34 @@ OnChainDiligence Agent Evidence v0 protocol. It creates deterministic records,
5
5
  validates the complete evidence DAG, seals bundles with Ed25519 DSSE, and
6
6
  verifies portable bundles offline with caller-supplied trust.
7
7
 
8
- The package is currently **packable and publish-ready, but not yet published to
9
- npm**. Do not advertise a registry install until the owner completes npm trusted
10
- publishing. From this repository, test the exact public artifact with:
8
+ The package is publicly available on npm:
11
9
 
12
10
  ```sh
13
- npm pack ./packages/agent-evidence
14
- npm install ./onchaindiligence-agent-evidence-0.1.0.tgz
11
+ npm install @onchaindiligence/agent-evidence
12
+ # or pin this release
13
+ npm install @onchaindiligence/agent-evidence@0.2.0
15
14
  ```
16
15
 
16
+ This source README reflects the public release. The immutable README embedded
17
+ in the already-published `0.1.0` tarball carried its pre-release wording; this
18
+ release includes the corrected package documentation.
19
+
17
20
  Node.js 20.19 or newer and ESM are required.
18
21
 
22
+ ## 0.2.0
23
+
24
+ - Adds strict parsing of generic Agent Evidence signer registries and
25
+ `TrustPolicy` construction from independently supplied registry metadata.
26
+ - Packages the key-registry JSON Schema, interoperability profile support, and
27
+ browser/offline-friendly registry types.
28
+ - Adds Technocore signed-message and tclk/1 coordination-evidence adapters.
29
+
30
+ The verifier remains caller-trust-controlled: embedded bundle keys are never
31
+ trust roots. A Technocore signature proves key possession/authorship of exact
32
+ bytes, not truth; tclk evidence proves coordination, not settlement; and
33
+ PaperRail represents no real value. `VALID`, `INVALID`, and `UNVERIFIABLE`
34
+ semantics are unchanged.
35
+
19
36
  ## What a signature proves
20
37
 
21
38
  A valid signature proves that the identified key signed the exact canonical
@@ -90,6 +107,81 @@ where policy withholds an invoice payment because recipient ownership evidence
90
107
  is missing. The execution is `withheld-not-submitted`; the example does not
91
108
  fabricate a transaction or settlement.
92
109
 
110
+ ## Technocore signed-message evidence
111
+
112
+ `technocore.chat` signed-lane messages can be captured as attributable, offline
113
+ verifiable input with no resolver or network call. The adapter mirrors the
114
+ official single-line sweep and verifies the exact UTF-8
115
+ `<room>|<nonce>|<stored-text>` string against the Ed25519 public key embedded in
116
+ the sender's `did:key`.
117
+
118
+ ```js
119
+ import { createTechnocoreEvidence, verifyTechnocoreMessage } from '@onchaindiligence/agent-evidence'
120
+
121
+ // Treat every field as untrusted data obtained from Technocore's JSON response.
122
+ if (!verifyTechnocoreMessage({ did, room, nonce, text, sig })) throw new Error('invalid assertion')
123
+ const evidence = createTechnocoreEvidence({ did, room, nonce, text, sig }, {
124
+ runRef: run.id,
125
+ observedAt: '2026-09-01T12:00:01.000Z',
126
+ serverMetadata: { seq: String(seq), ts: String(ts), generation: String(generation) },
127
+ })
128
+ ```
129
+
130
+ The resulting record preserves the DID, room, nonce, exact stored text, its
131
+ SHA-256 digest, signature, signing format, and optional server metadata. It
132
+ always uses `trust_mode: 'agent-assertion'`: a valid signature proves only that
133
+ that `did:key` asserted those bytes. It never proves the message is true,
134
+ authorizes an action, supplies a trusted instruction, or permits a wallet/
135
+ network action. `verifyTechnocoreMessage` and normal bundle verification are
136
+ fully offline and make no HTTP requests.
137
+
138
+ [`examples/technocore-evidence.mjs`](./examples/technocore-evidence.mjs) builds
139
+ Mandate → Technocore Evidence → Policy → Decision → non-execution → DSSE-sealed
140
+ bundle → offline `VALID` verification.
141
+
142
+ ## tclk/1 (Technocore Lock Protocol) transcript evidence
143
+
144
+ Signed agent-to-agent deal coordination on [`technocore.chat`](https://github.com/flop-labs/technocore-chat)
145
+ using FLOP Labs' [`@flop-labs/tclk`](https://github.com/flop-labs/tclk) (`offer →
146
+ accept → lock → reveal/refund`) can be captured as Agent Evidence. This adapter
147
+ uses the official `@flop-labs/tclk` package directly — it never reimplements
148
+ frame validation or the state machine, and never uses tclk's unaudited
149
+ PTLC/adaptor-signature path.
150
+
151
+ ```js
152
+ import { verifyTclkTranscript, createTclkEvidence } from '@onchaindiligence/agent-evidence'
153
+
154
+ // Each entry is a Technocore signed message whose text is a tclk/1 frame line,
155
+ // plus the wall-clock time (ms) at which that frame was applied.
156
+ const transcript = verifyTclkTranscript([
157
+ { message: offerMsg, atMs }, { message: acceptMsg, atMs }, { message: lockMsg, atMs },
158
+ ])
159
+ const evidence = createTclkEvidence(transcript, {
160
+ runRef: run.id, observedAt, messageEvidenceRefs: [/* one createTechnocoreEvidence(...).id per message */],
161
+ })
162
+ ```
163
+
164
+ `verifyTclkTranscript` verifies, independently, per frame: the Technocore
165
+ transport signature (reusing `verifyTechnocoreMessage`, not a second
166
+ implementation), the tclk frame's own validity, that the frame's `from` matches
167
+ the transport-authenticated DID, and the official state-machine transition. It
168
+ fails closed on a bad signature, a malformed frame, or a sender/DID mismatch; a
169
+ frame the *official* machine itself rejects as a designed-in no-op (a replay, a
170
+ duplicate, an out-of-order transition) is recorded in the result rather than
171
+ treated as fatal, per tclk's own spec.
172
+
173
+ **Valid signed coordination is evidence of what the agents agreed/asserted. The
174
+ named settlement rail remains authoritative for actual value movement** — a
175
+ `lock` frame is captured as "payer asserted/announced lock on rail X," never as
176
+ "funds were locked," unless the caller separately supplies an independently
177
+ verified `settlementRail` observation (this package implements no rail).
178
+
179
+ [`examples/tclk-evidence.mjs`](./examples/tclk-evidence.mjs) builds a full
180
+ hash-lock transcript (offer → accept → lock → reveal) between two local test
181
+ identities and turns it into Mandate → tclk Evidence → Policy → Decision
182
+ (`ACCEPT_COORDINATION_EVIDENCE`) → Execution (`NO_REAL_VALUE_SETTLEMENT`, since
183
+ no real rail is wired up) → sealed bundle → offline `VALID` verification.
184
+
93
185
  ## Schemas and interoperability
94
186
 
95
187
  The npm artifact includes the canonical v0 schemas and public conformance
package/dist/index.d.ts CHANGED
@@ -6,9 +6,15 @@ export { AgentEvidenceError, CanonicalizationError, EvidenceValidationError, Par
6
6
  export { validateBundlePayload } from './graph.js';
7
7
  export { createBundlePayload, createRecord } from './records.js';
8
8
  export type { CreateBundlePayloadOptions, CreateRecordOptions } from './records.js';
9
+ export { createTechnocoreEvidence, sweepTechnocoreText, technocoreDidFromPublicKey, technocoreSigningInput, technocoreTextDigest, verifyTechnocoreMessage, } from './technocore.js';
10
+ export type { TechnocoreEvidenceOptions, TechnocoreSignedMessage } from './technocore.js';
11
+ export { createTclkEvidence, verifyTclkTranscript } from './tclk.js';
12
+ export type { SettlementRailObservation, TclkEvidenceOptions, TclkTranscriptMessage, TclkTranscriptResult, TclkTranscriptStep, } from './tclk.js';
9
13
  export { validateDocument } from './schema.js';
10
14
  export { AttestationKey, createKeyRecord, deriveKeyId, evaluateKeyLifecycle, loadPublicKey, TrustPolicy, } from './trust.js';
11
15
  export type { CreateKeyRecordOptions, TrustPolicyOptions } from './trust.js';
16
+ export { parseAgentEvidenceKeyRegistry, trustPolicyFromKeyRegistry } from './registry.js';
17
+ export type { AgentEvidenceKeyRegistry, AgentEvidenceKeyRegistryEntry, ParseAgentEvidenceKeyRegistryOptions, } from './registry.js';
12
18
  export { overallState, verifyBundle } from './verifier.js';
13
19
  export type { AgentEvidenceRecord, AttestationKeyRecord, BundlePayload, ComponentResult, DsseEnvelope, DsseSignature, Ed25519Signer, JsonObject, JsonPrimitive, JsonValue, KeyInput, PortableBundle, RecordKind, VerificationMaterial, VerificationReport, VerificationState, } from './types.js';
14
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,cAAc,EACd,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,eAAe,EACf,SAAS,EACT,cAAc,GACf,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACpE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,EACV,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,GACjB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAChE,YAAY,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACnF,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EACL,cAAc,EACd,eAAe,EACf,WAAW,EACX,oBAAoB,EACpB,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC5E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC1D,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,aAAa,EACb,aAAa,EACb,UAAU,EACV,aAAa,EACb,SAAS,EACT,QAAQ,EACR,cAAc,EACd,UAAU,EACV,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,cAAc,EACd,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,eAAe,EACf,SAAS,EACT,cAAc,GACf,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACpE,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,EACV,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,GACjB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAChE,YAAY,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AACnF,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,iBAAiB,CAAA;AACxB,YAAY,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AACzF,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AACpE,YAAY,EACV,yBAAyB,EACzB,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EACL,cAAc,EACd,eAAe,EACf,WAAW,EACX,oBAAoB,EACpB,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC5E,OAAO,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAA;AACzF,YAAY,EACV,wBAAwB,EACxB,6BAA6B,EAC7B,oCAAoC,GACrC,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC1D,YAAY,EACV,mBAAmB,EACnB,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,aAAa,EACb,aAAa,EACb,UAAU,EACV,aAAa,EACb,SAAS,EACT,QAAQ,EACR,cAAc,EACd,UAAU,EACV,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,YAAY,CAAA"}
package/dist/index.js CHANGED
@@ -4,7 +4,10 @@ export { createEd25519Signer, dssePae, sealBundle } from './dsse.js';
4
4
  export { AgentEvidenceError, CanonicalizationError, EvidenceValidationError, ParseError, SchemaValidationError, SigningError, TrustPolicyError, } from './errors.js';
5
5
  export { validateBundlePayload } from './graph.js';
6
6
  export { createBundlePayload, createRecord } from './records.js';
7
+ export { createTechnocoreEvidence, sweepTechnocoreText, technocoreDidFromPublicKey, technocoreSigningInput, technocoreTextDigest, verifyTechnocoreMessage, } from './technocore.js';
8
+ export { createTclkEvidence, verifyTclkTranscript } from './tclk.js';
7
9
  export { validateDocument } from './schema.js';
8
10
  export { AttestationKey, createKeyRecord, deriveKeyId, evaluateKeyLifecycle, loadPublicKey, TrustPolicy, } from './trust.js';
11
+ export { parseAgentEvidenceKeyRegistry, trustPolicyFromKeyRegistry } from './registry.js';
9
12
  export { overallState, verifyBundle } from './verifier.js';
10
13
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,cAAc,EACd,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,eAAe,EACf,SAAS,EACT,cAAc,GACf,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEpE,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,EACV,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,GACjB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EACL,cAAc,EACd,eAAe,EACf,WAAW,EACX,oBAAoB,EACpB,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,cAAc,EACd,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,eAAe,EACf,SAAS,EACT,cAAc,GACf,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEpE,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,EACV,qBAAqB,EACrB,YAAY,EACZ,gBAAgB,GACjB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAEhE,OAAO,EACL,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,iBAAiB,CAAA;AAExB,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAQpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EACL,cAAc,EACd,eAAe,EACf,WAAW,EACX,oBAAoB,EACpB,aAAa,EACb,WAAW,GACZ,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAA;AAMzF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA"}
@@ -0,0 +1,76 @@
1
+ import { TrustPolicy, type TrustPolicyOptions } from './trust.js';
2
+ import type { JsonObject } from './types.js';
3
+ /**
4
+ * Agent Evidence Interoperability Profile v1 — public signer key registry.
5
+ *
6
+ * See docs/AGENT_EVIDENCE_INTEROP.md for the full profile. This module parses
7
+ * and validates the WIRE format any issuer (ArcFX is the current production
8
+ * reference) can publish at `GET /.well-known/agent-evidence-keys`, and maps
9
+ * validated entries into the existing `AttestationKeyRecord` shape so they
10
+ * flow through the same `TrustPolicy` / `evaluateKeyLifecycle` machinery as
11
+ * every other trusted key in this package — no second lifecycle model.
12
+ *
13
+ * This module does NOT fetch anything over the network. Network fetching is
14
+ * the caller's concern (see the profile doc for the recommended pattern); the
15
+ * core SDK stays fully usable offline. Hosting this endpoint is a discovery
16
+ * convenience only — it does not by itself make an issuer trustworthy, and an
17
+ * embedded bundle key never establishes trust regardless of what any registry
18
+ * says. Trust is always the caller's `TrustPolicy`.
19
+ */
20
+ export interface AgentEvidenceKeyRegistryEntry extends JsonObject {
21
+ key_id: string;
22
+ algorithm: 'Ed25519';
23
+ public_key_pem: string;
24
+ valid_from: string | null;
25
+ valid_until: string | null;
26
+ revoked_at: string | null;
27
+ status: 'active' | 'retired' | 'revoked' | 'compromised';
28
+ }
29
+ export interface AgentEvidenceKeyRegistry extends JsonObject {
30
+ schema_version: 1;
31
+ issuer: string;
32
+ environment: string;
33
+ keys: AgentEvidenceKeyRegistryEntry[];
34
+ }
35
+ export interface ParseAgentEvidenceKeyRegistryOptions {
36
+ /** Reject the registry unless `issuer` equals exactly this string. */
37
+ expectedIssuer?: string;
38
+ /** Reject the registry unless `environment` equals exactly this string. */
39
+ expectedEnvironment?: string;
40
+ }
41
+ /**
42
+ * Validates untrusted parsed JSON as an Agent Evidence key registry (schema
43
+ * `agent-evidence-key-registry.schema.json`), optionally pinning the exact
44
+ * `issuer`/`environment` a caller expects.
45
+ *
46
+ * Fails closed: throws `TrustPolicyError` on any structural violation
47
+ * (missing/extra fields, wrong types, a malformed key entry anywhere in the
48
+ * array, an issuer/environment mismatch) rather than returning a partial or
49
+ * best-effort result. A caller integrating this over the network should treat
50
+ * a thrown error here — like a failed fetch — as "no trust available from
51
+ * this source" (typically UNVERIFIABLE for anything that key would have
52
+ * signed), never as INVALID: an unreachable or misconfigured registry is not
53
+ * evidence that a bundle's signature is fraudulent.
54
+ *
55
+ * `key_id` alone is never sufficient to establish trust, and this function
56
+ * does not establish trust either — it only validates shape. Feed the result
57
+ * to `trustPolicyFromKeyRegistry`, or your own mapping, to actually build a
58
+ * `TrustPolicy`.
59
+ */
60
+ export declare function parseAgentEvidenceKeyRegistry(payload: unknown, options?: ParseAgentEvidenceKeyRegistryOptions): AgentEvidenceKeyRegistry;
61
+ /**
62
+ * Parses and validates an Agent Evidence key registry, then constructs a
63
+ * `TrustPolicy` from its keys — the recommended one-call path from an
64
+ * untrusted registry payload to a usable trust policy.
65
+ *
66
+ * Equivalent to `TrustPolicy.fromKeyRecords(parseAgentEvidenceKeyRegistry(payload, opts).keys.map(...), trustPolicyOptions)`,
67
+ * so it inherits every existing `TrustPolicy`/`evaluateKeyLifecycle` guarantee:
68
+ * a revoked or compromised key still fails closed to INVALID when it signs
69
+ * something, a key with no `valid_from` is UNVERIFIABLE, and so on — this
70
+ * function adds no new trust semantics, only a convenient on-ramp into the
71
+ * existing ones.
72
+ */
73
+ export declare function trustPolicyFromKeyRegistry(payload: unknown, options?: ParseAgentEvidenceKeyRegistryOptions & {
74
+ trustPolicy?: TrustPolicyOptions;
75
+ }): TrustPolicy;
76
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACjE,OAAO,KAAK,EAAwB,UAAU,EAAE,MAAM,YAAY,CAAA;AAElE;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,6BAA8B,SAAQ,UAAU;IAC/D,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAA;CACzD;AAED,MAAM,WAAW,wBAAyB,SAAQ,UAAU;IAC1D,cAAc,EAAE,CAAC,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,6BAA6B,EAAE,CAAA;CACtC;AAED,MAAM,WAAW,oCAAoC;IACnD,sEAAsE;IACtE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,2EAA2E;IAC3E,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,oCAAyC,GACjD,wBAAwB,CAmB1B;AA6BD;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,oCAAoC,GAAG;IAAE,WAAW,CAAC,EAAE,kBAAkB,CAAA;CAAO,GACxF,WAAW,CAGb"}
@@ -0,0 +1,83 @@
1
+ import { SchemaValidationError, TrustPolicyError } from './errors.js';
2
+ import { validateDocument } from './schema.js';
3
+ import { TrustPolicy } from './trust.js';
4
+ /**
5
+ * Validates untrusted parsed JSON as an Agent Evidence key registry (schema
6
+ * `agent-evidence-key-registry.schema.json`), optionally pinning the exact
7
+ * `issuer`/`environment` a caller expects.
8
+ *
9
+ * Fails closed: throws `TrustPolicyError` on any structural violation
10
+ * (missing/extra fields, wrong types, a malformed key entry anywhere in the
11
+ * array, an issuer/environment mismatch) rather than returning a partial or
12
+ * best-effort result. A caller integrating this over the network should treat
13
+ * a thrown error here — like a failed fetch — as "no trust available from
14
+ * this source" (typically UNVERIFIABLE for anything that key would have
15
+ * signed), never as INVALID: an unreachable or misconfigured registry is not
16
+ * evidence that a bundle's signature is fraudulent.
17
+ *
18
+ * `key_id` alone is never sufficient to establish trust, and this function
19
+ * does not establish trust either — it only validates shape. Feed the result
20
+ * to `trustPolicyFromKeyRegistry`, or your own mapping, to actually build a
21
+ * `TrustPolicy`.
22
+ */
23
+ export function parseAgentEvidenceKeyRegistry(payload, options = {}) {
24
+ try {
25
+ validateDocument('agent-evidence-key-registry.schema.json', payload);
26
+ }
27
+ catch (error) {
28
+ if (error instanceof SchemaValidationError)
29
+ throw new TrustPolicyError(error.message, { cause: error });
30
+ throw error;
31
+ }
32
+ const registry = payload;
33
+ if (options.expectedIssuer !== undefined && registry.issuer !== options.expectedIssuer) {
34
+ throw new TrustPolicyError(`registry issuer "${registry.issuer}" does not match the expected issuer "${options.expectedIssuer}"`);
35
+ }
36
+ if (options.expectedEnvironment !== undefined && registry.environment !== options.expectedEnvironment) {
37
+ throw new TrustPolicyError(`registry environment "${registry.environment}" does not match the expected environment "${options.expectedEnvironment}"`);
38
+ }
39
+ return registry;
40
+ }
41
+ /**
42
+ * Maps one validated registry entry onto the package's own trusted-key record
43
+ * shape. The internal `AttestationKeyRecord` model requires an "active" key to
44
+ * carry no `valid_until` (open-ended) -- a bounded validity window is what
45
+ * "retired" means internally. A generic registry has no such constraint (an
46
+ * issuer's own "active" just means "not revoked"), so a registry-reported
47
+ * active key with a bounded `valid_until` maps to the internal "retired"
48
+ * status; the underlying lifecycle window is honored either way via
49
+ * `evaluateKeyLifecycle`, only the label changes.
50
+ */
51
+ function toAttestationKeyRecord(entry) {
52
+ const revoked = entry.status === 'revoked' || entry.status === 'compromised';
53
+ const status = entry.status === 'active' && entry.valid_until !== null ? 'retired' : entry.status;
54
+ return {
55
+ key_id: entry.key_id,
56
+ algorithm: 'ed25519',
57
+ public_key_pem: entry.public_key_pem,
58
+ status,
59
+ valid_from: entry.valid_from,
60
+ valid_until: entry.valid_until,
61
+ status_changed_at: revoked ? entry.revoked_at : entry.valid_from,
62
+ replacement_key_id: null,
63
+ compromised_at: entry.status === 'compromised' ? entry.revoked_at : null,
64
+ ...(revoked ? { status_reason: `registry-reported ${entry.status} at ${entry.revoked_at ?? 'unknown time'}` } : {}),
65
+ };
66
+ }
67
+ /**
68
+ * Parses and validates an Agent Evidence key registry, then constructs a
69
+ * `TrustPolicy` from its keys — the recommended one-call path from an
70
+ * untrusted registry payload to a usable trust policy.
71
+ *
72
+ * Equivalent to `TrustPolicy.fromKeyRecords(parseAgentEvidenceKeyRegistry(payload, opts).keys.map(...), trustPolicyOptions)`,
73
+ * so it inherits every existing `TrustPolicy`/`evaluateKeyLifecycle` guarantee:
74
+ * a revoked or compromised key still fails closed to INVALID when it signs
75
+ * something, a key with no `valid_from` is UNVERIFIABLE, and so on — this
76
+ * function adds no new trust semantics, only a convenient on-ramp into the
77
+ * existing ones.
78
+ */
79
+ export function trustPolicyFromKeyRegistry(payload, options = {}) {
80
+ const registry = parseAgentEvidenceKeyRegistry(payload, options);
81
+ return TrustPolicy.fromKeyRecords(registry.keys.map(toAttestationKeyRecord), options.trustPolicy);
82
+ }
83
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,WAAW,EAA2B,MAAM,YAAY,CAAA;AA6CjE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,6BAA6B,CAC3C,OAAgB,EAChB,UAAgD,EAAE;IAElD,IAAI,CAAC;QACH,gBAAgB,CAAC,yCAAyC,EAAE,OAAO,CAAC,CAAA;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,qBAAqB;YAAE,MAAM,IAAI,gBAAgB,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAA;QACvG,MAAM,KAAK,CAAA;IACb,CAAC;IACD,MAAM,QAAQ,GAAG,OAAmC,CAAA;IACpD,IAAI,OAAO,CAAC,cAAc,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,CAAC,cAAc,EAAE,CAAC;QACvF,MAAM,IAAI,gBAAgB,CACxB,oBAAoB,QAAQ,CAAC,MAAM,yCAAyC,OAAO,CAAC,cAAc,GAAG,CACtG,CAAA;IACH,CAAC;IACD,IAAI,OAAO,CAAC,mBAAmB,KAAK,SAAS,IAAI,QAAQ,CAAC,WAAW,KAAK,OAAO,CAAC,mBAAmB,EAAE,CAAC;QACtG,MAAM,IAAI,gBAAgB,CACxB,yBAAyB,QAAQ,CAAC,WAAW,8CAA8C,OAAO,CAAC,mBAAmB,GAAG,CAC1H,CAAA;IACH,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,sBAAsB,CAAC,KAAoC;IAClE,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,aAAa,CAAA;IAC5E,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAA;IACjG,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,SAAS;QACpB,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,MAAM;QACN,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,iBAAiB,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU;QAChE,kBAAkB,EAAE,IAAI;QACxB,cAAc,EAAE,KAAK,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;QACxE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,qBAAqB,KAAK,CAAC,MAAM,OAAO,KAAK,CAAC,UAAU,IAAI,cAAc,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpH,CAAA;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAgB,EAChB,UAAuF,EAAE;IAEzF,MAAM,QAAQ,GAAG,6BAA6B,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;IAChE,OAAO,WAAW,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAA;AACnG,CAAC"}
package/dist/schema.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export declare const SCHEMA_BASE = "https://onchaindiligence.com/schemas/agent-evidence/v0/";
2
- export declare const SCHEMA_NAMES: readonly ["common.schema.json", "attestation-key.schema.json", "dsse-envelope.schema.json", "proof.schema.json", "record.schema.json", "bundle-payload.schema.json", "portable-file.schema.json"];
2
+ export declare const SCHEMA_NAMES: readonly ["common.schema.json", "attestation-key.schema.json", "dsse-envelope.schema.json", "proof.schema.json", "record.schema.json", "bundle-payload.schema.json", "portable-file.schema.json", "agent-evidence-key-registry.schema.json"];
3
3
  export declare function validateDocument(name: string, value: unknown): void;
4
4
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW,4DAA4D,CAAA;AACpF,eAAO,MAAM,YAAY,mMAQf,CAAA;AA6BV,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAOnE"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,WAAW,4DAA4D,CAAA;AACpF,eAAO,MAAM,YAAY,8OASf,CAAA;AA6BV,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAOnE"}
package/dist/schema.js CHANGED
@@ -11,6 +11,7 @@ export const SCHEMA_NAMES = [
11
11
  'record.schema.json',
12
12
  'bundle-payload.schema.json',
13
13
  'portable-file.schema.json',
14
+ 'agent-evidence-key-registry.schema.json',
14
15
  ];
15
16
  const Ajv2020 = Ajv2020Import;
16
17
  const addFormats = addFormatsImport;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,aAAa,EAAE,EAA2C,MAAM,kBAAkB,CAAA;AACzF,OAAO,gBAAgB,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAEnD,MAAM,CAAC,MAAM,WAAW,GAAG,yDAAyD,CAAA;AACpF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,oBAAoB;IACpB,6BAA6B;IAC7B,2BAA2B;IAC3B,mBAAmB;IACnB,oBAAoB;IACpB,4BAA4B;IAC5B,2BAA2B;CACnB,CAAA;AAOV,MAAM,OAAO,GAAG,aAAgF,CAAA;AAChG,MAAM,UAAU,GAAG,gBAA6D,CAAA;AAChF,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;AAC1D,UAAU,CAAC,GAAG,CAAC,CAAA;AACf,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,GAAG,CAAC,cAAc,IAAI,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAA;IAClF,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;AAClC,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,CAAE,YAAkC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,UAAU,CAAC,kCAAkC,IAAI,EAAE,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,WAAW,GAAG,IAAI,EAAE,CAAC,CAAA;IACvD,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,IAAI,EAAE,CAAC,CAAA;IACzF,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,SAAS,YAAY,CAAC,KAAkB;IACtC,OAAO,GAAG,KAAK,CAAC,YAAY,SAAS,KAAK,CAAC,UAAU,SAAS,KAAK,CAAC,OAAO,EAAE,CAAA;AAC/E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,KAAc;IAC3D,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAChC,IAAI,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAM;IAC3B,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACxH,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IACvB,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,qBAAqB,CAAC,GAAG,IAAI,6BAA6B,CAAC,CAAA;IACjF,MAAM,IAAI,qBAAqB,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,YAAY,IAAI,GAAG,KAAK,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;AAC3G,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,aAAa,EAAE,EAA2C,MAAM,kBAAkB,CAAA;AACzF,OAAO,gBAAgB,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAEnD,MAAM,CAAC,MAAM,WAAW,GAAG,yDAAyD,CAAA;AACpF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,oBAAoB;IACpB,6BAA6B;IAC7B,2BAA2B;IAC3B,mBAAmB;IACnB,oBAAoB;IACpB,4BAA4B;IAC5B,2BAA2B;IAC3B,yCAAyC;CACjC,CAAA;AAOV,MAAM,OAAO,GAAG,aAAgF,CAAA;AAChG,MAAM,UAAU,GAAG,gBAA6D,CAAA;AAChF,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;AAC1D,UAAU,CAAC,GAAG,CAAC,CAAA;AACf,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,GAAG,CAAC,cAAc,IAAI,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAA;IAClF,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;AAClC,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,CAAE,YAAkC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,UAAU,CAAC,kCAAkC,IAAI,EAAE,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS,CAAC,GAAG,WAAW,GAAG,IAAI,EAAE,CAAC,CAAA;IACvD,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,IAAI,EAAE,CAAC,CAAA;IACzF,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,SAAS,YAAY,CAAC,KAAkB;IACtC,OAAO,GAAG,KAAK,CAAC,YAAY,SAAS,KAAK,CAAC,UAAU,SAAS,KAAK,CAAC,OAAO,EAAE,CAAA;AAC/E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,KAAc;IAC3D,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IAChC,IAAI,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAM;IAC3B,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACxH,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;IACvB,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,qBAAqB,CAAC,GAAG,IAAI,6BAA6B,CAAC,CAAA;IACjF,MAAM,IAAI,qBAAqB,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,YAAY,IAAI,GAAG,KAAK,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;AAC3G,CAAC"}
package/dist/tclk.d.ts ADDED
@@ -0,0 +1,139 @@
1
+ import { type LockKind, type OfferFrame, type TclkFrame, type TclkStatus } from '@flop-labs/tclk';
2
+ import { type TechnocoreSignedMessage } from './technocore.js';
3
+ import type { AgentEvidenceRecord, JsonObject } from './types.js';
4
+ /**
5
+ * Technocore Lock Protocol (`tclk/1`, by FLOP Labs — https://github.com/flop-labs/tclk)
6
+ * adapter: turns a Technocore-carried tclk transcript into Agent Evidence.
7
+ *
8
+ * tclk is a coordination convention, not a settlement service: it proves which
9
+ * `did:key` signed a deal-coordination frame (offer/accept/lock/reveal/refund/
10
+ * cancel/receipt) and whether the transcript is valid under tclk's own
11
+ * fail-closed state machine (`applyFrame`). It does NOT prove the counterparty
12
+ * is trustworthy, that an asserted statement is objectively true, or that money
13
+ * actually moved — a named settlement rail remains authoritative for that. This
14
+ * module never implements a rail, never moves value, and deliberately does not
15
+ * use tclk's unaudited PTLC/adaptor-signature path (see SPEC.md §7).
16
+ *
17
+ * Verification here is layered and independently distinguishable, per frame:
18
+ * 1. transport — `verifyTechnocoreMessage` (the existing Technocore adapter;
19
+ * not reimplemented here)
20
+ * 2. frame — `decodeFrame`/`validateFrame` from the official `@flop-labs/tclk`
21
+ * package (not reimplemented here)
22
+ * 3. attribution — the frame's own `from` must equal the transport-verified DID
23
+ * 4. state — `openContract`/`applyFrame`, the official state machine
24
+ */
25
+ /** One Technocore message believed to carry a tclk/1 frame as its text. */
26
+ export type TclkTranscriptMessage = TechnocoreSignedMessage;
27
+ /**
28
+ * One transcript entry: a message plus the wall-clock time (unix ms) at which
29
+ * THAT frame was applied. tclk's deadline checks (`expiresMs`, `refundAfterMs`)
30
+ * are transition guards evaluated at the moment of each transition (see
31
+ * `applyFrame`'s `nowMs` parameter) — an `accept` many minutes after `offer` and
32
+ * a `refund` days later are each checked against their own real time, not a
33
+ * single "verification time" for the whole historical transcript. Reusing one
34
+ * frozen instant for every step would make it impossible to correctly replay a
35
+ * transcript that legitimately spans an offer's expiry window through to its
36
+ * refund window.
37
+ */
38
+ export interface TclkTranscriptEntry {
39
+ message: TclkTranscriptMessage;
40
+ atMs: number;
41
+ }
42
+ /** One step of a verified transcript: either an accepted transition or an official rejection. */
43
+ export interface TclkTranscriptStep {
44
+ message: TclkTranscriptMessage;
45
+ frameType: TclkFrame['type'];
46
+ accepted: boolean;
47
+ /** Present when `accepted` is false — the official machine's own rejection reason. */
48
+ reason?: string;
49
+ }
50
+ /** The result of successfully replaying a tclk transcript through the official state machine. */
51
+ export interface TclkTranscriptResult {
52
+ offer: OfferFrame;
53
+ /** Set once an `accept` frame is itself accepted. */
54
+ contract: string | null;
55
+ status: TclkStatus;
56
+ terminal: boolean;
57
+ outcome: 'claimed' | 'refunded' | 'cancelled' | null;
58
+ payerDid: string | null;
59
+ payeeDid: string | null;
60
+ amount: string;
61
+ asset: string;
62
+ lock: LockKind;
63
+ offeredRails: readonly string[];
64
+ /** Set once a `lock` frame is accepted — the rail the payer announced, not independently verified. */
65
+ rail: string | null;
66
+ railRef: string | null;
67
+ claimByMs: number;
68
+ refundAfterMs: number;
69
+ expiresMs: number;
70
+ /** Every message processed, in order, whether accepted or officially rejected. */
71
+ steps: readonly TclkTranscriptStep[];
72
+ }
73
+ /**
74
+ * Verifies a Technocore-carried tclk/1 transcript end to end and replays it
75
+ * through the official `@flop-labs/tclk` state machine.
76
+ *
77
+ * Fails closed (throws `EvidenceValidationError`) when:
78
+ * - a message's Technocore transport signature does not verify
79
+ * - a message's text does not decode/validate as a tclk/1 frame
80
+ * - a frame's own `from` does not match its message's transport-verified DID
81
+ * - the transcript does not open with a valid `offer` frame, or a second
82
+ * `offer` appears mid-transcript (which contract would the rest belong to?)
83
+ *
84
+ * A frame that decodes and is honestly attributed but that the OFFICIAL state
85
+ * machine itself rejects (wrong sender for the transition, a replay, a
86
+ * duplicate, an out-of-order transition, a tampered `contract`/`ref` id that
87
+ * fails the machine's own recomputation) is NOT a fail-closed error here: per
88
+ * tclk's own spec (SPEC.md §2, §4), those are designed-in no-op rejections a
89
+ * reader in a world-writable room must expect, not evidence the transcript
90
+ * itself is corrupt. Every such rejection is still recorded in `steps` with its
91
+ * reason — it is never silently discarded — and does not advance contract state.
92
+ *
93
+ * Each entry supplies its own `atMs` (see `TclkTranscriptEntry`); deadline
94
+ * guards are evaluated per-transition against that entry's own time, not a
95
+ * single instant for the whole replay.
96
+ */
97
+ export declare function verifyTclkTranscript(entries: readonly TclkTranscriptEntry[]): TclkTranscriptResult;
98
+ /**
99
+ * An OPTIONAL, independently-verified observation from a real settlement rail —
100
+ * NOT implemented, simulated, or connected to by this module. tclk coordination
101
+ * evidence plus a caller-supplied `SettlementRailObservation` is what would let a
102
+ * decision claim actual value movement; without one, a decision built on tclk
103
+ * evidence alone must describe the lock as asserted/announced, never as settled.
104
+ */
105
+ export interface SettlementRailObservation {
106
+ rail: string;
107
+ ref: string;
108
+ observedAt: string;
109
+ /** Free-form, source-specific detail the caller already independently verified. */
110
+ detail: JsonObject;
111
+ }
112
+ export interface TclkEvidenceOptions {
113
+ runRef: string;
114
+ observedAt: string;
115
+ /**
116
+ * Parent evidence ids for the underlying signed Technocore messages — recommended:
117
+ * one `createTechnocoreEvidence(...)` call per transcript step, so the raw signed
118
+ * room messages remain independently inspectable evidence in their own right.
119
+ */
120
+ messageEvidenceRefs: readonly string[];
121
+ expiresAt?: string | null;
122
+ toolVersion?: string;
123
+ /** See `SettlementRailObservation`. Never fabricated by this module. */
124
+ settlementRail?: SettlementRailObservation;
125
+ }
126
+ /**
127
+ * Converts a verified tclk transcript into schema-valid Agent Evidence. The
128
+ * transcript must already have passed `verifyTclkTranscript` — this function
129
+ * does not re-verify signatures or replay frames, only records what was found.
130
+ *
131
+ * A `lock` frame is reported as "payer asserted/announced lock on rail X",
132
+ * never as "funds were locked" — this module has no independent way to observe
133
+ * a settlement rail. If the caller supplies a verified `settlementRail`
134
+ * observation, that is captured alongside the coordination evidence and
135
+ * labeled as independently observed, but it is still the caller's evidence,
136
+ * not something this adapter establishes.
137
+ */
138
+ export declare function createTclkEvidence(transcript: TclkTranscriptResult, options: TclkEvidenceOptions): AgentEvidenceRecord;
139
+ //# sourceMappingURL=tclk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tclk.d.ts","sourceRoot":"","sources":["../src/tclk.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,UAAU,EAChB,MAAM,iBAAiB,CAAA;AAIxB,OAAO,EAA2B,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAA;AACvF,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEjE;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,2EAA2E;AAC3E,MAAM,MAAM,qBAAqB,GAAG,uBAAuB,CAAA;AAE3D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,qBAAqB,CAAA;IAC9B,IAAI,EAAE,MAAM,CAAA;CACb;AAED,iGAAiG;AACjG,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,qBAAqB,CAAA;IAC9B,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IAC5B,QAAQ,EAAE,OAAO,CAAA;IACjB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,iGAAiG;AACjG,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,UAAU,CAAA;IACjB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,UAAU,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,IAAI,CAAA;IACpD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,QAAQ,CAAA;IACd,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B,sGAAsG;IACtG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,kFAAkF;IAClF,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAA;CACrC;AAID;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,SAAS,mBAAmB,EAAE,GACtC,oBAAoB,CAgGtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,mFAAmF;IACnF,MAAM,EAAE,UAAU,CAAA;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,mBAAmB,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wEAAwE;IACxE,cAAc,CAAC,EAAE,yBAAyB,CAAA;CAC3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,oBAAoB,EAChC,OAAO,EAAE,mBAAmB,GAC3B,mBAAmB,CAyErB"}
package/dist/tclk.js ADDED
@@ -0,0 +1,190 @@
1
+ import { applyFrame, decodeFrame, openContract, validateFrame, } from '@flop-labs/tclk';
2
+ import { contentId } from './canonical.js';
3
+ import { EvidenceValidationError } from './errors.js';
4
+ import { createRecord } from './records.js';
5
+ import { verifyTechnocoreMessage } from './technocore.js';
6
+ const TERMINAL_STATUSES = new Set(['claimed', 'refunded', 'cancelled']);
7
+ /**
8
+ * Verifies a Technocore-carried tclk/1 transcript end to end and replays it
9
+ * through the official `@flop-labs/tclk` state machine.
10
+ *
11
+ * Fails closed (throws `EvidenceValidationError`) when:
12
+ * - a message's Technocore transport signature does not verify
13
+ * - a message's text does not decode/validate as a tclk/1 frame
14
+ * - a frame's own `from` does not match its message's transport-verified DID
15
+ * - the transcript does not open with a valid `offer` frame, or a second
16
+ * `offer` appears mid-transcript (which contract would the rest belong to?)
17
+ *
18
+ * A frame that decodes and is honestly attributed but that the OFFICIAL state
19
+ * machine itself rejects (wrong sender for the transition, a replay, a
20
+ * duplicate, an out-of-order transition, a tampered `contract`/`ref` id that
21
+ * fails the machine's own recomputation) is NOT a fail-closed error here: per
22
+ * tclk's own spec (SPEC.md §2, §4), those are designed-in no-op rejections a
23
+ * reader in a world-writable room must expect, not evidence the transcript
24
+ * itself is corrupt. Every such rejection is still recorded in `steps` with its
25
+ * reason — it is never silently discarded — and does not advance contract state.
26
+ *
27
+ * Each entry supplies its own `atMs` (see `TclkTranscriptEntry`); deadline
28
+ * guards are evaluated per-transition against that entry's own time, not a
29
+ * single instant for the whole replay.
30
+ */
31
+ export function verifyTclkTranscript(entries) {
32
+ if (entries.length === 0) {
33
+ throw new EvidenceValidationError('tclk transcript: no messages supplied');
34
+ }
35
+ const steps = [];
36
+ let offer = null;
37
+ let state = null;
38
+ for (const { message, atMs } of entries) {
39
+ if (!verifyTechnocoreMessage(message)) {
40
+ throw new EvidenceValidationError(`tclk transcript: message (room ${message.room}, nonce ${message.nonce}) has an invalid Technocore transport signature`);
41
+ }
42
+ let frame;
43
+ try {
44
+ frame = decodeFrame(message.text);
45
+ }
46
+ catch (error) {
47
+ throw new EvidenceValidationError(`tclk transcript: message (room ${message.room}, nonce ${message.nonce}) is not a valid tclk/1 frame: ${error instanceof Error ? error.message : String(error)}`);
48
+ }
49
+ if (frame.from !== message.did) {
50
+ throw new EvidenceValidationError(`tclk transcript: frame sender ${frame.from} does not match the transport-authenticated DID ${message.did}`);
51
+ }
52
+ if (frame.type === 'offer') {
53
+ if (offer !== null) {
54
+ throw new EvidenceValidationError('tclk transcript: a second offer frame cannot open a new contract mid-transcript');
55
+ }
56
+ try {
57
+ offer = validateFrame(frame);
58
+ state = openContract(offer);
59
+ }
60
+ catch (error) {
61
+ throw new EvidenceValidationError(`tclk transcript: invalid opening offer: ${error instanceof Error ? error.message : String(error)}`);
62
+ }
63
+ steps.push({ message, frameType: frame.type, accepted: true });
64
+ continue;
65
+ }
66
+ if (state === null) {
67
+ throw new EvidenceValidationError('tclk transcript: no opening offer frame appears before a subsequent frame');
68
+ }
69
+ const result = applyFrame(state, frame, atMs);
70
+ if (!result.ok) {
71
+ // Official, designed-in rejection (replay, duplicate, wrong sender for
72
+ // this transition, tampered id, out-of-order transition, …) — recorded,
73
+ // never dropped, never treated as fatal to the whole transcript.
74
+ steps.push({ message, frameType: frame.type, accepted: false, reason: result.reason ?? 'rejected' });
75
+ continue;
76
+ }
77
+ state = result.state;
78
+ steps.push({ message, frameType: frame.type, accepted: true });
79
+ }
80
+ if (offer === null || state === null) {
81
+ throw new EvidenceValidationError('tclk transcript: transcript never opened a contract');
82
+ }
83
+ const outcome = TERMINAL_STATUSES.has(state.status)
84
+ ? state.status
85
+ : null;
86
+ return {
87
+ offer,
88
+ contract: state.contract ?? null,
89
+ status: state.status,
90
+ terminal: TERMINAL_STATUSES.has(state.status),
91
+ outcome,
92
+ payerDid: state.payerDid ?? null,
93
+ payeeDid: state.payeeDid ?? null,
94
+ amount: offer.amount,
95
+ asset: offer.asset,
96
+ lock: offer.lock,
97
+ offeredRails: offer.rails,
98
+ rail: state.rail ?? null,
99
+ railRef: state.railRef ?? null,
100
+ claimByMs: offer.claimByMs,
101
+ refundAfterMs: offer.refundAfterMs,
102
+ expiresMs: offer.expiresMs,
103
+ steps,
104
+ };
105
+ }
106
+ /**
107
+ * Converts a verified tclk transcript into schema-valid Agent Evidence. The
108
+ * transcript must already have passed `verifyTclkTranscript` — this function
109
+ * does not re-verify signatures or replay frames, only records what was found.
110
+ *
111
+ * A `lock` frame is reported as "payer asserted/announced lock on rail X",
112
+ * never as "funds were locked" — this module has no independent way to observe
113
+ * a settlement rail. If the caller supplies a verified `settlementRail`
114
+ * observation, that is captured alongside the coordination evidence and
115
+ * labeled as independently observed, but it is still the caller's evidence,
116
+ * not something this adapter establishes.
117
+ */
118
+ export function createTclkEvidence(transcript, options) {
119
+ const lockNote = transcript.rail === null
120
+ ? 'no lock frame observed in this transcript'
121
+ : `payer asserted/announced lock on rail "${transcript.rail}"` +
122
+ (transcript.railRef !== null ? ` (rail ref: ${transcript.railRef})` : '') +
123
+ '; this is the payer\'s claim, not independent proof that funds were escrowed';
124
+ const captured = {
125
+ protocol: 'tclk/1',
126
+ offer_id: transcript.offer.id,
127
+ contract_id: transcript.contract,
128
+ payer_did: transcript.payerDid,
129
+ payee_did: transcript.payeeDid,
130
+ amount: transcript.amount,
131
+ asset: transcript.asset,
132
+ lock_kind: transcript.lock,
133
+ offered_rails: [...transcript.offeredRails],
134
+ asserted_settlement_rail: transcript.rail,
135
+ asserted_settlement_rail_ref: transcript.railRef,
136
+ settlement_note: lockNote,
137
+ claim_by_ms: transcript.claimByMs,
138
+ refund_after_ms: transcript.refundAfterMs,
139
+ expires_ms: transcript.expiresMs,
140
+ transcript_status: transcript.status,
141
+ terminal: transcript.terminal,
142
+ outcome: transcript.outcome,
143
+ frame_sequence: transcript.steps.map((step) => ({
144
+ type: step.frameType,
145
+ from: step.message.did,
146
+ room: step.message.room,
147
+ nonce: step.message.nonce,
148
+ accepted: step.accepted,
149
+ reason: step.reason ?? null,
150
+ })),
151
+ ...(options.settlementRail !== undefined
152
+ ? {
153
+ independent_settlement_observation: {
154
+ rail: options.settlementRail.rail,
155
+ ref: options.settlementRail.ref,
156
+ observed_at: options.settlementRail.observedAt,
157
+ detail: options.settlementRail.detail,
158
+ },
159
+ }
160
+ : {}),
161
+ verification: 'technocore-transport-and-tclk-state-machine-verified',
162
+ };
163
+ const request = { offer_id: transcript.offer.id, contract_id: transcript.contract };
164
+ return createRecord('evidence', {
165
+ evidence_type: 'tclk-transcript',
166
+ run_ref: options.runRef,
167
+ trust_mode: 'agent-assertion',
168
+ source: { id: 'https://github.com/flop-labs/tclk', type: 'tclk-technocore-lock-protocol' },
169
+ tool: { name: 'onchaindiligence-tclk-adapter', version: options.toolVersion ?? '1' },
170
+ request: {
171
+ digest: { sha256: contentId(request).slice('sha256:'.length) },
172
+ media_type: 'application/vnd.tclk.transcript-request+json',
173
+ },
174
+ response: {
175
+ mode: 'embedded',
176
+ media_type: 'application/vnd.tclk.transcript+json',
177
+ value: captured,
178
+ digest: { sha256: contentId(captured).slice('sha256:'.length) },
179
+ },
180
+ observed_at: options.observedAt,
181
+ expires_at: options.expiresAt ?? null,
182
+ scope: {
183
+ offer_id: transcript.offer.id,
184
+ contract_id: transcript.contract,
185
+ payer_did: transcript.payerDid,
186
+ payee_did: transcript.payeeDid,
187
+ },
188
+ }, { parents: [options.runRef, ...options.messageEvidenceRefs] });
189
+ }
190
+ //# sourceMappingURL=tclk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tclk.js","sourceRoot":"","sources":["../src/tclk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { AgentEvidenceRecord, JsonObject, KeyInput } from './types.js';
2
+ /** A stored Technocore signed-lane message. All fields are untrusted input. */
3
+ export interface TechnocoreSignedMessage {
4
+ did: string;
5
+ room: string;
6
+ nonce: string;
7
+ text: string;
8
+ sig: string;
9
+ }
10
+ /**
11
+ * Explicit server observations accompanying a message. Keep numeric server values
12
+ * as strings when they might exceed JavaScript's safe-integer range.
13
+ */
14
+ export interface TechnocoreEvidenceOptions {
15
+ runRef: string;
16
+ observedAt: string;
17
+ parents?: readonly string[];
18
+ expiresAt?: string | null;
19
+ serverMetadata?: JsonObject;
20
+ toolVersion?: string;
21
+ }
22
+ /** Mirrors Technocore's documented single-line sweep before it signs or stores text. */
23
+ export declare function sweepTechnocoreText(text: string): string;
24
+ /** The exact UTF-8 string verified by Technocore's signed message lane. */
25
+ export declare function technocoreSigningInput(message: Pick<TechnocoreSignedMessage, 'room' | 'nonce' | 'text'>): Uint8Array;
26
+ /** SHA-256 of the exact stored message text, encoded as unpadded base64url. */
27
+ export declare function technocoreTextDigest(text: string): string;
28
+ /** Derives the Ed25519 did:key identifier used by Technocore from a public key. */
29
+ export declare function technocoreDidFromPublicKey(publicKey: KeyInput): string;
30
+ /**
31
+ * Verifies a Technocore signed message entirely offline. A true result proves
32
+ * only that the embedded did:key signed this stored message, never that its text
33
+ * is true or safe to act on.
34
+ */
35
+ export declare function verifyTechnocoreMessage(message: TechnocoreSignedMessage): boolean;
36
+ /**
37
+ * Converts a verified Technocore assertion into schema-valid Agent Evidence.
38
+ * The embedded message remains untrusted data and uses agent-assertion trust mode.
39
+ */
40
+ export declare function createTechnocoreEvidence(message: TechnocoreSignedMessage, options: TechnocoreEvidenceOptions): AgentEvidenceRecord;
41
+ //# sourceMappingURL=technocore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"technocore.d.ts","sourceRoot":"","sources":["../src/technocore.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAY3E,+EAA+E;AAC/E,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,cAAc,CAAC,EAAE,UAAU,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,2EAA2E;AAC3E,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,IAAI,CAAC,uBAAuB,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,GAAG,UAAU,CAEpH;AAED,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,mFAAmF;AACnF,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,QAAQ,GAAG,MAAM,CAatE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAWjF;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,uBAAuB,EAChC,OAAO,EAAE,yBAAyB,GACjC,mBAAmB,CAuCrB"}
@@ -0,0 +1,157 @@
1
+ import { createHash, createPublicKey, KeyObject, verify } from 'node:crypto';
2
+ import { contentId } from './canonical.js';
3
+ import { EvidenceValidationError } from './errors.js';
4
+ import { createRecord } from './records.js';
5
+ const DID_PREFIX = 'did:key:';
6
+ const BASE58BTC_PREFIX = 'z';
7
+ const ED25519_MULTICODEC = Buffer.from([0xed, 0x01]);
8
+ const ED25519_SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex');
9
+ const BASE58BTC = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
10
+ const ROOM = /^[a-z0-9][a-z0-9_-]{0,47}$/;
11
+ const NONCE = /^[0-9]{1,19}$/;
12
+ const SIGNATURE = /^[A-Za-z0-9_-]{86}$/;
13
+ const INVISIBLE = /[\p{Cc}\p{Cf}\p{Cs}\p{Co}\p{Zl}\p{Zp}]/gu;
14
+ /** Mirrors Technocore's documented single-line sweep before it signs or stores text. */
15
+ export function sweepTechnocoreText(text) {
16
+ return text.replace(INVISIBLE, ' ').trim();
17
+ }
18
+ /** The exact UTF-8 string verified by Technocore's signed message lane. */
19
+ export function technocoreSigningInput(message) {
20
+ return Buffer.from(`${message.room}|${message.nonce}|${message.text}`, 'utf8');
21
+ }
22
+ /** SHA-256 of the exact stored message text, encoded as unpadded base64url. */
23
+ export function technocoreTextDigest(text) {
24
+ return createHash('sha256').update(text, 'utf8').digest('base64url');
25
+ }
26
+ /** Derives the Ed25519 did:key identifier used by Technocore from a public key. */
27
+ export function technocoreDidFromPublicKey(publicKey) {
28
+ const key = publicKey instanceof KeyObject && publicKey.type === 'public'
29
+ ? publicKey
30
+ : createPublicKey(publicKey instanceof Uint8Array ? Buffer.from(publicKey) : publicKey);
31
+ const spki = key.export({ format: 'der', type: 'spki' });
32
+ if (!Buffer.isBuffer(spki) || spki.length !== ED25519_SPKI_PREFIX.length + 32 ||
33
+ !spki.subarray(0, ED25519_SPKI_PREFIX.length).equals(ED25519_SPKI_PREFIX)) {
34
+ throw new EvidenceValidationError('Technocore requires an Ed25519 public key');
35
+ }
36
+ return `${DID_PREFIX}${BASE58BTC_PREFIX}${base58Encode(Buffer.concat([
37
+ ED25519_MULTICODEC,
38
+ spki.subarray(ED25519_SPKI_PREFIX.length),
39
+ ]))}`;
40
+ }
41
+ /**
42
+ * Verifies a Technocore signed message entirely offline. A true result proves
43
+ * only that the embedded did:key signed this stored message, never that its text
44
+ * is true or safe to act on.
45
+ */
46
+ export function verifyTechnocoreMessage(message) {
47
+ try {
48
+ if (!ROOM.test(message.room) || !NONCE.test(message.nonce) || !SIGNATURE.test(message.sig))
49
+ return false;
50
+ if (message.text !== sweepTechnocoreText(message.text) || Array.from(message.text).length > 4096)
51
+ return false;
52
+ const signature = Buffer.from(message.sig, 'base64url');
53
+ if (signature.length !== 64 || signature.toString('base64url') !== message.sig)
54
+ return false;
55
+ const publicKey = publicKeyFromDid(message.did);
56
+ return verify(null, technocoreSigningInput(message), publicKey, signature);
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ /**
63
+ * Converts a verified Technocore assertion into schema-valid Agent Evidence.
64
+ * The embedded message remains untrusted data and uses agent-assertion trust mode.
65
+ */
66
+ export function createTechnocoreEvidence(message, options) {
67
+ if (!verifyTechnocoreMessage(message)) {
68
+ throw new EvidenceValidationError('Technocore message has an invalid did:key signature or canonical form');
69
+ }
70
+ const captured = {
71
+ did: message.did,
72
+ room: message.room,
73
+ nonce: message.nonce,
74
+ text: message.text,
75
+ text_digest_sha256: technocoreTextDigest(message.text),
76
+ signature: message.sig,
77
+ signature_algorithm: 'ed25519',
78
+ signing_input: '<room>|<nonce>|<text-after-technocore-sweep>',
79
+ verification: 'valid-did-key-signature',
80
+ };
81
+ if (options.serverMetadata !== undefined)
82
+ captured.server_metadata = options.serverMetadata;
83
+ const request = { did: message.did, room: message.room, nonce: message.nonce };
84
+ return createRecord('evidence', {
85
+ evidence_type: 'technocore-signed-message',
86
+ run_ref: options.runRef,
87
+ trust_mode: 'agent-assertion',
88
+ source: { id: 'https://technocore.chat', type: 'technocore-chat' },
89
+ tool: { name: 'onchaindiligence-technocore-adapter', version: options.toolVersion ?? '1' },
90
+ request: {
91
+ digest: { sha256: contentId(request).slice('sha256:'.length) },
92
+ media_type: 'application/vnd.technocore.signed-message-request+json',
93
+ },
94
+ response: {
95
+ mode: 'embedded',
96
+ media_type: 'application/vnd.technocore.signed-message+json',
97
+ value: captured,
98
+ digest: { sha256: contentId(captured).slice('sha256:'.length) },
99
+ },
100
+ observed_at: options.observedAt,
101
+ expires_at: options.expiresAt ?? null,
102
+ scope: { did: message.did, room: message.room, nonce: message.nonce },
103
+ }, { parents: options.parents ?? [options.runRef] });
104
+ }
105
+ function publicKeyFromDid(did) {
106
+ if (!did.startsWith(`${DID_PREFIX}${BASE58BTC_PREFIX}`))
107
+ throw new EvidenceValidationError('not a base58btc did:key');
108
+ const decoded = base58Decode(did.slice(`${DID_PREFIX}${BASE58BTC_PREFIX}`.length));
109
+ if (decoded.length !== 34 || !decoded.subarray(0, 2).equals(ED25519_MULTICODEC)) {
110
+ throw new EvidenceValidationError('Technocore did:key is not an Ed25519 multicodec key');
111
+ }
112
+ return createPublicKey({
113
+ key: Buffer.concat([ED25519_SPKI_PREFIX, decoded.subarray(2)]),
114
+ format: 'der',
115
+ type: 'spki',
116
+ });
117
+ }
118
+ function base58Encode(bytes) {
119
+ let value = 0n;
120
+ for (const byte of bytes)
121
+ value = (value << 8n) | BigInt(byte);
122
+ let encoded = '';
123
+ while (value > 0n) {
124
+ const remainder = Number(value % 58n);
125
+ encoded = BASE58BTC[remainder] + encoded;
126
+ value /= 58n;
127
+ }
128
+ for (const byte of bytes) {
129
+ if (byte !== 0)
130
+ break;
131
+ encoded = `1${encoded}`;
132
+ }
133
+ return encoded || '1';
134
+ }
135
+ function base58Decode(value) {
136
+ if (value.length === 0)
137
+ throw new EvidenceValidationError('empty base58btc identifier');
138
+ let decoded = 0n;
139
+ for (const character of value) {
140
+ const index = BASE58BTC.indexOf(character);
141
+ if (index < 0)
142
+ throw new EvidenceValidationError('invalid base58btc identifier');
143
+ decoded = decoded * 58n + BigInt(index);
144
+ }
145
+ let hex = decoded.toString(16);
146
+ if (hex.length % 2 !== 0)
147
+ hex = `0${hex}`;
148
+ const bytes = decoded === 0n ? Buffer.alloc(0) : Buffer.from(hex, 'hex');
149
+ let leadingZeros = 0;
150
+ for (const character of value) {
151
+ if (character !== '1')
152
+ break;
153
+ leadingZeros += 1;
154
+ }
155
+ return Buffer.concat([Buffer.alloc(leadingZeros), bytes]);
156
+ }
157
+ //# sourceMappingURL=technocore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"technocore.js","sourceRoot":"","sources":["../src/technocore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ import { generateKeyPairSync, sign } from 'node:crypto'
2
+ import { encodeFrame, generateHashLock, makeAccept, makeOffer } from '@flop-labs/tclk'
3
+ import {
4
+ createBundlePayload,
5
+ createEd25519Signer,
6
+ createKeyRecord,
7
+ createRecord,
8
+ createTclkEvidence,
9
+ createTechnocoreEvidence,
10
+ contentId,
11
+ sealBundle,
12
+ sweepTechnocoreText,
13
+ technocoreDidFromPublicKey,
14
+ technocoreSigningInput,
15
+ TrustPolicy,
16
+ verifyBundle,
17
+ verifyTclkTranscript,
18
+ } from '@onchaindiligence/agent-evidence'
19
+
20
+ // This is an offline example: no real money, no real Technocore room, no
21
+ // PTLC/adaptor-signature material (SAFE hash-lock path only). It shows the
22
+ // generic shape a real integration follows: two agents coordinate a deal as
23
+ // signed tclk/1 frames, OnChainDiligence captures the verified transcript as
24
+ // Agent Evidence, and — because no real settlement rail is wired up here — the
25
+ // resulting execution record says so honestly rather than claiming a payment
26
+ // happened.
27
+ const ROOM = 'tclk-offers'
28
+ function frameMessage(privateKey, did, nonce, frame) {
29
+ const text = sweepTechnocoreText(encodeFrame(frame))
30
+ const sig = sign(null, technocoreSigningInput({ room: ROOM, nonce, text }), privateKey).toString('base64url')
31
+ return { did, room: ROOM, nonce, text, sig }
32
+ }
33
+
34
+ const payerKey = generateKeyPairSync('ed25519')
35
+ const payeeKey = generateKeyPairSync('ed25519')
36
+ const payerDid = technocoreDidFromPublicKey(payerKey.publicKey)
37
+ const payeeDid = technocoreDidFromPublicKey(payeeKey.publicKey)
38
+
39
+ const nowMs = Date.parse('2026-09-02T12:00:00.000Z')
40
+ const claimByMs = nowMs + 60 * 60 * 1000
41
+ const refundAfterMs = claimByMs + 60 * 60 * 1000
42
+ const expiresMs = nowMs + 30 * 60 * 1000
43
+
44
+ // offer -> accept -> lock announcement -> reveal (hash-lock path only).
45
+ const offer = makeOffer({
46
+ from: payerDid, role: 'payer', amount: '1000000', asset: 'FLOP', lock: 'hash',
47
+ rails: ['flop-htlc'], claimByMs, refundAfterMs, expiresMs,
48
+ })
49
+ const hashLock = generateHashLock()
50
+ const accept = makeAccept(offer, { from: payeeDid, statement: hashLock.hash })
51
+ const lock = { type: 'lock', from: payerDid, contract: accept.contract, rail: 'flop-htlc', ref: 'paper-escrow-1' }
52
+ const reveal = { type: 'reveal', from: payeeDid, contract: accept.contract, secret: hashLock.preimage }
53
+
54
+ const offerMsg = frameMessage(payerKey.privateKey, payerDid, '1756814400001', offer)
55
+ const acceptMsg = frameMessage(payeeKey.privateKey, payeeDid, '1756814400002', accept)
56
+ const lockMsg = frameMessage(payerKey.privateKey, payerDid, '1756814400003', lock)
57
+ const revealMsg = frameMessage(payeeKey.privateKey, payeeDid, '1756814400004', reveal)
58
+
59
+ // Verify: transport signature + tclk frame validity + sender attribution +
60
+ // official state-machine replay, each independently.
61
+ const transcript = verifyTclkTranscript([
62
+ { message: offerMsg, atMs: nowMs },
63
+ { message: acceptMsg, atMs: nowMs },
64
+ { message: lockMsg, atMs: nowMs },
65
+ { message: revealMsg, atMs: claimByMs - 1000 },
66
+ ])
67
+
68
+ const bundleKey = generateKeyPairSync('ed25519')
69
+ const key = createKeyRecord(bundleKey.publicKey, { validFrom: '2026-09-01T00:00:00.000Z' })
70
+ const principal = createRecord('principal', { principal_id: 'urn:example:ocd', principal_type: 'organization' })
71
+ const agent = createRecord('agent', {
72
+ agent_id: 'urn:example:ocd-tclk-agent', agent_version: '1', operator_ref: principal.id,
73
+ }, { parents: [principal.id] })
74
+ const mandate = createRecord('mandate', {
75
+ mandate_id: 'tclk-coordination-capture', principal_ref: principal.id, scope: { action: 'record-only' },
76
+ valid_from: '2026-09-01T00:00:00.000Z', valid_until: '2026-09-03T00:00:00.000Z',
77
+ }, { parents: [principal.id] })
78
+ const run = createRecord('run', {
79
+ run_external_id: 'tclk-example', agent_ref: agent.id, mandate_ref: mandate.id,
80
+ started_at: '2026-09-02T12:00:00.000Z',
81
+ }, { parents: [agent.id, mandate.id] })
82
+
83
+ // One Technocore evidence record per underlying signed message (reusing the
84
+ // existing Technocore adapter, not a second implementation of it) ...
85
+ const messageEvidence = [offerMsg, acceptMsg, lockMsg, revealMsg].map((message, i) =>
86
+ createTechnocoreEvidence(message, { runRef: run.id, observedAt: `2026-09-02T12:0${i}:00.000Z` }))
87
+ // ... plus one tclk-transcript evidence record summarizing the verified replay.
88
+ const tclkEvidence = createTclkEvidence(transcript, {
89
+ runRef: run.id, observedAt: '2026-09-02T12:05:00.000Z',
90
+ messageEvidenceRefs: messageEvidence.map((e) => e.id),
91
+ })
92
+
93
+ const policyDocument = { action: 'accept-coordination-evidence-only', require_real_rail_for_settlement_claim: true }
94
+ const policy = createRecord('policy', {
95
+ policy_id: 'tclk-coordination-capture', version: '1', source: 'https://example.invalid/policy/tclk',
96
+ digest: { sha256: contentId(policyDocument).slice('sha256:'.length) },
97
+ effective_from: '2026-09-01T00:00:00.000Z', policy: policyDocument,
98
+ }, { parents: [run.id] })
99
+
100
+ const evidenceRefs = [...messageEvidence.map((e) => e.id), tclkEvidence.id]
101
+ const decision = createRecord('decision', {
102
+ decision_id: 'accept-tclk-coordination-evidence', run_ref: run.id, agent_ref: agent.id,
103
+ decision_type: 'tclk-transcript-review',
104
+ outcome: {
105
+ disposition: 'ACCEPT_COORDINATION_EVIDENCE',
106
+ authorized_to_execute: false,
107
+ reason: 'valid signed coordination is evidence of what the agents agreed/asserted, not proof of settlement',
108
+ },
109
+ evidence_refs: evidenceRefs,
110
+ policy_ref: policy.id, policy_digest: policy.statement.digest,
111
+ decided_at: '2026-09-02T12:06:00.000Z',
112
+ }, { parents: [run.id, policy.id, ...evidenceRefs] })
113
+
114
+ // PaperRail-equivalent here: no real rail is wired up, so execution must say so.
115
+ const execution = createRecord('execution', {
116
+ execution_id: 'no-real-value-settlement', decision_ref: decision.id, execution_type: 'no-external-action',
117
+ status: 'NO_REAL_VALUE_SETTLEMENT', submitted_at: '2026-09-02T12:06:01.000Z',
118
+ }, { parents: [decision.id] })
119
+
120
+ const payload = createBundlePayload(
121
+ [principal, agent, mandate, run, ...messageEvidence, tclkEvidence, policy, decision, execution],
122
+ { createdAt: '2026-09-02T12:07:00.000Z' },
123
+ )
124
+ const bundle = await sealBundle(payload, createEd25519Signer(bundleKey.privateKey), { keys: [key] })
125
+ const report = verifyBundle(bundle, TrustPolicy.fromKeyRecords([key], { now: new Date('2026-09-02T12:08:00.000Z') }))
126
+
127
+ console.log(report.state, payload.bundle_id)
128
+ console.log('decision:', decision.statement.outcome.disposition)
129
+ console.log('execution:', execution.statement.status)
130
+ console.log('tclk transcript status:', transcript.status, '(terminal:', transcript.terminal + ')')
@@ -0,0 +1,69 @@
1
+ import { generateKeyPairSync, sign } from 'node:crypto'
2
+ import {
3
+ createBundlePayload,
4
+ createEd25519Signer,
5
+ createKeyRecord,
6
+ createRecord,
7
+ createTechnocoreEvidence,
8
+ contentId,
9
+ sealBundle,
10
+ sweepTechnocoreText,
11
+ technocoreDidFromPublicKey,
12
+ technocoreSigningInput,
13
+ TrustPolicy,
14
+ verifyBundle,
15
+ } from '@onchaindiligence/agent-evidence'
16
+
17
+ // This is an offline example. It never reads a room, follows message content,
18
+ // or sends a transaction. A real adapter caller passes the exact stored message
19
+ // returned by Technocore's JSON API and may retain server metadata alongside it.
20
+ const technocoreKey = generateKeyPairSync('ed25519')
21
+ const text = sweepTechnocoreText('A did:key signature establishes an assertion, not truth.')
22
+ const message = {
23
+ did: technocoreDidFromPublicKey(technocoreKey.publicKey),
24
+ room: 'ocd-evidence',
25
+ nonce: '1740000000001',
26
+ text,
27
+ sig: sign(null, technocoreSigningInput({ room: 'ocd-evidence', nonce: '1740000000001', text }), technocoreKey.privateKey)
28
+ .toString('base64url'),
29
+ }
30
+ const bundleKey = generateKeyPairSync('ed25519')
31
+ const key = createKeyRecord(bundleKey.publicKey, { validFrom: '2026-09-01T00:00:00.000Z' })
32
+ const principal = createRecord('principal', { principal_id: 'urn:example:ocd', principal_type: 'organization' })
33
+ const agent = createRecord('agent', {
34
+ agent_id: 'urn:example:ocd-technocore-agent', agent_version: '1', operator_ref: principal.id,
35
+ }, { parents: [principal.id] })
36
+ const mandate = createRecord('mandate', {
37
+ mandate_id: 'technocore-capture', principal_ref: principal.id, scope: { action: 'record-only' },
38
+ valid_from: '2026-09-01T00:00:00.000Z', valid_until: '2026-09-02T00:00:00.000Z',
39
+ }, { parents: [principal.id] })
40
+ const run = createRecord('run', {
41
+ run_external_id: 'technocore-example', agent_ref: agent.id, mandate_ref: mandate.id,
42
+ started_at: '2026-09-01T12:00:00.000Z',
43
+ }, { parents: [agent.id, mandate.id] })
44
+ const evidence = createTechnocoreEvidence(message, {
45
+ runRef: run.id, observedAt: '2026-09-01T12:00:01.000Z',
46
+ serverMetadata: { seq: '1', ts: '2026-09-01T12:00:01.123456Z' },
47
+ })
48
+ const policyDocument = { action: 'never-execute-from-technocore-content', require_signature: true }
49
+ const policy = createRecord('policy', {
50
+ policy_id: 'technocore-ingestion', version: '1', source: 'https://example.invalid/policy/technocore',
51
+ digest: { sha256: contentId(policyDocument).slice('sha256:'.length) },
52
+ effective_from: '2026-09-01T00:00:00.000Z', policy: policyDocument,
53
+ }, { parents: [run.id] })
54
+ const decision = createRecord('decision', {
55
+ decision_id: 'record-no-action', run_ref: run.id, agent_ref: agent.id, decision_type: 'technocore-message-review',
56
+ outcome: { execute: false, reason: 'signed assertion is not authorization or truth' }, evidence_refs: [evidence.id],
57
+ policy_ref: policy.id, policy_digest: policy.statement.digest, decided_at: '2026-09-01T12:00:02.000Z',
58
+ }, { parents: [run.id, evidence.id, policy.id] })
59
+ const execution = createRecord('execution', {
60
+ execution_id: 'non-execution', decision_ref: decision.id, execution_type: 'no-external-action',
61
+ status: 'withheld-not-submitted', submitted_at: '2026-09-01T12:00:03.000Z',
62
+ }, { parents: [decision.id] })
63
+ const payload = createBundlePayload(
64
+ [principal, agent, mandate, run, evidence, policy, decision, execution],
65
+ { createdAt: '2026-09-01T12:00:04.000Z' },
66
+ )
67
+ const bundle = await sealBundle(payload, createEd25519Signer(bundleKey.privateKey), { keys: [key] })
68
+ const report = verifyBundle(bundle, TrustPolicy.fromKeyRecords([key], { now: new Date('2026-09-01T12:01:00.000Z') }))
69
+ console.log(report.state, payload.bundle_id, execution.statement.status)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onchaindiligence/agent-evidence",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Deterministic Agent Evidence v0 construction, DSSE sealing, and offline tri-state verification for Node.js",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -51,6 +51,7 @@
51
51
  "node": ">=20.19"
52
52
  },
53
53
  "dependencies": {
54
+ "@flop-labs/tclk": "^0.1.0",
54
55
  "ajv": "^8.20.0",
55
56
  "ajv-formats": "^3.0.1"
56
57
  },
@@ -0,0 +1,74 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://onchaindiligence.com/schemas/agent-evidence/v0/agent-evidence-key-registry.schema.json",
4
+ "title": "Agent Evidence Interoperability Profile v1 — public signer key registry",
5
+ "description": "The recommended shape for GET /.well-known/agent-evidence-keys, as defined by docs/AGENT_EVIDENCE_INTEROP.md. This registry is public metadata: an issuer's own signer key_id, public key, and lifecycle -- never a private key. Hosting this endpoint is a discovery convenience only; it does not by itself make an issuer trustworthy, and a verifier's caller-supplied TrustPolicy remains the sole source of trust.",
6
+ "type": "object",
7
+ "required": ["schema_version", "issuer", "environment", "keys"],
8
+ "properties": {
9
+ "schema_version": { "const": 1 },
10
+ "issuer": { "$ref": "common.schema.json#/$defs/nonEmptyString" },
11
+ "environment": { "$ref": "common.schema.json#/$defs/nonEmptyString" },
12
+ "keys": {
13
+ "type": "array",
14
+ "items": { "$ref": "#/$defs/keyEntry" },
15
+ "maxItems": 256
16
+ }
17
+ },
18
+ "additionalProperties": false,
19
+ "$defs": {
20
+ "keyEntry": {
21
+ "type": "object",
22
+ "title": "One published signer key. key_id alone never establishes trust, and this record is a hint until a caller's TrustPolicy independently trusts it.",
23
+ "required": ["key_id", "algorithm", "public_key_pem", "valid_from", "valid_until", "revoked_at", "status"],
24
+ "properties": {
25
+ "key_id": {
26
+ "type": "string",
27
+ "pattern": "^ed25519-[A-Za-z0-9_-]{16}$",
28
+ "description": "Self-certifying: derived as ed25519-<first 16 base64url chars of sha256(SPKI DER)>, the same convention Agent Evidence's own AttestationKey uses. A verifier SHOULD re-derive and reject a mismatch."
29
+ },
30
+ "algorithm": { "const": "Ed25519" },
31
+ "public_key_pem": {
32
+ "type": "string",
33
+ "pattern": "^-----BEGIN PUBLIC KEY-----\\n[A-Za-z0-9+/=\\n]+-----END PUBLIC KEY-----\\n?$",
34
+ "maxLength": 4096
35
+ },
36
+ "valid_from": {
37
+ "anyOf": [
38
+ { "$ref": "common.schema.json#/$defs/timestamp" },
39
+ { "type": "null" }
40
+ ],
41
+ "description": "null means no defensible activation boundary is published; a verifier must then treat the key as UNVERIFIABLE, never VALID."
42
+ },
43
+ "valid_until": {
44
+ "anyOf": [
45
+ { "$ref": "common.schema.json#/$defs/timestamp" },
46
+ { "type": "null" }
47
+ ]
48
+ },
49
+ "revoked_at": {
50
+ "anyOf": [
51
+ { "$ref": "common.schema.json#/$defs/timestamp" },
52
+ { "type": "null" }
53
+ ]
54
+ },
55
+ "status": { "enum": ["active", "retired", "revoked", "compromised"] }
56
+ },
57
+ "additionalProperties": false,
58
+ "allOf": [
59
+ {
60
+ "if": {
61
+ "type": "object",
62
+ "properties": { "status": { "enum": ["revoked", "compromised"] } },
63
+ "required": ["status"]
64
+ },
65
+ "then": {
66
+ "type": "object",
67
+ "required": ["revoked_at"],
68
+ "properties": { "revoked_at": { "$ref": "common.schema.json#/$defs/timestamp" } }
69
+ }
70
+ }
71
+ ]
72
+ }
73
+ }
74
+ }
@@ -8,13 +8,15 @@
8
8
  "proof.schema.json",
9
9
  "record.schema.json",
10
10
  "bundle-payload.schema.json",
11
- "portable-file.schema.json"
11
+ "portable-file.schema.json",
12
+ "agent-evidence-key-registry.schema.json"
12
13
  ],
13
14
  "entry_points": {
14
15
  "portable_file": "portable-file.schema.json",
15
16
  "signed_payload": "bundle-payload.schema.json",
16
17
  "record": "record.schema.json",
17
18
  "proof": "proof.schema.json",
18
- "trusted_key_record": "attestation-key.schema.json"
19
+ "trusted_key_record": "attestation-key.schema.json",
20
+ "agent_evidence_key_registry": "agent-evidence-key-registry.schema.json"
19
21
  }
20
22
  }