@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.
Files changed (46) hide show
  1. package/LEARNING.md +20 -0
  2. package/dist/learning/contracts.js +2 -0
  3. package/dist/learning/index.js +2 -0
  4. package/dist/learning/iteration-eligibility.js +5 -2
  5. package/dist/learning/iteration-reservation-contracts.js +1 -0
  6. package/dist/learning/iteration-reservation-service.js +11 -2
  7. package/dist/learning/nightly-schedule.js +69 -0
  8. package/dist/learning/schedule-contracts.js +5 -1
  9. package/dist/learning/schedule-service.js +9 -5
  10. package/dist/learning/schedule-worker.js +22 -7
  11. package/dist/learning/service.js +10 -1
  12. package/dist/learning/task-queue-inspection.js +48 -0
  13. package/dist/learning/transport.js +1 -0
  14. package/dist/types/learning/contracts.d.ts +12 -0
  15. package/dist/types/learning/contracts.d.ts.map +1 -1
  16. package/dist/types/learning/index.d.ts +2 -0
  17. package/dist/types/learning/index.d.ts.map +1 -1
  18. package/dist/types/learning/iteration-eligibility.d.ts +8 -1
  19. package/dist/types/learning/iteration-eligibility.d.ts.map +1 -1
  20. package/dist/types/learning/iteration-reservation-contracts.d.ts +6 -0
  21. package/dist/types/learning/iteration-reservation-contracts.d.ts.map +1 -1
  22. package/dist/types/learning/iteration-reservation-service.d.ts.map +1 -1
  23. package/dist/types/learning/nightly-schedule.d.ts +13 -0
  24. package/dist/types/learning/nightly-schedule.d.ts.map +1 -0
  25. package/dist/types/learning/operations.d.ts +22 -0
  26. package/dist/types/learning/operations.d.ts.map +1 -1
  27. package/dist/types/learning/repository.d.ts +11 -0
  28. package/dist/types/learning/repository.d.ts.map +1 -1
  29. package/dist/types/learning/schedule-contracts.d.ts +4 -0
  30. package/dist/types/learning/schedule-contracts.d.ts.map +1 -1
  31. package/dist/types/learning/schedule-service.d.ts +4 -0
  32. package/dist/types/learning/schedule-service.d.ts.map +1 -1
  33. package/dist/types/learning/schedule-worker.d.ts.map +1 -1
  34. package/dist/types/learning/service.d.ts +10 -0
  35. package/dist/types/learning/service.d.ts.map +1 -1
  36. package/dist/types/learning/task-queue-inspection.d.ts +25 -0
  37. package/dist/types/learning/task-queue-inspection.d.ts.map +1 -0
  38. package/dist/types/learning/transport.d.ts +26 -0
  39. package/dist/types/learning/transport.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/schemas/learning/v1/command-request.schema.json +41 -0
  42. package/schemas/learning/v1/policy.schema.json +24 -0
  43. package/schemas/learning/v1/read-request.schema.json +28 -0
  44. package/schemas/learning/v1/reservation.schema.json +17 -0
  45. package/schemas/learning/v1/schedule.schema.json +44 -13
  46. 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,
@@ -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() } : input.trigger;
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 !== "schedule" || !policy.automation.train)
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 enabled = policy.enabled && policy.automation.train && intervalSeconds !== null;
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
- if (policy.executionOwner !== schedule.executionOwner || policy.trigger.kind !== "schedule"
32
- || policy.trigger.intervalSeconds !== schedule.intervalSeconds)
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: new Date(due + coalescedCount * interval).toISOString(),
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: new Date(due + (coalescedCount + 1) * interval).toISOString(), lastFire: learningRef(fire),
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;
@@ -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 === "schedule"))
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":"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AAO,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"}
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): Promise<{
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;;;;;;;;kBAY5E,YAAY;kBAAY,qBAAqB;;;GA2C1E"}
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;;;;;;4BAGzC,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
+ {"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,CA6ExK"}
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"}