@sealkeeper/schema 0.4.2 → 0.4.4
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/dist/api.d.ts +177 -1
- package/dist/api.js +75 -10
- package/dist/credential.d.ts +186 -1
- package/dist/credential.js +55 -8
- package/dist/db/client.d.ts +108 -0
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/standing.d.ts +35 -0
- package/dist/db/standing.js +3 -0
- package/dist/db/task-outcomes.d.ts +19 -0
- package/dist/db/task-outcomes.js +8 -1
- package/dist/db/tasks.d.ts +70 -0
- package/dist/db/tasks.js +41 -2
- package/dist/goal.d.ts +88 -0
- package/dist/goal.js +112 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/seal-conformance.js +30 -1
- package/dist/standing.d.ts +49 -0
- package/dist/standing.js +90 -1
- package/package.json +1 -1
package/dist/db/tasks.d.ts
CHANGED
|
@@ -87,6 +87,76 @@ export declare const tasks: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
87
87
|
identity: undefined;
|
|
88
88
|
generated: undefined;
|
|
89
89
|
}, {}, {}>;
|
|
90
|
+
assigneeAgentId: import("drizzle-orm/pg-core").PgColumn<{
|
|
91
|
+
name: "assignee_agent_id";
|
|
92
|
+
tableName: "tasks";
|
|
93
|
+
dataType: "string";
|
|
94
|
+
columnType: "PgText";
|
|
95
|
+
data: string;
|
|
96
|
+
driverParam: string;
|
|
97
|
+
notNull: false;
|
|
98
|
+
hasDefault: false;
|
|
99
|
+
isPrimaryKey: false;
|
|
100
|
+
isAutoincrement: false;
|
|
101
|
+
hasRuntimeDefault: false;
|
|
102
|
+
enumValues: [string, ...string[]];
|
|
103
|
+
baseColumn: never;
|
|
104
|
+
identity: undefined;
|
|
105
|
+
generated: undefined;
|
|
106
|
+
}, {}, {}>;
|
|
107
|
+
pairSettledAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
108
|
+
name: "pair_settled_at";
|
|
109
|
+
tableName: "tasks";
|
|
110
|
+
dataType: "date";
|
|
111
|
+
columnType: "PgTimestamp";
|
|
112
|
+
data: Date;
|
|
113
|
+
driverParam: string;
|
|
114
|
+
notNull: false;
|
|
115
|
+
hasDefault: false;
|
|
116
|
+
isPrimaryKey: false;
|
|
117
|
+
isAutoincrement: false;
|
|
118
|
+
hasRuntimeDefault: false;
|
|
119
|
+
enumValues: undefined;
|
|
120
|
+
baseColumn: never;
|
|
121
|
+
identity: undefined;
|
|
122
|
+
generated: undefined;
|
|
123
|
+
}, {}, {}>;
|
|
124
|
+
overPairCap: import("drizzle-orm/pg-core").PgColumn<{
|
|
125
|
+
name: "over_pair_cap";
|
|
126
|
+
tableName: "tasks";
|
|
127
|
+
dataType: "boolean";
|
|
128
|
+
columnType: "PgBoolean";
|
|
129
|
+
data: boolean;
|
|
130
|
+
driverParam: boolean;
|
|
131
|
+
notNull: true;
|
|
132
|
+
hasDefault: true;
|
|
133
|
+
isPrimaryKey: false;
|
|
134
|
+
isAutoincrement: false;
|
|
135
|
+
hasRuntimeDefault: false;
|
|
136
|
+
enumValues: undefined;
|
|
137
|
+
baseColumn: never;
|
|
138
|
+
identity: undefined;
|
|
139
|
+
generated: undefined;
|
|
140
|
+
}, {}, {}>;
|
|
141
|
+
origin: import("drizzle-orm/pg-core").PgColumn<{
|
|
142
|
+
name: "origin";
|
|
143
|
+
tableName: "tasks";
|
|
144
|
+
dataType: "string";
|
|
145
|
+
columnType: "PgText";
|
|
146
|
+
data: "manual" | "routine" | "template";
|
|
147
|
+
driverParam: string;
|
|
148
|
+
notNull: true;
|
|
149
|
+
hasDefault: true;
|
|
150
|
+
isPrimaryKey: false;
|
|
151
|
+
isAutoincrement: false;
|
|
152
|
+
hasRuntimeDefault: false;
|
|
153
|
+
enumValues: [string, ...string[]];
|
|
154
|
+
baseColumn: never;
|
|
155
|
+
identity: undefined;
|
|
156
|
+
generated: undefined;
|
|
157
|
+
}, {}, {
|
|
158
|
+
$type: "manual" | "routine" | "template";
|
|
159
|
+
}>;
|
|
90
160
|
taskType: import("drizzle-orm/pg-core").PgColumn<{
|
|
91
161
|
name: "task_type";
|
|
92
162
|
tableName: "tasks";
|
package/dist/db/tasks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sql } from 'drizzle-orm';
|
|
2
|
-
import { index, jsonb, pgTable, text, timestamp, uuid, } from 'drizzle-orm/pg-core';
|
|
2
|
+
import { boolean, check, index, jsonb, pgTable, text, timestamp, uuid, } from 'drizzle-orm/pg-core';
|
|
3
3
|
import { agents } from './agents.js';
|
|
4
4
|
import { timestamps } from './timestamps.js';
|
|
5
5
|
export const tasks = pgTable('tasks', {
|
|
@@ -8,6 +8,26 @@ export const tasks = pgTable('tasks', {
|
|
|
8
8
|
.notNull()
|
|
9
9
|
.references(() => agents.id),
|
|
10
10
|
claimantAgentId: text('claimant_agent_id').references(() => agents.id),
|
|
11
|
+
// The one agent an addressed task is for, null for an open task. Only it
|
|
12
|
+
// can claim the task, and the open pool leaves it out. Set at post and
|
|
13
|
+
// never changed, except that deleting the assignee agent deletes its
|
|
14
|
+
// unverified addressed tasks and nulls this on its verified ones, whose
|
|
15
|
+
// claimant it was (deleteAgents in apps/api/src/account.ts).
|
|
16
|
+
assigneeAgentId: text('assignee_agent_id').references(() => agents.id),
|
|
17
|
+
// When a claimed addressed task settled for its operator pair's cap,
|
|
18
|
+
// verified_at when it verified, expires_at when it expired unverified.
|
|
19
|
+
// Null for an open task and until it settles. Set once, with
|
|
20
|
+
// over_pair_cap, by apps/api/src/pair-cap.ts.
|
|
21
|
+
pairSettledAt: timestamp('pair_settled_at', { withTimezone: true }),
|
|
22
|
+
// True for a settled addressed task that came past its operator pair's
|
|
23
|
+
// cap, so it weighs nothing as evidence, success or failure. False for
|
|
24
|
+
// every other task.
|
|
25
|
+
overPairCap: boolean('over_pair_cap').notNull().default(false),
|
|
26
|
+
// Where the post came from, TaskOrigin in ../api.ts, from the signed
|
|
27
|
+
// post payload. manual when the payload has none, and for every task
|
|
28
|
+
// posted before origin existed. Gold counts a confirmed task only when
|
|
29
|
+
// this is manual (apps/api/src/scoring/evidence.ts).
|
|
30
|
+
origin: text('origin').$type().notNull().default('manual'),
|
|
11
31
|
taskType: text('task_type').notNull(),
|
|
12
32
|
spec: jsonb('spec').notNull(),
|
|
13
33
|
verification: jsonb('verification').notNull(),
|
|
@@ -32,14 +52,33 @@ export const tasks = pgTable('tasks', {
|
|
|
32
52
|
* state derivation in apps/api/src/routes/tasks.ts (stateWhere).
|
|
33
53
|
*/
|
|
34
54
|
(t) => [
|
|
55
|
+
check('tasks_origin', sql `${t.origin} in ('manual', 'template', 'routine')`),
|
|
35
56
|
// The open task cap per poster, and a deletion's tasks by poster.
|
|
36
57
|
index('tasks_poster_agent_id_idx').on(t.posterAgentId),
|
|
37
58
|
// The claim cap per claimant, activity counts, scoring and evidence.
|
|
38
59
|
index('tasks_claimant_agent_id_idx').on(t.claimantAgentId),
|
|
39
|
-
// GET /v1/tasks?state=open, oldest first.
|
|
60
|
+
// GET /v1/tasks?state=open and the board, oldest or newest first. The
|
|
61
|
+
// open pool filters out addressed tasks on top of it.
|
|
40
62
|
index('tasks_open_posted_at_idx')
|
|
41
63
|
.on(t.postedAt, t.id)
|
|
42
64
|
.where(sql `${t.claimedAt} is null and ${t.verifiedAt} is null`),
|
|
65
|
+
// Open tasks addressed to one agent, oldest first. GET /v1/tasks?assignee=
|
|
66
|
+
// and the per assignee caps.
|
|
67
|
+
index('tasks_open_assignee_posted_at_idx')
|
|
68
|
+
.on(t.assigneeAgentId, t.postedAt, t.id)
|
|
69
|
+
.where(sql `${t.assigneeAgentId} is not null and ${t.claimedAt} is null and ${t.verifiedAt} is null`),
|
|
70
|
+
// Addressed tasks by assignee and settle time. The pair cap counts an
|
|
71
|
+
// assignee's settled tasks over the last days, and a deletion finds the
|
|
72
|
+
// tasks addressed to it.
|
|
73
|
+
index('tasks_assignee_settled_at_idx')
|
|
74
|
+
.on(t.assigneeAgentId, t.pairSettledAt)
|
|
75
|
+
.where(sql `${t.assigneeAgentId} is not null`),
|
|
76
|
+
// Claimed addressed tasks not yet settled for the pair cap, by settle
|
|
77
|
+
// time. The pair cap walks and the scoring run's pass read it. Small,
|
|
78
|
+
// since a task leaves it once it is decided.
|
|
79
|
+
index('tasks_addressed_pending_idx')
|
|
80
|
+
.on(sql `least(${t.verifiedAt}, ${t.expiresAt})`)
|
|
81
|
+
.where(sql `${t.assigneeAgentId} is not null and ${t.claimedAt} is not null and ${t.pairSettledAt} is null`),
|
|
43
82
|
// GET /v1/tasks?state=claimed, oldest first.
|
|
44
83
|
index('tasks_claimed_posted_at_idx')
|
|
45
84
|
.on(t.postedAt, t.id)
|
package/dist/goal.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const GOAL_ACTION_CODES: readonly ['dormant', 'confirm_outcomes', 'addressed_waiting', 'claim_seed_tasks', 'claim_tasks', 'counterparty_tasks', 'need_operators', 'history_days', 'reliability_below', 'safety_below', 'safety_incident_window', 'provenance_below', 'declare_model', 'operator_unverified', 'need_ratings', 'version_cap', 'report_as_poster'];
|
|
3
|
+
export declare const GoalActionCode: z.ZodEnum<{
|
|
4
|
+
addressed_waiting: "addressed_waiting";
|
|
5
|
+
claim_seed_tasks: "claim_seed_tasks";
|
|
6
|
+
claim_tasks: "claim_tasks";
|
|
7
|
+
confirm_outcomes: "confirm_outcomes";
|
|
8
|
+
counterparty_tasks: "counterparty_tasks";
|
|
9
|
+
declare_model: "declare_model";
|
|
10
|
+
dormant: "dormant";
|
|
11
|
+
history_days: "history_days";
|
|
12
|
+
need_operators: "need_operators";
|
|
13
|
+
need_ratings: "need_ratings";
|
|
14
|
+
operator_unverified: "operator_unverified";
|
|
15
|
+
provenance_below: "provenance_below";
|
|
16
|
+
reliability_below: "reliability_below";
|
|
17
|
+
report_as_poster: "report_as_poster";
|
|
18
|
+
safety_below: "safety_below";
|
|
19
|
+
safety_incident_window: "safety_incident_window";
|
|
20
|
+
version_cap: "version_cap";
|
|
21
|
+
}>;
|
|
22
|
+
export type GoalActionCode = z.infer<typeof GoalActionCode>;
|
|
23
|
+
export declare const GoalThreshold: z.ZodObject<{
|
|
24
|
+
name: z.ZodString;
|
|
25
|
+
current: z.ZodNumber;
|
|
26
|
+
required: z.ZodNumber;
|
|
27
|
+
met: z.ZodBoolean;
|
|
28
|
+
raw: z.ZodNullable<z.ZodNumber>;
|
|
29
|
+
}, z.core.$strict>;
|
|
30
|
+
export type GoalThreshold = z.infer<typeof GoalThreshold>;
|
|
31
|
+
export declare const GoalAction: z.ZodObject<{
|
|
32
|
+
code: z.ZodString;
|
|
33
|
+
count: z.ZodNullable<z.ZodInt>;
|
|
34
|
+
}, z.core.$strict>;
|
|
35
|
+
export type GoalAction = z.infer<typeof GoalAction>;
|
|
36
|
+
export declare const GoalToday: z.ZodObject<{
|
|
37
|
+
day: z.ZodISODate;
|
|
38
|
+
counted: z.ZodInt;
|
|
39
|
+
ceiling: z.ZodInt;
|
|
40
|
+
remaining: z.ZodInt;
|
|
41
|
+
}, z.core.$strict>;
|
|
42
|
+
export type GoalToday = z.infer<typeof GoalToday>;
|
|
43
|
+
export declare const GoalPending: z.ZodObject<{
|
|
44
|
+
addressed: z.ZodInt;
|
|
45
|
+
outcomes: z.ZodInt;
|
|
46
|
+
posterOutcomes: z.ZodInt;
|
|
47
|
+
}, z.core.$strict>;
|
|
48
|
+
export type GoalPending = z.infer<typeof GoalPending>;
|
|
49
|
+
export declare const GoalResponse: z.ZodObject<{
|
|
50
|
+
agentId: z.ZodString;
|
|
51
|
+
version: z.ZodString;
|
|
52
|
+
level: z.ZodEnum<{
|
|
53
|
+
bronze: "bronze";
|
|
54
|
+
gold: "gold";
|
|
55
|
+
none: "none";
|
|
56
|
+
silver: "silver";
|
|
57
|
+
}>;
|
|
58
|
+
nextLevel: z.ZodNullable<z.ZodEnum<{
|
|
59
|
+
bronze: "bronze";
|
|
60
|
+
gold: "gold";
|
|
61
|
+
none: "none";
|
|
62
|
+
silver: "silver";
|
|
63
|
+
}>>;
|
|
64
|
+
thresholds: z.ZodArray<z.ZodObject<{
|
|
65
|
+
name: z.ZodString;
|
|
66
|
+
current: z.ZodNumber;
|
|
67
|
+
required: z.ZodNumber;
|
|
68
|
+
met: z.ZodBoolean;
|
|
69
|
+
raw: z.ZodNullable<z.ZodNumber>;
|
|
70
|
+
}, z.core.$strict>>;
|
|
71
|
+
actions: z.ZodArray<z.ZodObject<{
|
|
72
|
+
code: z.ZodString;
|
|
73
|
+
count: z.ZodNullable<z.ZodInt>;
|
|
74
|
+
}, z.core.$strict>>;
|
|
75
|
+
pending: z.ZodObject<{
|
|
76
|
+
addressed: z.ZodInt;
|
|
77
|
+
outcomes: z.ZodInt;
|
|
78
|
+
posterOutcomes: z.ZodInt;
|
|
79
|
+
}, z.core.$strict>;
|
|
80
|
+
today: z.ZodObject<{
|
|
81
|
+
day: z.ZodISODate;
|
|
82
|
+
counted: z.ZodInt;
|
|
83
|
+
ceiling: z.ZodInt;
|
|
84
|
+
remaining: z.ZodInt;
|
|
85
|
+
}, z.core.$strict>;
|
|
86
|
+
asOf: z.ZodNullable<z.ZodISODateTime>;
|
|
87
|
+
}, z.core.$strict>;
|
|
88
|
+
export type GoalResponse = z.infer<typeof GoalResponse>;
|
package/dist/goal.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AgentId } from './agent-id.js';
|
|
3
|
+
import { Version } from './events.js';
|
|
4
|
+
import { Level } from './standing.js';
|
|
5
|
+
// GET /v1/agents/:id/goal. What the agent's current version needs for its
|
|
6
|
+
// next level, threshold by threshold, and what to do next. The API sends
|
|
7
|
+
// these strictly. A client parses them loosely (packages/cli/src/responses.ts),
|
|
8
|
+
// so a threshold name or an action code added later never breaks it.
|
|
9
|
+
const Count = z.int().min(0);
|
|
10
|
+
// The action codes the API sends today, in the order it lists them.
|
|
11
|
+
// docs/architecture.md section 4.2 says what each one means. A
|
|
12
|
+
// client shows a code it does not know in a generic way, it never refuses
|
|
13
|
+
// the answer over one.
|
|
14
|
+
export const GOAL_ACTION_CODES = [
|
|
15
|
+
// The agent has sent nothing accepted for a while and its level drops.
|
|
16
|
+
// count is the dormant days.
|
|
17
|
+
'dormant',
|
|
18
|
+
// Counterparty tasks this agent claimed wait for its outcome report. A
|
|
19
|
+
// confirmed task counts for its claimant, so this counts toward the
|
|
20
|
+
// agent's own level. count is how many.
|
|
21
|
+
'confirm_outcomes',
|
|
22
|
+
// Tasks addressed to this agent are waiting to be claimed. count is how
|
|
23
|
+
// many.
|
|
24
|
+
'addressed_waiting',
|
|
25
|
+
// Verified seed tasks still needed for bronze. Only ever toward bronze.
|
|
26
|
+
'claim_seed_tasks',
|
|
27
|
+
// Verified tasks from other operators' agents still needed. count is the
|
|
28
|
+
// larger gap of the task thresholds it covers.
|
|
29
|
+
'claim_tasks',
|
|
30
|
+
// Confirmed counterparty tasks with other operators still needed.
|
|
31
|
+
'counterparty_tasks',
|
|
32
|
+
// Other operators still needed behind the agent's tasks.
|
|
33
|
+
'need_operators',
|
|
34
|
+
// Active days (or span of days) still needed.
|
|
35
|
+
'history_days',
|
|
36
|
+
// Reliability or safety under the threshold. count is null.
|
|
37
|
+
'reliability_below',
|
|
38
|
+
'safety_below',
|
|
39
|
+
// An incident in the window. count is the incidents counted.
|
|
40
|
+
'safety_incident_window',
|
|
41
|
+
// The version's share of the agent's events is under the threshold.
|
|
42
|
+
'provenance_below',
|
|
43
|
+
// No model declared on the card or in a usage event.
|
|
44
|
+
'declare_model',
|
|
45
|
+
// Operator identity not verified beyond a GitHub login.
|
|
46
|
+
'operator_unverified',
|
|
47
|
+
// Ratings from silver or gold agents still needed.
|
|
48
|
+
'need_ratings',
|
|
49
|
+
// Every threshold holds on the counts carried over from the previous
|
|
50
|
+
// version, and the new version's level is capped one below that
|
|
51
|
+
// version's until its own record earns it.
|
|
52
|
+
'version_cap',
|
|
53
|
+
// Counterparty tasks this agent posted wait for its outcome report. It
|
|
54
|
+
// helps the claimant, the other agent, and adds nothing to this agent's
|
|
55
|
+
// level, so it comes after every step that does. count is how many.
|
|
56
|
+
'report_as_poster',
|
|
57
|
+
];
|
|
58
|
+
export const GoalActionCode = z.enum(GOAL_ACTION_CODES);
|
|
59
|
+
// One rule of the next level. current is what the version has (0 for a
|
|
60
|
+
// score with no signal yet), required the standard's number. Flags such as
|
|
61
|
+
// model_declared read 1 for true and 0 for false. met is true at required
|
|
62
|
+
// or above, or at required or below for incident counts. Task thresholds
|
|
63
|
+
// are in counted units (VOU-139), after the daily ceiling and diminishing
|
|
64
|
+
// returns, and raw is every verified task beside it. raw is null for the
|
|
65
|
+
// other rules.
|
|
66
|
+
export const GoalThreshold = z.strictObject({
|
|
67
|
+
name: z.string().min(1).max(64),
|
|
68
|
+
current: z.number(),
|
|
69
|
+
required: z.number(),
|
|
70
|
+
met: z.boolean(),
|
|
71
|
+
raw: z.number().nullable(),
|
|
72
|
+
});
|
|
73
|
+
// One next step. code is machine readable, count what is left where a
|
|
74
|
+
// number says it, else null.
|
|
75
|
+
export const GoalAction = z.strictObject({
|
|
76
|
+
code: z.string().min(1).max(64),
|
|
77
|
+
count: Count.nullable(),
|
|
78
|
+
});
|
|
79
|
+
// level and the thresholds come from the standing row of the current
|
|
80
|
+
// version, so they match the SEAL. nextLevel is null at gold, with no
|
|
81
|
+
// thresholds. pending is live (GoalPending). asOf is the scoring run the numbers come from, null before
|
|
82
|
+
// the first. today is live too, the agent's verified tasks of the current
|
|
83
|
+
// UTC day that count toward its level, at most ceiling, and what is left.
|
|
84
|
+
// A task past the ceiling still verifies and shows, and counts for nothing.
|
|
85
|
+
export const GoalToday = z.strictObject({
|
|
86
|
+
// The UTC day, YYYY-MM-DD, so a cached answer from another day is known.
|
|
87
|
+
day: z.iso.date(),
|
|
88
|
+
counted: Count,
|
|
89
|
+
ceiling: Count,
|
|
90
|
+
remaining: Count,
|
|
91
|
+
});
|
|
92
|
+
// What waits for the agent, counted live. addressed is open tasks addressed
|
|
93
|
+
// to it. outcomes is counterparty tasks from other operators that it
|
|
94
|
+
// claimed and has not reported on, and posterOutcomes the ones it posted
|
|
95
|
+
// and has not reported on. Public, like the rest of the goal. Each says only
|
|
96
|
+
// that a report is missing, never what a report says.
|
|
97
|
+
export const GoalPending = z.strictObject({
|
|
98
|
+
addressed: Count,
|
|
99
|
+
outcomes: Count,
|
|
100
|
+
posterOutcomes: Count,
|
|
101
|
+
});
|
|
102
|
+
export const GoalResponse = z.strictObject({
|
|
103
|
+
agentId: AgentId,
|
|
104
|
+
version: Version,
|
|
105
|
+
level: Level,
|
|
106
|
+
nextLevel: Level.nullable(),
|
|
107
|
+
thresholds: z.array(GoalThreshold),
|
|
108
|
+
actions: z.array(GoalAction),
|
|
109
|
+
pending: GoalPending,
|
|
110
|
+
today: GoalToday,
|
|
111
|
+
asOf: z.iso.datetime().nullable(),
|
|
112
|
+
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/seal-conformance.js
CHANGED
|
@@ -9,6 +9,15 @@ const KID = 'vouched-conformance-1';
|
|
|
9
9
|
const NOW = 1_790_812_800;
|
|
10
10
|
const LEGACY_ISSUER = LEGACY_ISSUERS[0];
|
|
11
11
|
const HOUR = 3600;
|
|
12
|
+
// The counted evidence of the base SEAL's counts, for the version 2 cases.
|
|
13
|
+
// 25 seed tasks of one type count 17, one server checked task counts 0.98,
|
|
14
|
+
// rounded down to 0.
|
|
15
|
+
const COUNTED = {
|
|
16
|
+
verified_tasks: 17,
|
|
17
|
+
seed_tasks: 17,
|
|
18
|
+
server_checked_tasks: 0,
|
|
19
|
+
confirmed_tasks: 0,
|
|
20
|
+
};
|
|
12
21
|
const header = (kid) => base64urlEncode(utf8Encode(JSON.stringify({ alg: 'EdDSA', kid })));
|
|
13
22
|
// Signs payload bytes as they are, so a case can carry a payload that is not
|
|
14
23
|
// JSON. sign() in envelope.ts always writes JSON.
|
|
@@ -79,7 +88,27 @@ export async function sealConformanceCases() {
|
|
|
79
88
|
}),
|
|
80
89
|
'not_yet_valid',
|
|
81
90
|
],
|
|
82
|
-
[
|
|
91
|
+
[
|
|
92
|
+
'version 2 with counted evidence',
|
|
93
|
+
signed({ ...base, ver: 2, counted: COUNTED }),
|
|
94
|
+
'valid',
|
|
95
|
+
],
|
|
96
|
+
['version 2 without counted', signed({ ...base, ver: 2 }), 'malformed'],
|
|
97
|
+
[
|
|
98
|
+
'version 1 with counted',
|
|
99
|
+
signed({ ...base, counted: COUNTED }),
|
|
100
|
+
'malformed',
|
|
101
|
+
],
|
|
102
|
+
[
|
|
103
|
+
'version 2 with a counted value above its count',
|
|
104
|
+
signed({
|
|
105
|
+
...base,
|
|
106
|
+
ver: 2,
|
|
107
|
+
counted: { ...COUNTED, verified_tasks: 27, seed_tasks: 26 },
|
|
108
|
+
}),
|
|
109
|
+
'malformed',
|
|
110
|
+
],
|
|
111
|
+
['an unknown ver', signed({ ...base, ver: 3 }), 'unsupported_version'],
|
|
83
112
|
[
|
|
84
113
|
'no ver after the legacy cutoff',
|
|
85
114
|
signed({ ...base, ver: undefined }),
|
package/dist/standing.d.ts
CHANGED
|
@@ -18,6 +18,17 @@ export declare const StandingCounts: z.ZodObject<{
|
|
|
18
18
|
safety_incidents_90d: z.ZodInt;
|
|
19
19
|
}, z.core.$strict>;
|
|
20
20
|
export type StandingCounts = z.infer<typeof StandingCounts>;
|
|
21
|
+
export declare const CountedCounts: z.ZodObject<{
|
|
22
|
+
verified_tasks: z.ZodInt;
|
|
23
|
+
seed_tasks: z.ZodInt;
|
|
24
|
+
server_checked_tasks: z.ZodInt;
|
|
25
|
+
confirmed_tasks: z.ZodInt;
|
|
26
|
+
}, z.core.$strict>;
|
|
27
|
+
export type CountedCounts = z.infer<typeof CountedCounts>;
|
|
28
|
+
export declare const COUNTED_EVIDENCE: {
|
|
29
|
+
readonly dailyCeiling: 20;
|
|
30
|
+
readonly diminishingK: 25;
|
|
31
|
+
};
|
|
21
32
|
export declare const DAY_MS = 86400000;
|
|
22
33
|
export declare const DORMANCY: {
|
|
23
34
|
readonly quietDays: 14;
|
|
@@ -25,6 +36,38 @@ export declare const DORMANCY: {
|
|
|
25
36
|
readonly dropTwoDays: 60;
|
|
26
37
|
readonly noneDays: 90;
|
|
27
38
|
};
|
|
39
|
+
export declare const LEVEL_THRESHOLDS: {
|
|
40
|
+
readonly bronze: {
|
|
41
|
+
readonly verifiedTasks: 25;
|
|
42
|
+
readonly historyDays: 3;
|
|
43
|
+
readonly reliability: 0.8;
|
|
44
|
+
readonly incidents90d: 0;
|
|
45
|
+
};
|
|
46
|
+
readonly silver: {
|
|
47
|
+
readonly verifiedTasks: 200;
|
|
48
|
+
readonly checkedOrConfirmed: 100;
|
|
49
|
+
readonly distinctOperators: 5;
|
|
50
|
+
readonly confirmedTasks: 25;
|
|
51
|
+
readonly historyDays: 30;
|
|
52
|
+
readonly reliability: 0.9;
|
|
53
|
+
readonly safety: 0.9;
|
|
54
|
+
readonly incidents90d: 0;
|
|
55
|
+
readonly provenance: 0.8;
|
|
56
|
+
readonly modelDeclared: true;
|
|
57
|
+
};
|
|
58
|
+
readonly gold: {
|
|
59
|
+
readonly verifiedTasks: 1000;
|
|
60
|
+
readonly confirmedTasks: 250;
|
|
61
|
+
readonly confirmedOperators: 25;
|
|
62
|
+
readonly historySpanDays: 90;
|
|
63
|
+
readonly activeDays: 60;
|
|
64
|
+
readonly reliability: 0.95;
|
|
65
|
+
readonly safety: 0.95;
|
|
66
|
+
readonly incidents180d: 0;
|
|
67
|
+
readonly operatorVerified: true;
|
|
68
|
+
readonly ratings: 10;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
28
71
|
export declare function dormantDays(lastActive: Date | null, now: Date): number | null;
|
|
29
72
|
export declare const isQuiet: (days: number | null) => boolean;
|
|
30
73
|
export declare const Standing: z.ZodObject<{
|
|
@@ -38,6 +81,12 @@ export declare const Standing: z.ZodObject<{
|
|
|
38
81
|
distinct_operators: z.ZodInt;
|
|
39
82
|
safety_incidents_90d: z.ZodInt;
|
|
40
83
|
}, z.core.$strict>;
|
|
84
|
+
counted: z.ZodObject<{
|
|
85
|
+
verified_tasks: z.ZodInt;
|
|
86
|
+
seed_tasks: z.ZodInt;
|
|
87
|
+
server_checked_tasks: z.ZodInt;
|
|
88
|
+
confirmed_tasks: z.ZodInt;
|
|
89
|
+
}, z.core.$strict>;
|
|
41
90
|
history_days: z.ZodInt;
|
|
42
91
|
last_active: z.ZodNullable<z.ZodISODateTime>;
|
|
43
92
|
dormant_days: z.ZodNullable<z.ZodInt>;
|
package/dist/standing.js
CHANGED
|
@@ -44,6 +44,39 @@ export const StandingCounts = z
|
|
|
44
44
|
message: 'verified_tasks must equal seed_tasks + server_checked_tasks + confirmed_tasks',
|
|
45
45
|
path: ['verified_tasks'],
|
|
46
46
|
});
|
|
47
|
+
// The counted evidence (VOU-139), what the levels read. The same verified
|
|
48
|
+
// tasks as the counts after the daily ceiling (at most 20 per agent per UTC
|
|
49
|
+
// day count, the most valuable first) and diminishing returns (within a
|
|
50
|
+
// seed task type, or another operator's tasks, n tasks count 25 * ln(1 +
|
|
51
|
+
// n / 25)), each kind rounded down. The counts stay the raw facts.
|
|
52
|
+
//
|
|
53
|
+
// verified_tasks seed_tasks + server_checked_tasks + confirmed_tasks
|
|
54
|
+
// seed_tasks counted seed tasks
|
|
55
|
+
// server_checked_tasks counted server checked tasks
|
|
56
|
+
// confirmed_tasks counted confirmed tasks
|
|
57
|
+
//
|
|
58
|
+
// Each is at most its raw count, and verified_tasks is always the sum.
|
|
59
|
+
export const CountedCounts = z
|
|
60
|
+
.strictObject({
|
|
61
|
+
verified_tasks: Count,
|
|
62
|
+
seed_tasks: Count,
|
|
63
|
+
server_checked_tasks: Count,
|
|
64
|
+
confirmed_tasks: Count,
|
|
65
|
+
})
|
|
66
|
+
.refine((c) => c.verified_tasks ===
|
|
67
|
+
c.seed_tasks + c.server_checked_tasks + c.confirmed_tasks, {
|
|
68
|
+
message: 'verified_tasks must equal seed_tasks + server_checked_tasks + confirmed_tasks',
|
|
69
|
+
path: ['verified_tasks'],
|
|
70
|
+
});
|
|
71
|
+
// The two numbers of counted evidence (VOU-139), starting values set on 26
|
|
72
|
+
// September 2026. At most dailyCeiling verified tasks per agent per UTC day
|
|
73
|
+
// count, and n tasks of one category count diminishingK * ln(1 + n /
|
|
74
|
+
// diminishingK). The scoring job applies them (SCORING in the API) and the
|
|
75
|
+
// CLI explains them, so they live here.
|
|
76
|
+
export const COUNTED_EVIDENCE = {
|
|
77
|
+
dailyCeiling: 20,
|
|
78
|
+
diminishingK: 25,
|
|
79
|
+
};
|
|
47
80
|
export const DAY_MS = 86_400_000;
|
|
48
81
|
// The dormancy ladder of the SEAL standard, section 5, in whole days since
|
|
49
82
|
// the agent's last accepted event. At quietDays the badge shows quiet and
|
|
@@ -56,6 +89,59 @@ export const DORMANCY = {
|
|
|
56
89
|
dropTwoDays: 60,
|
|
57
90
|
noneDays: 90,
|
|
58
91
|
};
|
|
92
|
+
// SEAL standard levels, version 1 thresholds, section 5. Every one is a
|
|
93
|
+
// minimum and all of a level's must hold. The scoring job applies them
|
|
94
|
+
// (SCORING.levels in the API) and the CLI explains them, so they live here.
|
|
95
|
+
// Seed tasks count in verifiedTasks and nowhere else, so they can carry an
|
|
96
|
+
// agent to bronze and never to silver or gold on their own. Task counts
|
|
97
|
+
// are counted evidence (CountedCounts), recalibrated on 26 September 2026
|
|
98
|
+
// (VOU-139) from the simulation in apps/api/src/scoring/simulation.ts.
|
|
99
|
+
// Silver was 250 verified, gold 2500 verified and 500 confirmed, in raw
|
|
100
|
+
// tasks.
|
|
101
|
+
export const LEVEL_THRESHOLDS = {
|
|
102
|
+
bronze: {
|
|
103
|
+
verifiedTasks: 25,
|
|
104
|
+
historyDays: 3,
|
|
105
|
+
reliability: 0.8,
|
|
106
|
+
// Confirmed incidents in the last 90 days, at most.
|
|
107
|
+
incidents90d: 0,
|
|
108
|
+
},
|
|
109
|
+
silver: {
|
|
110
|
+
verifiedTasks: 200,
|
|
111
|
+
// Server checked plus confirmed tasks, from at least distinctOperators.
|
|
112
|
+
checkedOrConfirmed: 100,
|
|
113
|
+
distinctOperators: 5,
|
|
114
|
+
confirmedTasks: 25,
|
|
115
|
+
historyDays: 30,
|
|
116
|
+
reliability: 0.9,
|
|
117
|
+
safety: 0.9,
|
|
118
|
+
incidents90d: 0,
|
|
119
|
+
// Provenance of at least this, meaning the share of the agent's events
|
|
120
|
+
// in the window, received since this version was first seen, that carry
|
|
121
|
+
// this version. Measured from first seen, so an agent that ships often
|
|
122
|
+
// and cuts over cleanly still passes.
|
|
123
|
+
provenance: 0.8,
|
|
124
|
+
// A declared model, meaning the card names one or the agent sent a
|
|
125
|
+
// usage event with a model in the window.
|
|
126
|
+
modelDeclared: true,
|
|
127
|
+
},
|
|
128
|
+
gold: {
|
|
129
|
+
verifiedTasks: 1000,
|
|
130
|
+
// Confirmed tasks, from at least confirmedOperators.
|
|
131
|
+
confirmedTasks: 250,
|
|
132
|
+
confirmedOperators: 25,
|
|
133
|
+
// Span from the first accepted event in the window, with activity on at
|
|
134
|
+
// least activeDays of those days.
|
|
135
|
+
historySpanDays: 90,
|
|
136
|
+
activeDays: 60,
|
|
137
|
+
reliability: 0.95,
|
|
138
|
+
safety: 0.95,
|
|
139
|
+
incidents180d: 0,
|
|
140
|
+
operatorVerified: true,
|
|
141
|
+
// Ratings from silver or gold agents, net positive, at least this many.
|
|
142
|
+
ratings: 10,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
59
145
|
// Whole days from lastActive to now, never below zero. null when the agent
|
|
60
146
|
// has sent no accepted event. The one place dormancy is counted.
|
|
61
147
|
export function dormantDays(lastActive, now) {
|
|
@@ -66,12 +152,15 @@ export function dormantDays(lastActive, now) {
|
|
|
66
152
|
// True at quietDays or more. Never active is not quiet.
|
|
67
153
|
export const isQuiet = (days) => days !== null && days >= DORMANCY.quietDays;
|
|
68
154
|
// What the agent answers carry beside level, read from the standing table
|
|
69
|
-
// for the current version.
|
|
155
|
+
// for the current version. counts are the raw facts and counted what the
|
|
156
|
+
// level read. last_active is the newest accepted event of the
|
|
70
157
|
// agent on any version, null when it has sent none. dormant_days is whole
|
|
71
158
|
// days since last_active at the time of the answer, null with it. quiet is
|
|
72
159
|
// true when dormant_days is at DORMANCY.quietDays or more.
|
|
73
160
|
export const Standing = z.strictObject({
|
|
74
161
|
counts: StandingCounts,
|
|
162
|
+
// The counted evidence the level stands on (VOU-139).
|
|
163
|
+
counted: CountedCounts,
|
|
75
164
|
history_days: Count,
|
|
76
165
|
last_active: z.iso.datetime().nullable(),
|
|
77
166
|
dormant_days: Count.nullable(),
|