@sealkeeper/schema 0.4.6 → 0.4.8
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 +2 -2
- package/dist/api.d.ts +787 -35
- package/dist/api.js +357 -44
- package/dist/conformance.d.ts +4 -0
- package/dist/conformance.js +7 -0
- package/dist/credential.d.ts +196 -27
- package/dist/credential.js +128 -80
- package/dist/dimensions.d.ts +16 -3
- package/dist/dimensions.js +48 -2
- package/dist/events.d.ts +1 -0
- package/dist/events.js +13 -1
- package/dist/fingerprint-conformance.d.ts +17 -0
- package/dist/fingerprint-conformance.js +83 -0
- package/dist/fingerprint.d.ts +132 -0
- package/dist/fingerprint.js +166 -0
- package/dist/goal.d.ts +16 -1
- package/dist/goal.js +29 -6
- package/dist/handshake-conformance.d.ts +18 -0
- package/dist/handshake-conformance.js +276 -0
- package/dist/handshake.d.ts +66 -0
- package/dist/handshake.js +187 -0
- package/dist/hidden.d.ts +1 -0
- package/dist/hidden.js +5 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/moderation.js +1 -4
- package/dist/policy.d.ts +1 -1
- package/dist/policy.js +1 -1
- package/dist/seal-conformance.js +148 -4
- package/dist/seal-verify.d.ts +21 -0
- package/dist/seal-verify.js +63 -0
- package/dist/standing.d.ts +61 -0
- package/dist/standing.js +132 -4
- package/dist/task-templates.d.ts +46 -0
- package/dist/task-templates.js +501 -0
- package/dist/tasks.d.ts +43 -0
- package/dist/tasks.js +103 -0
- package/dist/template-conformance.d.ts +10 -0
- package/dist/template-conformance.js +298 -0
- package/dist/top-dimensions.d.ts +3 -3
- package/dist/top-dimensions.js +12 -6
- package/package.json +4 -8
- package/dist/db/agent-milestones.d.ts +0 -75
- package/dist/db/agent-milestones.js +0 -16
- package/dist/db/agent-renames.d.ts +0 -126
- package/dist/db/agent-renames.js +0 -20
- package/dist/db/agents.d.ts +0 -351
- package/dist/db/agents.js +0 -99
- package/dist/db/client.d.ts +0 -2561
- package/dist/db/client.js +0 -61
- package/dist/db/credentials.d.ts +0 -143
- package/dist/db/credentials.js +0 -16
- package/dist/db/deleted-operators.d.ts +0 -75
- package/dist/db/deleted-operators.js +0 -13
- package/dist/db/events.d.ts +0 -160
- package/dist/db/events.js +0 -41
- package/dist/db/feed-items.d.ts +0 -109
- package/dist/db/feed-items.js +0 -21
- package/dist/db/index.d.ts +0 -76
- package/dist/db/index.js +0 -28
- package/dist/db/migrate.d.ts +0 -1
- package/dist/db/migrate.js +0 -34
- package/dist/db/migrator.d.ts +0 -6
- package/dist/db/migrator.js +0 -36
- package/dist/db/operator-identities.d.ts +0 -211
- package/dist/db/operator-identities.js +0 -49
- package/dist/db/operator-level-grants.d.ts +0 -109
- package/dist/db/operator-level-grants.js +0 -30
- package/dist/db/operator-slugs.d.ts +0 -92
- package/dist/db/operator-slugs.js +0 -25
- package/dist/db/operators.d.ts +0 -228
- package/dist/db/operators.js +0 -39
- package/dist/db/quota-counters.d.ts +0 -109
- package/dist/db/quota-counters.js +0 -17
- package/dist/db/ratings.d.ts +0 -160
- package/dist/db/ratings.js +0 -27
- package/dist/db/scores.d.ts +0 -160
- package/dist/db/scores.js +0 -15
- package/dist/db/standing.d.ts +0 -264
- package/dist/db/standing.js +0 -34
- package/dist/db/task-claim-failures.d.ts +0 -143
- package/dist/db/task-claim-failures.js +0 -37
- package/dist/db/task-outcomes.d.ts +0 -145
- package/dist/db/task-outcomes.js +0 -25
- package/dist/db/tasks.d.ts +0 -381
- package/dist/db/tasks.js +0 -106
- package/dist/db/timestamps.d.ts +0 -4
- package/dist/db/timestamps.js +0 -24
- package/dist/db/url.d.ts +0 -12
- package/dist/db/url.js +0 -25
package/dist/api.js
CHANGED
|
@@ -3,14 +3,16 @@ import { AgentId } from './agent-id.js';
|
|
|
3
3
|
import { AgentName } from './agent-name.js';
|
|
4
4
|
import { base64urlDecode, base64urlEncode, utf8Decode, utf8Encode, } from './base64url.js';
|
|
5
5
|
import { CredentialPayload, SealPayload } from './credential.js';
|
|
6
|
-
import {
|
|
6
|
+
import { AcceptedDimension, COMPETENCE_TYPES_MAX, 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
|
+
import { AgentFingerprint, Fingerprint } from './fingerprint.js';
|
|
10
|
+
import { HANDSHAKE_MAX_CHARS, HandshakeAgainst, HandshakeNonce, HandshakeRefusal, HandshakeResult, } from './handshake.js';
|
|
9
11
|
import { boundedJsonObject } from './json-shape.js';
|
|
10
12
|
import { OPERATOR_DISPLAY_NAME_MAX, OPERATOR_SLUG_MAX, OperatorDisplayName, OperatorSlug, } from './moderation.js';
|
|
11
13
|
import { Runtime } from './runtime.js';
|
|
12
14
|
import { Level, Standing } from './standing.js';
|
|
13
|
-
import { PublicVerificationSpec, Sha256Hex, ShownVerificationSpec, TaskOutcome, TaskState, VerificationSpec, } from './tasks.js';
|
|
15
|
+
import { CheckMethod, Disclosure, PublicVerificationSpec, Sha256Hex, ShownVerificationSpec, TaskCategory, TaskInputRef, TaskOutcome, TaskOutputShape, TaskSize, TaskState, VerificationSpec, } from './tasks.js';
|
|
14
16
|
export const MAX_EVENTS_PER_BATCH = 500;
|
|
15
17
|
// The window an event's occurred_at must fall in for the API to take it, at
|
|
16
18
|
// most this many days old and this many seconds ahead of the API clock.
|
|
@@ -112,7 +114,7 @@ export const AgentCounts = z.strictObject({
|
|
|
112
114
|
export const AgentResponse = z.strictObject({
|
|
113
115
|
id: AgentId,
|
|
114
116
|
name: Name,
|
|
115
|
-
version:
|
|
117
|
+
version: StoredVersion,
|
|
116
118
|
operator: AgentOperator,
|
|
117
119
|
createdAt: Timestamp,
|
|
118
120
|
// True for an agent SealKeeper runs itself, such as the one that posts the
|
|
@@ -153,6 +155,13 @@ export const AgentResponse = z.strictObject({
|
|
|
153
155
|
// by handle, left out of registration and rename for the same reason as
|
|
154
156
|
// counts.
|
|
155
157
|
avatarUrl: z.url().optional(),
|
|
158
|
+
// The agent's current fingerprint (VB-4), the one with the latest
|
|
159
|
+
// captured_at any of its signed requests carried, as its hash, when it
|
|
160
|
+
// was captured and each part's state, never a part hash. null when it
|
|
161
|
+
// has declared none. A second record beside version, never the scoring
|
|
162
|
+
// key. Sent by GET by id and GET by handle only, for the same reason as
|
|
163
|
+
// counts.
|
|
164
|
+
fingerprint: AgentFingerprint.nullable().optional(),
|
|
156
165
|
});
|
|
157
166
|
// Old handles keep resolving, as a redirect, for this many days after an
|
|
158
167
|
// agent rename. The profile shows the old name for as long.
|
|
@@ -212,8 +221,6 @@ export const DeleteAgentBody = z.union([
|
|
|
212
221
|
z.strictObject({ envelope: Jws.max(MAX_ENVELOPE_CHARS) }),
|
|
213
222
|
z.strictObject({}),
|
|
214
223
|
]);
|
|
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
224
|
// The slug half of a handle as a caller writes it, in a URL, a query or
|
|
218
225
|
// tasks post --for. Letters, digits and hyphens, at most OPERATOR_SLUG_MAX.
|
|
219
226
|
// Slugs are lowercase and the API lowercases this before it looks one up,
|
|
@@ -285,20 +292,21 @@ export const AgentsListQuery = z.strictObject({
|
|
|
285
292
|
operator: HandleSlug.optional(),
|
|
286
293
|
});
|
|
287
294
|
export const TopScore = z.strictObject({
|
|
288
|
-
dimension:
|
|
295
|
+
dimension: Dimension,
|
|
289
296
|
value: z.number().min(0).max(1),
|
|
290
297
|
});
|
|
291
298
|
// One agent in the directory. lastSeenAt is the newest received_at of its
|
|
292
|
-
// events, null when it has sent none. topScores holds at most two
|
|
293
|
-
// dimensions on the current version,
|
|
294
|
-
//
|
|
299
|
+
// events, null when it has sent none. topScores holds at most two trust
|
|
300
|
+
// dimensions on the current version, base or competence category
|
|
301
|
+
// (topDimensions), highest first, only those with a value. cost_latency is
|
|
302
|
+
// never one of them. verifiedTasks and seedTasks are the
|
|
295
303
|
// same counts as on AgentResponse. level and standing are as on
|
|
296
304
|
// AgentResponse, left out until the current version has been scored.
|
|
297
305
|
export const AgentSummary = z.strictObject({
|
|
298
306
|
id: AgentId,
|
|
299
307
|
name: Name,
|
|
300
308
|
handle: AgentHandle,
|
|
301
|
-
version:
|
|
309
|
+
version: StoredVersion,
|
|
302
310
|
operator: OperatorRef,
|
|
303
311
|
// True for an agent SealKeeper runs itself. See AgentResponse.
|
|
304
312
|
operatedBySealKeeper: z.boolean(),
|
|
@@ -321,21 +329,18 @@ export const AgentsListResponse = z.strictObject({
|
|
|
321
329
|
agents: z.array(AgentSummary),
|
|
322
330
|
nextCursor: z.string().nullable(),
|
|
323
331
|
});
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
params: z.record(z.string(), z.unknown()).optional(),
|
|
331
|
-
})),
|
|
332
|
-
}),
|
|
333
|
-
});
|
|
332
|
+
// fingerprint is the signing agent's fingerprint as its CLI last computed
|
|
333
|
+
// it (VB-4), a JWS signed by the same agent over FingerprintDeclaration in
|
|
334
|
+
// ./fingerprint.ts. The API refuses one that does not verify, names
|
|
335
|
+
// another agent or whose hash is not the hash of its parts, and keeps it
|
|
336
|
+
// as the agent's current fingerprint when it was captured later than the
|
|
337
|
+
// stored one. Optional, so a CLI from before it syncs unchanged.
|
|
334
338
|
export const EventsBatchRequest = z.strictObject({
|
|
335
339
|
envelopes: z
|
|
336
340
|
.array(Jws.max(MAX_ENVELOPE_CHARS))
|
|
337
341
|
.min(1)
|
|
338
342
|
.max(MAX_EVENTS_PER_BATCH),
|
|
343
|
+
fingerprint: Jws.max(MAX_ENVELOPE_CHARS).optional(),
|
|
339
344
|
});
|
|
340
345
|
// accepted counts rows newly stored. duplicates counts events already stored
|
|
341
346
|
// for this agent (same event_id), which are skipped, so a retry is safe.
|
|
@@ -372,6 +377,11 @@ export const TaskOrigin = z.enum(['manual', 'template', 'routine']);
|
|
|
372
377
|
// poster gets 409. assignee addresses the task to one agent of another
|
|
373
378
|
// operator, resolved to its id at post. Only that agent can claim it, and it
|
|
374
379
|
// counts at reduced weight as evidence. Without it the task is open to all.
|
|
380
|
+
//
|
|
381
|
+
// The real task fields (RT-2) are optional. The API stores what the post
|
|
382
|
+
// says, else what derivedTaskFields gives from the type and the spec, so an
|
|
383
|
+
// older CLI posts without them. disclosure sealed and verdict_only are
|
|
384
|
+
// reserved, and the API refuses them with 400 disclosure_reserved.
|
|
375
385
|
export const PostTaskRequest = z.strictObject({
|
|
376
386
|
taskId: z.uuid(),
|
|
377
387
|
taskType: TaskType,
|
|
@@ -380,6 +390,52 @@ export const PostTaskRequest = z.strictObject({
|
|
|
380
390
|
expiresAt: Timestamp.optional(),
|
|
381
391
|
assignee: AgentRef.optional(),
|
|
382
392
|
origin: TaskOrigin.optional(),
|
|
393
|
+
category: TaskCategory.optional(),
|
|
394
|
+
size: TaskSize.optional(),
|
|
395
|
+
disclosure: Disclosure.optional(),
|
|
396
|
+
inputRef: TaskInputRef.optional(),
|
|
397
|
+
outputShape: TaskOutputShape.optional(),
|
|
398
|
+
});
|
|
399
|
+
/*
|
|
400
|
+
* An adoption (RT-11, D-RT-2), the other payload POST /v1/tasks takes. The
|
|
401
|
+
* agent names a category and the API picks a candidate in it, a task with a
|
|
402
|
+
* known answer SealKeeper made from the shared templates, and posts it as
|
|
403
|
+
* the agent's own open template task. So the payload carries no task type,
|
|
404
|
+
* spec or verification, the spec reaches only the agent that adopted it,
|
|
405
|
+
* and the known answer never leaves the server. origin is template, the
|
|
406
|
+
* default, or routine for a routine run's adoption (RT-12), so an adopted
|
|
407
|
+
* task carries the same origin as any other post of its kind. taskId and
|
|
408
|
+
* expiresAt work as in PostTaskRequest.
|
|
409
|
+
*/
|
|
410
|
+
export const AdoptTaskRequest = z.strictObject({
|
|
411
|
+
taskId: z.uuid(),
|
|
412
|
+
category: TaskCategory,
|
|
413
|
+
expiresAt: Timestamp.optional(),
|
|
414
|
+
origin: z.enum(['template', 'routine']).optional(),
|
|
415
|
+
});
|
|
416
|
+
// A task post always has a task type, a spec and a verification, and an
|
|
417
|
+
// adoption has none of them.
|
|
418
|
+
const ADOPTION_ABSENT = ['taskType', 'spec', 'verification'];
|
|
419
|
+
const isAdoption = (value) => typeof value === 'object' &&
|
|
420
|
+
value !== null &&
|
|
421
|
+
ADOPTION_ABSENT.every((key) => !Object.hasOwn(value, key));
|
|
422
|
+
/*
|
|
423
|
+
* The payload POST /v1/tasks parses. One with none of taskType, spec and
|
|
424
|
+
* verification is an adoption and parses as AdoptTaskRequest, any other as
|
|
425
|
+
* PostTaskRequest, so each failure names its own fields rather than a
|
|
426
|
+
* union's. A transform that picks the schema, shown once. The issues of
|
|
427
|
+
* the schema it picked are copied onto this one, paths and all.
|
|
428
|
+
*/
|
|
429
|
+
export const PostTaskPayload = z.unknown().transform((value, ctx) => {
|
|
430
|
+
const parsed = isAdoption(value)
|
|
431
|
+
? AdoptTaskRequest.safeParse(value)
|
|
432
|
+
: PostTaskRequest.safeParse(value);
|
|
433
|
+
if (parsed.success)
|
|
434
|
+
return parsed.data;
|
|
435
|
+
for (const issue of parsed.error.issues) {
|
|
436
|
+
ctx.addIssue({ ...issue, input: value });
|
|
437
|
+
}
|
|
438
|
+
return z.NEVER;
|
|
383
439
|
});
|
|
384
440
|
// The agent an addressed task is for, as it is now.
|
|
385
441
|
export const TaskAssignee = z.strictObject({
|
|
@@ -389,6 +445,24 @@ export const TaskAssignee = z.strictObject({
|
|
|
389
445
|
// from an API before runtimes parses.
|
|
390
446
|
runtime: Runtime.optional(),
|
|
391
447
|
});
|
|
448
|
+
/*
|
|
449
|
+
* The real task fields (RT-1), on TaskResponse and TaskView alike. category,
|
|
450
|
+
* checkMethod, disclosure and size always have a value, and the other three
|
|
451
|
+
* are null when the task does not say. The API always sends all seven. Each
|
|
452
|
+
* is optional, so an answer from an API before them parses.
|
|
453
|
+
*/
|
|
454
|
+
const realTaskFields = {
|
|
455
|
+
category: TaskCategory.optional(),
|
|
456
|
+
checkMethod: CheckMethod.optional(),
|
|
457
|
+
disclosure: Disclosure.optional(),
|
|
458
|
+
size: TaskSize.optional(),
|
|
459
|
+
// UTF-8 bytes of the task's input.
|
|
460
|
+
inputBytes: z.number().int().min(0).nullable().optional(),
|
|
461
|
+
// A link to a public input the task reads.
|
|
462
|
+
inputRef: z.string().nullable().optional(),
|
|
463
|
+
// A short statement of what the answer looks like.
|
|
464
|
+
outputShape: z.string().nullable().optional(),
|
|
465
|
+
};
|
|
392
466
|
export const TaskResponse = z.strictObject({
|
|
393
467
|
id: z.uuid(),
|
|
394
468
|
posterAgentId: AgentId,
|
|
@@ -408,22 +482,58 @@ export const TaskResponse = z.strictObject({
|
|
|
408
482
|
submittedAt: Timestamp.nullable(),
|
|
409
483
|
verifiedAt: Timestamp.nullable(),
|
|
410
484
|
expiresAt: Timestamp,
|
|
485
|
+
// When the poster of a counterparty task let its response time lapse and
|
|
486
|
+
// the claimant's success report stood, which verified the task (POST-4).
|
|
487
|
+
// Null otherwise. Optional so the CLI still parses an API from before it.
|
|
488
|
+
posterLapsedAt: Timestamp.nullable().optional(),
|
|
411
489
|
// True when the seed agent posted the task, so a CLI tells seed tasks
|
|
412
490
|
// apart without looking the poster up. A CLI reads an API from before it
|
|
413
491
|
// as not saying.
|
|
414
492
|
seed: z.boolean(),
|
|
493
|
+
...realTaskFields,
|
|
494
|
+
// Where the post came from, manual when the poster's CLI did not say, so
|
|
495
|
+
// a routine finds other operators' template tasks (RT-8). The API always
|
|
496
|
+
// sends it. Optional so the CLI still parses an API from before it.
|
|
497
|
+
origin: TaskOrigin.optional(),
|
|
498
|
+
// The poster as it is now, in list answers only (GET /v1/tasks and POST
|
|
499
|
+
// /v1/tasks/open). level is its current version's level from the last
|
|
500
|
+
// scoring run, left out until it is scored, so a routine tells a poster
|
|
501
|
+
// at bronze or above without a lookup (RT-8). Optional so the CLI still
|
|
502
|
+
// parses an API from before it.
|
|
503
|
+
poster: z
|
|
504
|
+
.strictObject({
|
|
505
|
+
handle: AgentHandle,
|
|
506
|
+
level: Level.optional(),
|
|
507
|
+
operatedBySealKeeper: z.boolean(),
|
|
508
|
+
})
|
|
509
|
+
.optional(),
|
|
415
510
|
// Present only in responses to the poster or the claimant.
|
|
416
511
|
submission: z.string().optional(),
|
|
417
512
|
});
|
|
418
513
|
// Claim and submit payloads name the task they are for, and the server checks
|
|
419
514
|
// it against the path. Without it a signed claim for one task could be
|
|
420
|
-
// replayed against any other.
|
|
421
|
-
|
|
515
|
+
// replayed against any other. origin is the claimant's, TaskOrigin above,
|
|
516
|
+
// routine when the unattended daily routine claims, which waits out the
|
|
517
|
+
// claim age threshold (RT-8). Absent means manual.
|
|
518
|
+
//
|
|
519
|
+
// fingerprint, on claim, submit and outcome, is the signing agent's
|
|
520
|
+
// fingerprint as its CLI last computed it (VB-3), Fingerprint in
|
|
521
|
+
// ./fingerprint.ts. The API stores it with the claim, replaces it with one
|
|
522
|
+
// a submit declares, keeps it when a submit declares none, and keeps the
|
|
523
|
+
// reporter's with each outcome report. It refuses one
|
|
524
|
+
// whose hash is not the hash of its parts. Absent means not declared, as
|
|
525
|
+
// from a CLI from before it.
|
|
526
|
+
export const ClaimTaskRequest = z.strictObject({
|
|
527
|
+
taskId: z.uuid(),
|
|
528
|
+
origin: TaskOrigin.optional(),
|
|
529
|
+
fingerprint: Fingerprint.optional(),
|
|
530
|
+
});
|
|
422
531
|
export const SubmitTaskRequest = z.strictObject({
|
|
423
532
|
taskId: z.uuid(),
|
|
424
533
|
submission: z
|
|
425
534
|
.string()
|
|
426
535
|
.refine((text) => utf8Encode(JSON.stringify(text)).length <= MAX_SUBMISSION_BYTES, `submission must be at most ${MAX_SUBMISSION_BYTES} bytes as JSON`),
|
|
536
|
+
fingerprint: Fingerprint.optional(),
|
|
427
537
|
});
|
|
428
538
|
// Named for its task like claim and submit, checked against the path.
|
|
429
539
|
// origin is the reporting side's, TaskOrigin above.
|
|
@@ -432,6 +542,7 @@ export const TaskOutcomeRequest = z.strictObject({
|
|
|
432
542
|
outcome: TaskOutcome,
|
|
433
543
|
evidenceHash: Sha256Hex.optional(),
|
|
434
544
|
origin: TaskOrigin.optional(),
|
|
545
|
+
fingerprint: Fingerprint.optional(),
|
|
435
546
|
});
|
|
436
547
|
// POST /v1/tasks/:id/submission, the poster's signed read of its task with
|
|
437
548
|
// the submission and both outcome reports. The public GET leaves the
|
|
@@ -474,7 +585,9 @@ const QueryFlag = z.union([
|
|
|
474
585
|
// assignee is given. assignee keeps the tasks addressed to that agent, in
|
|
475
586
|
// the state asked for. poster and claimant keep one agent's tasks on that
|
|
476
587
|
// side. seed true keeps only the tasks the seed agent posted and false
|
|
477
|
-
// leaves them out.
|
|
588
|
+
// leaves them out. origin keeps the tasks posted with that origin, so a
|
|
589
|
+
// routine reads other operators' template tasks without paging past every
|
|
590
|
+
// manual one (RT-8). Without these a caller reads one global page and a
|
|
478
591
|
// flood of older tasks can hide the ones it wants (VOU-208).
|
|
479
592
|
export const ListTasksQuery = z.strictObject({
|
|
480
593
|
state: TaskState.default('open'),
|
|
@@ -483,8 +596,23 @@ export const ListTasksQuery = z.strictObject({
|
|
|
483
596
|
poster: AgentId.optional(),
|
|
484
597
|
claimant: AgentId.optional(),
|
|
485
598
|
seed: QueryFlag.optional(),
|
|
599
|
+
origin: TaskOrigin.optional(),
|
|
600
|
+
limit: Limit,
|
|
601
|
+
cursor: TasksCursorParam.optional(),
|
|
602
|
+
});
|
|
603
|
+
// POST /v1/tasks/open, the open pool as the signing agent sees it
|
|
604
|
+
// (VOU-200). The same page as GET /v1/tasks?state=open with these filters,
|
|
605
|
+
// less the tasks this agent is barred from after its failed submits. Which
|
|
606
|
+
// tasks those are is the agent's own business, so it is a signed read and
|
|
607
|
+
// the public GET stays as it is. issuedAt bounds how long a captured
|
|
608
|
+
// envelope could be sent again, the window of the submission read.
|
|
609
|
+
export const OpenTasksRequest = z.strictObject({
|
|
610
|
+
taskType: TaskType.optional(),
|
|
611
|
+
seed: z.boolean().optional(),
|
|
612
|
+
origin: TaskOrigin.optional(),
|
|
486
613
|
limit: Limit,
|
|
487
614
|
cursor: TasksCursorParam.optional(),
|
|
615
|
+
issuedAt: Timestamp,
|
|
488
616
|
});
|
|
489
617
|
// nextCursor is null on the last page.
|
|
490
618
|
export const ListTasksResponse = z.strictObject({
|
|
@@ -499,6 +627,7 @@ export const ListTasksResponse = z.strictObject({
|
|
|
499
627
|
// with their assignee.
|
|
500
628
|
export const TaskBoardQuery = z.strictObject({
|
|
501
629
|
taskType: TaskType.optional(),
|
|
630
|
+
category: TaskCategory.optional(),
|
|
502
631
|
limit: Limit,
|
|
503
632
|
cursor: TasksCursorParam.optional(),
|
|
504
633
|
});
|
|
@@ -511,6 +640,18 @@ export const AgentTasksQuery = z.strictObject({
|
|
|
511
640
|
limit: Limit,
|
|
512
641
|
cursor: TasksCursorParam.optional(),
|
|
513
642
|
});
|
|
643
|
+
// Why the issuer withholds a SEAL for cause, the classes of the SEAL
|
|
644
|
+
// standard, section 6 (VOU-85), and why it voids a task's credit (COL-5).
|
|
645
|
+
// The class is public, on the SEAL routes' 404, in the feed and on a
|
|
646
|
+
// voided task. The detail never is. The agent_holds.reason and
|
|
647
|
+
// task_voids.reason check constraints list the same values.
|
|
648
|
+
export const HoldReason = z.enum([
|
|
649
|
+
'fraud',
|
|
650
|
+
'collusion',
|
|
651
|
+
'safety',
|
|
652
|
+
'operator_ban',
|
|
653
|
+
'key_compromise',
|
|
654
|
+
]);
|
|
514
655
|
// One side of a task, as it is now.
|
|
515
656
|
export const TaskParty = z.strictObject({
|
|
516
657
|
id: AgentId,
|
|
@@ -521,7 +662,9 @@ export const TaskParty = z.strictObject({
|
|
|
521
662
|
// The level of the agent's current version from the last scoring run,
|
|
522
663
|
// for the name line. Left out until the agent has been scored.
|
|
523
664
|
level: Level.optional(),
|
|
524
|
-
// True for an agent SealKeeper runs itself, the seed agent
|
|
665
|
+
// True for an agent SealKeeper runs itself, the seed agent that posts the
|
|
666
|
+
// seed tasks or the taker that completes template tasks nobody else took
|
|
667
|
+
// (TAKER-5). The taker is only ever a claimant.
|
|
525
668
|
operatedBySealKeeper: z.boolean(),
|
|
526
669
|
});
|
|
527
670
|
export const TaskView = z.strictObject({
|
|
@@ -539,6 +682,7 @@ export const TaskView = z.strictObject({
|
|
|
539
682
|
assignee: TaskParty.nullable(),
|
|
540
683
|
// Where the post came from, manual when the poster's CLI did not say.
|
|
541
684
|
origin: TaskOrigin,
|
|
685
|
+
...realTaskFields,
|
|
542
686
|
// The scoring rule. True when the poster is the seed agent or an agent of
|
|
543
687
|
// another operator than the claimant, false when both sides share an
|
|
544
688
|
// operator or the task is addressed and came past its operator pair's
|
|
@@ -550,8 +694,10 @@ export const TaskView = z.strictObject({
|
|
|
550
694
|
// when countsForTrust is false. Null when countsForTrust is null.
|
|
551
695
|
evidenceWeight: z.number().min(0).max(1).nullable(),
|
|
552
696
|
// What the task adds to the claimant's counted evidence (VOU-139), after
|
|
553
|
-
// the daily ceiling and diminishing returns and times evidenceWeight
|
|
554
|
-
//
|
|
697
|
+
// the daily ceiling and diminishing returns and times evidenceWeight, as
|
|
698
|
+
// the last scoring run computed it (VOU-216). 0 when countsForTrust is
|
|
699
|
+
// false, null when it is null, and null for a task verified since its
|
|
700
|
+
// claimant's last scoring run, until that run.
|
|
555
701
|
counted: z.number().min(0).max(1).nullable(),
|
|
556
702
|
// Why a task that counts adds less than its weight, or nothing.
|
|
557
703
|
// daily_ceiling when COUNTED_EVIDENCE.dailyCeiling heavier, more valuable
|
|
@@ -562,6 +708,10 @@ export const TaskView = z.strictObject({
|
|
|
562
708
|
countedNote: z
|
|
563
709
|
.enum(['daily_ceiling', 'diminishing', 'outside_window'])
|
|
564
710
|
.nullable(),
|
|
711
|
+
// The reason class of a void in force on the task (COL-5), which makes it
|
|
712
|
+
// weigh 0 and count for nothing on either side. Absent without one. Never
|
|
713
|
+
// the note. Optional so the web still reads an answer from an older API.
|
|
714
|
+
voided: HoldReason.optional(),
|
|
565
715
|
postedAt: Timestamp,
|
|
566
716
|
claimedAt: Timestamp.nullable(),
|
|
567
717
|
submittedAt: Timestamp.nullable(),
|
|
@@ -596,15 +746,27 @@ export const RatingResponse = z.strictObject({
|
|
|
596
746
|
value: RatingValue,
|
|
597
747
|
raterScoreAtTime: z.number().min(0).max(1),
|
|
598
748
|
});
|
|
749
|
+
// One task type's competence under its category (RT-3), verified over
|
|
750
|
+
// claimed for that type on the version's own signal. A breakdown for the
|
|
751
|
+
// profile, never a dimension and never in a SEAL.
|
|
752
|
+
export const CompetenceTypeScore = z.strictObject({
|
|
753
|
+
taskType: TaskType,
|
|
754
|
+
value: z.number().min(0).max(1),
|
|
755
|
+
});
|
|
599
756
|
// A base dimension with no row is still listed, with every field after
|
|
600
|
-
// dimension null. Competence entries appear only where a row exists
|
|
757
|
+
// dimension null. Competence entries appear only where a row exists, one
|
|
758
|
+
// per category. types is the per task type breakdown of a competence
|
|
759
|
+
// entry, highest claimed first, at most COMPETENCE_TYPES_MAX. It is left
|
|
760
|
+
// out on base entries and on a competence entry the version only
|
|
761
|
+
// inherited, since a breakdown is never fabricated from no signal.
|
|
601
762
|
export const ScoreEntry = z.strictObject({
|
|
602
|
-
version:
|
|
763
|
+
version: StoredVersion,
|
|
603
764
|
dimension: Dimension,
|
|
604
765
|
value: z.number().min(0).max(1).nullable(),
|
|
605
766
|
windowStart: Timestamp.nullable(),
|
|
606
767
|
windowEnd: Timestamp.nullable(),
|
|
607
768
|
computedAt: Timestamp.nullable(),
|
|
769
|
+
types: z.array(CompetenceTypeScore).max(COMPETENCE_TYPES_MAX).optional(),
|
|
608
770
|
});
|
|
609
771
|
// The agent's current version only.
|
|
610
772
|
export const ScoreResponse = z.strictObject({
|
|
@@ -621,7 +783,7 @@ export const MeAgent = z.strictObject({
|
|
|
621
783
|
name: Name,
|
|
622
784
|
handle: AgentHandle,
|
|
623
785
|
operator: OperatorRef,
|
|
624
|
-
version:
|
|
786
|
+
version: StoredVersion,
|
|
625
787
|
createdAt: Timestamp,
|
|
626
788
|
lastSeenAt: Timestamp.nullable(),
|
|
627
789
|
scores: ScoreResponse,
|
|
@@ -688,7 +850,7 @@ export const LeaderboardEntry = z.strictObject({
|
|
|
688
850
|
name: Name,
|
|
689
851
|
handle: AgentHandle,
|
|
690
852
|
operator: OperatorRef,
|
|
691
|
-
version:
|
|
853
|
+
version: StoredVersion,
|
|
692
854
|
// What the agent runs in. The API always sends it. Optional so the web
|
|
693
855
|
// still reads an answer from an older API.
|
|
694
856
|
runtime: Runtime.optional(),
|
|
@@ -722,9 +884,17 @@ export const FeedKind = z.enum([
|
|
|
722
884
|
'version_change',
|
|
723
885
|
'level_change',
|
|
724
886
|
'milestone',
|
|
887
|
+
// The issuer withheld the agent's SEAL for cause (VOU-85). Written when a
|
|
888
|
+
// hold is placed, one per agent it covers.
|
|
889
|
+
'refusal',
|
|
725
890
|
]);
|
|
726
|
-
//
|
|
727
|
-
|
|
891
|
+
// Why an agent was flagged. outcome_disagreement, the two sides of a
|
|
892
|
+
// counterparty task disagreed. taker_failures, the SealKeeper taker failed
|
|
893
|
+
// on TAKER_POSTER_FAILURES of the agent's tasks within
|
|
894
|
+
// TAKER_POSTER_FAILURE_DAYS and skips its tasks for now (TAKER-3). Written
|
|
895
|
+
// once per pause on the agent that posted them, with the task that paused
|
|
896
|
+
// it. Nothing is voided.
|
|
897
|
+
export const FeedFlagCode = z.enum(['outcome_disagreement', 'taker_failures']);
|
|
728
898
|
// Milestones an agent passes once. Its first SEAL level above none, then
|
|
729
899
|
// 100 and 1,000 verified tasks.
|
|
730
900
|
export const FeedMilestone = z.enum([
|
|
@@ -739,7 +909,7 @@ const FeedAgent = {
|
|
|
739
909
|
name: Name,
|
|
740
910
|
};
|
|
741
911
|
export const FeedPayloads = {
|
|
742
|
-
registration: z.strictObject({ ...FeedAgent, version:
|
|
912
|
+
registration: z.strictObject({ ...FeedAgent, version: StoredVersion }),
|
|
743
913
|
task_verified: z.strictObject({
|
|
744
914
|
...FeedAgent,
|
|
745
915
|
taskId: z.uuid(),
|
|
@@ -750,8 +920,9 @@ export const FeedPayloads = {
|
|
|
750
920
|
}),
|
|
751
921
|
score_change: z.strictObject({
|
|
752
922
|
...FeedAgent,
|
|
753
|
-
version:
|
|
754
|
-
|
|
923
|
+
version: StoredVersion,
|
|
924
|
+
// Old items can name a competence task type (AcceptedDimension).
|
|
925
|
+
dimension: AcceptedDimension,
|
|
755
926
|
// null when the dimension had no value before.
|
|
756
927
|
old: z.number().min(0).max(1).nullable(),
|
|
757
928
|
new: z.number().min(0).max(1),
|
|
@@ -765,24 +936,30 @@ export const FeedPayloads = {
|
|
|
765
936
|
// version, beside the agent every item names.
|
|
766
937
|
version_change: z.strictObject({
|
|
767
938
|
...FeedAgent,
|
|
768
|
-
old:
|
|
769
|
-
new:
|
|
939
|
+
old: StoredVersion,
|
|
940
|
+
new: StoredVersion,
|
|
770
941
|
}),
|
|
771
942
|
// The scoring run moved the level of the agent's current version, up or
|
|
772
943
|
// down. The first move above none is a first_seal milestone instead.
|
|
773
944
|
level_change: z.strictObject({
|
|
774
945
|
...FeedAgent,
|
|
775
|
-
version:
|
|
946
|
+
version: StoredVersion,
|
|
776
947
|
old: Level,
|
|
777
948
|
new: Level,
|
|
778
949
|
}),
|
|
779
950
|
// level is the current version's level when the milestone was passed.
|
|
780
951
|
milestone: z.strictObject({
|
|
781
952
|
...FeedAgent,
|
|
782
|
-
version:
|
|
953
|
+
version: StoredVersion,
|
|
783
954
|
milestone: FeedMilestone,
|
|
784
955
|
level: Level,
|
|
785
956
|
}),
|
|
957
|
+
// The SEAL is withheld for cause. The reason class only, as the SEAL
|
|
958
|
+
// standard's section 6 says, never the detail or the internal note.
|
|
959
|
+
refusal: z.strictObject({
|
|
960
|
+
...FeedAgent,
|
|
961
|
+
reason: HoldReason,
|
|
962
|
+
}),
|
|
786
963
|
};
|
|
787
964
|
const feedItemOf = (kind) => z.strictObject({
|
|
788
965
|
// The SSE event id. Ascending in insert order.
|
|
@@ -798,6 +975,10 @@ const feedItemOf = (kind) => z.strictObject({
|
|
|
798
975
|
// API's answer. level is left out until the agent has been scored.
|
|
799
976
|
runtime: Runtime.optional(),
|
|
800
977
|
level: Level.optional(),
|
|
978
|
+
// True when the agent is one SealKeeper runs itself, so a task_verified
|
|
979
|
+
// item of the taker reads as completed by SealKeeper (TAKER-5). The API
|
|
980
|
+
// always sends it. Optional so the web reads an older API's answer.
|
|
981
|
+
operatedBySealKeeper: z.boolean().optional(),
|
|
801
982
|
payload: FeedPayloads[kind],
|
|
802
983
|
createdAt: Timestamp,
|
|
803
984
|
});
|
|
@@ -809,6 +990,7 @@ export const FeedItem = z.discriminatedUnion('kind', [
|
|
|
809
990
|
feedItemOf('version_change'),
|
|
810
991
|
feedItemOf('level_change'),
|
|
811
992
|
feedItemOf('milestone'),
|
|
993
|
+
feedItemOf('refusal'),
|
|
812
994
|
]);
|
|
813
995
|
export const FEED_RECENT_MAX = 200;
|
|
814
996
|
export const FeedRecentQuery = z.strictObject({
|
|
@@ -824,6 +1006,10 @@ export const StatsResponse = z.strictObject({
|
|
|
824
1006
|
agents: z.int().min(0),
|
|
825
1007
|
verifiedTasks: z.int().min(0),
|
|
826
1008
|
eventsLast24h: z.int().min(0),
|
|
1009
|
+
// Tasks the SealKeeper taker completed in the last 24 hours, by
|
|
1010
|
+
// verified_at (TAKER-3). 0 while no taker is configured. The API always
|
|
1011
|
+
// sends it. Optional so the web still reads an older API's answer.
|
|
1012
|
+
takerCompletions24h: z.int().min(0).optional(),
|
|
827
1013
|
});
|
|
828
1014
|
// GET /v1/check/:slug/:name. One call for a caller that is about to
|
|
829
1015
|
// delegate work and wants a yes or no on the agent's track record. Query
|
|
@@ -909,9 +1095,31 @@ export const SealWithheldResponse = z.strictObject({
|
|
|
909
1095
|
id: AgentId,
|
|
910
1096
|
dormant_days: z.int().min(0).nullable(),
|
|
911
1097
|
});
|
|
1098
|
+
// The same three routes while a hold is in force on the agent or its
|
|
1099
|
+
// operator (VOU-85). No SEAL is issued until the hold is lifted, and a SEAL
|
|
1100
|
+
// issued before runs out at its own expiry. reason is the class only.
|
|
1101
|
+
export const SealHeldResponse = z.strictObject({
|
|
1102
|
+
error: z.strictObject({
|
|
1103
|
+
code: z.literal('withheld'),
|
|
1104
|
+
message: z.string(),
|
|
1105
|
+
}),
|
|
1106
|
+
id: AgentId,
|
|
1107
|
+
reason: HoldReason,
|
|
1108
|
+
});
|
|
912
1109
|
// POST /v1/seal/verify. The route's body cap keeps the SEAL small, so the
|
|
913
|
-
// string itself has no tighter limit here.
|
|
914
|
-
|
|
1110
|
+
// string itself has no tighter limit here. handshake is the agent's signed
|
|
1111
|
+
// handshake (VB-6, ./handshake.ts), checked beside the SEAL. nonce is the
|
|
1112
|
+
// one the caller handed the agent out of band, and needs a handshake.
|
|
1113
|
+
export const SealVerifyRequest = z
|
|
1114
|
+
.strictObject({
|
|
1115
|
+
seal: z.string(),
|
|
1116
|
+
handshake: z.string().max(HANDSHAKE_MAX_CHARS).optional(),
|
|
1117
|
+
nonce: HandshakeNonce.optional(),
|
|
1118
|
+
})
|
|
1119
|
+
.refine((b) => b.nonce === undefined || b.handshake !== undefined, {
|
|
1120
|
+
message: 'nonce needs a handshake',
|
|
1121
|
+
path: ['nonce'],
|
|
1122
|
+
});
|
|
915
1123
|
export const SealBrokenReason = z.enum([
|
|
916
1124
|
'malformed',
|
|
917
1125
|
'unknown_kid',
|
|
@@ -921,19 +1129,34 @@ export const SealBrokenReason = z.enum([
|
|
|
921
1129
|
'expired',
|
|
922
1130
|
'not_yet_valid',
|
|
923
1131
|
]);
|
|
1132
|
+
// The handshake beside a valid SEAL. Refused with its reason, or its
|
|
1133
|
+
// result and what it was compared with, the SEAL's own fingerprint or, for
|
|
1134
|
+
// a SEAL before version 3, the issuer's current record.
|
|
1135
|
+
export const HandshakeAnswer = z.discriminatedUnion('valid', [
|
|
1136
|
+
z.strictObject({
|
|
1137
|
+
valid: z.literal(true),
|
|
1138
|
+
result: HandshakeResult,
|
|
1139
|
+
against: HandshakeAgainst,
|
|
1140
|
+
}),
|
|
1141
|
+
z.strictObject({ valid: z.literal(false), reason: HandshakeRefusal }),
|
|
1142
|
+
]);
|
|
924
1143
|
// Always 200 for a SEAL, good or broken. expiresIn is whole seconds left.
|
|
925
|
-
// payload is version 1, or
|
|
926
|
-
//
|
|
1144
|
+
// payload is version 1, 2 or 3. handshake is there only when the request
|
|
1145
|
+
// carried one and the SEAL is valid. A broken SEAL names no agent to check
|
|
1146
|
+
// it against.
|
|
927
1147
|
export const SealVerifyResponse = z.discriminatedUnion('valid', [
|
|
928
1148
|
z.strictObject({
|
|
929
1149
|
valid: z.literal(true),
|
|
930
1150
|
payload: SealPayload,
|
|
931
1151
|
expiresIn: z.int().min(1),
|
|
1152
|
+
handshake: HandshakeAnswer.optional(),
|
|
932
1153
|
}),
|
|
933
1154
|
z.strictObject({ valid: z.literal(false), reason: SealBrokenReason }),
|
|
934
1155
|
]);
|
|
935
1156
|
export const ScoreRunResponse = z.strictObject({
|
|
936
1157
|
scored: z.int().min(0),
|
|
1158
|
+
// Feed items the run could not write after it committed. Zero normally.
|
|
1159
|
+
feedFailed: z.int().min(0),
|
|
937
1160
|
});
|
|
938
1161
|
// POST /internal/seed/run. open is the seed agent's open tasks after the
|
|
939
1162
|
// run, added is how many this run posted.
|
|
@@ -941,6 +1164,41 @@ export const SeedRunResponse = z.strictObject({
|
|
|
941
1164
|
open: z.int().min(0),
|
|
942
1165
|
added: z.int().min(0),
|
|
943
1166
|
});
|
|
1167
|
+
// POST /internal/candidates/run (RT-11). open is the candidates nobody has
|
|
1168
|
+
// adopted after the run, added is how many this run wrote.
|
|
1169
|
+
export const CandidateRunResponse = z.strictObject({
|
|
1170
|
+
open: z.int().min(0),
|
|
1171
|
+
added: z.int().min(0),
|
|
1172
|
+
});
|
|
1173
|
+
// POST /internal/taker/run (TAKER-3). medianMinutes is the gate's median
|
|
1174
|
+
// time to claim over the last 24 hours, null when nothing was claimed. A
|
|
1175
|
+
// run that ran says which gate branch let it, no_claims, median above the
|
|
1176
|
+
// threshold, or waiting for an eligible open task past it, and counts its
|
|
1177
|
+
// tasks. completed were claimed, submitted and verified. skipped were
|
|
1178
|
+
// left alone with no claim and no failure, a spec the template cannot
|
|
1179
|
+
// solve, a poster at silver or above at claim time, or a task taken or
|
|
1180
|
+
// gone meanwhile. failed counts a failure for the poster, a stored check
|
|
1181
|
+
// that disagrees with the template's answer or a submit that failed.
|
|
1182
|
+
// flagged is the posters this run paused and flagged. A run that did not
|
|
1183
|
+
// run says why. keeping_up, the median is at or below the threshold and no
|
|
1184
|
+
// eligible task waits past it. daily_cap, TAKER_PER_DAY is reached for the
|
|
1185
|
+
// UTC day. locked, another run holds the lock.
|
|
1186
|
+
export const TakerRunResponse = z.discriminatedUnion('ran', [
|
|
1187
|
+
z.strictObject({
|
|
1188
|
+
ran: z.literal(true),
|
|
1189
|
+
gate: z.enum(['no_claims', 'median', 'waiting']),
|
|
1190
|
+
medianMinutes: z.number().min(0).nullable(),
|
|
1191
|
+
completed: z.int().min(0),
|
|
1192
|
+
skipped: z.int().min(0),
|
|
1193
|
+
failed: z.int().min(0),
|
|
1194
|
+
flagged: z.int().min(0),
|
|
1195
|
+
}),
|
|
1196
|
+
z.strictObject({
|
|
1197
|
+
ran: z.literal(false),
|
|
1198
|
+
reason: z.enum(['keeping_up', 'daily_cap', 'locked']),
|
|
1199
|
+
medianMinutes: z.number().min(0).nullable(),
|
|
1200
|
+
}),
|
|
1201
|
+
]);
|
|
944
1202
|
// GET /internal/metrics (VOU-146). days is the number of UTC days the
|
|
945
1203
|
// perDay rows cover, today included.
|
|
946
1204
|
export const INTERNAL_METRICS_MAX_DAYS = 90;
|
|
@@ -952,6 +1210,49 @@ export const InternalMetricsQuery = z.strictObject({
|
|
|
952
1210
|
.max(INTERNAL_METRICS_MAX_DAYS)
|
|
953
1211
|
.default(30),
|
|
954
1212
|
});
|
|
1213
|
+
// POST /internal/holds places a hold on one agent or on every agent of one
|
|
1214
|
+
// operator (VOU-85), exactly one of agentId and operatorId. note is for the
|
|
1215
|
+
// person who placed it, stored and never served or logged.
|
|
1216
|
+
export const HOLD_NOTE_MAX = 2000;
|
|
1217
|
+
export const HoldPlaceRequest = z
|
|
1218
|
+
.strictObject({
|
|
1219
|
+
agentId: AgentId.optional(),
|
|
1220
|
+
operatorId: z.uuid().optional(),
|
|
1221
|
+
reason: HoldReason,
|
|
1222
|
+
note: z.string().min(1).max(HOLD_NOTE_MAX).optional(),
|
|
1223
|
+
})
|
|
1224
|
+
.refine((r) => (r.agentId === undefined) !== (r.operatorId === undefined), 'exactly one of agentId and operatorId');
|
|
1225
|
+
// DELETE /internal/holds/:id lifts one.
|
|
1226
|
+
export const HoldParams = z.strictObject({ id: z.uuid() });
|
|
1227
|
+
// Both routes answer the hold without its note. agents is how many agents
|
|
1228
|
+
// it covers now, the agent itself or the operator's agents.
|
|
1229
|
+
export const HoldResponse = z.strictObject({
|
|
1230
|
+
id: z.uuid(),
|
|
1231
|
+
agentId: AgentId.nullable(),
|
|
1232
|
+
operatorId: z.uuid().nullable(),
|
|
1233
|
+
reason: HoldReason,
|
|
1234
|
+
placedAt: Timestamp,
|
|
1235
|
+
liftedAt: Timestamp.nullable(),
|
|
1236
|
+
agents: z.int().min(0),
|
|
1237
|
+
});
|
|
1238
|
+
// POST /internal/voids voids one task's credit for cause (COL-5), with a
|
|
1239
|
+
// hold reason class. note is for the person who placed it, stored and never
|
|
1240
|
+
// served or logged.
|
|
1241
|
+
export const VoidPlaceRequest = z.strictObject({
|
|
1242
|
+
taskId: z.uuid(),
|
|
1243
|
+
reason: HoldReason,
|
|
1244
|
+
note: z.string().min(1).max(HOLD_NOTE_MAX).optional(),
|
|
1245
|
+
});
|
|
1246
|
+
// DELETE /internal/voids/:id lifts one.
|
|
1247
|
+
export const VoidParams = z.strictObject({ id: z.uuid() });
|
|
1248
|
+
// Both routes answer the void without its note.
|
|
1249
|
+
export const VoidResponse = z.strictObject({
|
|
1250
|
+
id: z.uuid(),
|
|
1251
|
+
taskId: z.uuid(),
|
|
1252
|
+
reason: HoldReason,
|
|
1253
|
+
voidedAt: Timestamp,
|
|
1254
|
+
liftedAt: Timestamp.nullable(),
|
|
1255
|
+
});
|
|
955
1256
|
// A count split by operator. sealkeeper is the operator that owns the seed
|
|
956
1257
|
// agent (SEED_AGENT_ID), others is everyone else.
|
|
957
1258
|
const OperatorSplit = z.strictObject({
|
|
@@ -983,6 +1284,18 @@ const MetricsDay = z.strictObject({
|
|
|
983
1284
|
tasksPosted: z.int().min(0),
|
|
984
1285
|
outcomes: z.int().min(0),
|
|
985
1286
|
}),
|
|
1287
|
+
// The median minutes from post to first claim of the tasks with origin
|
|
1288
|
+
// template or routine whose first claim fell that day, a released claim
|
|
1289
|
+
// included and the taker's claims left out. null when there were none.
|
|
1290
|
+
claimLatencyMedianMinutes: z.number().min(0).nullable(),
|
|
1291
|
+
// The SealKeeper taker that day (TAKER-3). completions, tasks it claimed
|
|
1292
|
+
// that were verified that day. flags, the taker_failures flags written
|
|
1293
|
+
// that day, one per poster it paused. Both 0 while no taker is
|
|
1294
|
+
// configured.
|
|
1295
|
+
taker: z.strictObject({
|
|
1296
|
+
completions: z.int().min(0),
|
|
1297
|
+
flags: z.int().min(0),
|
|
1298
|
+
}),
|
|
986
1299
|
});
|
|
987
1300
|
export const InternalMetricsResponse = z.strictObject({
|
|
988
1301
|
days: z.int().min(1),
|