@openpond/evals 0.10.6 → 0.10.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LEARNING.md +18 -0
- package/dist/learning/authoring-service.js +11 -1
- package/dist/learning/authoring.js +1 -0
- package/dist/learning/contracts.js +36 -1
- package/dist/learning/index.js +2 -0
- package/dist/learning/iteration-candidate-decision.js +12 -7
- package/dist/learning/iteration-reservation-contracts.js +2 -1
- package/dist/learning/iteration-reservation-service.js +5 -1
- package/dist/learning/iteration-training-parent.js +47 -0
- package/dist/learning/policy-inspection.js +15 -3
- package/dist/learning/rating-reward-fixture.js +19 -0
- package/dist/learning/service.js +7 -2
- package/dist/learning/transport.js +1 -1
- package/dist/types/learning/authoring-service.d.ts +11 -0
- package/dist/types/learning/authoring-service.d.ts.map +1 -1
- package/dist/types/learning/authoring.d.ts +55 -0
- package/dist/types/learning/authoring.d.ts.map +1 -1
- package/dist/types/learning/contracts.d.ts +75 -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-candidate-decision.d.ts +16 -0
- package/dist/types/learning/iteration-candidate-decision.d.ts.map +1 -1
- package/dist/types/learning/iteration-reservation-contracts.d.ts +14 -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/iteration-training-parent.d.ts +37 -0
- package/dist/types/learning/iteration-training-parent.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/policy-inspection.d.ts +34 -0
- package/dist/types/learning/policy-inspection.d.ts.map +1 -1
- package/dist/types/learning/rating-reward-fixture.d.ts +8 -0
- package/dist/types/learning/rating-reward-fixture.d.ts.map +1 -0
- package/dist/types/learning/repository.d.ts +50 -0
- package/dist/types/learning/repository.d.ts.map +1 -1
- package/dist/types/learning/service.d.ts +34 -0
- package/dist/types/learning/service.d.ts.map +1 -1
- package/dist/types/learning/transport.d.ts +64 -0
- package/dist/types/learning/transport.d.ts.map +1 -1
- package/package.json +1 -1
- package/schemas/learning/v1/chain.schema.json +75 -2
- package/schemas/learning/v1/command-request.schema.json +63 -20
- package/schemas/learning/v1/draft.schema.json +31 -0
- package/schemas/learning/v1/feedback-submission.schema.json +55 -37
- package/schemas/learning/v1/feedback.schema.json +94 -38
- package/schemas/learning/v1/iteration.schema.json +47 -0
- package/schemas/learning/v1/policy-inspection.schema.json +127 -33
- package/schemas/learning/v1/read-request.schema.json +7 -0
package/LEARNING.md
CHANGED
|
@@ -79,6 +79,24 @@ for untrusted schemas and deliberately rejects unsupported capabilities.
|
|
|
79
79
|
|
|
80
80
|
## Host responsibilities
|
|
81
81
|
|
|
82
|
+
### Accepted checkpoints between iterations
|
|
83
|
+
|
|
84
|
+
Candidate decisions are reconciled with their verified `decidedAt`, immutable
|
|
85
|
+
decision reference, execution, evaluation and terminal receipt. The chain records
|
|
86
|
+
the latest accepted candidate. New reservations capture its exact accepted
|
|
87
|
+
iteration revision in `trainingParentSelection`; `trainingParent` becomes that
|
|
88
|
+
candidate's artifact reference. Before the first acceptance, the configured base
|
|
89
|
+
parent is used. A rejected candidate is removed from future parent selection;
|
|
90
|
+
already reserved iterations keep their captured parent and original review.
|
|
91
|
+
|
|
92
|
+
`inspectPolicy` returns the resolved next `trainingParent`, or a blocker when its
|
|
93
|
+
accepted evidence or underlying model/method is incompatible. Execution owners
|
|
94
|
+
must resolve the captured iteration revision, verify the team/Model-scoped
|
|
95
|
+
terminal checkpoint and materialize it through their existing continuation
|
|
96
|
+
adapter. The hosted adapter uses fresh optimizer state. Acceptance does not
|
|
97
|
+
activate serving. Candidate decisions lacking verified timing must be reconciled
|
|
98
|
+
from their retained provider receipts before another reservation can use them.
|
|
99
|
+
|
|
82
100
|
### Reward fixture checks
|
|
83
101
|
|
|
84
102
|
Reward drafts may contain up to 50 named fixtures. JSON and numeric editor fields
|
|
@@ -2,7 +2,7 @@ import { assertBoundedTaskJson } from "../task-schema.js";
|
|
|
2
2
|
import { AuthoringDraftSchema } from "./authoring.js";
|
|
3
3
|
import { LearningDomainError } from "./errors.js";
|
|
4
4
|
import { learningRef, sameLearningRef, sealLearningContent } from "./contracts.js";
|
|
5
|
-
import { requireLearningRelease } from "./repository.js";
|
|
5
|
+
import { requireLearningRelease, requireLearningResource } from "./repository.js";
|
|
6
6
|
export async function saveAuthoringDraft(tx, input, now) {
|
|
7
7
|
// A 100-record page remains below the common 16 MiB response limit.
|
|
8
8
|
assertBoundedTaskJson(input.draft, 131_072);
|
|
@@ -14,6 +14,16 @@ export async function saveAuthoringDraft(tx, input, now) {
|
|
|
14
14
|
throw new LearningDomainError("authoring_draft_base_mismatch", 422);
|
|
15
15
|
await requireLearningRelease(tx, input.draft.targetKind, input.draft.baseRelease);
|
|
16
16
|
}
|
|
17
|
+
if (input.draft.targetKind === "reward")
|
|
18
|
+
for (const fixture of input.draft.fields.fixtures ?? []) {
|
|
19
|
+
if (!fixture.sourceLabel)
|
|
20
|
+
continue;
|
|
21
|
+
const { evidence, feedback } = fixture.sourceLabel;
|
|
22
|
+
await requireLearningRelease(tx, "evidence", evidence);
|
|
23
|
+
const label = await requireLearningResource(tx, "feedback", feedback.id, feedback.revision);
|
|
24
|
+
if (!label.evidence || !sameLearningRef(label.evidence, evidence))
|
|
25
|
+
throw new LearningDomainError("reward_fixture_label_mismatch", 422);
|
|
26
|
+
}
|
|
17
27
|
const draft = AuthoringDraftSchema.parse(sealLearningContent({ ...input.draft, schemaVersion: "openpond.authoringDraft.v1", revision: input.expectedRevision + 1, status: "draft", publishedRelease: null, createdAt: previous?.createdAt ?? now, updatedAt: now }));
|
|
18
28
|
await tx.put("draft", draft, input.expectedRevision, { parentId: draft.targetKind, status: draft.status });
|
|
19
29
|
return { kind: "draft", id: draft.id, revision: draft.revision };
|
|
@@ -10,6 +10,7 @@ export const RewardFixtureAuthoringFieldsSchema = z.object({
|
|
|
10
10
|
infrastructureError: z.string().max(20_000),
|
|
11
11
|
expectedStatus: z.enum(["scored", "pending", "unavailable", "failed"]),
|
|
12
12
|
minimumScore: z.string(), maximumScore: z.string(), expectedPassed: z.enum(["true", "false", "any"]),
|
|
13
|
+
sourceLabel: z.object({ evidence: LearningRevisionRefSchema, feedback: z.object({ id: ReleaseIdSchema, revision: z.number().int().positive() }).strict() }).strict().optional(),
|
|
13
14
|
}).strict();
|
|
14
15
|
export const RewardAuthoringFieldsSchema = z.object({
|
|
15
16
|
name: z.string().max(500), description: z.string().max(10_000),
|
|
@@ -105,6 +105,20 @@ export const TaskEvidenceContentSchema = z.object({
|
|
|
105
105
|
receivedAt: ReleaseTimestampSchema,
|
|
106
106
|
}).strict();
|
|
107
107
|
export const TaskEvidenceSchema = TaskEvidenceContentSchema.extend({ contentHash: ReleaseHashSchema }).strict();
|
|
108
|
+
/** A retained judgment of this exact attempt, separate from task admission. */
|
|
109
|
+
export const TaskRatingSchema = z.object({
|
|
110
|
+
schemaVersion: z.literal("openpond.taskRating.v1"),
|
|
111
|
+
criteria: z.string().trim().min(1).max(20_000),
|
|
112
|
+
scale: z.object({ minimum: z.number().finite(), maximum: z.number().finite() }).strict(),
|
|
113
|
+
score: z.number().finite(),
|
|
114
|
+
evidence: z.string().max(20_000),
|
|
115
|
+
explanation: z.string().max(20_000),
|
|
116
|
+
}).strict().superRefine((rating, context) => {
|
|
117
|
+
if (rating.scale.minimum >= rating.scale.maximum)
|
|
118
|
+
context.addIssue({ code: "custom", path: ["scale"], message: "The score scale must have an increasing range." });
|
|
119
|
+
if (rating.score < rating.scale.minimum || rating.score > rating.scale.maximum)
|
|
120
|
+
context.addIssue({ code: "custom", path: ["score"], message: "The score must be within its declared scale." });
|
|
121
|
+
});
|
|
108
122
|
export const TaskFeedbackSubmissionSchema = z.object({
|
|
109
123
|
schemaVersion: z.literal("openpond.taskFeedback.v1"),
|
|
110
124
|
sourceId: ReleaseIdSchema,
|
|
@@ -116,7 +130,18 @@ export const TaskFeedbackSubmissionSchema = z.object({
|
|
|
116
130
|
kind: z.enum(["outcome", "target_correction", "ground_truth_correction", "input_correction", "family_resolution"]),
|
|
117
131
|
value: LearningJsonObjectSchema,
|
|
118
132
|
note: z.string().max(20_000),
|
|
119
|
-
}).strict()
|
|
133
|
+
}).strict().superRefine((submission, context) => {
|
|
134
|
+
if (submission.value.schemaVersion !== "openpond.taskRating.v1")
|
|
135
|
+
return;
|
|
136
|
+
if (submission.expectedEvidenceHash === null)
|
|
137
|
+
context.addIssue({ code: "custom", path: ["expectedEvidenceHash"], message: "A rating must identify the exact evidence revision." });
|
|
138
|
+
if (submission.kind !== "outcome")
|
|
139
|
+
context.addIssue({ code: "custom", path: ["kind"], message: "Ratings must be submitted as outcomes." });
|
|
140
|
+
const rating = TaskRatingSchema.safeParse(submission.value);
|
|
141
|
+
if (!rating.success)
|
|
142
|
+
for (const issue of rating.error.issues)
|
|
143
|
+
context.addIssue({ code: "custom", path: ["value", ...issue.path], message: issue.message });
|
|
144
|
+
});
|
|
120
145
|
export const TaskFeedbackSchema = z.object({
|
|
121
146
|
schemaVersion: z.literal("openpond.taskFeedbackRecord.v1"),
|
|
122
147
|
id: ReleaseIdSchema,
|
|
@@ -125,6 +150,7 @@ export const TaskFeedbackSchema = z.object({
|
|
|
125
150
|
evidence: LearningRevisionRefSchema.nullable(),
|
|
126
151
|
createdAt: ReleaseTimestampSchema,
|
|
127
152
|
revision: z.number().int().positive(),
|
|
153
|
+
submittedBy: z.object({ id: ReleaseIdSchema, role: z.enum(["editor", "reviewer", "source"]), sourceId: ReleaseIdSchema.nullable() }).strict().nullable().default(null),
|
|
128
154
|
review: z.object({ actorId: ReleaseIdSchema, decision: LearningRevisionRefSchema.nullable(), note: z.string().max(20_000), resolvedAt: ReleaseTimestampSchema }).strict().nullable().default(null),
|
|
129
155
|
}).strict();
|
|
130
156
|
export const TaskAdmissionDecisionContentSchema = z.object({
|
|
@@ -217,6 +243,13 @@ export const LearningPolicyContentSchema = z.object({
|
|
|
217
243
|
context.addIssue({ code: "custom", path: ["limits"], message: "Daily spend must permit the iteration budget." });
|
|
218
244
|
});
|
|
219
245
|
export const LearningPolicySchema = LearningPolicyContentSchema.safeExtend({ contentHash: ReleaseHashSchema }).strict();
|
|
246
|
+
export const LearningAcceptedParentSchema = z.object({
|
|
247
|
+
iterationId: ReleaseIdSchema,
|
|
248
|
+
iterationRevision: z.number().int().positive(),
|
|
249
|
+
candidate: ImmutableReleaseRefSchema,
|
|
250
|
+
decision: LearningRevisionRefSchema,
|
|
251
|
+
decidedAt: ReleaseTimestampSchema,
|
|
252
|
+
}).strict();
|
|
220
253
|
export const LearningIterationStatusSchema = z.enum(["waiting_for_data", "waiting_for_review", "ready", "dispatching", "training", "evaluating", "candidate_ready", "accepted", "rejected", "paused", "failed", "cancelling", "cancelled", "completed_without_candidate"]);
|
|
221
254
|
export const LearningIterationSchema = z.object({
|
|
222
255
|
schemaVersion: z.literal("openpond.learningIteration.v1"),
|
|
@@ -228,12 +261,14 @@ export const LearningIterationSchema = z.object({
|
|
|
228
261
|
batch: LearningRevisionRefSchema.nullable(),
|
|
229
262
|
sourceWatermarks: z.record(ReleaseIdSchema, z.number().int().nonnegative()),
|
|
230
263
|
trainingParent: ImmutableReleaseRefSchema,
|
|
264
|
+
trainingParentSelection: LearningAcceptedParentSchema.nullable().optional(),
|
|
231
265
|
teacher: ImmutableReleaseRefSchema.nullable(),
|
|
232
266
|
upstreamEvent: ImmutableReleaseRefSchema.nullable(),
|
|
233
267
|
trainingJob: ImmutableReleaseRefSchema.nullable(),
|
|
234
268
|
evaluationJob: ImmutableReleaseRefSchema.nullable(),
|
|
235
269
|
candidateVersion: ImmutableReleaseRefSchema.nullable(),
|
|
236
270
|
candidateDecision: LearningRevisionRefSchema.nullable().default(null),
|
|
271
|
+
candidateDecisionAt: ReleaseTimestampSchema.nullable().optional(),
|
|
237
272
|
dispatchId: ReleaseIdSchema,
|
|
238
273
|
retryCount: z.number().int().nonnegative(),
|
|
239
274
|
spendUsd: z.number().nonnegative(),
|
package/dist/learning/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./transport.js";
|
|
|
9
9
|
export * from "./errors.js";
|
|
10
10
|
export * from "./authoring.js";
|
|
11
11
|
export * from "./reward-authoring.js";
|
|
12
|
+
export * from "./rating-reward-fixture.js";
|
|
12
13
|
export * from "./reward-checks.js";
|
|
13
14
|
export * from "./reward-check-worker.js";
|
|
14
15
|
export * from "./reward-fixture-executor.js";
|
|
@@ -16,6 +17,7 @@ export * from "./iteration-reservation-contracts.js";
|
|
|
16
17
|
export * from "./iteration-dispatch-contracts.js";
|
|
17
18
|
export * from "./iteration-dispatch-worker.js";
|
|
18
19
|
export * from "./iteration-candidate-decision.js";
|
|
20
|
+
export { resolveLearningTrainingParent } from "./iteration-training-parent.js";
|
|
19
21
|
export * from "./schedule-contracts.js";
|
|
20
22
|
export * from "./schedule-service.js";
|
|
21
23
|
export * from "./schedule-worker.js";
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ImmutableReleaseRefSchema, ReleaseIdSchema } from "@openpond/harness";
|
|
2
|
+
import { ImmutableReleaseRefSchema, ReleaseIdSchema, ReleaseTimestampSchema } from "@openpond/harness";
|
|
3
3
|
import { LearningIterationSchema, LearningRevisionRefSchema } from "./contracts.js";
|
|
4
4
|
import { LearningDomainError } from "./errors.js";
|
|
5
5
|
import { LearningChainSchema } from "./iteration-reservation-contracts.js";
|
|
6
6
|
import { requireLearningResource } from "./repository.js";
|
|
7
|
+
import { latestAcceptedLearningParent } from "./iteration-training-parent.js";
|
|
7
8
|
export const LearningCandidateDecisionObservationSchema = z.object({
|
|
8
9
|
scope: ReleaseIdSchema,
|
|
9
10
|
iterationId: ReleaseIdSchema,
|
|
10
11
|
decision: LearningRevisionRefSchema,
|
|
12
|
+
decidedAt: ReleaseTimestampSchema,
|
|
11
13
|
outcome: z.enum(["accepted", "rejected"]),
|
|
12
14
|
execution: ImmutableReleaseRefSchema,
|
|
13
15
|
candidate: ImmutableReleaseRefSchema,
|
|
@@ -34,18 +36,21 @@ export async function reconcileLearningCandidateDecision(repository, value, opti
|
|
|
34
36
|
if (previous && input.decision.revision < previous.revision)
|
|
35
37
|
return iteration;
|
|
36
38
|
if (previous && input.decision.revision === previous.revision) {
|
|
37
|
-
if (!same(previous, input.decision) || iteration.status !== input.outcome
|
|
39
|
+
if (!same(previous, input.decision) || iteration.status !== input.outcome
|
|
40
|
+
|| (iteration.candidateDecisionAt != null && iteration.candidateDecisionAt !== input.decidedAt))
|
|
38
41
|
throw new LearningDomainError("learning_candidate_decision_revision_conflict", 409);
|
|
39
|
-
|
|
42
|
+
if (iteration.candidateDecisionAt != null)
|
|
43
|
+
return iteration;
|
|
40
44
|
}
|
|
41
45
|
const now = (options.now ?? (() => new Date().toISOString()))();
|
|
42
46
|
const updated = LearningIterationSchema.parse({ ...iteration, revision: iteration.revision + 1,
|
|
43
|
-
candidateDecision: input.decision, status: input.outcome, updatedAt: now });
|
|
47
|
+
candidateDecision: input.decision, candidateDecisionAt: input.decidedAt, status: input.outcome, updatedAt: now });
|
|
44
48
|
await tx.put("iteration", updated, iteration.revision, { parentId: dispatch.chainId, status: updated.status });
|
|
45
49
|
const chain = await requireLearningResource(tx, "chain", dispatch.chainId);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
const acceptedParent = await latestAcceptedLearningParent(tx, chain.id);
|
|
51
|
+
await tx.put("chain", LearningChainSchema.parse({ ...chain, acceptedParent,
|
|
52
|
+
revision: chain.revision + 1, activeIterationId: chain.activeIterationId === iteration.id ? null : chain.activeIterationId,
|
|
53
|
+
updatedAt: now }), chain.revision, { parentId: chain.modelProjectId });
|
|
49
54
|
return updated;
|
|
50
55
|
});
|
|
51
56
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { ReleaseHashSchema, ReleaseIdSchema, ReleaseTimestampSchema } from "@openpond/harness";
|
|
3
|
-
import { LearningRevisionRefSchema } from "./contracts.js";
|
|
3
|
+
import { LearningAcceptedParentSchema, LearningRevisionRefSchema } from "./contracts.js";
|
|
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(),
|
|
@@ -12,6 +12,7 @@ export const LearningChainSchema = z.object({
|
|
|
12
12
|
revision: z.number().int().positive(),
|
|
13
13
|
modelProjectId: ReleaseIdSchema,
|
|
14
14
|
activeIterationId: ReleaseIdSchema.nullable(),
|
|
15
|
+
acceptedParent: LearningAcceptedParentSchema.nullable().optional(),
|
|
15
16
|
latestIterationId: ReleaseIdSchema,
|
|
16
17
|
lastReservedAt: ReleaseTimestampSchema.nullable(),
|
|
17
18
|
updatedAt: ReleaseTimestampSchema,
|
|
@@ -6,6 +6,7 @@ import { inspectIterationEligibility, learningChainId, learningConsumptionId } f
|
|
|
6
6
|
import { readLearningIterationBudget } from "./iteration-budget.js";
|
|
7
7
|
import { LearningChainSchema, LearningConsumptionSchema, LearningIterationReservationSchema } from "./iteration-reservation-contracts.js";
|
|
8
8
|
import { requireLearningRelease, requireLearningResource } from "./repository.js";
|
|
9
|
+
import { latestAcceptedLearningParent, resolveLearningTrainingParent } from "./iteration-training-parent.js";
|
|
9
10
|
/** The caller owns one scope-serialized transaction. This never submits a Job. */
|
|
10
11
|
export async function reserveLearningIteration(transaction, input, actorId, now) {
|
|
11
12
|
const policy = await requireLearningRelease(transaction, "policy", input.policy);
|
|
@@ -44,6 +45,8 @@ export async function reserveLearningIteration(transaction, input, actorId, now)
|
|
|
44
45
|
const ready = eligibility.counts.eligible >= policy.admission.minimumApprovedExamples;
|
|
45
46
|
const status = ready ? "ready" : eligibility.counts.awaitingReview > 0 ? "waiting_for_review" : "waiting_for_data";
|
|
46
47
|
const pointers = [];
|
|
48
|
+
const acceptedParent = await latestAcceptedLearningParent(transaction, chainId, true);
|
|
49
|
+
const parent = await resolveLearningTrainingParent(transaction, policy, acceptedParent);
|
|
47
50
|
let batch = null;
|
|
48
51
|
if (ready) {
|
|
49
52
|
await assertAvailableBudget(transaction, chainId, now, policy.limits.maxIterationSpendUsd, policy.limits.maxDailySpendUsd);
|
|
@@ -68,7 +71,7 @@ export async function reserveLearningIteration(transaction, input, actorId, now)
|
|
|
68
71
|
triggerIdentity, batch,
|
|
69
72
|
// Existing evidence has no ordered ingress sequence. Consumption records,
|
|
70
73
|
// not a count or lexicographic ID cursor, decide whether an example is new.
|
|
71
|
-
sourceWatermarks: {},
|
|
74
|
+
sourceWatermarks: {}, ...parent, teacher: policy.teacher, upstreamEvent: null,
|
|
72
75
|
trainingJob: null, evaluationJob: null, candidateVersion: null, dispatchId: `dispatch-${contentHash(id)}`,
|
|
73
76
|
retryCount: 0, spendUsd: 0, failure: null, createdAt: now, updatedAt: now,
|
|
74
77
|
});
|
|
@@ -82,6 +85,7 @@ export async function reserveLearningIteration(transaction, input, actorId, now)
|
|
|
82
85
|
const updatedChain = LearningChainSchema.parse({
|
|
83
86
|
schemaVersion: "openpond.learningChain.v1", id: chainId, revision: (chain?.revision ?? 0) + 1,
|
|
84
87
|
modelProjectId: policy.modelProjectId, activeIterationId: ready ? id : null, latestIterationId: id,
|
|
88
|
+
acceptedParent,
|
|
85
89
|
lastReservedAt: ready ? now : chain?.lastReservedAt ?? null, updatedAt: now,
|
|
86
90
|
});
|
|
87
91
|
await transaction.put("iteration", iteration, 0, { parentId: chainId, status });
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { LearningAcceptedParentSchema, sameLearningRef } from "./contracts.js";
|
|
2
|
+
import { LearningDomainError } from "./errors.js";
|
|
3
|
+
import { requireLearningRelease, requireLearningResource } from "./repository.js";
|
|
4
|
+
/** Select the latest accepted human decision. A later rejection removes that
|
|
5
|
+
* candidate from future selection without rewriting reserved descendants. */
|
|
6
|
+
export async function latestAcceptedLearningParent(tx, chainId, requireComplete = false) {
|
|
7
|
+
let selected = null;
|
|
8
|
+
let afterId;
|
|
9
|
+
do {
|
|
10
|
+
const page = await tx.list("iteration", { parentId: chainId, status: "accepted", limit: 100, ...(afterId ? { afterId } : {}) });
|
|
11
|
+
for (const iteration of page.items) {
|
|
12
|
+
if (!iteration.candidateVersion || !iteration.candidateDecision || !iteration.candidateDecisionAt || !iteration.trainingJob) {
|
|
13
|
+
if (requireComplete)
|
|
14
|
+
throw new LearningDomainError("learning_accepted_parent_evidence_missing", 409);
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const candidate = LearningAcceptedParentSchema.parse({ iterationId: iteration.id, iterationRevision: iteration.revision,
|
|
18
|
+
candidate: iteration.candidateVersion, decision: iteration.candidateDecision, decidedAt: iteration.candidateDecisionAt });
|
|
19
|
+
const order = [Date.parse(candidate.decidedAt), candidate.decision.id, candidate.decision.revision];
|
|
20
|
+
const previous = selected ? [Date.parse(selected.decidedAt), selected.decision.id, selected.decision.revision] : null;
|
|
21
|
+
if (!previous || order[0] > previous[0] || (order[0] === previous[0]
|
|
22
|
+
&& (order[1] > previous[1] || (order[1] === previous[1] && order[2] > previous[2]))))
|
|
23
|
+
selected = candidate;
|
|
24
|
+
}
|
|
25
|
+
afterId = page.nextCursor ?? undefined;
|
|
26
|
+
} while (afterId);
|
|
27
|
+
return selected;
|
|
28
|
+
}
|
|
29
|
+
/** Reservation captures an accepted revision before dispatch or later reviews.
|
|
30
|
+
* Switching the underlying base requires a separately reviewed learning chain. */
|
|
31
|
+
export async function resolveLearningTrainingParent(tx, policy, selection) {
|
|
32
|
+
if (!selection)
|
|
33
|
+
return { trainingParent: policy.trainingParent, trainingParentSelection: null };
|
|
34
|
+
const parent = await requireLearningResource(tx, "iteration", selection.iterationId, selection.iterationRevision);
|
|
35
|
+
const sourcePolicy = await requireLearningRelease(tx, "policy", parent.policy);
|
|
36
|
+
if (parent.status !== "accepted" || !parent.candidateVersion || !parent.candidateDecision || !parent.trainingJob
|
|
37
|
+
|| parent.candidateVersion.id !== selection.candidate.id || parent.candidateVersion.contentHash !== selection.candidate.contentHash
|
|
38
|
+
|| !sameLearningRef(parent.candidateDecision, selection.decision) || parent.candidateDecisionAt !== selection.decidedAt
|
|
39
|
+
|| sourcePolicy.modelProjectId !== policy.modelProjectId || sourcePolicy.executionOwner !== policy.executionOwner) {
|
|
40
|
+
throw new LearningDomainError("learning_accepted_parent_evidence_mismatch", 409);
|
|
41
|
+
}
|
|
42
|
+
if (sourcePolicy.trainingParent.id !== policy.trainingParent.id || sourcePolicy.trainingParent.contentHash !== policy.trainingParent.contentHash
|
|
43
|
+
|| sourcePolicy.training.method !== policy.training.method) {
|
|
44
|
+
throw new LearningDomainError("learning_accepted_parent_configuration_mismatch", 409, "The accepted checkpoint belongs to a different starting model or training method.");
|
|
45
|
+
}
|
|
46
|
+
return { trainingParent: selection.candidate, trainingParentSelection: selection };
|
|
47
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { ReleaseIdSchema, ReleaseTimestampSchema } from "@openpond/harness";
|
|
1
|
+
import { ImmutableReleaseRefSchema, ReleaseIdSchema, ReleaseTimestampSchema } from "@openpond/harness";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { LearningRevisionRefSchema, learningRef, sameLearningRef } from "./contracts.js";
|
|
3
|
+
import { LearningAcceptedParentSchema, LearningRevisionRefSchema, learningRef, sameLearningRef } from "./contracts.js";
|
|
4
4
|
import { prepareLearningBatch } from "./batch-service.js";
|
|
5
5
|
import { LearningDomainError } from "./errors.js";
|
|
6
6
|
import { readLearningIterationBudget } from "./iteration-budget.js";
|
|
7
7
|
import { inspectIterationEligibility, learningChainId } from "./iteration-eligibility.js";
|
|
8
8
|
import { LearningChainSchema, LearningEligibilityCountsSchema } from "./iteration-reservation-contracts.js";
|
|
9
9
|
import { requireLearningRelease, requireLearningResource } from "./repository.js";
|
|
10
|
+
import { latestAcceptedLearningParent, resolveLearningTrainingParent } from "./iteration-training-parent.js";
|
|
10
11
|
/** A scope-serialized snapshot of shared reservation readiness, not a Job guarantee.
|
|
11
12
|
* No iteration, timer, batch, consumption or operation record is written. */
|
|
12
13
|
export const LearningPolicyInspectionResultSchema = z.object({
|
|
@@ -14,6 +15,7 @@ export const LearningPolicyInspectionResultSchema = z.object({
|
|
|
14
15
|
modelProjectId: ReleaseIdSchema,
|
|
15
16
|
inspectedAt: ReleaseTimestampSchema,
|
|
16
17
|
chain: LearningChainSchema.nullable(),
|
|
18
|
+
trainingParent: z.object({ reference: ImmutableReleaseRefSchema, selection: LearningAcceptedParentSchema.nullable() }).strict().nullable().default(null),
|
|
17
19
|
counts: LearningEligibilityCountsSchema.nullable(),
|
|
18
20
|
minimumApprovedExamples: z.number().int().positive(),
|
|
19
21
|
canReserve: z.boolean(),
|
|
@@ -73,8 +75,18 @@ export async function inspectLearningPolicy(transaction, reference, actorId, now
|
|
|
73
75
|
// must remain visible while the Model's settings and history can still load.
|
|
74
76
|
block(error.code, error.message.slice(0, 20_000));
|
|
75
77
|
}
|
|
78
|
+
let trainingParent = null;
|
|
79
|
+
try {
|
|
80
|
+
const resolved = await resolveLearningTrainingParent(transaction, policy, await latestAcceptedLearningParent(transaction, chainId, true));
|
|
81
|
+
trainingParent = { reference: resolved.trainingParent, selection: resolved.trainingParentSelection };
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (!(error instanceof LearningDomainError))
|
|
85
|
+
throw error;
|
|
86
|
+
block(error.code, error.message.slice(0, 20_000));
|
|
87
|
+
}
|
|
76
88
|
return LearningPolicyInspectionResultSchema.parse({
|
|
77
|
-
policy: learningRef(policy), modelProjectId: policy.modelProjectId, inspectedAt: now, chain,
|
|
89
|
+
policy: learningRef(policy), modelProjectId: policy.modelProjectId, inspectedAt: now, chain, trainingParent,
|
|
78
90
|
counts, minimumApprovedExamples: policy.admission.minimumApprovedExamples, canReserve: blockers.length === 0,
|
|
79
91
|
blockers, cooldownUntil,
|
|
80
92
|
budget: { ...budget, maximumIterationSpendUsd: policy.limits.maxIterationSpendUsd, maximumDailySpendUsd: policy.limits.maxDailySpendUsd },
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { learningRef, sameLearningRef, TaskRatingSchema } from "./contracts.js";
|
|
2
|
+
import { LearningDomainError } from "./errors.js";
|
|
3
|
+
/** Copy a retained label into editable check data while preserving its exact origin. */
|
|
4
|
+
export function rewardFixtureFromRating(evidence, feedback, scale = { minimum: 0, maximum: 1 }) {
|
|
5
|
+
if (!feedback.evidence || !sameLearningRef(feedback.evidence, learningRef(evidence)) || feedback.submission.expectedEvidenceHash !== evidence.contentHash || feedback.submission.kind !== "outcome" || !evidence.submission.observedOutput)
|
|
6
|
+
throw new LearningDomainError("rating_fixture_evidence_mismatch", 422);
|
|
7
|
+
const rating = TaskRatingSchema.parse(feedback.submission.value);
|
|
8
|
+
if (!Number.isFinite(scale.minimum) || !Number.isFinite(scale.maximum) || scale.minimum >= scale.maximum)
|
|
9
|
+
throw new LearningDomainError("rating_fixture_scale_invalid", 422);
|
|
10
|
+
const score = scale.minimum + (rating.score - rating.scale.minimum) / (rating.scale.maximum - rating.scale.minimum) * (scale.maximum - scale.minimum);
|
|
11
|
+
return {
|
|
12
|
+
id: `label-${feedback.id}-${feedback.revision}`, name: evidence.submission.exampleId,
|
|
13
|
+
input: JSON.stringify(evidence.submission.input, null, 2), output: JSON.stringify(evidence.submission.observedOutput, null, 2),
|
|
14
|
+
expectedOutput: evidence.submission.expected ? JSON.stringify(evidence.submission.expected, null, 2) : "",
|
|
15
|
+
evaluatorContext: evidence.submission.evaluatorContext ? JSON.stringify(evidence.submission.evaluatorContext, null, 2) : "",
|
|
16
|
+
artifactRefs: [], runtimeEventRefs: [], infrastructureError: "", expectedStatus: "scored", minimumScore: String(score), maximumScore: String(score), expectedPassed: "any",
|
|
17
|
+
sourceLabel: { evidence: learningRef(evidence), feedback: { id: feedback.id, revision: feedback.revision } },
|
|
18
|
+
};
|
|
19
|
+
}
|
package/dist/learning/service.js
CHANGED
|
@@ -70,7 +70,7 @@ export function createLearningService(repository, options = {}) {
|
|
|
70
70
|
pointers = [await submit(transaction, input)];
|
|
71
71
|
break;
|
|
72
72
|
case "submit_feedback":
|
|
73
|
-
pointers = [await feedback(transaction, input)];
|
|
73
|
+
pointers = [await feedback(transaction, input, context.actor)];
|
|
74
74
|
break;
|
|
75
75
|
case "apply_correction":
|
|
76
76
|
pointers = await correct(transaction, input, context.actor.id);
|
|
@@ -193,16 +193,19 @@ export function createLearningService(repository, options = {}) {
|
|
|
193
193
|
} while (afterId);
|
|
194
194
|
return pointer("evidence", evidence);
|
|
195
195
|
}
|
|
196
|
-
async function feedback(transaction, input) {
|
|
196
|
+
async function feedback(transaction, input, actor) {
|
|
197
197
|
const source = await requireLearningResource(transaction, "source", input.feedback.sourceId);
|
|
198
198
|
if (!source.enabled)
|
|
199
199
|
throw new LearningDomainError("learning_source_disabled", 409);
|
|
200
200
|
const evidenceId = learningEvidenceId(source.id, input.feedback.exampleId, input.feedback.attemptId);
|
|
201
201
|
const evidence = await transaction.get("evidence", evidenceId);
|
|
202
|
+
if (input.feedback.value.schemaVersion === "openpond.taskRating.v1" && (!evidence || evidence.contentHash !== input.feedback.expectedEvidenceHash || !evidence.submission.observedOutput))
|
|
203
|
+
throw new LearningDomainError("task_rating_evidence_stale", 409, "Open the current observed response before submitting a rating.");
|
|
202
204
|
const record = TaskFeedbackSchema.parse({
|
|
203
205
|
schemaVersion: "openpond.taskFeedbackRecord.v1", id: `feedback-${contentHash([source.id, input.feedback.idempotencyKey])}`,
|
|
204
206
|
submission: input.feedback, status: evidence ? "pending_review" : "pending_example",
|
|
205
207
|
evidence: evidence ? learningRef(evidence) : null, createdAt: now(), revision: 1,
|
|
208
|
+
submittedBy: { id: actor.id, role: actor.role, sourceId: actor.sourceId ?? null },
|
|
206
209
|
});
|
|
207
210
|
await transaction.put("feedback", record, 0, { parentId: evidenceId, status: record.status });
|
|
208
211
|
return pointer("feedback", record);
|
|
@@ -348,6 +351,8 @@ export function createLearningService(repository, options = {}) {
|
|
|
348
351
|
},
|
|
349
352
|
async list(context, kind, query = {}) {
|
|
350
353
|
authorizeRead(context);
|
|
354
|
+
if (query.reviewState !== undefined && (kind !== "evidence" || !["inbox", "reviewed"].includes(query.reviewState)))
|
|
355
|
+
throw new LearningDomainError("learning_review_filter_invalid", 400);
|
|
351
356
|
const limit = Math.max(1, Math.min(100, Math.trunc(query.limit ?? 50)));
|
|
352
357
|
return repository.transaction(context.scope, (transaction) => transaction.list(kind, { ...query, limit }));
|
|
353
358
|
},
|
|
@@ -20,7 +20,7 @@ export const LearningReadRequestSchema = z.discriminatedUnion("action", [
|
|
|
20
20
|
z.object({ action: z.literal("inspect_policy"), scope: ReleaseIdSchema, policy: LearningRevisionRefSchema }).strict(),
|
|
21
21
|
z.object({ action: z.literal("inspect_evidence"), scope: ReleaseIdSchema, evidence: LearningRevisionRefSchema }).strict(),
|
|
22
22
|
z.object({ action: z.literal("get"), scope: ReleaseIdSchema, kind: LearningResourceKindSchema, id: ReleaseIdSchema, revision: z.number().int().positive().optional() }).strict(),
|
|
23
|
-
z.object({ action: z.literal("list"), scope: ReleaseIdSchema, kind: LearningResourceKindSchema, parentId: ReleaseIdSchema.optional(), status: z.string().min(1).max(200).optional(), afterId: ReleaseIdSchema.optional(), limit: z.number().int().min(1).max(100).default(50) }).strict(),
|
|
23
|
+
z.object({ action: z.literal("list"), scope: ReleaseIdSchema, kind: LearningResourceKindSchema, parentId: ReleaseIdSchema.optional(), status: z.string().min(1).max(200).optional(), reviewState: z.enum(["inbox", "reviewed"]).optional(), afterId: ReleaseIdSchema.optional(), limit: z.number().int().min(1).max(100).default(50) }).strict(),
|
|
24
24
|
]);
|
|
25
25
|
export const TaskEvidenceInspectionResultSchema = z.object({
|
|
26
26
|
evidence: LearningRevisionRefSchema,
|
|
@@ -130,6 +130,17 @@ export declare function currentDraft(tx: LearningTransaction, ref: LearningRevis
|
|
|
130
130
|
minimumScore: string;
|
|
131
131
|
maximumScore: string;
|
|
132
132
|
expectedPassed: "any" | "true" | "false";
|
|
133
|
+
sourceLabel?: {
|
|
134
|
+
evidence: {
|
|
135
|
+
id: string;
|
|
136
|
+
contentHash: string;
|
|
137
|
+
revision: number;
|
|
138
|
+
};
|
|
139
|
+
feedback: {
|
|
140
|
+
id: string;
|
|
141
|
+
revision: number;
|
|
142
|
+
};
|
|
143
|
+
} | undefined;
|
|
133
144
|
}[] | undefined;
|
|
134
145
|
};
|
|
135
146
|
schemaVersion: "openpond.authoringDraft.v1";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authoring-service.d.ts","sourceRoot":"","sources":["../../../../../src/learning/authoring-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAEhF,OAAO,EAAqD,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC7G,OAAO,
|
|
1
|
+
{"version":3,"file":"authoring-service.d.ts","sourceRoot":"","sources":["../../../../../src/learning/authoring-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAEhF,OAAO,EAAqD,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC7G,OAAO,EAAmD,KAAK,uBAAuB,EAAE,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC1I,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,mBAAmB,EAAE,KAAK,EAAE;IAAE,KAAK,EAAE,mBAAmB,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,EAAE,MAAM;;;;GAmB7I;AAED,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,mBAAmB,EAAE,GAAG,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM;;;;GAMzG;AAED,wBAAsB,sBAAsB,CAAC,EAAE,EAAE,mBAAmB,EAAE,KAAK,EAAE,OAAO,CAAC,eAAe,EAAE;IAAE,MAAM,EAAE,SAAS,GAAG,mBAAmB,CAAA;CAAE,CAAC,EAAE,SAAS,EAAE,uBAAuB,EAAE,EAAE,GAAG,EAAE,MAAM;;;;UAUpM;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,mBAAmB,EAAE,GAAG,EAAE,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAMnF"}
|
|
@@ -23,6 +23,17 @@ export declare const RewardFixtureAuthoringFieldsSchema: z.ZodObject<{
|
|
|
23
23
|
true: "true";
|
|
24
24
|
false: "false";
|
|
25
25
|
}>;
|
|
26
|
+
sourceLabel: z.ZodOptional<z.ZodObject<{
|
|
27
|
+
evidence: z.ZodObject<{
|
|
28
|
+
id: z.ZodString;
|
|
29
|
+
contentHash: z.ZodString;
|
|
30
|
+
revision: z.ZodNumber;
|
|
31
|
+
}, z.core.$strict>;
|
|
32
|
+
feedback: z.ZodObject<{
|
|
33
|
+
id: z.ZodString;
|
|
34
|
+
revision: z.ZodNumber;
|
|
35
|
+
}, z.core.$strict>;
|
|
36
|
+
}, z.core.$strict>>;
|
|
26
37
|
}, z.core.$strict>;
|
|
27
38
|
export type RewardFixtureAuthoringFields = z.infer<typeof RewardFixtureAuthoringFieldsSchema>;
|
|
28
39
|
export declare const RewardAuthoringFieldsSchema: z.ZodObject<{
|
|
@@ -83,6 +94,17 @@ export declare const RewardAuthoringFieldsSchema: z.ZodObject<{
|
|
|
83
94
|
true: "true";
|
|
84
95
|
false: "false";
|
|
85
96
|
}>;
|
|
97
|
+
sourceLabel: z.ZodOptional<z.ZodObject<{
|
|
98
|
+
evidence: z.ZodObject<{
|
|
99
|
+
id: z.ZodString;
|
|
100
|
+
contentHash: z.ZodString;
|
|
101
|
+
revision: z.ZodNumber;
|
|
102
|
+
}, z.core.$strict>;
|
|
103
|
+
feedback: z.ZodObject<{
|
|
104
|
+
id: z.ZodString;
|
|
105
|
+
revision: z.ZodNumber;
|
|
106
|
+
}, z.core.$strict>;
|
|
107
|
+
}, z.core.$strict>>;
|
|
86
108
|
}, z.core.$strict>>>;
|
|
87
109
|
}, z.core.$strict>;
|
|
88
110
|
export declare const TaskFormatAuthoringFieldsSchema: z.ZodObject<{
|
|
@@ -291,6 +313,17 @@ export declare const AuthoringDraftInputSchema: z.ZodDiscriminatedUnion<[z.ZodOb
|
|
|
291
313
|
true: "true";
|
|
292
314
|
false: "false";
|
|
293
315
|
}>;
|
|
316
|
+
sourceLabel: z.ZodOptional<z.ZodObject<{
|
|
317
|
+
evidence: z.ZodObject<{
|
|
318
|
+
id: z.ZodString;
|
|
319
|
+
contentHash: z.ZodString;
|
|
320
|
+
revision: z.ZodNumber;
|
|
321
|
+
}, z.core.$strict>;
|
|
322
|
+
feedback: z.ZodObject<{
|
|
323
|
+
id: z.ZodString;
|
|
324
|
+
revision: z.ZodNumber;
|
|
325
|
+
}, z.core.$strict>;
|
|
326
|
+
}, z.core.$strict>>;
|
|
294
327
|
}, z.core.$strict>>>;
|
|
295
328
|
}, z.core.$strict>;
|
|
296
329
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -475,6 +508,17 @@ export declare const AuthoringDraftContentSchema: z.ZodDiscriminatedUnion<[z.Zod
|
|
|
475
508
|
true: "true";
|
|
476
509
|
false: "false";
|
|
477
510
|
}>;
|
|
511
|
+
sourceLabel: z.ZodOptional<z.ZodObject<{
|
|
512
|
+
evidence: z.ZodObject<{
|
|
513
|
+
id: z.ZodString;
|
|
514
|
+
contentHash: z.ZodString;
|
|
515
|
+
revision: z.ZodNumber;
|
|
516
|
+
}, z.core.$strict>;
|
|
517
|
+
feedback: z.ZodObject<{
|
|
518
|
+
id: z.ZodString;
|
|
519
|
+
revision: z.ZodNumber;
|
|
520
|
+
}, z.core.$strict>;
|
|
521
|
+
}, z.core.$strict>>;
|
|
478
522
|
}, z.core.$strict>>>;
|
|
479
523
|
}, z.core.$strict>;
|
|
480
524
|
schemaVersion: z.ZodLiteral<"openpond.authoringDraft.v1">;
|
|
@@ -688,6 +732,17 @@ export declare const AuthoringDraftSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
|
|
|
688
732
|
true: "true";
|
|
689
733
|
false: "false";
|
|
690
734
|
}>;
|
|
735
|
+
sourceLabel: z.ZodOptional<z.ZodObject<{
|
|
736
|
+
evidence: z.ZodObject<{
|
|
737
|
+
id: z.ZodString;
|
|
738
|
+
contentHash: z.ZodString;
|
|
739
|
+
revision: z.ZodNumber;
|
|
740
|
+
}, z.core.$strict>;
|
|
741
|
+
feedback: z.ZodObject<{
|
|
742
|
+
id: z.ZodString;
|
|
743
|
+
revision: z.ZodNumber;
|
|
744
|
+
}, z.core.$strict>;
|
|
745
|
+
}, z.core.$strict>>;
|
|
691
746
|
}, z.core.$strict>>>;
|
|
692
747
|
}, z.core.$strict>;
|
|
693
748
|
schemaVersion: z.ZodLiteral<"openpond.authoringDraft.v1">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authoring.d.ts","sourceRoot":"","sources":["../../../../../src/learning/authoring.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,sFAAsF;AACtF,eAAO,MAAM,kCAAkC
|
|
1
|
+
{"version":3,"file":"authoring.d.ts","sourceRoot":"","sources":["../../../../../src/learning/authoring.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,sFAAsF;AACtF,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAQpC,CAAC;AACZ,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAE9F,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAQ7B,CAAC;AACZ,eAAO,MAAM,+BAA+B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAIjC,CAAC;AACZ,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAErC,CAAC;AACZ,eAAO,MAAM,yBAAyB;;;;EAA8C,CAAC;AAErF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAIpC,CAAC;AAMH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAAoO,CAAC;AAC7Q,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kCAA2T,CAAC;AAC7V,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAC5E,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,mBAAmB,IAAI,OAAO,CAAC,cAAc,EAAE;IAAE,UAAU,EAAE,CAAC,CAAA;CAAE,CAAC,CAAC;AAE1G,sFAAsF;AACtF,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;kBAAqI,CAAC"}
|