@openpond/evals 0.11.21 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/artifact-verification.js +2 -0
- package/dist/connected-evidence/codex-command-observations.js +81 -0
- package/dist/connected-evidence/contracts.js +13 -0
- package/dist/connected-evidence/git-file-contracts.js +16 -0
- package/dist/connected-evidence/git-file-proof.js +86 -0
- package/dist/connected-evidence/git-starting-state.js +81 -0
- package/dist/connected-evidence/git.js +2 -0
- package/dist/connected-evidence/imports.js +2 -1
- package/dist/connected-evidence/index.js +1 -0
- package/dist/connected-evidence/normalize.js +1 -0
- package/dist/connected-evidence/sources/claude-branches.js +34 -1
- package/dist/connected-evidence/sources/claude-code.js +1 -1
- package/dist/connected-evidence/sources/codex-metadata.js +33 -0
- package/dist/connected-evidence/sources/codex.js +16 -2
- package/dist/graders.js +10 -4
- package/dist/javascript-verifier.js +1 -0
- package/dist/native-conversations/codex-window-inventory.js +6 -7
- package/dist/native-conversations/collector-acquisition.js +17 -6
- package/dist/native-conversations/collector-source-cache.js +1 -1
- package/dist/native-conversations/collector-store.js +27 -2
- package/dist/native-conversations/collector.js +4 -3
- package/dist/native-conversations/git-assets.js +61 -0
- package/dist/native-conversations/history.js +7 -0
- package/dist/native-conversations/index.js +2 -0
- package/dist/native-conversations/selection.js +57 -0
- package/dist/native-conversations/supervisor.js +2 -0
- package/dist/prepared-process-isolation.js +131 -0
- package/dist/rewards.js +17 -5
- package/dist/tasksets.js +7 -0
- package/dist/types/artifact-verification.d.ts.map +1 -1
- package/dist/types/benchmarks.d.ts +22 -22
- package/dist/types/benchmarks.d.ts.map +1 -1
- package/dist/types/builtin-benchmarks/harness-refiner.d.ts +40 -35
- package/dist/types/builtin-benchmarks/harness-refiner.d.ts.map +1 -1
- package/dist/types/compatibility.d.ts.map +1 -1
- package/dist/types/conformance.d.ts +98 -88
- package/dist/types/conformance.d.ts.map +1 -1
- package/dist/types/connected-evidence/codex-command-observations.d.ts +15 -0
- package/dist/types/connected-evidence/codex-command-observations.d.ts.map +1 -0
- package/dist/types/connected-evidence/collector-coverage-contracts.d.ts +6 -6
- package/dist/types/connected-evidence/collector-coverage-contracts.d.ts.map +1 -1
- package/dist/types/connected-evidence/contracts.d.ts +80 -58
- package/dist/types/connected-evidence/contracts.d.ts.map +1 -1
- package/dist/types/connected-evidence/git-file-contracts.d.ts +18 -0
- package/dist/types/connected-evidence/git-file-contracts.d.ts.map +1 -0
- package/dist/types/connected-evidence/git-file-proof.d.ts +13 -0
- package/dist/types/connected-evidence/git-file-proof.d.ts.map +1 -0
- package/dist/types/connected-evidence/git-starting-state.d.ts +28 -0
- package/dist/types/connected-evidence/git-starting-state.d.ts.map +1 -0
- package/dist/types/connected-evidence/git.d.ts +3 -0
- package/dist/types/connected-evidence/git.d.ts.map +1 -0
- package/dist/types/connected-evidence/imports.d.ts.map +1 -1
- package/dist/types/connected-evidence/index.d.ts +1 -0
- package/dist/types/connected-evidence/index.d.ts.map +1 -1
- package/dist/types/connected-evidence/normalize.d.ts +1 -0
- package/dist/types/connected-evidence/normalize.d.ts.map +1 -1
- package/dist/types/connected-evidence/python-correctness.d.ts +38 -38
- package/dist/types/connected-evidence/python-correctness.d.ts.map +1 -1
- package/dist/types/connected-evidence/sources/claude-branches.d.ts +1 -0
- package/dist/types/connected-evidence/sources/claude-branches.d.ts.map +1 -1
- package/dist/types/connected-evidence/sources/claude-code.d.ts +25 -15
- package/dist/types/connected-evidence/sources/claude-code.d.ts.map +1 -1
- package/dist/types/connected-evidence/sources/codex-authorization.d.ts.map +1 -1
- package/dist/types/connected-evidence/sources/codex-metadata.d.ts +10 -0
- package/dist/types/connected-evidence/sources/codex-metadata.d.ts.map +1 -0
- package/dist/types/connected-evidence/sources/codex.d.ts +25 -15
- package/dist/types/connected-evidence/sources/codex.d.ts.map +1 -1
- package/dist/types/connected-evidence/sources/grok-build.d.ts +25 -15
- package/dist/types/connected-evidence/sources/grok-build.d.ts.map +1 -1
- package/dist/types/connected-evidence/sources/history.d.ts +50 -30
- package/dist/types/connected-evidence/sources/history.d.ts.map +1 -1
- package/dist/types/connected-evidence/sources/opencode.d.ts +25 -15
- package/dist/types/connected-evidence/sources/opencode.d.ts.map +1 -1
- package/dist/types/connected-evidence/sources/pi.d.ts +25 -15
- package/dist/types/connected-evidence/sources/pi.d.ts.map +1 -1
- package/dist/types/connected-evidence/sources/usage.d.ts.map +1 -1
- package/dist/types/connected-evidence/usage-summary.d.ts.map +1 -1
- package/dist/types/deterministic-graders.d.ts.map +1 -1
- package/dist/types/environment-execution-services-contract.d.ts +19 -19
- package/dist/types/environment-execution-services-contract.d.ts.map +1 -1
- package/dist/types/environment-execution-services.d.ts.map +1 -1
- package/dist/types/evidence/authoring.d.ts.map +1 -1
- package/dist/types/evidence/conformance.d.ts +98 -98
- package/dist/types/evidence/conformance.d.ts.map +1 -1
- package/dist/types/evidence/contracts.d.ts +183 -183
- package/dist/types/evidence/contracts.d.ts.map +1 -1
- package/dist/types/evidence/eligibility.d.ts +160 -160
- package/dist/types/evidence/eligibility.d.ts.map +1 -1
- package/dist/types/evidence/index.d.ts.map +1 -1
- package/dist/types/execution-contracts.d.ts +118 -110
- package/dist/types/execution-contracts.d.ts.map +1 -1
- package/dist/types/execution-receipts.d.ts.map +1 -1
- package/dist/types/experiments.d.ts +96 -96
- package/dist/types/experiments.d.ts.map +1 -1
- package/dist/types/graders.d.ts +38 -35
- package/dist/types/graders.d.ts.map +1 -1
- package/dist/types/harness-experiment-source.d.ts.map +1 -1
- package/dist/types/harness.d.ts.map +1 -1
- package/dist/types/human-review/comparison.d.ts +189 -189
- package/dist/types/human-review/comparison.d.ts.map +1 -1
- package/dist/types/human-review/contracts.d.ts +178 -178
- package/dist/types/human-review/contracts.d.ts.map +1 -1
- package/dist/types/human-review/execution.d.ts +53 -53
- package/dist/types/human-review/execution.d.ts.map +1 -1
- package/dist/types/human-review/handoff.d.ts +43 -43
- package/dist/types/human-review/handoff.d.ts.map +1 -1
- package/dist/types/human-review/index.d.ts.map +1 -1
- package/dist/types/human-review/local-publication.d.ts +4 -4
- package/dist/types/human-review/local-publication.d.ts.map +1 -1
- package/dist/types/human-review/repository.d.ts.map +1 -1
- package/dist/types/human-review/results.d.ts +8 -8
- package/dist/types/human-review/results.d.ts.map +1 -1
- package/dist/types/human-review/service.d.ts +292 -292
- package/dist/types/human-review/service.d.ts.map +1 -1
- package/dist/types/human-review/task-proposals.d.ts +2 -2
- package/dist/types/human-review/task-proposals.d.ts.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/javascript-environment-attempt.d.ts.map +1 -1
- package/dist/types/javascript-environment-contract.d.ts +39 -39
- package/dist/types/javascript-environment-contract.d.ts.map +1 -1
- package/dist/types/javascript-environment-node.d.ts.map +1 -1
- package/dist/types/javascript-environment.d.ts +14 -14
- package/dist/types/javascript-environment.d.ts.map +1 -1
- package/dist/types/javascript-isolate-node.d.ts.map +1 -1
- package/dist/types/javascript-isolate-process-entry.d.ts.map +1 -1
- package/dist/types/javascript-isolate-process.d.ts.map +1 -1
- package/dist/types/javascript-isolate.d.ts.map +1 -1
- package/dist/types/javascript-verifier-contract.d.ts.map +1 -1
- package/dist/types/javascript-verifier-node.d.ts.map +1 -1
- package/dist/types/javascript-verifier-worker.d.ts.map +1 -1
- package/dist/types/javascript-verifier.d.ts +1 -0
- package/dist/types/javascript-verifier.d.ts.map +1 -1
- package/dist/types/learned-preference.d.ts +10 -10
- package/dist/types/learned-preference.d.ts.map +1 -1
- package/dist/types/learning/acceptance-group.d.ts +44 -44
- package/dist/types/learning/acceptance-group.d.ts.map +1 -1
- package/dist/types/learning/acceptance-plan.d.ts +8 -8
- package/dist/types/learning/acceptance-plan.d.ts.map +1 -1
- package/dist/types/learning/admission.d.ts +38 -36
- package/dist/types/learning/admission.d.ts.map +1 -1
- package/dist/types/learning/assets.d.ts +2 -2
- package/dist/types/learning/assets.d.ts.map +1 -1
- package/dist/types/learning/authoring-service.d.ts +11 -9
- package/dist/types/learning/authoring-service.d.ts.map +1 -1
- package/dist/types/learning/authoring.d.ts +46 -38
- package/dist/types/learning/authoring.d.ts.map +1 -1
- package/dist/types/learning/batch-service.d.ts +75 -68
- package/dist/types/learning/batch-service.d.ts.map +1 -1
- package/dist/types/learning/budgeted-reward-fixtures.d.ts.map +1 -1
- package/dist/types/learning/contracts.d.ts +314 -290
- package/dist/types/learning/contracts.d.ts.map +1 -1
- package/dist/types/learning/errors.d.ts.map +1 -1
- package/dist/types/learning/grade-judge-budget.d.ts.map +1 -1
- package/dist/types/learning/grade-worker.d.ts.map +1 -1
- package/dist/types/learning/index.d.ts.map +1 -1
- package/dist/types/learning/intake-contracts.d.ts +10 -10
- package/dist/types/learning/intake-contracts.d.ts.map +1 -1
- package/dist/types/learning/intake-csv.d.ts.map +1 -1
- package/dist/types/learning/intake-history.d.ts.map +1 -1
- package/dist/types/learning/intake-service.d.ts.map +1 -1
- package/dist/types/learning/intake-text.d.ts.map +1 -1
- package/dist/types/learning/intake.d.ts.map +1 -1
- package/dist/types/learning/iteration-budget.d.ts.map +1 -1
- package/dist/types/learning/iteration-candidate-decision.d.ts +16 -16
- package/dist/types/learning/iteration-candidate-decision.d.ts.map +1 -1
- package/dist/types/learning/iteration-dispatch-commands.d.ts.map +1 -1
- package/dist/types/learning/iteration-dispatch-contracts.d.ts +4 -4
- package/dist/types/learning/iteration-dispatch-contracts.d.ts.map +1 -1
- package/dist/types/learning/iteration-dispatch-worker.d.ts.map +1 -1
- package/dist/types/learning/iteration-eligibility.d.ts +1 -1
- package/dist/types/learning/iteration-eligibility.d.ts.map +1 -1
- package/dist/types/learning/iteration-reservation-cancellation.d.ts.map +1 -1
- 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.map +1 -1
- package/dist/types/learning/judge-budget.d.ts +1 -1
- package/dist/types/learning/judge-budget.d.ts.map +1 -1
- package/dist/types/learning/model-judge.d.ts.map +1 -1
- package/dist/types/learning/nightly-schedule.d.ts.map +1 -1
- package/dist/types/learning/operations.d.ts +312 -298
- package/dist/types/learning/operations.d.ts.map +1 -1
- package/dist/types/learning/policy-inspection.d.ts.map +1 -1
- package/dist/types/learning/rating-reward-fixture.d.ts.map +1 -1
- package/dist/types/learning/repository.d.ts +197 -180
- package/dist/types/learning/repository.d.ts.map +1 -1
- package/dist/types/learning/reward-authoring.d.ts.map +1 -1
- package/dist/types/learning/reward-calibration-closure.d.ts +252 -244
- package/dist/types/learning/reward-calibration-closure.d.ts.map +1 -1
- package/dist/types/learning/reward-calibration.d.ts +62 -62
- package/dist/types/learning/reward-calibration.d.ts.map +1 -1
- package/dist/types/learning/reward-check-budget.d.ts.map +1 -1
- package/dist/types/learning/reward-check-service.d.ts.map +1 -1
- package/dist/types/learning/reward-check-worker.d.ts.map +1 -1
- package/dist/types/learning/reward-checks.d.ts +30 -28
- package/dist/types/learning/reward-checks.d.ts.map +1 -1
- package/dist/types/learning/reward-fixture-executor.d.ts.map +1 -1
- package/dist/types/learning/schedule-contracts.d.ts +3 -3
- package/dist/types/learning/schedule-contracts.d.ts.map +1 -1
- package/dist/types/learning/schedule-service.d.ts +2 -2
- 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 +3 -3
- package/dist/types/learning/service.d.ts.map +1 -1
- package/dist/types/learning/task-queue-inspection.d.ts.map +1 -1
- package/dist/types/learning/training-handoff.d.ts +9 -9
- package/dist/types/learning/training-handoff.d.ts.map +1 -1
- package/dist/types/learning/transport.d.ts +2203 -2179
- package/dist/types/learning/transport.d.ts.map +1 -1
- package/dist/types/metric-policy.d.ts +6 -6
- package/dist/types/metric-policy.d.ts.map +1 -1
- package/dist/types/metrics-node.d.ts.map +1 -1
- package/dist/types/metrics.d.ts.map +1 -1
- package/dist/types/model-improvement-qualification.d.ts +17 -17
- package/dist/types/model-improvement-qualification.d.ts.map +1 -1
- package/dist/types/native-conversations/appimage-runtime.d.ts.map +1 -1
- package/dist/types/native-conversations/codex-window-inventory.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-acquisition.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-branches.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-calendar-gate.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-contracts.d.ts +3 -0
- package/dist/types/native-conversations/collector-contracts.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-coverage.d.ts +2 -2
- package/dist/types/native-conversations/collector-coverage.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-cron.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-destinations.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-errors.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-progress.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-schedule.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-service-files.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-snapshots.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-source-cache.d.ts +2 -2
- package/dist/types/native-conversations/collector-source-cache.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-store.d.ts.map +1 -1
- package/dist/types/native-conversations/collector-sync-requests.d.ts.map +1 -1
- package/dist/types/native-conversations/collector.d.ts.map +1 -1
- package/dist/types/native-conversations/contracts.d.ts.map +1 -1
- package/dist/types/native-conversations/database.d.ts.map +1 -1
- package/dist/types/native-conversations/discovery.d.ts.map +1 -1
- package/dist/types/native-conversations/git-assets.d.ts +32 -0
- package/dist/types/native-conversations/git-assets.d.ts.map +1 -0
- package/dist/types/native-conversations/history.d.ts +1 -0
- package/dist/types/native-conversations/history.d.ts.map +1 -1
- package/dist/types/native-conversations/index.d.ts +2 -0
- package/dist/types/native-conversations/index.d.ts.map +1 -1
- package/dist/types/native-conversations/location.d.ts.map +1 -1
- package/dist/types/native-conversations/openclaw-cold-archive.d.ts.map +1 -1
- package/dist/types/native-conversations/openclaw-database.d.ts.map +1 -1
- package/dist/types/native-conversations/readiness.d.ts.map +1 -1
- package/dist/types/native-conversations/selection.d.ts +32 -0
- package/dist/types/native-conversations/selection.d.ts.map +1 -0
- package/dist/types/native-conversations/source-locations.d.ts.map +1 -1
- package/dist/types/native-conversations/supervisor.d.ts.map +1 -1
- package/dist/types/native-conversations/titles.d.ts.map +1 -1
- package/dist/types/native-harness-experiment-attempt.d.ts.map +1 -1
- package/dist/types/preferences.d.ts +22 -22
- package/dist/types/preferences.d.ts.map +1 -1
- package/dist/types/prepared-process-isolation.d.ts +5 -0
- package/dist/types/prepared-process-isolation.d.ts.map +1 -0
- package/dist/types/profile-evaluation-comparisons.d.ts +18 -18
- package/dist/types/profile-evaluation-comparisons.d.ts.map +1 -1
- package/dist/types/profile-evaluation-execution.d.ts.map +1 -1
- package/dist/types/profile-evaluation-reports.d.ts +2 -2
- package/dist/types/profile-evaluation-reports.d.ts.map +1 -1
- package/dist/types/profile-evaluation-suites.d.ts.map +1 -1
- package/dist/types/profile-evaluation-target.d.ts.map +1 -1
- package/dist/types/profile-evaluations.d.ts +15 -15
- package/dist/types/profile-evaluations.d.ts.map +1 -1
- package/dist/types/profile-external-evaluation.d.ts +84 -84
- package/dist/types/profile-external-evaluation.d.ts.map +1 -1
- package/dist/types/profile-source-candidate.d.ts.map +1 -1
- package/dist/types/review-conformance.d.ts +58 -58
- package/dist/types/review-conformance.d.ts.map +1 -1
- package/dist/types/rewards.d.ts +110 -101
- package/dist/types/rewards.d.ts.map +1 -1
- package/dist/types/rollouts.d.ts +16 -16
- package/dist/types/rollouts.d.ts.map +1 -1
- package/dist/types/runs.d.ts +22 -22
- package/dist/types/runs.d.ts.map +1 -1
- package/dist/types/sql-execution-contract.d.ts +3 -3
- package/dist/types/sql-execution-contract.d.ts.map +1 -1
- package/dist/types/sql-execution-engine.d.ts.map +1 -1
- package/dist/types/sql-execution-node.d.ts.map +1 -1
- package/dist/types/sql-execution-process-entry.d.ts.map +1 -1
- package/dist/types/task-schema-validation.d.ts.map +1 -1
- package/dist/types/task-schema.d.ts.map +1 -1
- package/dist/types/task-value-validator.d.ts.map +1 -1
- package/dist/types/taskset-run-contract.d.ts +26 -26
- package/dist/types/taskset-run-contract.d.ts.map +1 -1
- package/dist/types/tasksets.d.ts +89 -69
- package/dist/types/tasksets.d.ts.map +1 -1
- package/dist/types/telemetry/index.d.ts.map +1 -1
- package/dist/types/telemetry-analysis.d.ts +6 -6
- package/dist/types/telemetry-analysis.d.ts.map +1 -1
- package/dist/types/telemetry-bundle.d.ts +42 -42
- package/dist/types/telemetry-bundle.d.ts.map +1 -1
- package/dist/types/telemetry-catalog.d.ts +67 -67
- package/dist/types/telemetry-catalog.d.ts.map +1 -1
- package/dist/types/telemetry.d.ts +44 -44
- package/dist/types/telemetry.d.ts.map +1 -1
- package/package.json +6 -1
- package/schemas/learning/v1/binding.schema.json +8 -0
- package/schemas/learning/v1/command-request.schema.json +12 -0
- package/schemas/learning/v1/decision.schema.json +5 -1
- package/schemas/learning/v1/definition.schema.json +4 -0
- package/schemas/learning/v1/draft.schema.json +8 -0
- package/schemas/learning/v1/evidence.schema.json +4 -0
- package/schemas/learning/v1/example-submission.schema.json +4 -0
- package/schemas/learning/v1/grade.schema.json +5 -1
- package/schemas/learning/v1/package.schema.json +117 -93
- package/schemas/learning/v1/reward_check.schema.json +2 -1
|
@@ -12,7 +12,7 @@ export class CollectorSourceCache {
|
|
|
12
12
|
}
|
|
13
13
|
selection(connection, until, revision) {
|
|
14
14
|
return contentHash([connection.source, connection.projectId, connection.teamId,
|
|
15
|
-
connection.apiBaseUrl, connection.account ?? null, connection.since, until, revision]);
|
|
15
|
+
connection.apiBaseUrl, connection.account ?? null, connection.since, connection.selectedSessionKeys ?? null, until, revision]);
|
|
16
16
|
}
|
|
17
17
|
read(connection, until, sessionKey, revision) {
|
|
18
18
|
const row = this.store.database.prepare("SELECT value FROM source_read_cache WHERE connection_id=? AND session_key=? AND selection_hash=?").get(connection.id, sessionKey, this.selection(connection, until, revision));
|
|
@@ -61,6 +61,20 @@ export class CollectorStore {
|
|
|
61
61
|
this.database.exec("COMMIT");
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
|
+
if (prior && JSON.stringify(prior.selectedSessionKeys) !== JSON.stringify(connection.selectedSessionKeys)) {
|
|
65
|
+
const owner = JSON.parse(this.setting("owner") || "{}");
|
|
66
|
+
if (owner.pid) {
|
|
67
|
+
let alive = true;
|
|
68
|
+
try {
|
|
69
|
+
process.kill(owner.pid, 0);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
alive = error.code !== "ESRCH";
|
|
73
|
+
}
|
|
74
|
+
if (alive)
|
|
75
|
+
throw new Error("Cancel or finish the running import before changing its conversation selection.");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
64
78
|
const identityChanged = !!prior &&
|
|
65
79
|
(prior.source.instanceId !== connection.source.instanceId ||
|
|
66
80
|
prior.projectId !== connection.projectId ||
|
|
@@ -69,7 +83,8 @@ export class CollectorStore {
|
|
|
69
83
|
prior.account !== connection.account);
|
|
70
84
|
if (identityChanged)
|
|
71
85
|
connection = { ...connection, destinations: undefined };
|
|
72
|
-
if (prior && (identityChanged || prior.since !== connection.since
|
|
86
|
+
if (prior && (identityChanged || prior.since !== connection.since ||
|
|
87
|
+
JSON.stringify(prior.selectedSessionKeys) !== JSON.stringify(connection.selectedSessionKeys))) {
|
|
73
88
|
this.database.prepare("DELETE FROM settings WHERE key=?").run(`coverage:${connection.id}`);
|
|
74
89
|
this.database.prepare("DELETE FROM coverage_sessions WHERE connection_id=?").run(connection.id);
|
|
75
90
|
// Scope changes fence queued evidence too: do not upload a wider old
|
|
@@ -81,7 +96,16 @@ export class CollectorStore {
|
|
|
81
96
|
this.database.prepare("DELETE FROM settings WHERE key=?").run(`syncAcknowledged:${connection.id}`);
|
|
82
97
|
connection = { ...connection, completedSyncRevision: 0 };
|
|
83
98
|
this.error(connection.id, null);
|
|
84
|
-
|
|
99
|
+
if (!identityChanged && prior.since === connection.since) {
|
|
100
|
+
// Preserve acknowledged boundaries when adding conversations, but
|
|
101
|
+
// reacquire every queued boundary whose snapshot is being discarded.
|
|
102
|
+
this.database.prepare(`DELETE FROM checkpoints WHERE connection_id=? AND EXISTS (
|
|
103
|
+
SELECT 1 FROM pending p, json_each(p.payload,'$.boundaryIds') b
|
|
104
|
+
WHERE p.connection_id=checkpoints.connection_id
|
|
105
|
+
AND json_extract(p.payload,'$.sessionKey')=checkpoints.session_key
|
|
106
|
+
AND b.value=checkpoints.boundary_id)`).run(connection.id);
|
|
107
|
+
}
|
|
108
|
+
for (const table of identityChanged || prior.since !== connection.since ? ["source_scans", "checkpoints", "pending"] : ["source_scans", "pending"])
|
|
85
109
|
this.database
|
|
86
110
|
.prepare(`DELETE FROM ${table} WHERE connection_id=?`)
|
|
87
111
|
.run(connection.id);
|
|
@@ -270,6 +294,7 @@ export class CollectorStore {
|
|
|
270
294
|
.get(String(row.id))?.bytes ?? 0),
|
|
271
295
|
lastAdmissionAt: this.setting(`lastAdmission:${row.id}`),
|
|
272
296
|
since: config.since,
|
|
297
|
+
selectedConversations: config.selectedSessionKeys?.length ?? null,
|
|
273
298
|
schedule,
|
|
274
299
|
nextRunAt: schedule && config.state === "active" ? nextScheduledSync(schedule) : null,
|
|
275
300
|
lastSuccessfulSyncAt: this.setting(`lastSuccess:${row.id}`),
|
|
@@ -36,7 +36,7 @@ export async function runCollector(input) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
const now = new Date();
|
|
39
|
-
selected = store.connections().filter(connection => connection.state !== "disconnected" &&
|
|
39
|
+
selected = store.connections().filter(connection => connection.state !== "disconnected" && connection.selectedSessionKeys?.length !== 0 &&
|
|
40
40
|
(!input.connectionIds || input.connectionIds.includes(connection.id)) &&
|
|
41
41
|
(input.trigger !== "scheduled" || (connection.state === "active" && scheduledSyncDue(store.schedule(connection.id), store.setting(`scheduledMinute:${connection.id}`), now))));
|
|
42
42
|
if (input.trigger === "scheduled")
|
|
@@ -173,13 +173,14 @@ export async function runCollector(input) {
|
|
|
173
173
|
for (let pass = 0; pass < 3; pass++) {
|
|
174
174
|
await check();
|
|
175
175
|
const revision = connection.revision, requested = connection.requestedSyncRevision ?? 0;
|
|
176
|
+
const selection = JSON.stringify(connection.selectedSessionKeys);
|
|
176
177
|
phase = "source";
|
|
177
178
|
new CollectorSourceCache(store).seed(connection, until, store.coverage.manifest(connection.id));
|
|
178
179
|
store.coverage.begin(connection, `${nonce}-${pass}`, run.startedAt, until);
|
|
179
180
|
const checkAcquisition = async () => {
|
|
180
181
|
await check();
|
|
181
182
|
phase = "source";
|
|
182
|
-
if (connection.revision !== revision)
|
|
183
|
+
if (connection.revision !== revision || JSON.stringify(connection.selectedSessionKeys) !== selection)
|
|
183
184
|
throw new CollectorScopeChangedError("Source settings changed during acquisition.");
|
|
184
185
|
};
|
|
185
186
|
try {
|
|
@@ -193,7 +194,7 @@ export async function runCollector(input) {
|
|
|
193
194
|
}
|
|
194
195
|
errors.set(connection.id, "source", null);
|
|
195
196
|
await drain();
|
|
196
|
-
await input.transport.publishCoverage(connection, store.coverage.finish(connection.id,
|
|
197
|
+
await input.transport.publishCoverage(connection, store.coverage.finish(connection.id, connection.selectedSessionKeys === undefined), signal);
|
|
197
198
|
connection = retained(connection);
|
|
198
199
|
if (connection.revision !== revision) {
|
|
199
200
|
if (pass === 2)
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { realpath } from "node:fs/promises";
|
|
3
|
+
import { isAbsolute } from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { ConnectedRepositoryContextSchema } from "../connected-evidence/contracts.js";
|
|
6
|
+
import { ConnectedGitFileProofSchema, verifyConnectedGitFileProof } from "../connected-evidence/git-file-proof.js";
|
|
7
|
+
const execute = promisify(execFile);
|
|
8
|
+
/** Capture only recorded Git objects. A missing historical object is an explicit
|
|
9
|
+
* gap; this operation never reads the current worktree or fetches another repo. */
|
|
10
|
+
export async function captureNativeGitAssetProofs(input) {
|
|
11
|
+
const context = ConnectedRepositoryContextSchema.parse(input.repositoryContext);
|
|
12
|
+
if (!isAbsolute(input.repositoryPath) || !input.paths.length || input.paths.length > 100
|
|
13
|
+
|| new Set(input.paths).size !== input.paths.length)
|
|
14
|
+
throw new Error("native_git_asset_selection_invalid");
|
|
15
|
+
// Validate selections before invoking Git, including paths prohibited by the
|
|
16
|
+
// source asset policy. The remaining fields are filled from immutable objects.
|
|
17
|
+
for (const path of input.paths)
|
|
18
|
+
ConnectedGitFileProofSchema.shape.path.parse(path);
|
|
19
|
+
const repository = await realpath(input.repositoryPath);
|
|
20
|
+
const read = async (args, maxBuffer = 2 * 1024 * 1024) => {
|
|
21
|
+
input.signal?.throwIfAborted();
|
|
22
|
+
const result = await execute("git", ["-C", repository, ...args], {
|
|
23
|
+
encoding: "buffer", timeout: 15_000, maxBuffer, signal: input.signal,
|
|
24
|
+
});
|
|
25
|
+
return result.stdout;
|
|
26
|
+
};
|
|
27
|
+
const objectId = async (ref) => {
|
|
28
|
+
const hash = (await read(["rev-parse", "--verify", ref], 1_024)).toString("ascii").trim();
|
|
29
|
+
if (!new RegExp(`^[a-f0-9]{${context.commitHash.length}}$`).test(hash))
|
|
30
|
+
throw new Error("native_git_object_identity_invalid");
|
|
31
|
+
return hash;
|
|
32
|
+
};
|
|
33
|
+
const commit = await read(["cat-file", "commit", context.commitHash], 256 * 1024);
|
|
34
|
+
const cache = new Map();
|
|
35
|
+
let totalBytes = 0;
|
|
36
|
+
const proofs = [];
|
|
37
|
+
for (const path of input.paths) {
|
|
38
|
+
const directories = ["", ...path.split("/").slice(0, -1).map((_, index, parts) => parts.slice(0, index + 1).join("/"))];
|
|
39
|
+
const trees = [];
|
|
40
|
+
for (const directory of directories) {
|
|
41
|
+
const ref = directory ? `${context.commitHash}:${directory}` : `${context.commitHash}^{tree}`;
|
|
42
|
+
let tree = cache.get(ref);
|
|
43
|
+
if (!tree) {
|
|
44
|
+
const hash = await objectId(ref);
|
|
45
|
+
tree = { hash, base64: (await read(["cat-file", "tree", hash])).toString("base64") };
|
|
46
|
+
cache.set(ref, tree);
|
|
47
|
+
}
|
|
48
|
+
trees.push(tree);
|
|
49
|
+
}
|
|
50
|
+
const blob = await objectId(`${context.commitHash}:${path}`);
|
|
51
|
+
const proof = ConnectedGitFileProofSchema.parse({ schemaVersion: "openpond.connectedGitFileProof.v1", path,
|
|
52
|
+
commit: { hash: context.commitHash, base64: commit.toString("base64") }, trees,
|
|
53
|
+
contentsBase64: (await read(["cat-file", "blob", blob])).toString("base64") });
|
|
54
|
+
const verified = verifyConnectedGitFileProof(context, proof);
|
|
55
|
+
totalBytes += Buffer.byteLength(JSON.stringify(proof));
|
|
56
|
+
if (totalBytes > 16 * 1024 * 1024)
|
|
57
|
+
throw new Error("native_git_asset_capture_limit");
|
|
58
|
+
proofs.push({ proof, verified });
|
|
59
|
+
}
|
|
60
|
+
return proofs;
|
|
61
|
+
}
|
|
@@ -293,6 +293,13 @@ export async function readSession(source, session, input = {}) {
|
|
|
293
293
|
const graph = claudeGraph(connectedJsonLines(file));
|
|
294
294
|
if (graph.sessionId !== session.nativeSessionId)
|
|
295
295
|
throw new Error("Native session changed identity.");
|
|
296
|
+
if (input.latestBranch) {
|
|
297
|
+
if (input.branchLeafId || input.expectedBranchRevision || input.branchAnchor)
|
|
298
|
+
throw new Error("Choose either the latest conversation or an explicit branch.");
|
|
299
|
+
// Desktop inspection follows the native conversation. Imports keep their
|
|
300
|
+
// existing explicit branch authority and never enable this option.
|
|
301
|
+
files = [{ ...file, text: graph.select(graph.latestLeafId()).chain.map(row => JSON.stringify(row)).join("\n") + "\n" }];
|
|
302
|
+
}
|
|
296
303
|
if (input.branchAnchor) {
|
|
297
304
|
if (input.branchLeafId || input.expectedBranchRevision)
|
|
298
305
|
throw new Error("Choose either a frozen branch snapshot or a followed branch anchor.");
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
export * from "./contracts.js";
|
|
3
3
|
export * from "./discovery.js";
|
|
4
4
|
export * from "./history.js";
|
|
5
|
+
export * from "./selection.js";
|
|
5
6
|
export * from "./collector-contracts.js";
|
|
6
7
|
export * from "./collector-store.js";
|
|
7
8
|
export * from "./collector.js";
|
|
@@ -10,3 +11,4 @@ export * from "./location.js";
|
|
|
10
11
|
export * from "./collector-branches.js";
|
|
11
12
|
export * from "./collector-destinations.js";
|
|
12
13
|
export * from "./collector-schedule.js";
|
|
14
|
+
export { captureNativeGitAssetProofs } from "./git-assets.js";
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { contentHash } from "@openpond/harness";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { listSessions } from "./history.js";
|
|
4
|
+
export const NativeUploadSelectionSchema = z.object({
|
|
5
|
+
sourceInstanceId: z.string().min(1).max(500),
|
|
6
|
+
sessionKeys: z.array(z.string().regex(/^[a-f0-9]{64}$/)).min(1).max(10_000),
|
|
7
|
+
}).strict().refine(value => new Set(value.sessionKeys).size === value.sessionKeys.length, "Conversation selection contains duplicates.");
|
|
8
|
+
/** Includes the source path so duplicate native IDs cannot select a sibling file. */
|
|
9
|
+
export function nativeSessionSelectionKey(session) {
|
|
10
|
+
return contentHash(JSON.stringify([session.path, session.nativeSessionId]));
|
|
11
|
+
}
|
|
12
|
+
export async function nativeUploadInventory(source) {
|
|
13
|
+
if (!source.available || !source.capabilities.history)
|
|
14
|
+
throw new Error("The selected conversation source is unavailable.");
|
|
15
|
+
const items = [];
|
|
16
|
+
let cursor;
|
|
17
|
+
const seen = new Set();
|
|
18
|
+
do {
|
|
19
|
+
const page = await listSessions(source, { cursor, limit: 100 });
|
|
20
|
+
items.push(...page.items);
|
|
21
|
+
if (items.length > 10_000)
|
|
22
|
+
throw new Error("Choose a source with no more than 10,000 conversations.");
|
|
23
|
+
cursor = page.nextCursor ?? undefined;
|
|
24
|
+
if (cursor && seen.has(cursor))
|
|
25
|
+
throw new Error("Conversation listing did not advance. Refresh the source.");
|
|
26
|
+
if (cursor)
|
|
27
|
+
seen.add(cursor);
|
|
28
|
+
} while (cursor);
|
|
29
|
+
return items;
|
|
30
|
+
}
|
|
31
|
+
export async function validateNativeUploadSelection(source, raw) {
|
|
32
|
+
const selection = NativeUploadSelectionSchema.parse(raw);
|
|
33
|
+
if (selection.sourceInstanceId !== source.instanceId)
|
|
34
|
+
throw new Error("Conversation selection belongs to another source installation.");
|
|
35
|
+
const available = new Set((await nativeUploadInventory(source)).map(nativeSessionSelectionKey));
|
|
36
|
+
if (selection.sessionKeys.some(key => !available.has(key)))
|
|
37
|
+
throw new Error("A selected conversation is no longer available. Refresh and select it again.");
|
|
38
|
+
return selection;
|
|
39
|
+
}
|
|
40
|
+
export function nativeUploadConversationPage(connection, inventory, input) {
|
|
41
|
+
const query = (input.query ?? "").trim().toLocaleLowerCase(), range = input.range ?? "all", offset = input.offset ?? 0;
|
|
42
|
+
if (query.length > 500 || !["day", "week", "all"].includes(range) || !Number.isInteger(offset) || offset < 0 || offset > 10_000)
|
|
43
|
+
throw new Error("Invalid conversation search or page.");
|
|
44
|
+
const since = range === "all" ? 0 : Date.now() - (range === "day" ? 1 : 7) * 86400000;
|
|
45
|
+
const items = inventory.filter(item => Date.parse(item.updatedAt) >= since &&
|
|
46
|
+
(!query || [item.title, item.cwd, item.nativeSessionId].some(text => text?.toLocaleLowerCase().includes(query))))
|
|
47
|
+
.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
48
|
+
const approved = connection.selectedSessionKeys ? new Set(connection.selectedSessionKeys) : null;
|
|
49
|
+
return {
|
|
50
|
+
total: items.length, nextOffset: offset + 50 < items.length ? offset + 50 : null,
|
|
51
|
+
items: items.slice(offset, offset + 50).map(item => ({
|
|
52
|
+
key: nativeSessionSelectionKey(item), title: item.title, cwd: item.cwd,
|
|
53
|
+
nativeSessionId: item.nativeSessionId, updatedAt: item.updatedAt, issue: item.issue ?? null,
|
|
54
|
+
approved: approved === null || approved.has(nativeSessionSelectionKey(item)),
|
|
55
|
+
})),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -164,6 +164,8 @@ export async function setCollectorSchedule(input, connectionId, schedule) {
|
|
|
164
164
|
const connection = store.connections().find(item => item.id === connectionId);
|
|
165
165
|
if (!connection || (schedule && connection.state === "disconnected"))
|
|
166
166
|
throw new Error("Select a connected source before scheduling imports.");
|
|
167
|
+
if (schedule && connection.selectedSessionKeys?.length === 0)
|
|
168
|
+
throw new Error("Choose conversations to upload before enabling continual imports.");
|
|
167
169
|
const owner = store.setting("scheduleOwner");
|
|
168
170
|
if (owner) {
|
|
169
171
|
const { pid } = JSON.parse(owner);
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/** Staged by the private verifier owner. Untrusted policy programs run with no
|
|
2
|
+
* capabilities as a different UID, outside the sealed private verifier tree.
|
|
3
|
+
* The parent must assess returned behavior; an exit code is never correctness. */
|
|
4
|
+
export const PREPARED_PROCESS_ISOLATION_SOURCE = String.raw `
|
|
5
|
+
import fs from "node:fs/promises";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { randomInt } from "node:crypto";
|
|
10
|
+
|
|
11
|
+
const MAX_BYTES = 15 * 1024 * 1024, MAX_OUTPUT = 1024 * 1024;
|
|
12
|
+
const usedUsers = new Set();
|
|
13
|
+
const safePath = value => typeof value === "string" && value.length > 0 && value.length <= 2000
|
|
14
|
+
&& !value.startsWith("/") && !/[\\\x00-\x1f\x7f]/.test(value)
|
|
15
|
+
&& value.split("/").every(part => part && part !== "." && part !== ".." && !part.startsWith(".env"));
|
|
16
|
+
|
|
17
|
+
/** files contain only public original/policy bytes and a public invocation
|
|
18
|
+
* adapter. Never stage independent assertions, expected answers or checkers. */
|
|
19
|
+
export async function runPolicyProgram(input) {
|
|
20
|
+
const privateRoot = path.dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
if (process.getuid?.() !== 0 || !path.basename(privateRoot).startsWith(".openpond-reward-verifier-"))
|
|
22
|
+
throw new Error("policy_process_isolation_runtime_unavailable");
|
|
23
|
+
if (!Array.isArray(input.files) || input.files.length < 1 || input.files.length > 100
|
|
24
|
+
|| !safePath(input.entrypoint) || !input.files.some(file => file.path === input.entrypoint)
|
|
25
|
+
|| !Number.isSafeInteger(input.timeoutMs) || input.timeoutMs < 1 || input.timeoutMs > 60000
|
|
26
|
+
|| !Array.isArray(input.args ?? []) || (input.args ?? []).length > 100
|
|
27
|
+
|| (input.args ?? []).some(arg => typeof arg !== "string" || arg.length > 2000 || arg.includes("\0")))
|
|
28
|
+
throw new Error("policy_process_isolation_input_invalid");
|
|
29
|
+
let total = 0;
|
|
30
|
+
const paths = new Set();
|
|
31
|
+
const files = input.files.map(file => {
|
|
32
|
+
if (!safePath(file.path) || paths.has(file.path) || typeof file.base64 !== "string")
|
|
33
|
+
throw new Error("policy_process_isolation_file_invalid");
|
|
34
|
+
paths.add(file.path);
|
|
35
|
+
const bytes = Buffer.from(file.base64, "base64");
|
|
36
|
+
if (bytes.toString("base64") !== file.base64) throw new Error("policy_process_isolation_file_invalid");
|
|
37
|
+
total += bytes.length;
|
|
38
|
+
if (total > MAX_BYTES) throw new Error("policy_process_isolation_file_limit");
|
|
39
|
+
return { path: file.path, bytes };
|
|
40
|
+
});
|
|
41
|
+
// Directory access seals request JSON, checker modules, helper source and
|
|
42
|
+
// private artifacts before any untrusted program can be spawned.
|
|
43
|
+
await fs.chmod(privateRoot, 0o700);
|
|
44
|
+
const stat = await fs.stat(privateRoot);
|
|
45
|
+
if (stat.uid !== 0 || (stat.mode & 0o777) !== 0o700) throw new Error("policy_process_private_tree_not_sealed");
|
|
46
|
+
for (const executable of ["/usr/bin/setsid", "/usr/bin/setpriv", "/usr/local/bin/bun"])
|
|
47
|
+
await fs.access(executable, 1);
|
|
48
|
+
const directory = await fs.mkdtemp(path.join(os.tmpdir(), "openpond-policy-"));
|
|
49
|
+
let user;
|
|
50
|
+
do { user = randomInt(1000000, 2000000); } while (usedUsers.has(user));
|
|
51
|
+
usedUsers.add(user);
|
|
52
|
+
let child, timer, timedOut = false;
|
|
53
|
+
const kill = () => {
|
|
54
|
+
if (!child) return;
|
|
55
|
+
try { process.kill(-child.pid, "SIGKILL"); } catch {}
|
|
56
|
+
try { child.kill("SIGKILL"); } catch {}
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
await fs.chmod(directory, 0o700);
|
|
60
|
+
await fs.chown(directory, user, user);
|
|
61
|
+
for (const file of files) {
|
|
62
|
+
const target = path.join(directory, file.path);
|
|
63
|
+
const parent = path.dirname(target);
|
|
64
|
+
await fs.mkdir(parent, { recursive: true, mode: 0o700 });
|
|
65
|
+
let current = parent;
|
|
66
|
+
while (current !== directory) {
|
|
67
|
+
await fs.chmod(current, 0o700); await fs.chown(current, user, user);
|
|
68
|
+
current = path.dirname(current);
|
|
69
|
+
}
|
|
70
|
+
await fs.writeFile(target, file.bytes, { mode: 0o600, flag: "wx" });
|
|
71
|
+
await fs.chown(target, user, user);
|
|
72
|
+
}
|
|
73
|
+
child = Bun.spawn(["/usr/bin/setsid", "/usr/bin/setpriv", "--reuid=" + user, "--regid=" + user, "--clear-groups",
|
|
74
|
+
"--no-new-privs", "--bounding-set=-all", "--inh-caps=-all", "--ambient-caps=-all",
|
|
75
|
+
"/usr/local/bin/bun", path.join(directory, input.entrypoint), ...(input.args ?? [])], {
|
|
76
|
+
cwd: directory, env: { PATH: "/usr/local/bin:/usr/bin:/bin", TMPDIR: directory }, stdout: "pipe", stderr: "pipe", stdin: "ignore",
|
|
77
|
+
});
|
|
78
|
+
timer = setTimeout(() => { timedOut = true; kill(); }, input.timeoutMs);
|
|
79
|
+
const read = async stream => {
|
|
80
|
+
const reader = stream.getReader(), chunks = [];
|
|
81
|
+
let bytes = 0;
|
|
82
|
+
try {
|
|
83
|
+
while (true) {
|
|
84
|
+
const item = await reader.read(); if (item.done) break;
|
|
85
|
+
bytes += item.value.byteLength;
|
|
86
|
+
if (bytes > MAX_OUTPUT) { kill(); throw new Error("policy_process_output_limit"); }
|
|
87
|
+
chunks.push(item.value);
|
|
88
|
+
}
|
|
89
|
+
return new TextDecoder("utf8", { fatal: true }).decode(Buffer.concat(chunks));
|
|
90
|
+
} finally { await reader.cancel(); reader.releaseLock(); }
|
|
91
|
+
};
|
|
92
|
+
const [stdout, stderr, exitCode] = await Promise.all([read(child.stdout), read(child.stderr), child.exited]);
|
|
93
|
+
return { stdout, stderr, exitCode, timedOut, isolation: { uid: user, gid: user, privateTreeSealed: true } };
|
|
94
|
+
} finally {
|
|
95
|
+
if (timer) clearTimeout(timer);
|
|
96
|
+
kill();
|
|
97
|
+
// A policy child can call setsid and escape its initial process group.
|
|
98
|
+
// Drain every process with this invocation's unique real UID before the
|
|
99
|
+
// next call; namespaces cannot grant a different outside UID or privilege.
|
|
100
|
+
try { await drainPolicyProcesses(user); }
|
|
101
|
+
finally { await fs.rm(directory, { recursive: true, force: true }); }
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function drainPolicyProcesses(user) {
|
|
106
|
+
const deadline = Date.now() + 2000;
|
|
107
|
+
let empty = 0;
|
|
108
|
+
while (Date.now() < deadline) {
|
|
109
|
+
const entries = (await fs.readdir("/proc")).filter(value => /^\d+$/.test(value));
|
|
110
|
+
if (entries.length > 10000) throw new Error("policy_process_inventory_limit");
|
|
111
|
+
let owned = 0;
|
|
112
|
+
for (const entry of entries) {
|
|
113
|
+
let status;
|
|
114
|
+
try { status = await fs.readFile("/proc/" + entry + "/status", "utf8"); }
|
|
115
|
+
catch (error) { if (["ENOENT", "ESRCH"].includes(error.code)) continue; throw error; }
|
|
116
|
+
const ids = /^Uid:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/m.exec(status);
|
|
117
|
+
if (ids && ids.slice(1).some(value => Number(value) === user)) {
|
|
118
|
+
// Zombies cannot fork, inspect a subsequent invocation or hold files.
|
|
119
|
+
if (/^State:\s+Z/m.test(status)) continue;
|
|
120
|
+
owned++;
|
|
121
|
+
try { process.kill(Number(entry), "SIGKILL"); }
|
|
122
|
+
catch (error) { if (error.code !== "ESRCH") throw error; }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
empty = owned === 0 ? empty + 1 : 0;
|
|
126
|
+
if (empty >= 2) return;
|
|
127
|
+
await new Promise(resolve => setTimeout(resolve, 20));
|
|
128
|
+
}
|
|
129
|
+
throw new Error("policy_process_cleanup_unconfirmed");
|
|
130
|
+
}
|
|
131
|
+
`;
|
package/dist/rewards.js
CHANGED
|
@@ -4,7 +4,7 @@ import { ImmutableAssetRefSchema, ImmutableReleaseRefSchema, ReleaseHashSchema,
|
|
|
4
4
|
import { gradeEvidence, GraderEvidenceSchema } from "./graders.js";
|
|
5
5
|
import { CustomVerifierGraderSpecSchema, DeterministicGraderSpecSchema, GraderSpecSchema, HumanGraderSpecSchema, ModelJudgeGraderSpecSchema } from "./tasksets.js";
|
|
6
6
|
import { assertBoundedTaskJson, validateTaskSchema } from "./task-schema.js";
|
|
7
|
-
const bindingFields = { id: true, version: true, weight: true, hardGate: true, rewardEligible: true, privileged: true };
|
|
7
|
+
const bindingFields = { taskIds: true, id: true, version: true, weight: true, hardGate: true, rewardEligible: true, privileged: true };
|
|
8
8
|
export const FeedbackKeySchema = z.string().regex(/^[a-z][a-z0-9_]{0,79}$/);
|
|
9
9
|
export function feedbackKeyForReward(reward) {
|
|
10
10
|
return reward.feedbackKey ?? `reward_${contentHash(reward.id).slice(0, 24)}`;
|
|
@@ -49,6 +49,7 @@ export const RewardNormalizationSchema = z.discriminatedUnion("kind", [
|
|
|
49
49
|
]);
|
|
50
50
|
export const RewardBindingSourceSchema = z.object({
|
|
51
51
|
graderId: ReleaseIdSchema,
|
|
52
|
+
taskIds: z.array(ReleaseIdSchema).min(1).max(10_000).refine(ids => new Set(ids).size === ids.length, "Task scope must be unique.").optional(),
|
|
52
53
|
reward: RewardReleaseRefSchema,
|
|
53
54
|
role: z.enum(["training", "evaluation"]),
|
|
54
55
|
normalization: RewardNormalizationSchema,
|
|
@@ -87,7 +88,7 @@ export const BoundRewardResultSchema = z.object({
|
|
|
87
88
|
graderId: ReleaseIdSchema,
|
|
88
89
|
reward: RewardReleaseRefSchema,
|
|
89
90
|
role: z.enum(["training", "evaluation"]),
|
|
90
|
-
status: z.enum(["scored", "pending", "unavailable", "failed"]),
|
|
91
|
+
status: z.enum(["scored", "pending", "unavailable", "failed", "not_applicable"]),
|
|
91
92
|
rawScore: z.number().finite().nullable(),
|
|
92
93
|
normalizedScore: z.number().min(0).max(1).nullable(),
|
|
93
94
|
passed: z.boolean().nullable(),
|
|
@@ -99,6 +100,7 @@ export const RewardCompositionContentSchema = z.object({
|
|
|
99
100
|
schemaVersion: z.literal("openpond.rewardComposition.v1"),
|
|
100
101
|
binding: RewardReleaseRefSchema,
|
|
101
102
|
taskHash: ReleaseHashSchema,
|
|
103
|
+
taskId: ReleaseIdSchema.optional(),
|
|
102
104
|
outputHash: ReleaseHashSchema,
|
|
103
105
|
results: z.array(BoundRewardResultSchema).max(100),
|
|
104
106
|
training: z.object({ status: z.enum(["scored", "pending", "unscorable", "not_configured"]), score: z.number().min(0).max(1).nullable(), passed: z.boolean().nullable() }).strict(),
|
|
@@ -149,6 +151,10 @@ export async function executeRewardBinding(input) {
|
|
|
149
151
|
for (const { source, reward } of resolved) {
|
|
150
152
|
input.signal?.throwIfAborted();
|
|
151
153
|
const result = { graderId: source.graderId, reward: source.reward, role: source.role, status: "unavailable", rawScore: null, normalizedScore: null, passed: null, evidenceHashes: [], message: null };
|
|
154
|
+
if (source.taskIds && !source.taskIds.includes(input.task.id)) {
|
|
155
|
+
results.push({ ...result, status: "not_applicable" });
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
152
158
|
try {
|
|
153
159
|
if (reward.implementation.kind === "human") {
|
|
154
160
|
result.status = "pending";
|
|
@@ -183,11 +189,13 @@ export async function executeRewardBinding(input) {
|
|
|
183
189
|
}
|
|
184
190
|
results.push(BoundRewardResultSchema.parse(result));
|
|
185
191
|
}
|
|
186
|
-
return composeBoundRewards({ binding: input.binding, taskHash: contentHash(input.task), outputHash: contentHash(input.evidence), results });
|
|
192
|
+
return composeBoundRewards({ binding: input.binding, ...(input.binding.sources.some(source => source.taskIds) ? { taskId: input.task.id } : {}), taskHash: contentHash(input.task), outputHash: contentHash(input.evidence), results });
|
|
187
193
|
}
|
|
188
194
|
export function composeBoundRewards(input) {
|
|
189
195
|
const binding = RewardBindingSchema.parse(input.binding);
|
|
190
196
|
assertRewardHash(binding);
|
|
197
|
+
if (binding.sources.some(source => source.taskIds) && !input.taskId)
|
|
198
|
+
throw new LearningDomainError("reward_task_scope_missing");
|
|
191
199
|
const results = input.results.map((result) => BoundRewardResultSchema.parse(result));
|
|
192
200
|
if (results.length !== binding.sources.length || new Set(results.map((result) => result.graderId)).size !== results.length)
|
|
193
201
|
throw new LearningDomainError("reward_result_set_incomplete");
|
|
@@ -195,6 +203,9 @@ export function composeBoundRewards(input) {
|
|
|
195
203
|
const result = results.find((candidate) => candidate.graderId === source.graderId);
|
|
196
204
|
if (!result || contentHash(result.reward) !== contentHash(source.reward) || result.role !== source.role)
|
|
197
205
|
throw new LearningDomainError("reward_result_binding_mismatch");
|
|
206
|
+
const applicable = !source.taskIds || source.taskIds.includes(input.taskId);
|
|
207
|
+
if (applicable === (result.status === "not_applicable") || !applicable && (result.graderEvidence || result.evidenceHashes.length || result.message !== null))
|
|
208
|
+
throw new LearningDomainError("reward_result_task_scope_mismatch");
|
|
198
209
|
if (result.graderEvidence) {
|
|
199
210
|
const { contentHash: evidenceHash, ...body } = result.graderEvidence;
|
|
200
211
|
if (contentHash(body) !== evidenceHash || !result.evidenceHashes.includes(evidenceHash)
|
|
@@ -219,6 +230,7 @@ export function composeBoundRewards(input) {
|
|
|
219
230
|
schemaVersion: "openpond.rewardComposition.v1",
|
|
220
231
|
binding: { id: binding.id, revision: binding.revision, contentHash: binding.contentHash },
|
|
221
232
|
taskHash: input.taskHash,
|
|
233
|
+
...(input.taskId ? { taskId: input.taskId } : {}),
|
|
222
234
|
outputHash: input.outputHash,
|
|
223
235
|
results,
|
|
224
236
|
training: aggregate("training"),
|
|
@@ -226,7 +238,7 @@ export function composeBoundRewards(input) {
|
|
|
226
238
|
});
|
|
227
239
|
return RewardCompositionSchema.parse({ ...content, contentHash: contentHash(content) });
|
|
228
240
|
function aggregate(role) {
|
|
229
|
-
const selected = binding.sources.filter((source) => source.role === role).map((source) => ({ source, result: results.find((candidate) => candidate.graderId === source.graderId) }));
|
|
241
|
+
const selected = binding.sources.filter((source) => source.role === role && (!source.taskIds || source.taskIds.includes(input.taskId))).map((source) => ({ source, result: results.find((candidate) => candidate.graderId === source.graderId) }));
|
|
230
242
|
if (!selected.length)
|
|
231
243
|
return { status: "not_configured", score: null, passed: null };
|
|
232
244
|
if (selected.some(({ source, result }) => source.required && result.status !== "scored" && result.status !== "pending"))
|
|
@@ -250,5 +262,5 @@ function withoutRewardHash(value) { const { contentHash: _hash, ...content } = v
|
|
|
250
262
|
function compileSource(source, reward) {
|
|
251
263
|
if (reward.implementation.kind === "learned_model")
|
|
252
264
|
throw new LearningDomainError("learned_reward_requires_model_execution_adapter");
|
|
253
|
-
return GraderSpecSchema.parse({ ...reward.implementation, id: source.graderId, version: String(reward.revision), weight: source.weight, hardGate: source.hardGate, rewardEligible: source.role === "training", privileged: source.privileged });
|
|
265
|
+
return GraderSpecSchema.parse({ ...reward.implementation, ...(source.taskIds ? { taskIds: source.taskIds } : {}), id: source.graderId, version: String(reward.revision), weight: source.weight, hardGate: source.hardGate, rewardEligible: source.role === "training", privileged: source.privileged });
|
|
254
266
|
}
|
package/dist/tasksets.js
CHANGED
|
@@ -7,6 +7,7 @@ export const RequiredOutputContractSchema = z.object({
|
|
|
7
7
|
path: z.string().trim().min(1).max(2_000).refine(safeRelativePath),
|
|
8
8
|
mediaType: z.string().trim().min(1).max(200),
|
|
9
9
|
schemaRef: ImmutableAssetRefSchema.nullable().default(null),
|
|
10
|
+
submissionMode: z.literal("structured_json").optional(),
|
|
10
11
|
maxBytes: z.number().int().positive().max(250_000_000).nullable().default(null),
|
|
11
12
|
metadata: MetadataSchema,
|
|
12
13
|
}).strict();
|
|
@@ -28,6 +29,7 @@ export const EnvironmentContractSchema = z.object({
|
|
|
28
29
|
}).strict();
|
|
29
30
|
const GraderBaseSchema = z.object({
|
|
30
31
|
id: ReleaseIdSchema,
|
|
32
|
+
taskIds: z.array(ReleaseIdSchema).min(1).max(10_000).refine(ids => new Set(ids).size === ids.length, "Grader task IDs must be unique.").optional(),
|
|
31
33
|
version: z.string().trim().min(1).max(100),
|
|
32
34
|
weight: z.number().nonnegative().max(1_000).default(1),
|
|
33
35
|
hardGate: z.boolean().default(false),
|
|
@@ -120,6 +122,11 @@ export function validateTasksetRelease(input) {
|
|
|
120
122
|
path: "environmentRelease",
|
|
121
123
|
});
|
|
122
124
|
}
|
|
125
|
+
const taskIds = new Set(taskset.tasks.map(task => task.id));
|
|
126
|
+
for (const grader of taskset.graders)
|
|
127
|
+
if (grader.taskIds?.some(id => !taskIds.has(id))) {
|
|
128
|
+
issues.push({ code: "grader_task_missing", severity: "error", message: `Grader ${grader.id} refers to a task outside this release.`, path: "graders" });
|
|
129
|
+
}
|
|
123
130
|
const clusterSplits = new Map();
|
|
124
131
|
for (const task of taskset.tasks) {
|
|
125
132
|
if (taskset.metrics?.aggregation === "weighted_mean" && !Object.hasOwn(taskset.metrics.taskWeights, task.id)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-verification.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"artifact-verification.d.ts","sourceRoot":"","sources":["../../src/artifact-verification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EAGL,KAAK,gBAAgB,EAGrB,KAAK,sBAAsB,EAC5B,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAE5D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,WAAW,CAAC,EAAE,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACpD,YAAY,CAAC,EAAE,eAAe,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACrD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,aAAa,GAAG,IAAI,CAAC;IAC7D,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,GAAG,gBAAgB,CAwEnB;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE;IAC3C,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,QAAQ,EAAE,gBAAgB,CAAC;CAC5B,GAAG,sBAAsB,EAAE,CAqC3B"}
|
|
@@ -2,10 +2,10 @@ import { z } from "zod";
|
|
|
2
2
|
import { type AttemptReceipt, type EvaluationResult } from "./runs.js";
|
|
3
3
|
export { harnessRefinerBenchmarkAssets, harnessRefinerBenchmarkRelease, } from "./builtin-benchmarks/harness-refiner.js";
|
|
4
4
|
export declare const BenchmarkMetricSchema: z.ZodEnum<{
|
|
5
|
+
cost_usd: "cost_usd";
|
|
5
6
|
foreground_tokens: "foreground_tokens";
|
|
6
|
-
success_rate: "success_rate";
|
|
7
7
|
latency_ms: "latency_ms";
|
|
8
|
-
|
|
8
|
+
success_rate: "success_rate";
|
|
9
9
|
}>;
|
|
10
10
|
export declare const BenchmarkRunPhaseSchema: z.ZodEnum<{
|
|
11
11
|
baseline: "baseline";
|
|
@@ -13,10 +13,10 @@ export declare const BenchmarkRunPhaseSchema: z.ZodEnum<{
|
|
|
13
13
|
}>;
|
|
14
14
|
export declare const BenchmarkProtocolSchema: z.ZodObject<{
|
|
15
15
|
split: z.ZodEnum<{
|
|
16
|
+
frozen_eval: "frozen_eval";
|
|
17
|
+
test: "test";
|
|
16
18
|
train: "train";
|
|
17
19
|
validation: "validation";
|
|
18
|
-
test: "test";
|
|
19
|
-
frozen_eval: "frozen_eval";
|
|
20
20
|
}>;
|
|
21
21
|
taskIds: z.ZodArray<z.ZodString>;
|
|
22
22
|
seeds: z.ZodArray<z.ZodString>;
|
|
@@ -36,27 +36,27 @@ export declare const BenchmarkDefinitionSchema: z.ZodObject<{
|
|
|
36
36
|
contentHash: z.ZodString;
|
|
37
37
|
}, z.core.$strict>;
|
|
38
38
|
adaptationSplit: z.ZodEnum<{
|
|
39
|
+
frozen_eval: "frozen_eval";
|
|
40
|
+
test: "test";
|
|
39
41
|
train: "train";
|
|
40
42
|
validation: "validation";
|
|
41
|
-
test: "test";
|
|
42
|
-
frozen_eval: "frozen_eval";
|
|
43
43
|
}>;
|
|
44
44
|
evaluationSplit: z.ZodEnum<{
|
|
45
|
+
frozen_eval: "frozen_eval";
|
|
46
|
+
test: "test";
|
|
45
47
|
train: "train";
|
|
46
48
|
validation: "validation";
|
|
47
|
-
test: "test";
|
|
48
|
-
frozen_eval: "frozen_eval";
|
|
49
49
|
}>;
|
|
50
50
|
primaryMetric: z.ZodEnum<{
|
|
51
|
+
cost_usd: "cost_usd";
|
|
51
52
|
foreground_tokens: "foreground_tokens";
|
|
52
|
-
success_rate: "success_rate";
|
|
53
53
|
latency_ms: "latency_ms";
|
|
54
|
-
|
|
54
|
+
success_rate: "success_rate";
|
|
55
55
|
}>;
|
|
56
56
|
qualityGate: z.ZodEnum<{
|
|
57
|
-
none: "none";
|
|
58
|
-
non_regression: "non_regression";
|
|
59
57
|
all_pass: "all_pass";
|
|
58
|
+
non_regression: "non_regression";
|
|
59
|
+
none: "none";
|
|
60
60
|
}>;
|
|
61
61
|
caseCounts: z.ZodObject<{
|
|
62
62
|
adaptation: z.ZodNumber;
|
|
@@ -80,10 +80,10 @@ export declare const BenchmarkRunRequestSchema: z.ZodObject<{
|
|
|
80
80
|
}, z.core.$strict>;
|
|
81
81
|
reasoningEffort: z.ZodNullable<z.ZodString>;
|
|
82
82
|
split: z.ZodEnum<{
|
|
83
|
+
frozen_eval: "frozen_eval";
|
|
84
|
+
test: "test";
|
|
83
85
|
train: "train";
|
|
84
86
|
validation: "validation";
|
|
85
|
-
test: "test";
|
|
86
|
-
frozen_eval: "frozen_eval";
|
|
87
87
|
}>;
|
|
88
88
|
seeds: z.ZodArray<z.ZodString>;
|
|
89
89
|
repetitions: z.ZodNumber;
|
|
@@ -119,10 +119,10 @@ export declare const BenchmarkRunSummaryContentSchema: z.ZodObject<{
|
|
|
119
119
|
reasoningEffort: z.ZodNullable<z.ZodString>;
|
|
120
120
|
protocol: z.ZodObject<{
|
|
121
121
|
split: z.ZodEnum<{
|
|
122
|
+
frozen_eval: "frozen_eval";
|
|
123
|
+
test: "test";
|
|
122
124
|
train: "train";
|
|
123
125
|
validation: "validation";
|
|
124
|
-
test: "test";
|
|
125
|
-
frozen_eval: "frozen_eval";
|
|
126
126
|
}>;
|
|
127
127
|
taskIds: z.ZodArray<z.ZodString>;
|
|
128
128
|
seeds: z.ZodArray<z.ZodString>;
|
|
@@ -175,10 +175,10 @@ export declare const BenchmarkRunSummarySchema: z.ZodObject<{
|
|
|
175
175
|
reasoningEffort: z.ZodNullable<z.ZodString>;
|
|
176
176
|
protocol: z.ZodObject<{
|
|
177
177
|
split: z.ZodEnum<{
|
|
178
|
+
frozen_eval: "frozen_eval";
|
|
179
|
+
test: "test";
|
|
178
180
|
train: "train";
|
|
179
181
|
validation: "validation";
|
|
180
|
-
test: "test";
|
|
181
|
-
frozen_eval: "frozen_eval";
|
|
182
182
|
}>;
|
|
183
183
|
taskIds: z.ZodArray<z.ZodString>;
|
|
184
184
|
seeds: z.ZodArray<z.ZodString>;
|
|
@@ -218,10 +218,10 @@ export declare const BenchmarkComparisonContentSchema: z.ZodObject<{
|
|
|
218
218
|
contentHash: z.ZodString;
|
|
219
219
|
}, z.core.$strict>;
|
|
220
220
|
primaryMetric: z.ZodEnum<{
|
|
221
|
+
cost_usd: "cost_usd";
|
|
221
222
|
foreground_tokens: "foreground_tokens";
|
|
222
|
-
success_rate: "success_rate";
|
|
223
223
|
latency_ms: "latency_ms";
|
|
224
|
-
|
|
224
|
+
success_rate: "success_rate";
|
|
225
225
|
}>;
|
|
226
226
|
qualityPassed: z.ZodBoolean;
|
|
227
227
|
baselinePassRate: z.ZodNumber;
|
|
@@ -248,10 +248,10 @@ export declare const BenchmarkComparisonSchema: z.ZodObject<{
|
|
|
248
248
|
contentHash: z.ZodString;
|
|
249
249
|
}, z.core.$strict>;
|
|
250
250
|
primaryMetric: z.ZodEnum<{
|
|
251
|
+
cost_usd: "cost_usd";
|
|
251
252
|
foreground_tokens: "foreground_tokens";
|
|
252
|
-
success_rate: "success_rate";
|
|
253
253
|
latency_ms: "latency_ms";
|
|
254
|
-
|
|
254
|
+
success_rate: "success_rate";
|
|
255
255
|
}>;
|
|
256
256
|
qualityPassed: z.ZodBoolean;
|
|
257
257
|
baselinePassRate: z.ZodNumber;
|