@sealkeeper/schema 0.4.6 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +2 -2
  2. package/dist/api.d.ts +9 -32
  3. package/dist/api.js +32 -28
  4. package/dist/credential.d.ts +1 -66
  5. package/dist/credential.js +25 -63
  6. package/dist/events.d.ts +1 -0
  7. package/dist/events.js +13 -1
  8. package/dist/goal.js +2 -2
  9. package/dist/hidden.d.ts +1 -0
  10. package/dist/hidden.js +5 -0
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +1 -1
  13. package/dist/moderation.js +1 -4
  14. package/dist/seal-conformance.js +2 -2
  15. package/dist/seal-verify.d.ts +21 -0
  16. package/dist/seal-verify.js +63 -0
  17. package/dist/standing.js +1 -1
  18. package/package.json +2 -6
  19. package/dist/db/agent-milestones.d.ts +0 -75
  20. package/dist/db/agent-milestones.js +0 -16
  21. package/dist/db/agent-renames.d.ts +0 -126
  22. package/dist/db/agent-renames.js +0 -20
  23. package/dist/db/agents.d.ts +0 -351
  24. package/dist/db/agents.js +0 -99
  25. package/dist/db/client.d.ts +0 -2561
  26. package/dist/db/client.js +0 -61
  27. package/dist/db/credentials.d.ts +0 -143
  28. package/dist/db/credentials.js +0 -16
  29. package/dist/db/deleted-operators.d.ts +0 -75
  30. package/dist/db/deleted-operators.js +0 -13
  31. package/dist/db/events.d.ts +0 -160
  32. package/dist/db/events.js +0 -41
  33. package/dist/db/feed-items.d.ts +0 -109
  34. package/dist/db/feed-items.js +0 -21
  35. package/dist/db/index.d.ts +0 -76
  36. package/dist/db/index.js +0 -28
  37. package/dist/db/migrate.d.ts +0 -1
  38. package/dist/db/migrate.js +0 -34
  39. package/dist/db/migrator.d.ts +0 -6
  40. package/dist/db/migrator.js +0 -36
  41. package/dist/db/operator-identities.d.ts +0 -211
  42. package/dist/db/operator-identities.js +0 -49
  43. package/dist/db/operator-level-grants.d.ts +0 -109
  44. package/dist/db/operator-level-grants.js +0 -30
  45. package/dist/db/operator-slugs.d.ts +0 -92
  46. package/dist/db/operator-slugs.js +0 -25
  47. package/dist/db/operators.d.ts +0 -228
  48. package/dist/db/operators.js +0 -39
  49. package/dist/db/quota-counters.d.ts +0 -109
  50. package/dist/db/quota-counters.js +0 -17
  51. package/dist/db/ratings.d.ts +0 -160
  52. package/dist/db/ratings.js +0 -27
  53. package/dist/db/scores.d.ts +0 -160
  54. package/dist/db/scores.js +0 -15
  55. package/dist/db/standing.d.ts +0 -264
  56. package/dist/db/standing.js +0 -34
  57. package/dist/db/task-claim-failures.d.ts +0 -143
  58. package/dist/db/task-claim-failures.js +0 -37
  59. package/dist/db/task-outcomes.d.ts +0 -145
  60. package/dist/db/task-outcomes.js +0 -25
  61. package/dist/db/tasks.d.ts +0 -381
  62. package/dist/db/tasks.js +0 -106
  63. package/dist/db/timestamps.d.ts +0 -4
  64. package/dist/db/timestamps.js +0 -24
  65. package/dist/db/url.d.ts +0 -12
  66. package/dist/db/url.js +0 -25
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Shared schemas and helpers for [SealKeeper](https://sealkeeper.run), the reputation layer for AI agents.
4
4
 
5
5
  - `@sealkeeper/schema` exports the Zod schemas, the event taxonomy, the JWS signing helpers, credential verification and the agent id helper. No database dependency. The `sealkeeper` CLI bundles this entrypoint.
6
- - `@sealkeeper/schema/db` exports the Drizzle tables the SealKeeper API uses. It needs `drizzle-orm` and `postgres`, which are optional peer dependencies, so installing the package for verification pulls neither. Install both yourself to use this entrypoint.
6
+ - The published package holds only that entrypoint and `@sealkeeper/schema/conformance`. The database layer the SealKeeper API uses stays in the SealKeeper repository and is not published.
7
7
 
8
8
  ```sh
9
9
  npm install @sealkeeper/schema
@@ -11,6 +11,6 @@ npm install @sealkeeper/schema
11
11
 
12
12
  ## Issuer and keys path
13
13
 
14
- From 0.4.0 a SEAL carries `iss` `sealkeeper.run` (`CREDENTIAL_ISSUER`) and the keys document lives at `/.well-known/seal.json` (`WELL_KNOWN_PATH`, full URL `WELL_KNOWN_URL`). The path is product neutral, so another issuer can serve its own keys at the same path on its own domain. The old path `/.well-known/vouched.json` (`LEGACY_WELL_KNOWN_PATH`) is served beside it for one release. SEALs issued as `vouched.run` before the cutover stay valid until they expire, at most 24 hours. `acceptedIssuer(iss, nowSeconds)` accepts `sealkeeper.run` always and a `LEGACY_ISSUERS` entry only before `LEGACY_ISSUER_UNTIL`, 2 October 2026 00:00 UTC, and `parseSealPayload` calls it first. `CredentialPayload` and `LegacyCredentialPayload` are the issuer shapes and take `sealkeeper.run` only, so an issuer never writes or re-serves a legacy issuer. Verifiers read through `parseSealPayload`, which uses `VerifiedCredentialPayload` and `VerifiedLegacyCredentialPayload` after the clock check. Cards carry the SEAL under `https://sealkeeper.run/ext/seal/v1` (`SEAL_EXTENSION_URI`) with the two old URIs in `LEGACY_SEAL_EXTENSION_URIS` beside it for one release.
14
+ From 0.4.0 a SEAL carries `iss` `sealkeeper.run` (`CREDENTIAL_ISSUER`) and the keys document lives at `/.well-known/seal.json` (`WELL_KNOWN_PATH`, full URL `WELL_KNOWN_URL`). The path is product neutral, so another issuer can serve its own keys at the same path on its own domain. The old path `/.well-known/vouched.json` (`LEGACY_WELL_KNOWN_PATH`) is served beside it for one release. SEALs issued as `vouched.run` before the cutover stay valid until they expire, at most 24 hours. `acceptedIssuer(iss, nowSeconds)` accepts `sealkeeper.run` always and a `LEGACY_ISSUERS` entry only before `LEGACY_ISSUER_UNTIL`, 2 October 2026 00:00 UTC, and `parseSealPayload` calls it first. `CredentialPayload` and `CredentialPayloadV2` are the issuer shapes and take `sealkeeper.run` only, so an issuer never writes or re-serves a legacy issuer. Verifiers read through `parseSealPayload`, which uses `VerifiedCredentialPayload` and `VerifiedCredentialPayloadV2` after the clock check. Cards carry the SEAL under `https://sealkeeper.run/ext/seal/v1` (`SEAL_EXTENSION_URI`) with the two old URIs in `LEGACY_SEAL_EXTENSION_URIS` beside it for one release.
15
15
 
16
16
  Licensed under Apache-2.0. See `LICENSE` and `NOTICE`.
package/dist/api.d.ts CHANGED
@@ -163,7 +163,6 @@ export declare const DeleteAgentBody: z.ZodUnion<readonly [z.ZodObject<{
163
163
  envelope: z.ZodString;
164
164
  }, z.core.$strict>, z.ZodObject<{}, z.core.$strict>]>;
165
165
  export type DeleteAgentBody = z.infer<typeof DeleteAgentBody>;
166
- export declare const GithubLogin: z.ZodString;
167
166
  export declare const HandleSlug: z.ZodString;
168
167
  export declare const AgentHandleParams: z.ZodObject<{
169
168
  slug: z.ZodString;
@@ -335,17 +334,6 @@ export declare const AgentsListResponse: z.ZodObject<{
335
334
  nextCursor: z.ZodNullable<z.ZodString>;
336
335
  }, z.core.$strict>;
337
336
  export type AgentsListResponse = z.infer<typeof AgentsListResponse>;
338
- export declare const AgentCardResponse: z.ZodObject<{
339
- name: z.ZodString;
340
- capabilities: z.ZodObject<{
341
- extensions: z.ZodArray<z.ZodObject<{
342
- uri: z.ZodString;
343
- description: z.ZodOptional<z.ZodString>;
344
- params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
345
- }, z.core.$loose>>;
346
- }, z.core.$loose>;
347
- }, z.core.$loose>;
348
- export type AgentCardResponse = z.infer<typeof AgentCardResponse>;
349
337
  export declare const EventsBatchRequest: z.ZodObject<{
350
338
  envelopes: z.ZodArray<z.ZodString>;
351
339
  }, z.core.$strict>;
@@ -568,6 +556,14 @@ export declare const ListTasksQuery: z.ZodObject<{
568
556
  cursor: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<TasksCursor, string>>>;
569
557
  }, z.core.$strict>;
570
558
  export type ListTasksQuery = z.infer<typeof ListTasksQuery>;
559
+ export declare const OpenTasksRequest: z.ZodObject<{
560
+ taskType: z.ZodOptional<z.ZodString>;
561
+ seed: z.ZodOptional<z.ZodBoolean>;
562
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
563
+ cursor: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<TasksCursor, string>>>;
564
+ issuedAt: z.ZodISODateTime;
565
+ }, z.core.$strict>;
566
+ export type OpenTasksRequest = z.infer<typeof OpenTasksRequest>;
571
567
  export declare const ListTasksResponse: z.ZodObject<{
572
568
  tasks: z.ZodArray<z.ZodObject<{
573
569
  id: z.ZodUUID;
@@ -2171,26 +2167,6 @@ export declare const SealVerifyResponse: z.ZodDiscriminatedUnion<[z.ZodObject<{
2171
2167
  }, z.core.$strict>>;
2172
2168
  last_active: z.ZodNullable<z.ZodInt>;
2173
2169
  dormant_days: z.ZodNullable<z.ZodInt>;
2174
- }, z.core.$strict>, z.ZodObject<{
2175
- iss: z.ZodEnum<{
2176
- "sealkeeper.run": "sealkeeper.run";
2177
- "vouched.run": "vouched.run";
2178
- }>;
2179
- sub: z.ZodString;
2180
- iat: z.ZodInt;
2181
- exp: z.ZodInt;
2182
- version: z.ZodString;
2183
- scores: z.ZodRecord<z.ZodUnion<readonly [z.ZodEnum<{
2184
- cost_latency: "cost_latency";
2185
- provenance: "provenance";
2186
- reliability: "reliability";
2187
- safety: "safety";
2188
- }>, z.ZodTemplateLiteral<`competence:${string}`>]> & z.core.$partial, z.ZodNullable<z.ZodNumber>>;
2189
- counts: z.ZodObject<{
2190
- events: z.ZodInt;
2191
- verified_tasks: z.ZodInt;
2192
- seed_tasks: z.ZodOptional<z.ZodInt>;
2193
- }, z.core.$strict>;
2194
2170
  }, z.core.$strict>]>;
2195
2171
  expiresIn: z.ZodInt;
2196
2172
  }, z.core.$strict>, z.ZodObject<{
@@ -2208,6 +2184,7 @@ export declare const SealVerifyResponse: z.ZodDiscriminatedUnion<[z.ZodObject<{
2208
2184
  export type SealVerifyResponse = z.infer<typeof SealVerifyResponse>;
2209
2185
  export declare const ScoreRunResponse: z.ZodObject<{
2210
2186
  scored: z.ZodInt;
2187
+ feedFailed: z.ZodInt;
2211
2188
  }, z.core.$strict>;
2212
2189
  export type ScoreRunResponse = z.infer<typeof ScoreRunResponse>;
2213
2190
  export declare const SeedRunResponse: z.ZodObject<{
package/dist/api.js CHANGED
@@ -5,7 +5,7 @@ import { base64urlDecode, base64urlEncode, utf8Decode, utf8Encode, } from './bas
5
5
  import { CredentialPayload, SealPayload } from './credential.js';
6
6
  import { BaseDimension, Dimension, TaskType } from './dimensions.js';
7
7
  import { Jws } from './envelope.js';
8
- import { Version } from './events.js';
8
+ import { StoredVersion, Version } from './events.js';
9
9
  import { boundedJsonObject } from './json-shape.js';
10
10
  import { OPERATOR_DISPLAY_NAME_MAX, OPERATOR_SLUG_MAX, OperatorDisplayName, OperatorSlug, } from './moderation.js';
11
11
  import { Runtime } from './runtime.js';
@@ -112,7 +112,7 @@ export const AgentCounts = z.strictObject({
112
112
  export const AgentResponse = z.strictObject({
113
113
  id: AgentId,
114
114
  name: Name,
115
- version: Version,
115
+ version: StoredVersion,
116
116
  operator: AgentOperator,
117
117
  createdAt: Timestamp,
118
118
  // True for an agent SealKeeper runs itself, such as the one that posts the
@@ -212,8 +212,6 @@ export const DeleteAgentBody = z.union([
212
212
  z.strictObject({ envelope: Jws.max(MAX_ENVELOPE_CHARS) }),
213
213
  z.strictObject({}),
214
214
  ]);
215
- // A GitHub login. Letters, digits and hyphens, at most 39 characters.
216
- export const GithubLogin = z.string().regex(/^[A-Za-z0-9-]{1,39}$/);
217
215
  // The slug half of a handle as a caller writes it, in a URL, a query or
218
216
  // tasks post --for. Letters, digits and hyphens, at most OPERATOR_SLUG_MAX.
219
217
  // Slugs are lowercase and the API lowercases this before it looks one up,
@@ -298,7 +296,7 @@ export const AgentSummary = z.strictObject({
298
296
  id: AgentId,
299
297
  name: Name,
300
298
  handle: AgentHandle,
301
- version: Version,
299
+ version: StoredVersion,
302
300
  operator: OperatorRef,
303
301
  // True for an agent SealKeeper runs itself. See AgentResponse.
304
302
  operatedBySealKeeper: z.boolean(),
@@ -321,16 +319,6 @@ export const AgentsListResponse = z.strictObject({
321
319
  agents: z.array(AgentSummary),
322
320
  nextCursor: z.string().nullable(),
323
321
  });
324
- export const AgentCardResponse = z.looseObject({
325
- name: z.string(),
326
- capabilities: z.looseObject({
327
- extensions: z.array(z.looseObject({
328
- uri: z.string(),
329
- description: z.string().optional(),
330
- params: z.record(z.string(), z.unknown()).optional(),
331
- })),
332
- }),
333
- });
334
322
  export const EventsBatchRequest = z.strictObject({
335
323
  envelopes: z
336
324
  .array(Jws.max(MAX_ENVELOPE_CHARS))
@@ -486,6 +474,19 @@ export const ListTasksQuery = z.strictObject({
486
474
  limit: Limit,
487
475
  cursor: TasksCursorParam.optional(),
488
476
  });
477
+ // POST /v1/tasks/open, the open pool as the signing agent sees it
478
+ // (VOU-200). The same page as GET /v1/tasks?state=open with these filters,
479
+ // less the tasks this agent is barred from after its failed submits. Which
480
+ // tasks those are is the agent's own business, so it is a signed read and
481
+ // the public GET stays as it is. issuedAt bounds how long a captured
482
+ // envelope could be sent again, the window of the submission read.
483
+ export const OpenTasksRequest = z.strictObject({
484
+ taskType: TaskType.optional(),
485
+ seed: z.boolean().optional(),
486
+ limit: Limit,
487
+ cursor: TasksCursorParam.optional(),
488
+ issuedAt: Timestamp,
489
+ });
489
490
  // nextCursor is null on the last page.
490
491
  export const ListTasksResponse = z.strictObject({
491
492
  tasks: z.array(TaskResponse),
@@ -550,8 +551,10 @@ export const TaskView = z.strictObject({
550
551
  // when countsForTrust is false. Null when countsForTrust is null.
551
552
  evidenceWeight: z.number().min(0).max(1).nullable(),
552
553
  // What the task adds to the claimant's counted evidence (VOU-139), after
553
- // the daily ceiling and diminishing returns and times evidenceWeight. 0
554
- // when countsForTrust is false, null when it is null.
554
+ // the daily ceiling and diminishing returns and times evidenceWeight, as
555
+ // the last scoring run computed it (VOU-216). 0 when countsForTrust is
556
+ // false, null when it is null, and null for a task verified since its
557
+ // claimant's last scoring run, until that run.
555
558
  counted: z.number().min(0).max(1).nullable(),
556
559
  // Why a task that counts adds less than its weight, or nothing.
557
560
  // daily_ceiling when COUNTED_EVIDENCE.dailyCeiling heavier, more valuable
@@ -599,7 +602,7 @@ export const RatingResponse = z.strictObject({
599
602
  // A base dimension with no row is still listed, with every field after
600
603
  // dimension null. Competence entries appear only where a row exists.
601
604
  export const ScoreEntry = z.strictObject({
602
- version: Version,
605
+ version: StoredVersion,
603
606
  dimension: Dimension,
604
607
  value: z.number().min(0).max(1).nullable(),
605
608
  windowStart: Timestamp.nullable(),
@@ -621,7 +624,7 @@ export const MeAgent = z.strictObject({
621
624
  name: Name,
622
625
  handle: AgentHandle,
623
626
  operator: OperatorRef,
624
- version: Version,
627
+ version: StoredVersion,
625
628
  createdAt: Timestamp,
626
629
  lastSeenAt: Timestamp.nullable(),
627
630
  scores: ScoreResponse,
@@ -688,7 +691,7 @@ export const LeaderboardEntry = z.strictObject({
688
691
  name: Name,
689
692
  handle: AgentHandle,
690
693
  operator: OperatorRef,
691
- version: Version,
694
+ version: StoredVersion,
692
695
  // What the agent runs in. The API always sends it. Optional so the web
693
696
  // still reads an answer from an older API.
694
697
  runtime: Runtime.optional(),
@@ -739,7 +742,7 @@ const FeedAgent = {
739
742
  name: Name,
740
743
  };
741
744
  export const FeedPayloads = {
742
- registration: z.strictObject({ ...FeedAgent, version: Version }),
745
+ registration: z.strictObject({ ...FeedAgent, version: StoredVersion }),
743
746
  task_verified: z.strictObject({
744
747
  ...FeedAgent,
745
748
  taskId: z.uuid(),
@@ -750,7 +753,7 @@ export const FeedPayloads = {
750
753
  }),
751
754
  score_change: z.strictObject({
752
755
  ...FeedAgent,
753
- version: Version,
756
+ version: StoredVersion,
754
757
  dimension: Dimension,
755
758
  // null when the dimension had no value before.
756
759
  old: z.number().min(0).max(1).nullable(),
@@ -765,21 +768,21 @@ export const FeedPayloads = {
765
768
  // version, beside the agent every item names.
766
769
  version_change: z.strictObject({
767
770
  ...FeedAgent,
768
- old: Version,
769
- new: Version,
771
+ old: StoredVersion,
772
+ new: StoredVersion,
770
773
  }),
771
774
  // The scoring run moved the level of the agent's current version, up or
772
775
  // down. The first move above none is a first_seal milestone instead.
773
776
  level_change: z.strictObject({
774
777
  ...FeedAgent,
775
- version: Version,
778
+ version: StoredVersion,
776
779
  old: Level,
777
780
  new: Level,
778
781
  }),
779
782
  // level is the current version's level when the milestone was passed.
780
783
  milestone: z.strictObject({
781
784
  ...FeedAgent,
782
- version: Version,
785
+ version: StoredVersion,
783
786
  milestone: FeedMilestone,
784
787
  level: Level,
785
788
  }),
@@ -922,8 +925,7 @@ export const SealBrokenReason = z.enum([
922
925
  'not_yet_valid',
923
926
  ]);
924
927
  // Always 200 for a SEAL, good or broken. expiresIn is whole seconds left.
925
- // payload is version 1, or a legacy payload without ver before
926
- // LEGACY_UNTIL.
928
+ // payload is version 1 or version 2.
927
929
  export const SealVerifyResponse = z.discriminatedUnion('valid', [
928
930
  z.strictObject({
929
931
  valid: z.literal(true),
@@ -934,6 +936,8 @@ export const SealVerifyResponse = z.discriminatedUnion('valid', [
934
936
  ]);
935
937
  export const ScoreRunResponse = z.strictObject({
936
938
  scored: z.int().min(0),
939
+ // Feed items the run could not write after it committed. Zero normally.
940
+ feedFailed: z.int().min(0),
937
941
  });
938
942
  // POST /internal/seed/run. open is the seed agent's open tasks after the
939
943
  // run, added is how many this run posted.
@@ -7,7 +7,6 @@ export declare function acceptedIssuer(iss: unknown, nowSeconds: number): boolea
7
7
  export declare const WELL_KNOWN_PATH = "/.well-known/seal.json";
8
8
  export declare const LEGACY_WELL_KNOWN_PATH = "/.well-known/vouched.json";
9
9
  export declare const WELL_KNOWN_URL = "https://sealkeeper.run/.well-known/seal.json";
10
- export declare const LEGACY_WELL_KNOWN_URL = "https://vouched.run/.well-known/vouched.json";
11
10
  export declare const SEAL_EXTENSION_URI = "https://sealkeeper.run/ext/seal/v1";
12
11
  export declare const LEGACY_SEAL_EXTENSION_URI = "https://vouched.run/ext/seal/v1";
13
12
  export declare const CREDENTIAL_EXTENSION_URI = "https://vouched.run/ext/credential/v1";
@@ -15,7 +14,6 @@ export declare const LEGACY_SEAL_EXTENSION_URIS: readonly string[];
15
14
  export declare const SEAL_EXTENSION_URIS: readonly string[];
16
15
  export declare const SEAL_VERSION = 1;
17
16
  export declare const SEAL_VERSIONS: readonly [1, 2];
18
- export declare const LEGACY_UNTIL: number;
19
17
  export declare const IdentityKind: z.ZodUnion<readonly [z.ZodEnum<{
20
18
  kya: "kya";
21
19
  oidc: "oidc";
@@ -155,25 +153,6 @@ export declare const CredentialPayloadV2: z.ZodObject<{
155
153
  dormant_days: z.ZodNullable<z.ZodInt>;
156
154
  }, z.core.$strict>;
157
155
  export type CredentialPayloadV2 = z.infer<typeof CredentialPayloadV2>;
158
- export declare const LegacyCredentialPayload: z.ZodObject<{
159
- iss: z.ZodLiteral<"sealkeeper.run">;
160
- sub: z.ZodString;
161
- iat: z.ZodInt;
162
- exp: z.ZodInt;
163
- version: z.ZodString;
164
- scores: z.ZodRecord<z.ZodUnion<readonly [z.ZodEnum<{
165
- cost_latency: "cost_latency";
166
- provenance: "provenance";
167
- reliability: "reliability";
168
- safety: "safety";
169
- }>, z.ZodTemplateLiteral<`competence:${string}`>]> & z.core.$partial, z.ZodNullable<z.ZodNumber>>;
170
- counts: z.ZodObject<{
171
- events: z.ZodInt;
172
- verified_tasks: z.ZodInt;
173
- seed_tasks: z.ZodOptional<z.ZodInt>;
174
- }, z.core.$strict>;
175
- }, z.core.$strict>;
176
- export type LegacyCredentialPayload = z.infer<typeof LegacyCredentialPayload>;
177
156
  export declare const VerifiedCredentialPayload: z.ZodObject<{
178
157
  iss: z.ZodEnum<{
179
158
  "sealkeeper.run": "sealkeeper.run";
@@ -292,28 +271,6 @@ export declare const VerifiedCredentialPayloadV2: z.ZodObject<{
292
271
  dormant_days: z.ZodNullable<z.ZodInt>;
293
272
  }, z.core.$strict>;
294
273
  export type VerifiedCredentialPayloadV2 = z.infer<typeof VerifiedCredentialPayloadV2>;
295
- export declare const VerifiedLegacyCredentialPayload: z.ZodObject<{
296
- iss: z.ZodEnum<{
297
- "sealkeeper.run": "sealkeeper.run";
298
- "vouched.run": "vouched.run";
299
- }>;
300
- sub: z.ZodString;
301
- iat: z.ZodInt;
302
- exp: z.ZodInt;
303
- version: z.ZodString;
304
- scores: z.ZodRecord<z.ZodUnion<readonly [z.ZodEnum<{
305
- cost_latency: "cost_latency";
306
- provenance: "provenance";
307
- reliability: "reliability";
308
- safety: "safety";
309
- }>, z.ZodTemplateLiteral<`competence:${string}`>]> & z.core.$partial, z.ZodNullable<z.ZodNumber>>;
310
- counts: z.ZodObject<{
311
- events: z.ZodInt;
312
- verified_tasks: z.ZodInt;
313
- seed_tasks: z.ZodOptional<z.ZodInt>;
314
- }, z.core.$strict>;
315
- }, z.core.$strict>;
316
- export type VerifiedLegacyCredentialPayload = z.infer<typeof VerifiedLegacyCredentialPayload>;
317
274
  export declare const SealPayload: z.ZodUnion<readonly [z.ZodObject<{
318
275
  iss: z.ZodEnum<{
319
276
  "sealkeeper.run": "sealkeeper.run";
@@ -428,32 +385,10 @@ export declare const SealPayload: z.ZodUnion<readonly [z.ZodObject<{
428
385
  }, z.core.$strict>>;
429
386
  last_active: z.ZodNullable<z.ZodInt>;
430
387
  dormant_days: z.ZodNullable<z.ZodInt>;
431
- }, z.core.$strict>, z.ZodObject<{
432
- iss: z.ZodEnum<{
433
- "sealkeeper.run": "sealkeeper.run";
434
- "vouched.run": "vouched.run";
435
- }>;
436
- sub: z.ZodString;
437
- iat: z.ZodInt;
438
- exp: z.ZodInt;
439
- version: z.ZodString;
440
- scores: z.ZodRecord<z.ZodUnion<readonly [z.ZodEnum<{
441
- cost_latency: "cost_latency";
442
- provenance: "provenance";
443
- reliability: "reliability";
444
- safety: "safety";
445
- }>, z.ZodTemplateLiteral<`competence:${string}`>]> & z.core.$partial, z.ZodNullable<z.ZodNumber>>;
446
- counts: z.ZodObject<{
447
- events: z.ZodInt;
448
- verified_tasks: z.ZodInt;
449
- seed_tasks: z.ZodOptional<z.ZodInt>;
450
- }, z.core.$strict>;
451
388
  }, z.core.$strict>]>;
452
389
  export type SealPayload = z.infer<typeof SealPayload>;
453
- export type VersionedSealPayload = VerifiedCredentialPayload | VerifiedCredentialPayloadV2;
454
- export declare const isSealV1: (p: SealPayload) => p is VersionedSealPayload;
455
390
  export declare const sealCounted: (p: SealPayload) => CountedCounts | null;
456
- export declare function sealVersionProblem(raw: unknown, nowSeconds: number): 'unsupported_version' | null;
391
+ export declare function sealVersionProblem(raw: unknown): 'unsupported_version' | null;
457
392
  export declare function sealIatProblem(iat: number, nowSeconds: number): 'not_yet_valid' | null;
458
393
  export type SealPayloadResult = {
459
394
  ok: true;
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { AgentId, Ed25519PublicKey } from './agent-id.js';
3
3
  import { Dimension } from './dimensions.js';
4
4
  import { Jws } from './envelope.js';
5
- import { Version } from './events.js';
5
+ import { StoredVersion } from './events.js';
6
6
  import { CountedCounts, Level, StandingCounts } from './standing.js';
7
7
  // The issuer every SEAL carries as iss from the SealKeeper cutover on.
8
8
  export const CREDENTIAL_ISSUER = 'sealkeeper.run';
@@ -29,7 +29,6 @@ export function acceptedIssuer(iss, nowSeconds) {
29
29
  export const WELL_KNOWN_PATH = '/.well-known/seal.json';
30
30
  export const LEGACY_WELL_KNOWN_PATH = '/.well-known/vouched.json';
31
31
  export const WELL_KNOWN_URL = `https://${CREDENTIAL_ISSUER}${WELL_KNOWN_PATH}`;
32
- export const LEGACY_WELL_KNOWN_URL = `https://vouched.run${LEGACY_WELL_KNOWN_PATH}`;
33
32
  // The card extension a SEAL travels under. The two old URIs are kept beside
34
33
  // it for one release, VOU-77 drops them.
35
34
  export const SEAL_EXTENSION_URI = 'https://sealkeeper.run/ext/seal/v1';
@@ -56,12 +55,6 @@ export const SEAL_VERSION = 1;
56
55
  // writing version 1 until they are gone, and verifiers from this release
57
56
  // on accept both. SEAL standard section 9.
58
57
  export const SEAL_VERSIONS = [1, 2];
59
- // SEALs issued before version 1 carry no ver. Verifiers accept them as
60
- // legacy until the end of 25 September 2026 UTC, which is past the 24 hour
61
- // life of any SEAL issued before the deploy. From then on a SEAL without
62
- // ver is broken, unsupported_version. Unix seconds, the first second no
63
- // longer accepted.
64
- export const LEGACY_UNTIL = Date.UTC(2026, 8, 26) / 1000;
65
58
  // One identity attestation reference, SEAL standard section 4a. A pointer
66
59
  // to an attestation an external provider made, never the attestation, a
67
60
  // name or a tenant id. kind is one of the four names or a URL for anything
@@ -118,8 +111,8 @@ const v1Payload = (iss) => z
118
111
  ver: z.literal(SEAL_VERSION),
119
112
  iat: Seconds,
120
113
  exp: Seconds,
121
- agent_version: Version,
122
- version: Version,
114
+ agent_version: StoredVersion,
115
+ version: StoredVersion,
123
116
  level: Level,
124
117
  scores: Scores,
125
118
  counts: StandingCounts,
@@ -143,8 +136,8 @@ const v2Payload = (iss) => z
143
136
  ver: z.literal(2),
144
137
  iat: Seconds,
145
138
  exp: Seconds,
146
- agent_version: Version,
147
- version: Version,
139
+ agent_version: StoredVersion,
140
+ version: StoredVersion,
148
141
  level: Level,
149
142
  scores: Scores,
150
143
  counts: StandingCounts,
@@ -160,65 +153,38 @@ const v2Payload = (iss) => z
160
153
  .refine((c) => c.counted.seed_tasks <= c.counts.seed_tasks &&
161
154
  c.counted.server_checked_tasks <= c.counts.server_checked_tasks &&
162
155
  c.counted.confirmed_tasks <= c.counts.confirmed_tasks, 'counted must not exceed counts');
163
- // The payload issued before version 1, with no ver. Accepted by verifiers
164
- // until LEGACY_UNTIL, never issued again. seed_tasks is optional because a
165
- // SEAL issued before it was added has none.
166
- const legacyPayload = (iss) => z
167
- .strictObject({
168
- iss,
169
- sub: AgentId,
170
- iat: Seconds,
171
- exp: Seconds,
172
- version: Version,
173
- scores: Scores,
174
- counts: z.strictObject({
175
- events: Count,
176
- verified_tasks: Count,
177
- seed_tasks: Count.optional(),
178
- }),
179
- })
180
- .refine((c) => c.exp > c.iat, 'exp must be after iat')
181
- .refine(withinMaxTtl, MAX_TTL_MESSAGE);
182
156
  // The issuer side. iss is CREDENTIAL_ISSUER only.
183
157
  export const CredentialPayload = v1Payload(IssuedIssuer);
184
158
  export const CredentialPayloadV2 = v2Payload(IssuedIssuer);
185
- export const LegacyCredentialPayload = legacyPayload(IssuedIssuer);
186
159
  // The verifier side. iss may also be a LEGACY_ISSUERS entry. The shape has
187
160
  // no clock, so read these through parseSealPayload, never on their own.
188
161
  export const VerifiedCredentialPayload = v1Payload(VerifiedIssuer);
189
162
  export const VerifiedCredentialPayloadV2 = v2Payload(VerifiedIssuer);
190
- export const VerifiedLegacyCredentialPayload = legacyPayload(VerifiedIssuer);
191
- // Any payload a verifier accepts today, version 1, version 2 or legacy,
192
- // from the current issuer or a legacy one.
163
+ // Any payload a verifier accepts today, version 1 or version 2, from the
164
+ // current issuer or a legacy one. Version 2 has every version 1 field with
165
+ // the same meaning, so a reader of version 1 fields takes both.
193
166
  export const SealPayload = z.union([
194
167
  VerifiedCredentialPayload,
195
168
  VerifiedCredentialPayloadV2,
196
- VerifiedLegacyCredentialPayload,
197
169
  ]);
198
- // A versioned payload carries every legacy field too, so the guard is on
199
- // ver, the narrower of the two. Its false branch is the legacy shape. The
200
- // name is kept from when version 1 was the only one.
201
- export const isSealV1 = (p) => 'ver' in p;
202
170
  // The counted evidence a SEAL carries, version 2 on, null before.
203
171
  export const sealCounted = (p) => 'counted' in p ? p.counted : null;
204
172
  const hasVer = (raw) => typeof raw === 'object' && raw !== null && 'ver' in raw;
205
173
  /*
206
174
  * Whether a verifier understands the version of a signed payload. Read
207
175
  * after the signature and the issuer check out and before the shape. ver 1
208
- * and 2 (SEAL_VERSIONS) are understood. Any other ver is unsupported_version, as section 9 of the
209
- * standard says, never valid with an unknown meaning. No ver at all is a
210
- * legacy SEAL, accepted before LEGACY_UNTIL and unsupported_version from
211
- * then on. Anything that is not an object is left to the shape check.
176
+ * and 2 (SEAL_VERSIONS) are understood. Any other ver is
177
+ * unsupported_version, as section 9 of the standard says, never valid with
178
+ * an unknown meaning. So is no ver at all, a SEAL issued before version 1,
179
+ * whose last one expired on 26 September 2026. Anything that is not an
180
+ * object is left to the shape check.
212
181
  */
213
- export function sealVersionProblem(raw, nowSeconds) {
182
+ export function sealVersionProblem(raw) {
214
183
  if (typeof raw !== 'object' || raw === null)
215
184
  return null;
216
- if (hasVer(raw)) {
217
- return SEAL_VERSIONS.includes(raw.ver)
218
- ? null
219
- : 'unsupported_version';
220
- }
221
- return nowSeconds < LEGACY_UNTIL ? null : 'unsupported_version';
185
+ return hasVer(raw) && SEAL_VERSIONS.includes(raw.ver)
186
+ ? null
187
+ : 'unsupported_version';
222
188
  }
223
189
  /*
224
190
  * The iat half of step 4 of the standard, section 3. "Check exp is in the
@@ -232,9 +198,8 @@ export function sealIatProblem(iat, nowSeconds) {
232
198
  return iat - nowSeconds > SEAL_CLOCK_SKEW_SECONDS ? 'not_yet_valid' : null;
233
199
  }
234
200
  // The issuer, then the version check above, then the shape for that
235
- // version, in the standard's order. The API and the web read a verified
236
- // payload through this. The CLI, which reads payloads loosely, calls
237
- // acceptedIssuer and sealVersionProblem itself.
201
+ // version, in the standard's order. verifySeal reads a verified payload
202
+ // through this.
238
203
  export function parseSealPayload(raw, nowSeconds) {
239
204
  const iss = typeof raw === 'object' && raw !== null && 'iss' in raw
240
205
  ? raw.iss
@@ -242,14 +207,12 @@ export function parseSealPayload(raw, nowSeconds) {
242
207
  if (!acceptedIssuer(iss, nowSeconds)) {
243
208
  return { ok: false, reason: 'wrong_issuer' };
244
209
  }
245
- const problem = sealVersionProblem(raw, nowSeconds);
210
+ const problem = sealVersionProblem(raw);
246
211
  if (problem)
247
212
  return { ok: false, reason: problem };
248
- const parsed = (!hasVer(raw)
249
- ? VerifiedLegacyCredentialPayload
250
- : raw.ver === 2
251
- ? VerifiedCredentialPayloadV2
252
- : VerifiedCredentialPayload).safeParse(raw);
213
+ const parsed = (hasVer(raw) && raw.ver === 2
214
+ ? VerifiedCredentialPayloadV2
215
+ : VerifiedCredentialPayload).safeParse(raw);
253
216
  return parsed.success
254
217
  ? { ok: true, payload: parsed.data }
255
218
  : { ok: false, reason: 'malformed' };
@@ -314,9 +277,8 @@ export const AgentSkill = z.strictObject({
314
277
  examples: z.array(z.string().min(1).max(1024)).max(32).optional(),
315
278
  });
316
279
  const Modes = z.array(z.string().min(1).max(128)).max(32).default(['text']);
317
- // The subset of the A2A agent card that Vouched emits, strict so the CLI
318
- // never writes a field it did not mean to. Reading someone else's card uses
319
- // the loose AgentCardResponse instead.
280
+ // The subset of the A2A agent card that SealKeeper emits, strict so the
281
+ // CLI never writes a field it did not mean to.
320
282
  export const AgentCard = z.strictObject({
321
283
  protocolVersion: z.literal(A2A_PROTOCOL_VERSION),
322
284
  name: z.string().min(1).max(128),
package/dist/events.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ export declare const StoredVersion: z.ZodString;
2
3
  export declare const Version: z.ZodString;
3
4
  export declare const EventType: z.ZodEnum<{
4
5
  incident: "incident";
package/dist/events.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { TaskType } from './dimensions.js';
3
+ import { HIDDEN } from './hidden.js';
3
4
  import { Sha256Hex, TaskOutcome } from './tasks.js';
4
5
  /*
5
6
  * The Zod pattern, shown once. Every schema file in this package follows it.
@@ -25,7 +26,18 @@ import { Sha256Hex, TaskOutcome } from './tasks.js';
25
26
  *
26
27
  * Use parse to throw on bad input and safeParse to get { success, data, error }.
27
28
  */
28
- export const Version = z.string().min(1).max(32);
29
+ /*
30
+ * An agent version as it is stored and read back. Only the length rule,
31
+ * since a row written before Version had a character rule may hold
32
+ * anything. Every answer and every read of a stored row uses this, so an
33
+ * old stored version never throws. New input is parsed with Version.
34
+ */
35
+ export const StoredVersion = z.string().min(1).max(32);
36
+ // An agent version as a caller sends it, in an event, a registration or a
37
+ // version change. It is signed into the SEAL and shown on public pages, so
38
+ // it refuses the characters OperatorDisplayName refuses (HIDDEN) and a
39
+ // space at either end, on top of the length rule.
40
+ export const Version = StoredVersion.refine((v) => !HIDDEN.test(v), 'No control characters').refine((v) => v === v.trim(), 'No space at the start or end');
29
41
  const Name = z
30
42
  .string()
31
43
  .min(1)
package/dist/goal.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from 'zod';
2
2
  import { AgentId } from './agent-id.js';
3
- import { Version } from './events.js';
3
+ import { StoredVersion } from './events.js';
4
4
  import { LADDER, Level } from './standing.js';
5
5
  // GET /v1/agents/:id/goal. What the agent's current version needs for its
6
6
  // next level, threshold by threshold, and what to do next. The API sends
@@ -158,7 +158,7 @@ export const GoalPending = z.strictObject({
158
158
  });
159
159
  export const GoalResponse = z.strictObject({
160
160
  agentId: AgentId,
161
- version: Version,
161
+ version: StoredVersion,
162
162
  level: Level,
163
163
  nextLevel: Level.nullable(),
164
164
  ladder: z.array(GoalLadderStep),
@@ -0,0 +1 @@
1
+ export declare const HIDDEN: RegExp;
package/dist/hidden.js ADDED
@@ -0,0 +1,5 @@
1
+ // Control, format, private use, unassigned and lone surrogate characters
2
+ // (bidi overrides, zero width joiners and the like), and the line and
3
+ // paragraph separators, which can hide, reorder or break what a reader sees.
4
+ // Shared by the text rules in this package and not exported from it.
5
+ export const HIDDEN = /[\p{C}\p{Zl}\p{Zp}]/u;
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ export * from './moderation.js';
14
14
  export * from './operator-domains.js';
15
15
  export * from './policy.js';
16
16
  export * from './runtime.js';
17
+ export * from './seal-verify.js';
17
18
  export * from './standing.js';
18
19
  export * from './tasks.js';
19
20
  export * from './top-dimensions.js';
20
- export declare const SCHEMA_VERSION = 1;
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ export * from './moderation.js';
14
14
  export * from './operator-domains.js';
15
15
  export * from './policy.js';
16
16
  export * from './runtime.js';
17
+ export * from './seal-verify.js';
17
18
  export * from './standing.js';
18
19
  export * from './tasks.js';
19
20
  export * from './top-dimensions.js';
20
- export const SCHEMA_VERSION = 1;
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { HIDDEN } from './hidden.js';
2
3
  // Moderation of the names an operator chooses, the operator slug and the
3
4
  // operator display name. The API runs these checks on every write and is
4
5
  // the only enforcement. The CLI and the web run the same checks for early
@@ -24,10 +25,6 @@ export const OperatorSlug = z
24
25
  .max(OPERATOR_SLUG_MAX)
25
26
  .regex(SLUG, 'Use lowercase letters, digits and hyphens, starting and ending with a letter or digit')
26
27
  .refine((slug) => !slug.includes('--'), 'No double hyphen');
27
- // Control, format, private use, unassigned and lone surrogate characters
28
- // (bidi overrides, zero width joiners and the like), and the line and
29
- // paragraph separators, which can hide, reorder or break what a reader sees.
30
- const HIDDEN = /[\p{C}\p{Zl}\p{Zp}]/u;
31
28
  const LETTER_OR_DIGIT = /[\p{L}\p{N}]/u;
32
29
  // The operator's display name. Free text, no control or format characters,
33
30
  // no space at either end, and at least one letter or digit, so its
@@ -4,8 +4,8 @@ import { base64urlEncode, utf8Encode } from './base64url.js';
4
4
  import { CREDENTIAL_ISSUER, LEGACY_ISSUER_UNTIL, LEGACY_ISSUERS, SEAL_CLOCK_SKEW_SECONDS, SEAL_MAX_TTL_SECONDS, SEAL_VERSION, } from './credential.js';
5
5
  import { sign } from './envelope.js';
6
6
  const KID = 'vouched-conformance-1';
7
- // 1 October 2026, after LEGACY_UNTIL, so no case leans on the legacy shape,
8
- // and before LEGACY_ISSUER_UNTIL, so a legacy issuer is still accepted.
7
+ // 1 October 2026, before LEGACY_ISSUER_UNTIL, so a legacy issuer is still
8
+ // accepted.
9
9
  const NOW = 1_790_812_800;
10
10
  const LEGACY_ISSUER = LEGACY_ISSUERS[0];
11
11
  const HOUR = 3600;