@openpond/evals 0.10.10 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LEARNING.md +20 -0
- package/dist/learning/contracts.js +2 -0
- package/dist/learning/index.js +2 -0
- package/dist/learning/iteration-eligibility.js +5 -2
- package/dist/learning/iteration-reservation-contracts.js +1 -0
- package/dist/learning/iteration-reservation-service.js +11 -2
- package/dist/learning/nightly-schedule.js +69 -0
- package/dist/learning/schedule-contracts.js +5 -1
- package/dist/learning/schedule-service.js +9 -5
- package/dist/learning/schedule-worker.js +22 -7
- package/dist/learning/service.js +10 -1
- package/dist/learning/task-queue-inspection.js +48 -0
- package/dist/learning/transport.js +1 -0
- package/dist/types/learning/contracts.d.ts +12 -0
- package/dist/types/learning/contracts.d.ts.map +1 -1
- package/dist/types/learning/index.d.ts +2 -0
- package/dist/types/learning/index.d.ts.map +1 -1
- package/dist/types/learning/iteration-eligibility.d.ts +8 -1
- package/dist/types/learning/iteration-eligibility.d.ts.map +1 -1
- package/dist/types/learning/iteration-reservation-contracts.d.ts +6 -0
- package/dist/types/learning/iteration-reservation-contracts.d.ts.map +1 -1
- package/dist/types/learning/iteration-reservation-service.d.ts.map +1 -1
- package/dist/types/learning/nightly-schedule.d.ts +13 -0
- package/dist/types/learning/nightly-schedule.d.ts.map +1 -0
- package/dist/types/learning/operations.d.ts +22 -0
- package/dist/types/learning/operations.d.ts.map +1 -1
- package/dist/types/learning/repository.d.ts +11 -0
- package/dist/types/learning/repository.d.ts.map +1 -1
- package/dist/types/learning/schedule-contracts.d.ts +4 -0
- package/dist/types/learning/schedule-contracts.d.ts.map +1 -1
- package/dist/types/learning/schedule-service.d.ts +4 -0
- package/dist/types/learning/schedule-service.d.ts.map +1 -1
- package/dist/types/learning/schedule-worker.d.ts.map +1 -1
- package/dist/types/learning/service.d.ts +10 -0
- package/dist/types/learning/service.d.ts.map +1 -1
- package/dist/types/learning/task-queue-inspection.d.ts +25 -0
- package/dist/types/learning/task-queue-inspection.d.ts.map +1 -0
- package/dist/types/learning/transport.d.ts +26 -0
- package/dist/types/learning/transport.d.ts.map +1 -1
- package/package.json +1 -1
- package/schemas/learning/v1/command-request.schema.json +41 -0
- package/schemas/learning/v1/policy.schema.json +24 -0
- package/schemas/learning/v1/read-request.schema.json +28 -0
- package/schemas/learning/v1/reservation.schema.json +17 -0
- package/schemas/learning/v1/schedule.schema.json +44 -13
- package/schemas/learning/v1/task-queue-inspection.schema.json +72 -0
package/LEARNING.md
CHANGED
|
@@ -339,3 +339,23 @@ Taskset output paths, media types, schema references and size bounds. Evidence
|
|
|
339
339
|
conversion copies them into every task before grading or sealing a batch, so a
|
|
340
340
|
changed output contract requires a new definition and new matching evidence and
|
|
341
341
|
review receipts. Definitions without this field retain their existing hashes.
|
|
342
|
+
|
|
343
|
+
## Nightly and task-count triggers
|
|
344
|
+
|
|
345
|
+
Policies may use `trigger: { kind: "nightly", localTime: "20:00", timeZone:
|
|
346
|
+
"America/New_York" }`. The durable timer computes the next local date in that
|
|
347
|
+
IANA timezone. DST repeats use the earlier occurrence once; missing local times
|
|
348
|
+
advance by the DST gap. Calendar edits recompute the due time; unchanged calendars
|
|
349
|
+
retain it. Existing `schedule` policies retain elapsed-interval semantics.
|
|
350
|
+
|
|
351
|
+
`trigger: { kind: "approved_count" }` uses `admission.minimumApprovedExamples`
|
|
352
|
+
as its threshold and checks once per minute. Below-threshold checks advance the
|
|
353
|
+
timer without creating iterations or fire records. Once ready, the same atomic
|
|
354
|
+
reservation, consumption, budget, cooldown and execution-owner checks apply.
|
|
355
|
+
Both new automatic triggers require reviewer authorization to enable.
|
|
356
|
+
|
|
357
|
+
`service.inspectTaskQueue(context, modelProjectId?)` is a read-only snapshot of
|
|
358
|
+
unique eligible, unconsumed training attempts across current policies. It
|
|
359
|
+
deduplicates shared sources and excludes held-out family reservations. Paused
|
|
360
|
+
policies retain pending tasks. An invalid policy yields a null count and explicit
|
|
361
|
+
issues rather than a misleading zero. Source credentials cannot read the queue.
|
|
@@ -5,6 +5,7 @@ import { RewardBindingSchema, RewardCompositionSchema, RewardReleaseRefSchema, R
|
|
|
5
5
|
import { TaskRecordSchema, TaskSplitSchema, TasksetReleaseContentSchema } from "../tasksets.js";
|
|
6
6
|
import { assertBoundedTaskJson, validateTaskSchema } from "../task-schema.js";
|
|
7
7
|
import { JudgeCallReservationSchema } from "./judge-budget.js";
|
|
8
|
+
import { NightlyScheduleSchema } from "./nightly-schedule.js";
|
|
8
9
|
export const LearningJsonObjectSchema = z.record(z.string(), z.json());
|
|
9
10
|
export const LearningRevisionRefSchema = RewardReleaseRefSchema;
|
|
10
11
|
export const LearningJsonPointerSchema = z.string().max(2_000).refine((value) => value === "" || (value.startsWith("/") && !/~(?![01])/u.test(value)), "Use an RFC 6901 JSON pointer.");
|
|
@@ -222,6 +223,7 @@ export const LearningPolicyContentSchema = z.object({
|
|
|
222
223
|
z.object({ kind: z.literal("manual") }).strict(),
|
|
223
224
|
z.object({ kind: z.literal("approved_count") }).strict(),
|
|
224
225
|
z.object({ kind: z.literal("schedule"), intervalSeconds: z.number().int().min(60).max(31_536_000) }).strict(),
|
|
226
|
+
NightlyScheduleSchema.extend({ kind: z.literal("nightly") }).strict(),
|
|
225
227
|
z.object({ kind: z.literal("upstream_accepted"), modelProjectId: ReleaseIdSchema }).strict(),
|
|
226
228
|
]),
|
|
227
229
|
trainingParent: ImmutableReleaseRefSchema,
|
package/dist/learning/index.js
CHANGED
|
@@ -29,4 +29,6 @@ export { resolveLearningTrainingParent } from "./iteration-training-parent.js";
|
|
|
29
29
|
export * from "./schedule-contracts.js";
|
|
30
30
|
export * from "./schedule-service.js";
|
|
31
31
|
export * from "./schedule-worker.js";
|
|
32
|
+
export * from "./nightly-schedule.js";
|
|
32
33
|
export * from "./policy-inspection.js";
|
|
34
|
+
export * from "./task-queue-inspection.js";
|
|
@@ -9,7 +9,7 @@ export function learningChainId(modelProjectId) {
|
|
|
9
9
|
export function learningConsumptionId(chainId, evidence) {
|
|
10
10
|
return `consumption-${contentHash([chainId, evidence.id, evidence.revision])}`;
|
|
11
11
|
}
|
|
12
|
-
export async function inspectIterationEligibility(transaction, policy) {
|
|
12
|
+
export async function inspectIterationEligibility(transaction, policy, options = {}) {
|
|
13
13
|
// These are the methods supported by the approved-batch materializer.
|
|
14
14
|
const purpose = policy.training.method === "sft" ? "supervised_training" : "reward_training";
|
|
15
15
|
if (!["sft", "grpo", "ppo"].includes(policy.training.method)) {
|
|
@@ -24,6 +24,7 @@ export async function inspectIterationEligibility(transaction, policy) {
|
|
|
24
24
|
throw new LearningDomainError("learning_policy_binding_mismatch", 422);
|
|
25
25
|
const counts = { eligible: 0, awaitingReview: 0, excluded: 0, consumed: 0 };
|
|
26
26
|
const selected = [];
|
|
27
|
+
const eligibleEvidence = [];
|
|
27
28
|
const chainId = learningChainId(policy.modelProjectId);
|
|
28
29
|
const seen = new Set();
|
|
29
30
|
let backlog = 0;
|
|
@@ -66,11 +67,13 @@ export async function inspectIterationEligibility(transaction, policy) {
|
|
|
66
67
|
continue;
|
|
67
68
|
}
|
|
68
69
|
counts.eligible += 1;
|
|
70
|
+
if (options.collectEligible)
|
|
71
|
+
eligibleEvidence.push(learningRef(evidence));
|
|
69
72
|
if (selected.length < policy.limits.maxBatchExamples)
|
|
70
73
|
selected.push({ evidence, decision });
|
|
71
74
|
}
|
|
72
75
|
afterId = page.nextCursor ?? undefined;
|
|
73
76
|
} while (afterId);
|
|
74
77
|
}
|
|
75
|
-
return { counts, selected, purpose };
|
|
78
|
+
return { counts, selected, purpose, eligibleEvidence };
|
|
76
79
|
}
|
|
@@ -4,6 +4,7 @@ import { LearningAcceptedParentSchema, LearningRevisionRefSchema } from "./contr
|
|
|
4
4
|
export const LearningIterationTriggerSchema = z.discriminatedUnion("kind", [
|
|
5
5
|
z.object({ kind: z.literal("manual"), identity: ReleaseIdSchema }).strict(),
|
|
6
6
|
z.object({ kind: z.literal("schedule"), scheduledAt: ReleaseTimestampSchema }).strict(),
|
|
7
|
+
z.object({ kind: z.literal("approved_count"), checkedAt: ReleaseTimestampSchema }).strict(),
|
|
7
8
|
]);
|
|
8
9
|
/** Stable across policy edits: a Model owns one learning chain in its scope. */
|
|
9
10
|
export const LearningChainSchema = z.object({
|
|
@@ -11,7 +11,8 @@ import { latestAcceptedLearningParent, resolveLearningTrainingParent } from "./i
|
|
|
11
11
|
export async function reserveLearningIteration(transaction, input, actorId, now) {
|
|
12
12
|
const policy = await requireLearningRelease(transaction, "policy", input.policy);
|
|
13
13
|
const chainId = learningChainId(policy.modelProjectId);
|
|
14
|
-
const trigger = input.trigger.kind === "schedule" ? { ...input.trigger, scheduledAt: new Date(input.trigger.scheduledAt).toISOString() }
|
|
14
|
+
const trigger = input.trigger.kind === "schedule" ? { ...input.trigger, scheduledAt: new Date(input.trigger.scheduledAt).toISOString() }
|
|
15
|
+
: input.trigger.kind === "approved_count" ? { ...input.trigger, checkedAt: new Date(input.trigger.checkedAt).toISOString() } : input.trigger;
|
|
15
16
|
const triggerIdentity = contentHash([input.policy.id, trigger]);
|
|
16
17
|
const id = `iteration-${contentHash([chainId, triggerIdentity])}`;
|
|
17
18
|
const requestHash = contentHash({ policy: input.policy, trigger });
|
|
@@ -30,11 +31,17 @@ export async function reserveLearningIteration(transaction, input, actorId, now)
|
|
|
30
31
|
if (policy.automation.accept || policy.automation.serve)
|
|
31
32
|
throw new LearningDomainError("learning_automatic_acceptance_not_available", 422);
|
|
32
33
|
if (input.trigger.kind === "schedule") {
|
|
33
|
-
if (policy.trigger.kind
|
|
34
|
+
if (!["schedule", "nightly"].includes(policy.trigger.kind) || !policy.automation.train)
|
|
34
35
|
throw new LearningDomainError("learning_schedule_not_enabled", 409);
|
|
35
36
|
if (Date.parse(input.trigger.scheduledAt) > Date.parse(now))
|
|
36
37
|
throw new LearningDomainError("learning_schedule_not_due", 409);
|
|
37
38
|
}
|
|
39
|
+
if (input.trigger.kind === "approved_count") {
|
|
40
|
+
if (policy.trigger.kind !== "approved_count" || !policy.automation.train)
|
|
41
|
+
throw new LearningDomainError("learning_count_trigger_not_enabled", 409);
|
|
42
|
+
if (Date.parse(input.trigger.checkedAt) > Date.parse(now))
|
|
43
|
+
throw new LearningDomainError("learning_count_trigger_not_due", 409);
|
|
44
|
+
}
|
|
38
45
|
const chain = await transaction.get("chain", chainId);
|
|
39
46
|
if (chain?.activeIterationId)
|
|
40
47
|
throw new LearningDomainError("learning_iteration_active", 409, chain.activeIterationId);
|
|
@@ -43,6 +50,8 @@ export async function reserveLearningIteration(transaction, input, actorId, now)
|
|
|
43
50
|
}
|
|
44
51
|
const eligibility = await inspectIterationEligibility(transaction, policy);
|
|
45
52
|
const ready = eligibility.counts.eligible >= policy.admission.minimumApprovedExamples;
|
|
53
|
+
if (input.trigger.kind === "approved_count" && !ready)
|
|
54
|
+
throw new LearningDomainError("learning_count_threshold_not_met", 409);
|
|
46
55
|
const status = ready ? "ready" : eligibility.counts.awaitingReview > 0 ? "waiting_for_review" : "waiting_for_data";
|
|
47
56
|
const pointers = [];
|
|
48
57
|
const acceptedParent = await latestAcceptedLearningParent(transaction, chainId, true);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const NightlyScheduleSchema = z.object({
|
|
3
|
+
localTime: z.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/),
|
|
4
|
+
timeZone: z.string().min(1).max(200).refine(value => {
|
|
5
|
+
try {
|
|
6
|
+
new Intl.DateTimeFormat("en", { timeZone: value });
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}, "Choose a valid IANA timezone."),
|
|
13
|
+
}).strict();
|
|
14
|
+
const DAY = 86_400_000;
|
|
15
|
+
function formatter(calendar) {
|
|
16
|
+
return new Intl.DateTimeFormat("en-US", { timeZone: calendar.timeZone, year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", hourCycle: "h23" });
|
|
17
|
+
}
|
|
18
|
+
function wallTime(format, instant) {
|
|
19
|
+
const parts = Object.fromEntries(format.formatToParts(instant).filter(part => part.type !== "literal").map(part => [part.type, Number(part.value)]));
|
|
20
|
+
return Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute);
|
|
21
|
+
}
|
|
22
|
+
function localDay(format, instant) { return Math.floor(wallTime(format, instant) / DAY) * DAY; }
|
|
23
|
+
/** One occurrence per local date. A repeated time uses its first occurrence;
|
|
24
|
+
* a missing time advances by the DST gap. Entirely skipped dates have no fire. */
|
|
25
|
+
function occurrence(format, calendar, date) {
|
|
26
|
+
const [hour, minute] = calendar.localTime.split(":").map(Number);
|
|
27
|
+
const requested = date + hour * 3_600_000 + minute * 60_000;
|
|
28
|
+
const offsets = new Set();
|
|
29
|
+
for (let hours = -36; hours <= 36; hours += 6) {
|
|
30
|
+
const probe = requested + hours * 3_600_000;
|
|
31
|
+
offsets.add(wallTime(format, probe) - probe);
|
|
32
|
+
}
|
|
33
|
+
const candidates = [...offsets].map(offset => requested - offset).sort((a, b) => a - b);
|
|
34
|
+
const exact = candidates.find(instant => wallTime(format, instant) === requested);
|
|
35
|
+
if (exact !== undefined)
|
|
36
|
+
return exact;
|
|
37
|
+
const shifted = candidates.filter(instant => localDay(format, instant) === date && wallTime(format, instant) > requested);
|
|
38
|
+
return shifted.sort((a, b) => wallTime(format, a) - wallTime(format, b))[0] ?? null;
|
|
39
|
+
}
|
|
40
|
+
export function nextNightlyOccurrence(calendar, after) {
|
|
41
|
+
const parsed = NightlyScheduleSchema.parse(calendar);
|
|
42
|
+
const time = Date.parse(after);
|
|
43
|
+
if (!Number.isFinite(time))
|
|
44
|
+
throw new Error("A nightly schedule requires a valid timestamp.");
|
|
45
|
+
const format = formatter(parsed);
|
|
46
|
+
const date = localDay(format, time);
|
|
47
|
+
for (let days = 0; days < 4; days++) {
|
|
48
|
+
const candidate = occurrence(format, parsed, date + days * DAY);
|
|
49
|
+
if (candidate !== null && candidate > time)
|
|
50
|
+
return new Date(candidate).toISOString();
|
|
51
|
+
}
|
|
52
|
+
throw new Error("Unable to resolve the next nightly occurrence.");
|
|
53
|
+
}
|
|
54
|
+
export function coalesceNightlyOccurrences(calendar, due, now) {
|
|
55
|
+
const parsed = NightlyScheduleSchema.parse(calendar);
|
|
56
|
+
const format = formatter(parsed);
|
|
57
|
+
const time = Date.parse(now);
|
|
58
|
+
const date = localDay(format, time);
|
|
59
|
+
for (let days = 0; days < 4; days++) {
|
|
60
|
+
const candidate = occurrence(format, parsed, date - days * DAY);
|
|
61
|
+
if (candidate !== null && candidate <= time)
|
|
62
|
+
return {
|
|
63
|
+
coalescedThroughAt: new Date(candidate).toISOString(),
|
|
64
|
+
coalescedCount: Math.max(0, Math.round((localDay(format, candidate) - localDay(format, Date.parse(due))) / DAY)),
|
|
65
|
+
nextRunAt: nextNightlyOccurrence(parsed, now),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
throw new Error("Unable to resolve the due nightly occurrence.");
|
|
69
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { ReleaseHashSchema, ReleaseIdSchema, ReleaseTimestampSchema } from "@openpond/harness";
|
|
3
3
|
import { LearningRevisionRefSchema } from "./contracts.js";
|
|
4
|
+
import { NightlyScheduleSchema } from "./nightly-schedule.js";
|
|
4
5
|
/** The durable timer is operational state; every fire retains its own policy. */
|
|
5
6
|
export const LearningScheduleSchema = z.object({
|
|
6
7
|
schemaVersion: z.literal("openpond.learningSchedule.v1"),
|
|
@@ -11,6 +12,7 @@ export const LearningScheduleSchema = z.object({
|
|
|
11
12
|
executionOwner: z.enum(["local", "hosted"]),
|
|
12
13
|
state: z.enum(["scheduled", "disabled", "blocked"]),
|
|
13
14
|
intervalSeconds: z.number().int().min(60).max(31_536_000).nullable(),
|
|
15
|
+
calendar: NightlyScheduleSchema.nullable().default(null),
|
|
14
16
|
nextRunAt: ReleaseTimestampSchema.nullable(),
|
|
15
17
|
lastFire: LearningRevisionRefSchema.nullable(),
|
|
16
18
|
consecutiveFailures: z.number().int().nonnegative(),
|
|
@@ -19,10 +21,12 @@ export const LearningScheduleSchema = z.object({
|
|
|
19
21
|
createdAt: ReleaseTimestampSchema,
|
|
20
22
|
updatedAt: ReleaseTimestampSchema,
|
|
21
23
|
}).strict().superRefine((value, context) => {
|
|
22
|
-
if (value.state !== "disabled" && (!value.intervalSeconds || !value.nextRunAt))
|
|
24
|
+
if (value.state !== "disabled" && ((!value.intervalSeconds && !value.calendar) || !value.nextRunAt))
|
|
23
25
|
context.addIssue({ code: "custom", path: ["nextRunAt"], message: "An active timer must retain its cadence and due time." });
|
|
24
26
|
if (value.state === "disabled" && value.nextRunAt)
|
|
25
27
|
context.addIssue({ code: "custom", path: ["nextRunAt"], message: "A disabled timer cannot have a pending occurrence." });
|
|
28
|
+
if (value.intervalSeconds && value.calendar)
|
|
29
|
+
context.addIssue({ code: "custom", path: ["calendar"], message: "A timer uses either an interval or a nightly calendar." });
|
|
26
30
|
});
|
|
27
31
|
/** Immutable occurrence evidence survives timer edits and coalesced downtime. */
|
|
28
32
|
export const LearningScheduleFireSchema = z.object({
|
|
@@ -2,7 +2,8 @@ import { contentHash } from "@openpond/harness";
|
|
|
2
2
|
import { assertLearningContentHash, learningRef, sameLearningRef } from "./contracts.js";
|
|
3
3
|
import { LearningScheduleSchema } from "./schedule-contracts.js";
|
|
4
4
|
import { LearningDomainError } from "./errors.js";
|
|
5
|
-
import { requireLearningResource } from "./repository.js";
|
|
5
|
+
import { requireLearningRelease, requireLearningResource } from "./repository.js";
|
|
6
|
+
import { nextNightlyOccurrence } from "./nightly-schedule.js";
|
|
6
7
|
export function learningScheduleId(policyId) { return `schedule-${contentHash(policyId)}`; }
|
|
7
8
|
/** Called atomically with policy publication. No external timer or Work is made. */
|
|
8
9
|
export async function synchronizeLearningSchedule(tx, policy, now) {
|
|
@@ -14,15 +15,18 @@ export async function synchronizeLearningSchedule(tx, policy, now) {
|
|
|
14
15
|
const previous = await tx.get("schedule", id);
|
|
15
16
|
if (previous && sameLearningRef(previous.policy, learningRef(policy)))
|
|
16
17
|
return previous;
|
|
17
|
-
const intervalSeconds = policy.trigger.kind === "schedule" ? policy.trigger.intervalSeconds : null;
|
|
18
|
-
const
|
|
18
|
+
const intervalSeconds = policy.trigger.kind === "schedule" ? policy.trigger.intervalSeconds : policy.trigger.kind === "approved_count" ? 60 : null;
|
|
19
|
+
const calendar = policy.trigger.kind === "nightly" ? { localTime: policy.trigger.localTime, timeZone: policy.trigger.timeZone } : null;
|
|
20
|
+
const enabled = policy.enabled && policy.automation.train && (intervalSeconds !== null || calendar !== null);
|
|
21
|
+
const previousPolicy = previous ? await requireLearningRelease(tx, "policy", previous.policy) : null;
|
|
19
22
|
const preserveDue = previous?.nextRunAt && previous.intervalSeconds === intervalSeconds
|
|
23
|
+
&& JSON.stringify(previous.calendar) === JSON.stringify(calendar) && previousPolicy?.trigger.kind === policy.trigger.kind
|
|
20
24
|
&& previous.executionOwner === policy.executionOwner;
|
|
21
25
|
const schedule = LearningScheduleSchema.parse({
|
|
22
26
|
schemaVersion: "openpond.learningSchedule.v1", id, revision: (previous?.revision ?? 0) + 1,
|
|
23
27
|
policy: learningRef(policy), modelProjectId: policy.modelProjectId, executionOwner: policy.executionOwner,
|
|
24
|
-
state: enabled ? "scheduled" : "disabled", intervalSeconds,
|
|
25
|
-
nextRunAt: enabled ? preserveDue ? previous.nextRunAt : new Date(Date.parse(now) + intervalSeconds * 1_000).toISOString() : null,
|
|
28
|
+
state: enabled ? "scheduled" : "disabled", intervalSeconds, calendar,
|
|
29
|
+
nextRunAt: enabled ? preserveDue ? previous.nextRunAt : calendar ? nextNightlyOccurrence(calendar, now) : new Date(Date.parse(now) + intervalSeconds * 1_000).toISOString() : null,
|
|
26
30
|
lastFire: previous?.lastFire ?? null, consecutiveFailures: 0, nextAttemptAt: null, lastError: null,
|
|
27
31
|
createdAt: previous?.createdAt ?? now, updatedAt: now,
|
|
28
32
|
});
|
|
@@ -4,6 +4,8 @@ import { LearningDomainError } from "./errors.js";
|
|
|
4
4
|
import { reserveLearningIteration } from "./iteration-reservation-service.js";
|
|
5
5
|
import { LearningScheduleFireSchema, LearningScheduleSchema } from "./schedule-contracts.js";
|
|
6
6
|
import { requireLearningRelease, requireLearningResource } from "./repository.js";
|
|
7
|
+
import { inspectIterationEligibility } from "./iteration-eligibility.js";
|
|
8
|
+
import { coalesceNightlyOccurrences } from "./nightly-schedule.js";
|
|
7
9
|
const skipReasons = new Map([
|
|
8
10
|
["learning_iteration_active", "active_iteration"], ["learning_iteration_cooldown", "cooldown"],
|
|
9
11
|
["learning_daily_budget_exhausted", "daily_budget"],
|
|
@@ -28,20 +30,33 @@ export function createLearningScheduleWorker(repository, options) {
|
|
|
28
30
|
attempt = { schedule, maxRetries: 0 };
|
|
29
31
|
const policy = await requireLearningRelease(tx, "policy", schedule.policy);
|
|
30
32
|
attempt.maxRetries = policy.limits.maxRetries;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
const matches = policy.trigger.kind === "nightly" ? schedule.intervalSeconds === null && schedule.calendar?.localTime === policy.trigger.localTime && schedule.calendar.timeZone === policy.trigger.timeZone
|
|
34
|
+
: policy.trigger.kind === "schedule" ? schedule.calendar === null && policy.trigger.intervalSeconds === schedule.intervalSeconds
|
|
35
|
+
: policy.trigger.kind === "approved_count" && schedule.calendar === null && schedule.intervalSeconds === 60;
|
|
36
|
+
if (policy.executionOwner !== schedule.executionOwner || !matches)
|
|
33
37
|
throw new LearningDomainError("learning_schedule_policy_mismatch", 409);
|
|
34
38
|
const scheduledAt = schedule.nextRunAt;
|
|
35
|
-
const interval = schedule.intervalSeconds * 1_000;
|
|
39
|
+
const interval = (schedule.intervalSeconds ?? 86_400) * 1_000;
|
|
36
40
|
const due = Date.parse(scheduledAt);
|
|
37
41
|
const coalescedCount = Math.floor((time - due) / interval);
|
|
42
|
+
const occurrence = schedule.calendar ? coalesceNightlyOccurrences(schedule.calendar, scheduledAt, timestamp) : {
|
|
43
|
+
coalescedCount, coalescedThroughAt: new Date(due + coalescedCount * interval).toISOString(), nextRunAt: new Date(due + (coalescedCount + 1) * interval).toISOString(),
|
|
44
|
+
};
|
|
45
|
+
// Below-threshold count checks advance their timer without filling the
|
|
46
|
+
// Model's history with empty iterations or consuming any evidence.
|
|
47
|
+
if (policy.trigger.kind === "approved_count" && (await inspectIterationEligibility(tx, policy)).counts.eligible < policy.admission.minimumApprovedExamples) {
|
|
48
|
+
const updated = LearningScheduleSchema.parse({ ...schedule, revision: schedule.revision + 1, nextRunAt: occurrence.nextRunAt,
|
|
49
|
+
consecutiveFailures: 0, nextAttemptAt: null, lastError: null, updatedAt: timestamp });
|
|
50
|
+
await tx.put("schedule", updated, schedule.revision, { parentId: schedule.modelProjectId, status: updated.state });
|
|
51
|
+
return updated;
|
|
52
|
+
}
|
|
38
53
|
const id = `schedule-fire-${contentHash([schedule.id, scheduledAt])}`;
|
|
39
54
|
let outcome = "skipped";
|
|
40
55
|
let reason = null;
|
|
41
56
|
let iteration = null;
|
|
42
57
|
try {
|
|
43
58
|
const pointers = await reserveLearningIteration(tx, { action: "reserve_iteration", operationId: id,
|
|
44
|
-
policy: schedule.policy, trigger: { kind: "schedule", scheduledAt } }, actorId, timestamp);
|
|
59
|
+
policy: schedule.policy, trigger: policy.trigger.kind === "approved_count" ? { kind: "approved_count", checkedAt: scheduledAt } : { kind: "schedule", scheduledAt } }, actorId, timestamp);
|
|
45
60
|
const pointer = pointers.find(value => value.kind === "iteration");
|
|
46
61
|
if (!pointer)
|
|
47
62
|
throw new LearningDomainError("learning_schedule_reservation_missing", 409);
|
|
@@ -59,12 +74,12 @@ export function createLearningScheduleWorker(repository, options) {
|
|
|
59
74
|
}
|
|
60
75
|
const fire = LearningScheduleFireSchema.parse(sealLearningContent({
|
|
61
76
|
schemaVersion: "openpond.learningScheduleFire.v1", id, revision: 1, scheduleId,
|
|
62
|
-
policy: schedule.policy, scheduledAt, coalescedThroughAt:
|
|
63
|
-
coalescedCount, outcome, reason, iteration, createdAt: timestamp,
|
|
77
|
+
policy: schedule.policy, scheduledAt, coalescedThroughAt: occurrence.coalescedThroughAt,
|
|
78
|
+
coalescedCount: occurrence.coalescedCount, outcome, reason, iteration, createdAt: timestamp,
|
|
64
79
|
}));
|
|
65
80
|
await tx.put("schedule_fire", fire, 0, { parentId: schedule.id, status: outcome });
|
|
66
81
|
const updated = LearningScheduleSchema.parse({ ...schedule, revision: schedule.revision + 1,
|
|
67
|
-
nextRunAt:
|
|
82
|
+
nextRunAt: occurrence.nextRunAt, lastFire: learningRef(fire),
|
|
68
83
|
consecutiveFailures: 0, nextAttemptAt: null, lastError: null, updatedAt: timestamp });
|
|
69
84
|
await tx.put("schedule", updated, schedule.revision, { parentId: schedule.modelProjectId, status: updated.state });
|
|
70
85
|
return updated;
|
package/dist/learning/service.js
CHANGED
|
@@ -9,6 +9,8 @@ import { assertRewardCalibration, qualifyRewardCheck } from "./reward-calibratio
|
|
|
9
9
|
import { queueRewardCheck, cancelRewardCheck } from "./reward-check-service.js";
|
|
10
10
|
import { LearningDomainError } from "./errors.js";
|
|
11
11
|
import { contentHash } from "@openpond/harness";
|
|
12
|
+
import { inspectLearningTaskQueue } from "./task-queue-inspection.js";
|
|
13
|
+
import { LearningReadRequestSchema } from "./transport.js";
|
|
12
14
|
import { createRewardBinding, createRewardRelease } from "../rewards.js";
|
|
13
15
|
import { assertBoundedTaskJson, validateTaskValue } from "../task-schema.js";
|
|
14
16
|
import { assertAdmissionDecision, assertGradeIdentity, inspectTaskEvidence } from "./admission.js";
|
|
@@ -360,6 +362,13 @@ export function createLearningService(repository, options = {}) {
|
|
|
360
362
|
}
|
|
361
363
|
return {
|
|
362
364
|
command,
|
|
365
|
+
async inspectTaskQueue(context, modelProjectId = null) {
|
|
366
|
+
authorizeRead(context);
|
|
367
|
+
const input = LearningReadRequestSchema.parse({ action: "inspect_task_queue", scope: context.scope, modelProjectId });
|
|
368
|
+
if (input.action !== "inspect_task_queue")
|
|
369
|
+
throw new LearningDomainError("learning_request_invalid", 400);
|
|
370
|
+
return repository.transaction(context.scope, transaction => inspectLearningTaskQueue(transaction, input.modelProjectId, now()));
|
|
371
|
+
},
|
|
363
372
|
async inspectPolicy(context, reference) {
|
|
364
373
|
authorizeRead(context);
|
|
365
374
|
const ref = LearningRevisionRefSchema.parse(reference);
|
|
@@ -407,7 +416,7 @@ function authorize(context, input) {
|
|
|
407
416
|
throw new LearningDomainError("learning_scope_required", 400);
|
|
408
417
|
const publications = input.action === "publish" ? [input] : input.action === "publish_resources" ? input.resources : [];
|
|
409
418
|
if (context.actor.role !== "reviewer" && publications.some(value => value.kind === "policy" && value.content.enabled
|
|
410
|
-
&& value.content.automation.train && value.content.trigger.kind
|
|
419
|
+
&& value.content.automation.train && value.content.trigger.kind !== "manual"))
|
|
411
420
|
throw new LearningDomainError("learning_review_not_authorized", 403);
|
|
412
421
|
if (context.actor.role === "source") {
|
|
413
422
|
const sourceId = input.action === "submit_example" ? input.example.sourceId : input.action === "submit_feedback" ? input.feedback.sourceId : null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ReleaseIdSchema, ReleaseTimestampSchema } from "@openpond/harness";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { LearningDomainError } from "./errors.js";
|
|
4
|
+
import { inspectIterationEligibility } from "./iteration-eligibility.js";
|
|
5
|
+
import { taskFamilyReservations } from "./admission.js";
|
|
6
|
+
import { requireLearningRelease } from "./repository.js";
|
|
7
|
+
export const LearningTaskQueueInspectionSchema = z.object({
|
|
8
|
+
modelProjectId: ReleaseIdSchema.nullable(),
|
|
9
|
+
inspectedAt: ReleaseTimestampSchema,
|
|
10
|
+
pendingTrainingCount: z.number().int().nonnegative().nullable(),
|
|
11
|
+
issues: z.array(z.object({ policyId: ReleaseIdSchema, code: z.string(), message: z.string() }).strict()),
|
|
12
|
+
}).strict();
|
|
13
|
+
/** Count exact eligible, unconsumed attempts once across selected policies.
|
|
14
|
+
* Paused policies still have pending work; review-only and held-out tasks do not. */
|
|
15
|
+
export async function inspectLearningTaskQueue(transaction, modelProjectId, now) {
|
|
16
|
+
const eligible = new Set();
|
|
17
|
+
const issues = [];
|
|
18
|
+
let afterId;
|
|
19
|
+
do {
|
|
20
|
+
const page = await transaction.list("policy", { limit: 100, ...(modelProjectId ? { parentId: modelProjectId } : {}), ...(afterId ? { afterId } : {}) });
|
|
21
|
+
for (const policy of page.items) {
|
|
22
|
+
try {
|
|
23
|
+
const inspection = await inspectIterationEligibility(transaction, policy, { collectEligible: true });
|
|
24
|
+
const definition = await requireLearningRelease(transaction, "definition", policy.taskDefinition);
|
|
25
|
+
for (const reference of inspection.eligibleEvidence) {
|
|
26
|
+
const evidence = await requireLearningRelease(transaction, "evidence", reference);
|
|
27
|
+
let heldOut = false;
|
|
28
|
+
for (const family of taskFamilyReservations(evidence, definition)) {
|
|
29
|
+
const split = await transaction.familySplit(family.namespace, family.kind, family.key);
|
|
30
|
+
if (split !== null && split !== "train") {
|
|
31
|
+
heldOut = true;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (!heldOut)
|
|
36
|
+
eligible.add(JSON.stringify([reference.id, reference.revision, reference.contentHash]));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (!(error instanceof LearningDomainError))
|
|
41
|
+
throw error;
|
|
42
|
+
issues.push({ policyId: policy.id, code: error.code, message: error.message });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
afterId = page.nextCursor ?? undefined;
|
|
46
|
+
} while (afterId);
|
|
47
|
+
return LearningTaskQueueInspectionSchema.parse({ modelProjectId, inspectedAt: now, pendingTrainingCount: issues.length ? null : eligible.size, issues });
|
|
48
|
+
}
|
|
@@ -17,6 +17,7 @@ export function assertLearningRequestJson(raw) {
|
|
|
17
17
|
/** Scope selection is never authorization; each host resolves its authenticated owner. */
|
|
18
18
|
export const LearningCommandRequestSchema = z.object({ scope: ReleaseIdSchema, command: LearningCommandSchema }).strict();
|
|
19
19
|
export const LearningReadRequestSchema = z.discriminatedUnion("action", [
|
|
20
|
+
z.object({ action: z.literal("inspect_task_queue"), scope: ReleaseIdSchema, modelProjectId: ReleaseIdSchema.nullable() }).strict(),
|
|
20
21
|
z.object({ action: z.literal("inspect_policy"), scope: ReleaseIdSchema, policy: LearningRevisionRefSchema }).strict(),
|
|
21
22
|
z.object({ action: z.literal("inspect_evidence"), scope: ReleaseIdSchema, evidence: LearningRevisionRefSchema }).strict(),
|
|
22
23
|
z.object({ action: z.literal("get"), scope: ReleaseIdSchema, kind: LearningResourceKindSchema, id: ReleaseIdSchema, revision: z.number().int().positive().optional() }).strict(),
|
|
@@ -1198,6 +1198,10 @@ export declare const LearningPolicyContentSchema: z.ZodObject<{
|
|
|
1198
1198
|
}, z.core.$strict>, z.ZodObject<{
|
|
1199
1199
|
kind: z.ZodLiteral<"schedule">;
|
|
1200
1200
|
intervalSeconds: z.ZodNumber;
|
|
1201
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
1202
|
+
localTime: z.ZodString;
|
|
1203
|
+
timeZone: z.ZodString;
|
|
1204
|
+
kind: z.ZodLiteral<"nightly">;
|
|
1201
1205
|
}, z.core.$strict>, z.ZodObject<{
|
|
1202
1206
|
kind: z.ZodLiteral<"upstream_accepted">;
|
|
1203
1207
|
modelProjectId: z.ZodString;
|
|
@@ -1301,6 +1305,10 @@ export declare const LearningPolicySchema: z.ZodObject<{
|
|
|
1301
1305
|
}, z.core.$strict>, z.ZodObject<{
|
|
1302
1306
|
kind: z.ZodLiteral<"schedule">;
|
|
1303
1307
|
intervalSeconds: z.ZodNumber;
|
|
1308
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
1309
|
+
localTime: z.ZodString;
|
|
1310
|
+
timeZone: z.ZodString;
|
|
1311
|
+
kind: z.ZodLiteral<"nightly">;
|
|
1304
1312
|
}, z.core.$strict>, z.ZodObject<{
|
|
1305
1313
|
kind: z.ZodLiteral<"upstream_accepted">;
|
|
1306
1314
|
modelProjectId: z.ZodString;
|
|
@@ -2375,6 +2383,10 @@ export declare const LearningResourceSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
2375
2383
|
}, z.core.$strict>, z.ZodObject<{
|
|
2376
2384
|
kind: z.ZodLiteral<"schedule">;
|
|
2377
2385
|
intervalSeconds: z.ZodNumber;
|
|
2386
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
2387
|
+
localTime: z.ZodString;
|
|
2388
|
+
timeZone: z.ZodString;
|
|
2389
|
+
kind: z.ZodLiteral<"nightly">;
|
|
2378
2390
|
}, z.core.$strict>, z.ZodObject<{
|
|
2379
2391
|
kind: z.ZodLiteral<"upstream_accepted">;
|
|
2380
2392
|
modelProjectId: z.ZodString;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../../../../src/learning/contracts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../../../../src/learning/contracts.ts"],"names":[],"mappings":"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C;AAEZ,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAoBpB,CAAC;AAEZ,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oBAA2P,CAAC;AAE/R,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAChF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAClF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAChF,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AACxD,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AACxE,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACtE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E,wBAAgB,WAAW,CAAC,QAAQ,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,mBAAmB,CAEhH;AACD,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAE9F;AACD,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,CAG9G;AACD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAIjF"}
|
|
@@ -29,5 +29,7 @@ export { resolveLearningTrainingParent } from "./iteration-training-parent.js";
|
|
|
29
29
|
export * from "./schedule-contracts.js";
|
|
30
30
|
export * from "./schedule-service.js";
|
|
31
31
|
export * from "./schedule-worker.js";
|
|
32
|
+
export * from "./nightly-schedule.js";
|
|
32
33
|
export * from "./policy-inspection.js";
|
|
34
|
+
export * from "./task-queue-inspection.js";
|
|
33
35
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/learning/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/learning/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,OAAO,EAAE,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAC/E,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC"}
|
|
@@ -2,7 +2,9 @@ import { type LearningPolicy, type TaskAdmissionDecision, type TaskEvidence } fr
|
|
|
2
2
|
import { type LearningTransaction } from "./repository.js";
|
|
3
3
|
export declare function learningChainId(modelProjectId: string): string;
|
|
4
4
|
export declare function learningConsumptionId(chainId: string, evidence: TaskEvidence): string;
|
|
5
|
-
export declare function inspectIterationEligibility(transaction: LearningTransaction, policy: LearningPolicy
|
|
5
|
+
export declare function inspectIterationEligibility(transaction: LearningTransaction, policy: LearningPolicy, options?: {
|
|
6
|
+
collectEligible?: boolean;
|
|
7
|
+
}): Promise<{
|
|
6
8
|
counts: {
|
|
7
9
|
eligible: number;
|
|
8
10
|
awaitingReview: number;
|
|
@@ -14,5 +16,10 @@ export declare function inspectIterationEligibility(transaction: LearningTransac
|
|
|
14
16
|
decision: TaskAdmissionDecision;
|
|
15
17
|
}[];
|
|
16
18
|
purpose: "supervised_training" | "reward_training";
|
|
19
|
+
eligibleEvidence: {
|
|
20
|
+
id: string;
|
|
21
|
+
contentHash: string;
|
|
22
|
+
revision: number;
|
|
23
|
+
}[];
|
|
17
24
|
}>;
|
|
18
25
|
//# sourceMappingURL=iteration-eligibility.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iteration-eligibility.d.ts","sourceRoot":"","sources":["../../../../../src/learning/iteration-eligibility.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgC,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAkB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGlJ,OAAO,EAAmD,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE5G,wBAAgB,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,MAAM,CAErF;AAED,wBAAsB,2BAA2B,CAAC,WAAW,EAAE,mBAAmB,EAAE,MAAM,EAAE,cAAc;;;;;;;;
|
|
1
|
+
{"version":3,"file":"iteration-eligibility.d.ts","sourceRoot":"","sources":["../../../../../src/learning/iteration-eligibility.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgC,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAkB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGlJ,OAAO,EAAmD,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAE5G,wBAAgB,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,MAAM,CAErF;AAED,wBAAsB,2BAA2B,CAAC,WAAW,EAAE,mBAAmB,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAO;;;;;;;;kBAYzH,YAAY;kBAAY,qBAAqB;;;;;;;;GA6C1E"}
|
|
@@ -5,6 +5,9 @@ export declare const LearningIterationTriggerSchema: z.ZodDiscriminatedUnion<[z.
|
|
|
5
5
|
}, z.core.$strict>, z.ZodObject<{
|
|
6
6
|
kind: z.ZodLiteral<"schedule">;
|
|
7
7
|
scheduledAt: z.ZodString;
|
|
8
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
9
|
+
kind: z.ZodLiteral<"approved_count">;
|
|
10
|
+
checkedAt: z.ZodString;
|
|
8
11
|
}, z.core.$strict>], "kind">;
|
|
9
12
|
/** Stable across policy edits: a Model owns one learning chain in its scope. */
|
|
10
13
|
export declare const LearningChainSchema: z.ZodObject<{
|
|
@@ -75,6 +78,9 @@ export declare const LearningIterationReservationSchema: z.ZodObject<{
|
|
|
75
78
|
}, z.core.$strict>, z.ZodObject<{
|
|
76
79
|
kind: z.ZodLiteral<"schedule">;
|
|
77
80
|
scheduledAt: z.ZodString;
|
|
81
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
82
|
+
kind: z.ZodLiteral<"approved_count">;
|
|
83
|
+
checkedAt: z.ZodString;
|
|
78
84
|
}, z.core.$strict>], "kind">;
|
|
79
85
|
requestHash: z.ZodString;
|
|
80
86
|
outcome: z.ZodEnum<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iteration-reservation-contracts.d.ts","sourceRoot":"","sources":["../../../../../src/learning/iteration-reservation-contracts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,8BAA8B
|
|
1
|
+
{"version":3,"file":"iteration-reservation-contracts.d.ts","sourceRoot":"","sources":["../../../../../src/learning/iteration-reservation-contracts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,8BAA8B;;;;;;;;;4BAIzC,CAAC;AAEH,gFAAgF;AAChF,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;kBAUrB,CAAC;AAEZ,eAAO,MAAM,+BAA+B;;;;;kBAKjC,CAAC;AAEZ;qFACqF;AACrF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;kBAS3B,CAAC;AAEZ,uFAAuF;AACvF,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAmBpC,CAAC;AAEZ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAChE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAC9F,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,8BAA8B,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iteration-reservation-service.d.ts","sourceRoot":"","sources":["../../../../../src/learning/iteration-reservation-service.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAmD,KAAK,uBAAuB,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG1I,KAAK,cAAc,GAAG,OAAO,CAAC,eAAe,EAAE;IAAE,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAC,CAAC;AAEhF,kFAAkF;AAClF,wBAAsB,wBAAwB,CAAC,WAAW,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"iteration-reservation-service.d.ts","sourceRoot":"","sources":["../../../../../src/learning/iteration-reservation-service.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAmD,KAAK,uBAAuB,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG1I,KAAK,cAAc,GAAG,OAAO,CAAC,eAAe,EAAE;IAAE,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAC,CAAC;AAEhF,kFAAkF;AAClF,wBAAsB,wBAAwB,CAAC,WAAW,EAAE,mBAAmB,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAmFxK"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const NightlyScheduleSchema: z.ZodObject<{
|
|
3
|
+
localTime: z.ZodString;
|
|
4
|
+
timeZone: z.ZodString;
|
|
5
|
+
}, z.core.$strict>;
|
|
6
|
+
export type NightlySchedule = z.infer<typeof NightlyScheduleSchema>;
|
|
7
|
+
export declare function nextNightlyOccurrence(calendar: NightlySchedule, after: string): string;
|
|
8
|
+
export declare function coalesceNightlyOccurrences(calendar: NightlySchedule, due: string, now: string): {
|
|
9
|
+
coalescedThroughAt: string;
|
|
10
|
+
coalescedCount: number;
|
|
11
|
+
nextRunAt: string;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=nightly-schedule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nightly-schedule.d.ts","sourceRoot":"","sources":["../../../../../src/learning/nightly-schedule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,qBAAqB;;;kBAKvB,CAAC;AACZ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AA6BpE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAWtF;AAED,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;;;;EAc7F"}
|