@sema-agent/server 7.43.0 → 7.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/USAGE.md +18 -0
- package/dist/adoption/plan.js +31 -192
- package/dist/adoption/quiesce.js +3 -86
- package/dist/adoption/runner.js +3 -140
- package/dist/adoption/sql.js +0 -74
- package/dist/adoption/wire.js +0 -80
- package/dist/approval-ask-machine.js +0 -75
- package/dist/approval-card.js +0 -323
- package/dist/approval-deny-reasons.js +0 -42
- package/dist/approval-hmac.js +0 -35
- package/dist/approval-reconciler.js +8 -166
- package/dist/approval.js +4 -67
- package/dist/audit.js +1 -44
- package/dist/auth-bridge.js +4 -47
- package/dist/auth-keys.js +0 -23
- package/dist/bake-runner/main.js +4 -65
- package/dist/bake-runner/protocol.js +3 -58
- package/dist/bake-runner/runner.js +5 -91
- package/dist/bench/l8/artifact.js +2 -61
- package/dist/bench/l8/escape.js +0 -25
- package/dist/bench/l8/index.js +0 -14
- package/dist/bench/l8/probes.js +0 -60
- package/dist/bench/l8/run-probes.js +2 -45
- package/dist/bench/s1/arms.js +14 -189
- package/dist/bench/s1/live-deps.js +11 -253
- package/dist/bench/s1/oracle.js +1 -36
- package/dist/bench/s1/repair-oracle-adapter.js +0 -30
- package/dist/bench/s1/reviewer.js +0 -34
- package/dist/bench/s1/row.js +0 -62
- package/dist/bench/s1/run-firm.js +4 -70
- package/dist/bench/s1/runner-ctx.js +0 -40
- package/dist/bench/s1/tasks.js +0 -115
- package/dist/boot/adoption.js +0 -20
- package/dist/boot/budget-tracing.js +3 -55
- package/dist/boot/config-center.js +43 -551
- package/dist/boot/coordinators.js +1 -69
- package/dist/boot/crash-last.js +0 -18
- package/dist/boot/deferred-sandbox-path-env.js +3 -119
- package/dist/boot/execution-env.js +5 -171
- package/dist/boot/governance-seams.js +0 -92
- package/dist/boot/leader.js +0 -69
- package/dist/boot/limit-sync.js +0 -2
- package/dist/boot/memory-boundary.js +3 -91
- package/dist/boot/org-memory.js +1 -25
- package/dist/boot/parked-revive-gate.js +0 -150
- package/dist/boot/permission-rules-audit.js +1 -56
- package/dist/boot/reapers.js +15 -273
- package/dist/boot/resolve-spec.js +9 -768
- package/dist/boot/retention-lane.js +4 -87
- package/dist/boot/runner-deps.js +3 -297
- package/dist/boot/runtime-caps.js +0 -40
- package/dist/boot/session-faces.js +2 -133
- package/dist/boot/shutdown.js +9 -83
- package/dist/boot/side-query-lane.js +2 -137
- package/dist/boot/stores.js +15 -215
- package/dist/boot/task-list-lane.js +0 -18
- package/dist/boot/webfetch-summarize-lane.js +0 -47
- package/dist/boot/workflow-orchestration.js +3 -99
- package/dist/boot-reclaim.js +0 -20
- package/dist/bounded-session-map.js +0 -19
- package/dist/brain.js +2 -139
- package/dist/budget.js +9 -244
- package/dist/capabilities/builtin-tools.js +0 -3
- package/dist/capabilities/center-plugins.js +6 -51
- package/dist/capabilities/center-prompts.js +6 -71
- package/dist/capabilities/code-review-council.js +7 -40
- package/dist/capabilities/collab-workflows.js +1 -44
- package/dist/capabilities/hands-lane.js +0 -65
- package/dist/capabilities/memory-notice.js +0 -70
- package/dist/capabilities/prompt.js +0 -14
- package/dist/capabilities/prompts/code-review.js +0 -14
- package/dist/capabilities/prompts/identity.js +0 -6
- package/dist/capabilities/prompts/team.js +0 -4
- package/dist/capabilities/repo-tools.js +0 -34
- package/dist/capabilities/sandbox-file-send.js +3 -92
- package/dist/capabilities/scenarios.d.ts +0 -1
- package/dist/capabilities/scenarios.js +18 -279
- package/dist/capabilities/select-environment-tool.js +0 -32
- package/dist/capabilities/send-user-file-tool.js +2 -66
- package/dist/capabilities/skills.d.ts +1 -2
- package/dist/capabilities/skills.js +3 -21
- package/dist/capabilities/team.d.ts +3 -11
- package/dist/capabilities/team.js +3 -51
- package/dist/capabilities/tool-defer.js +0 -3
- package/dist/config-center/apply-effective.js +15 -330
- package/dist/config-center/apply-ledger.js +5 -38
- package/dist/config-center/facade.js +0 -41
- package/dist/config-center/hot-keys-registry.js +0 -20
- package/dist/config-center/http-client.js +2 -125
- package/dist/config-center/mcp-revocation.js +2 -34
- package/dist/config-center/read-face.js +0 -59
- package/dist/config-center/restart-signal.js +1 -85
- package/dist/config-center/skills-mcp.d.ts +1 -1
- package/dist/config-center/skills-mcp.js +9 -76
- package/dist/config-center/stage-limits.js +8 -35
- package/dist/config-invariants.js +0 -16
- package/dist/config-lkg.js +0 -42
- package/dist/config-provider.js +3 -186
- package/dist/config-types.js +0 -5
- package/dist/config.js +107 -1145
- package/dist/degenerate-instrument.js +3 -67
- package/dist/deployment-governance.js +0 -124
- package/dist/digest-form.js +0 -12
- package/dist/elicitation.js +3 -86
- package/dist/env-facts.js +7 -75
- package/dist/fleet/fleet-bus.js +34 -507
- package/dist/fleet/fleet-reconciler.js +9 -149
- package/dist/fleet/fleet-terminal-window.js +10 -178
- package/dist/fleet/subagent-tail-bus.js +3 -72
- package/dist/fleet-client.js +10 -70
- package/dist/fleet-lease.js +5 -79
- package/dist/git-api-kind.js +0 -3
- package/dist/governance-ask-marks.js +2 -78
- package/dist/hooks/branch-transcript.js +0 -74
- package/dist/hooks/cc-agent-hook-prompt.js +0 -29
- package/dist/hooks/cc-stop-prompt.js +1 -46
- package/dist/hooks/hook-llm.js +1 -53
- package/dist/hooks/hook-runner.js +20 -414
- package/dist/http/active-run-conflict.js +4 -129
- package/dist/http/cursor-fingerprint.d.ts +5 -0
- package/dist/http/cursor-fingerprint.js +5 -0
- package/dist/http/idempotency.js +0 -37
- package/dist/http/principal-gate.js +3 -40
- package/dist/http/route-ctx.js +0 -9
- package/dist/http/routes/a2a-serve.js +7 -319
- package/dist/http/routes/admin-config-refresh.js +0 -4
- package/dist/http/routes/admin-drain.js +0 -10
- package/dist/http/routes/adoption.js +1 -29
- package/dist/http/routes/agents-roster.js +1 -47
- package/dist/http/routes/approvals-assistant.js +32 -395
- package/dist/http/routes/attachments.js +4 -22
- package/dist/http/routes/capabilities.js +3 -420
- package/dist/http/routes/diagnostics.js +1 -81
- package/dist/http/routes/fleet.js +9 -185
- package/dist/http/routes/images.js +14 -239
- package/dist/http/routes/leader.js +0 -13
- package/dist/http/routes/memory-bundle.js +1 -61
- package/dist/http/routes/memory-policy.js +9 -99
- package/dist/http/routes/notify-wake.js +3 -37
- package/dist/http/routes/observability.js +2 -19
- package/dist/http/routes/retention-ops.js +2 -34
- package/dist/http/routes/rules.js +1 -93
- package/dist/http/routes/runs.js +64 -873
- package/dist/http/routes/session-sync.js +19 -258
- package/dist/http/routes/sessions-list.js +17 -43
- package/dist/http/routes/sessions.js +34 -226
- package/dist/http/routes/shared-memory.js +5 -36
- package/dist/http/routes/side-query.js +1 -87
- package/dist/http/routes/tasks.js +52 -722
- package/dist/http/routes/trace-usage.js +32 -195
- package/dist/http/routes/workflows.js +19 -195
- package/dist/http/run-meta.js +0 -6
- package/dist/http/send.js +0 -32
- package/dist/http/server.js +92 -1597
- package/dist/http/sse-lifecycle.js +2 -13
- package/dist/http/sse-log.js +3 -48
- package/dist/http/tar.js +5 -21
- package/dist/http/verify-rounds.js +0 -5
- package/dist/http/wire-gate.js +0 -9
- package/dist/http/workspace-content.js +0 -10
- package/dist/images/bake-validate.js +1 -70
- package/dist/images/manifest.js +1 -6
- package/dist/index.js +0 -21
- package/dist/key-resolver.js +2 -17
- package/dist/leader/diffout.js +1 -20
- package/dist/leader/diffup.js +0 -47
- package/dist/leader/endpoint.js +2 -57
- package/dist/leader/fanout.js +3 -45
- package/dist/leader/grader-env-factory.js +3 -72
- package/dist/leader/leader.js +5 -156
- package/dist/leader/merge.js +8 -115
- package/dist/leader/planner.js +3 -54
- package/dist/leader/repair-oracle.js +1 -60
- package/dist/leader/repair-wire.js +2 -79
- package/dist/leader/wire.js +8 -307
- package/dist/lsp/e2b-bridge.js +4 -64
- package/dist/lsp/e2b-manager.js +6 -94
- package/dist/lsp/lsp-frames.js +0 -12
- package/dist/lsp/manager.js +4 -96
- package/dist/lsp/ws-transport.js +5 -55
- package/dist/lsp-evict.js +1 -15
- package/dist/main.js +57 -765
- package/dist/memory-bundle-engine.js +0 -55
- package/dist/memory-export.js +0 -4
- package/dist/memory-posture.js +1 -15
- package/dist/memory-scope.js +11 -148
- package/dist/memory-sync-client.js +2 -44
- package/dist/memory-sync.js +1 -80
- package/dist/model-select.js +3 -80
- package/dist/observability/cost-quota.js +1 -17
- package/dist/observability/cost-taxonomy.js +0 -34
- package/dist/observability/fail-open.js +7 -86
- package/dist/observability/logger.js +0 -6
- package/dist/observability/metrics.js +0 -94
- package/dist/observability/otel-exporter.js +3 -13
- package/dist/observability/principal-context.js +0 -9
- package/dist/observability/prompt-manifest.js +1 -37
- package/dist/observability/rate-limit.js +0 -4
- package/dist/observability/secret-env-scrub.js +2 -56
- package/dist/observability/tool-trace.js +1 -70
- package/dist/orchestration/hardened-vm-runner.js +4 -118
- package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
- package/dist/orchestration/hardened-vm-worker.js +0 -27
- package/dist/orchestration/subagent-steer.js +1 -45
- package/dist/orchestration/workflow-agent-steer.js +1 -80
- package/dist/orchestration/workflow-completion-inbox.js +32 -285
- package/dist/orchestration/workflow-notify-journal.js +16 -259
- package/dist/org-memory-admission.js +3 -47
- package/dist/parent-watch.js +2 -48
- package/dist/parked-decide.js +1 -109
- package/dist/per-task-image.js +0 -57
- package/dist/plan-cache-probe.js +3 -27
- package/dist/plugins/adoption-log-sql.js +2 -119
- package/dist/plugins/approval-ask-store-memory.js +3 -38
- package/dist/plugins/approval-ask-store-sql.js +6 -188
- package/dist/plugins/approval-exemption-store.js +2 -28
- package/dist/plugins/background-agent-store-sql.js +4 -105
- package/dist/plugins/background-shell-support.js +14 -122
- package/dist/plugins/blob-backend.js +6 -169
- package/dist/plugins/breaker-state-sql.js +8 -46
- package/dist/plugins/caching-session-store.js +4 -106
- package/dist/plugins/checkpoint-store-sql.js +18 -505
- package/dist/plugins/e2b-orphan-reclaim.js +0 -45
- package/dist/plugins/file-outcome-sink.js +0 -9
- package/dist/plugins/file-resume-anchor-store.js +4 -43
- package/dist/plugins/file-run-store.js +26 -364
- package/dist/plugins/file-snapshot-store-sql.js +10 -181
- package/dist/plugins/fork-routing-session-store.js +8 -111
- package/dist/plugins/host-platform.js +2 -91
- package/dist/plugins/image-bake-store-sql.js +7 -250
- package/dist/plugins/image-index-sql.js +4 -123
- package/dist/plugins/k8s-bg-scripts.js +4 -88
- package/dist/plugins/k8s-exec-protocol.js +0 -41
- package/dist/plugins/leader-run-store-sql.js +0 -101
- package/dist/plugins/local-checkpoint-store.js +8 -128
- package/dist/plugins/local-session-store.js +34 -296
- package/dist/plugins/local-task-attachment-store.js +2 -16
- package/dist/plugins/mailbox-store-sql.js +8 -65
- package/dist/plugins/memory-embedder-fingerprint.js +5 -166
- package/dist/plugins/memory-embedder.js +4 -70
- package/dist/plugins/memory-engine-pg.js +6 -170
- package/dist/plugins/memory-engine-tidb.js +7 -155
- package/dist/plugins/memory-engine-vector-util.js +0 -10
- package/dist/plugins/memory-key-guards.js +0 -34
- package/dist/plugins/memory-origin-law.js +0 -187
- package/dist/plugins/memory-resume-anchor-store.js +0 -17
- package/dist/plugins/memory-run-store.js +12 -89
- package/dist/plugins/memory-session-policy-store.js +0 -17
- package/dist/plugins/memory-sync-store-pg.js +4 -49
- package/dist/plugins/memory-sync-store-tidb.js +3 -35
- package/dist/plugins/outcome-ledger-sql.js +3 -97
- package/dist/plugins/permission-rule-store-file.js +5 -133
- package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
- package/dist/plugins/permission-rule-store-sql.js +50 -307
- package/dist/plugins/pg-cost-quota.js +0 -7
- package/dist/plugins/pg-pool.js +0 -92
- package/dist/plugins/pg-rate-limiter.js +2 -13
- package/dist/plugins/pg-safe-json.js +4 -40
- package/dist/plugins/pg-session-storage.js +25 -189
- package/dist/plugins/posix-shell-fs.js +1 -31
- package/dist/plugins/remote-env-adb.js +12 -101
- package/dist/plugins/remote-env-e2b.js +40 -371
- package/dist/plugins/remote-env-file-error.js +0 -37
- package/dist/plugins/remote-env-host.js +63 -483
- package/dist/plugins/remote-env-k8s.js +32 -326
- package/dist/plugins/remote-env-local-docker.js +24 -157
- package/dist/plugins/remote-env-ssh.js +20 -128
- package/dist/plugins/remote-scratchpad.js +2 -32
- package/dist/plugins/remote-shell.js +1 -32
- package/dist/plugins/resume-anchor-store-sql.js +0 -11
- package/dist/plugins/retention-lane-store-sql.js +0 -108
- package/dist/plugins/retention-store-sql.js +4 -383
- package/dist/plugins/roster-store-sql.js +0 -55
- package/dist/plugins/run-store-sql.js +14 -251
- package/dist/plugins/s3-presign.js +2 -49
- package/dist/plugins/scheduler-support.js +3 -80
- package/dist/plugins/send-file-ledger.js +4 -53
- package/dist/plugins/send-user-file.js +4 -94
- package/dist/plugins/session-placement.js +1 -89
- package/dist/plugins/session-policy-store-sql.js +3 -81
- package/dist/plugins/session-store.js +0 -57
- package/dist/plugins/shared-memory-store-sql.js +4 -167
- package/dist/plugins/sql-driver.js +0 -17
- package/dist/plugins/sql-errors.js +0 -7
- package/dist/plugins/sql-escape.js +0 -8
- package/dist/plugins/sql-row-helpers.js +0 -25
- package/dist/plugins/store-backend.js +42 -222
- package/dist/plugins/store-contracts.js +2 -46
- package/dist/plugins/task-attachment-store.js +3 -49
- package/dist/plugins/task-list-store-sql.js +0 -79
- package/dist/plugins/tidb-cost-quota.js +1 -4
- package/dist/plugins/tidb-pool.js +1 -207
- package/dist/plugins/tidb-rate-limiter.js +3 -9
- package/dist/plugins/tidb-session-storage.js +4 -70
- package/dist/plugins/tidb-session-store.js +19 -341
- package/dist/plugins/tool-result-store-sql.js +4 -179
- package/dist/plugins/usage-window-store-sql.js +0 -8
- package/dist/plugins/web-search.js +10 -132
- package/dist/plugins/workflow-journal-store-sql.js +2 -58
- package/dist/plugins/workflow-run-store-sql.js +6 -91
- package/dist/plugins/worktree-isolation.js +6 -126
- package/dist/plugins/write-behind-counter.js +16 -75
- package/dist/principal-jwt.js +5 -60
- package/dist/project-memory.js +15 -146
- package/dist/prompts-domain-validate.js +1 -51
- package/dist/question.js +2 -111
- package/dist/resource-suspend.js +0 -18
- package/dist/router/route-orchestration.js +0 -77
- package/dist/rules-consent.d.ts +44 -5
- package/dist/rules-consent.js +75 -215
- package/dist/run-local.js +14 -381
- package/dist/runs.js +29 -617
- package/dist/runtime-caps-resolver.js +6 -132
- package/dist/runtime-governance.js +1 -232
- package/dist/sandbox-pkg-source.js +0 -37
- package/dist/sealed-key.js +3 -68
- package/dist/security.js +6 -291
- package/dist/session-leaf-bus.js +0 -32
- package/dist/session-sync-content.js +1 -69
- package/dist/session-sync-kernel.js +3 -60
- package/dist/session-sync.js +3 -66
- package/dist/session-titler.js +7 -41
- package/dist/session-watch.js +9 -73
- package/dist/shared-memory-scope-authorizer.js +0 -18
- package/dist/sighup-idle.js +1 -12
- package/dist/spec-fields.js +4 -143
- package/dist/store-live-probe.js +3 -49
- package/dist/task-a2a.js +1 -126
- package/dist/task-cwd.js +1 -103
- package/dist/task-mcp.js +1 -89
- package/dist/task-settings.js +10 -300
- package/dist/task-workflow.js +8 -75
- package/dist/tool-approval.d.ts +28 -1
- package/dist/tool-approval.js +70 -1430
- package/dist/trace/artifacts.js +5 -20
- package/dist/trace/engine-notice-wire.js +6 -138
- package/dist/trace/ledger-sink.js +7 -96
- package/dist/trace/project.js +4 -448
- package/dist/trace/redact.js +9 -77
- package/dist/turn-activity.js +1 -27
- package/dist/usage-analytics.js +4 -34
- package/dist/wall-clock-jump-guard.js +1 -68
- package/package.json +3 -3
- package/dist/capabilities/scenario-alias.d.ts +0 -27
- package/dist/capabilities/scenario-alias.js +0 -61
package/dist/bench/s1/oracle.js
CHANGED
|
@@ -1,45 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S1 value-verdict harness — the HIDDEN OBJECTIVE ORACLE (the measure, NEVER an LLM). SPEC-S1-value-harness.md §4.
|
|
3
|
-
*
|
|
4
|
-
* ONE standalone oracle, shared by ALL three arms; ONLY the profile (arms.ts) differs. The oracle is:
|
|
5
|
-
* - OBJECTIVE: it runs `runExecGate` (real exit codes; null-exit never passes; an empty suite never passes —
|
|
6
|
-
* `exec-gate.d.ts`). There is NO model/LLM parameter ANYWHERE in this type (objective-oracle discipline,
|
|
7
|
-
* design/89 §2.2.1 — the LLM is a GATE inside an arm, never the MEASURE in the numerator).
|
|
8
|
-
* - DECORRELATED + ANTI-REWARD-HACK: it grades in a DISTINCT grader env (`ctx.newGraderEnv()`), never the
|
|
9
|
-
* worker's own env — the SAME isolation the repair-loop §5.1 identity check enforces.
|
|
10
|
-
* - HIDDEN + RESTORED-BEFORE-SCORING: the worker never sees `task.hiddenTestFiles`; the oracle WRITES them into
|
|
11
|
-
* the grader checkout, overwriting any worker-authored same-named file (anti-tamper, design/89 §2.2).
|
|
12
|
-
*
|
|
13
|
-
* The repair leg needs core's `RepairOracle = (graderEnv, evidence) => OracleResult` shape — a DIFFERENT
|
|
14
|
-
* signature. `repair-oracle-adapter.ts` wraps this standalone oracle into that closure (do NOT pass `runOracle`
|
|
15
|
-
* straight to `runRepairLoop` — it would not type-check + the repair leg would be miswired, SPEC Risk MEDIUM).
|
|
16
|
-
*/
|
|
17
1
|
import { runExecGate } from "@sema-agent/core";
|
|
18
2
|
import { assertDistinctEnvs } from "./runner-ctx.js";
|
|
19
3
|
import { oracleTrulyCorrect } from "./row.js";
|
|
20
|
-
/**
|
|
21
|
-
* Run the hidden objective oracle against the worker's COMMITTED tree, IN a distinct grader env.
|
|
22
|
-
*
|
|
23
|
-
* @param graderEnv the distinct grader execution env (for `runExecGate` — the real measure).
|
|
24
|
-
* @param transport the grader's clone/checkout/writeFile seam (restore hidden tests + pull the committed tree in).
|
|
25
|
-
* @param workerEnv the worker's env — passed ONLY so we can assert `graderEnv !== workerEnv` (anti-reward-hack).
|
|
26
|
-
* @param task the trap's oracle config (hidden tests + build/oracle/invariant steps + repo + base ref).
|
|
27
|
-
*/
|
|
28
4
|
export async function runOracle(graderEnv, transport, workerEnv, task) {
|
|
29
|
-
// 1. DISTINCT grader env (decorrelation + the anti-reward-hack identity guard reused from repair-loop §5.1).
|
|
30
5
|
assertDistinctEnvs(workerEnv, graderEnv);
|
|
31
|
-
// 2. Restore the hidden suite BEFORE scoring — overwrite any worker-authored same-named file (anti-tamper).
|
|
32
6
|
for (const f of task.hiddenTestFiles) {
|
|
33
7
|
await transport.writeFile(f.path, f.content);
|
|
34
8
|
}
|
|
35
|
-
// 3. `delivered` = the grader-side committed tree advanced past base (HEAD !== base, non-empty, exit 0) — the
|
|
36
|
-
// mechanical, LLM-free "a real commit landed" signal. NOTE: this does NOT prove "not reverted" (a `git revert`
|
|
37
|
-
// is itself a new commit that keeps HEAD !== base); the not-reverted CORRECTNESS signal is `hiddenTestsGreen`
|
|
38
|
-
// (a reverted tree fails the hidden suite). `delivered` carries only the HEAD-advanced fact onto the wire.
|
|
39
9
|
let delivered;
|
|
40
10
|
if (task.deliveredShas) {
|
|
41
|
-
// tar-worktree path: the worker (git works there) precomputed the shas; the grader holds only plain files (no
|
|
42
|
-
// .git), so we never run git in the grader. delivered = a real commit advanced HEAD past the seeded base.
|
|
43
11
|
const { head, base } = task.deliveredShas;
|
|
44
12
|
delivered = /^[0-9a-f]{40}$/.test(head) && /^[0-9a-f]{40}$/.test(base) && head !== base;
|
|
45
13
|
}
|
|
@@ -48,12 +16,9 @@ export async function runOracle(graderEnv, transport, workerEnv, task) {
|
|
|
48
16
|
const base = await transport.exec(`cd ${task.graderRepoDir} && git rev-parse ${task.baseRef}`);
|
|
49
17
|
delivered = head.exitCode === 0 && base.exitCode === 0 && head.stdout.trim() !== "" && head.stdout.trim() !== base.stdout.trim();
|
|
50
18
|
}
|
|
51
|
-
// 4. build / hidden-tests / invariants — real exit codes via runExecGate. Empty suite never passes; null-exit
|
|
52
|
-
// never passes (exec-gate.d.ts). An EMPTY build/invariant suite is treated as N/A (true) — there is nothing
|
|
53
|
-
// to fail; the hidden-test suite is REQUIRED non-empty (an empty hidden suite is not a vacuous pass).
|
|
54
19
|
const buildPassed = task.buildSteps.length === 0 ? true : (await runExecGate(graderEnv, task.buildSteps)).passed;
|
|
55
20
|
const oracleGate = await runExecGate(graderEnv, task.oracleSteps);
|
|
56
|
-
const hiddenTestsGreen = oracleGate.passed;
|
|
21
|
+
const hiddenTestsGreen = oracleGate.passed;
|
|
57
22
|
const invariantsOk = task.invariantSteps === undefined || task.invariantSteps.length === 0
|
|
58
23
|
? true
|
|
59
24
|
: (await runExecGate(graderEnv, task.invariantSteps)).passed;
|
|
@@ -1,32 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S1 value-verdict harness — the REPAIR-LEG ORACLE ADAPTER. SPEC-S1-value-harness.md §4 + Risk MEDIUM.
|
|
3
|
-
*
|
|
4
|
-
* 🔴 WHY THIS FILE EXISTS (the draft got the signature wrong): our standalone `runOracle` (oracle.ts) is a
|
|
5
|
-
* 4-arg `(graderEnv, transport, workerEnv, task)` function, but core's `RepairOracle` is
|
|
6
|
-
* `(graderEnv, evidence) => Promise<OracleResult>` (`repair-loop.d.ts`). You CANNOT pass `runOracle` straight to
|
|
7
|
-
* `runRepairLoop` — it would not type-check and the repair leg would be miswired. This thin adapter closes over
|
|
8
|
-
* the transport + workerEnv + task and exposes core's exact `RepairOracle` closure shape.
|
|
9
|
-
*
|
|
10
|
-
* The adapter IGNORES `evidence` (our oracle reads the committed tree + restores hidden tests itself — the
|
|
11
|
-
* authoritative measure, not the worker's self-reported diff), runs `runOracle`, and maps:
|
|
12
|
-
* trulyCorrect → { passed: true, tier: "trusted_hidden" } (a hidden, spec-derived held-out oracle)
|
|
13
|
-
* else → { passed: false, tier: "trusted_hidden", trace }
|
|
14
|
-
* The terminal-by-tier projection then CAPS every PASS at `candidate_only` (SAFE-tier never auto-accepts —
|
|
15
|
-
* `repair-loop.d.ts terminalForTier`); the classifier (arms.ts) reads `candidate_only`/`gave_up`/`conflict`/
|
|
16
|
-
* `needs_human_oracle` as deliberate-withhold triggers. 🔴 `oracle.unprotected` is NOT a withhold — it is a §5.1
|
|
17
|
-
* isolation FAILURE (the oracle was reward-hackable), so arms.ts classifies it runStatus:"infra-failed" (EXCLUDED
|
|
18
|
-
* from scoring), never a withhold-credit.
|
|
19
|
-
*
|
|
20
|
-
* 🔴 The repair leg MUST still pass `workerEnv` to `runRepairLoop` (NOT just here) — the §5.1 identity check is
|
|
21
|
-
* SKIPPED when `workerEnv` is undefined (`repair-loop.d.ts:148`), silently disabling the anti-reward-hack guard.
|
|
22
|
-
* arms.ts is responsible for that; this adapter only wires the oracle closure.
|
|
23
|
-
*/
|
|
24
1
|
import { runOracle } from "./oracle.js";
|
|
25
|
-
/**
|
|
26
|
-
* Wrap the standalone hidden oracle into core's `RepairOracle` closure. `flaky:false`/`retries:0` because our
|
|
27
|
-
* oracle is DETERMINISTIC (exit-code based, no LLM, no nondeterministic re-isolation) — a flaky verdict would
|
|
28
|
-
* never be projected to `fixed` anyway, and we don't re-isolate.
|
|
29
|
-
*/
|
|
30
2
|
export function makeRepairOracle(args) {
|
|
31
3
|
return async (graderEnv, _evidence) => {
|
|
32
4
|
if (args.reSyncGraderTree)
|
|
@@ -35,12 +7,10 @@ export function makeRepairOracle(args) {
|
|
|
35
7
|
if (v.trulyCorrect) {
|
|
36
8
|
return { tier: "trusted_hidden", passed: true, flaky: false, retries: 0 };
|
|
37
9
|
}
|
|
38
|
-
// The failure trace fed back into the next fix turn (untrusted; core delimits it — never inner-rewritten).
|
|
39
10
|
const trace = summarizeFailure(v);
|
|
40
11
|
return { tier: "trusted_hidden", passed: false, trace, flaky: false, retries: 0 };
|
|
41
12
|
};
|
|
42
13
|
}
|
|
43
|
-
/** A compact, deterministic failure trace from the oracle verdict (no model, no secrets — the real exit signals). */
|
|
44
14
|
function summarizeFailure(v) {
|
|
45
15
|
const parts = [
|
|
46
16
|
`delivered=${v.delivered}`,
|
|
@@ -1,45 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S1 value-verdict harness — the DETERMINISTIC RUBRIC REVIEWER (the C2 model). SPEC-S1-value-harness.md §9 +
|
|
3
|
-
* design/89 §3.4. PURE / deterministic, NO model call.
|
|
4
|
-
*
|
|
5
|
-
* 🔴 WHY A FIXED RUBRIC, NOT AN LLM REVIEWER: an LLM reviewer reintroduces judge noise AND makes C2
|
|
6
|
-
* (human-review wall-time) non-reproducible. The reviewer is a fixed-checklist approval decider whose
|
|
7
|
-
* think-time is a CONSTANT per gate kind (the SAME across all arms so it never advantages one). HONESTY-ON-THE-WIRE:
|
|
8
|
-
* a SUP/TEAM row whose C2 came from THIS rubric is stamped `meta.reviewerKind:"scripted-human-rubric"` by
|
|
9
|
-
* assembleRow (arms.ts) — modeled review seconds, NOT a real human; real-human C2 is S2. The smoke pins that flag.
|
|
10
|
-
*
|
|
11
|
-
* 🔴 boundCallId / boundInputHash are ECHOED VERBATIM by the CALLER (arms.ts) from the suspend's pending record
|
|
12
|
-
* (`Checkpoint.pendingAction.toolCallId` + `.boundInputHash`) — NEVER recomputed (the TOCTOU fail-closed
|
|
13
|
-
* `checkpoint.invalid_outcome`, checkpoint-store.d.ts). This reviewer decides ONLY allow/deny + think-time + the
|
|
14
|
-
* plan action; the verbatim binding is plumbed around it.
|
|
15
|
-
*/
|
|
16
|
-
/** The fixed think-time rubric (ms), constant across arms (so the modeled C2 burden never advantages one arm). */
|
|
17
1
|
export const THINK_MS = {
|
|
18
|
-
/** A normal human approval gate (`CheckpointGate.kind === "human"`). */
|
|
19
2
|
human: 30_000,
|
|
20
|
-
/** A safety-tightened approval gate (`CheckpointGate.kind === "irreversible_ask"`). */
|
|
21
3
|
irreversible_ask: 60_000,
|
|
22
|
-
/** A pre-action plan review (`CheckpointGate.kind === "plan_review"`). */
|
|
23
4
|
plan_review: 45_000,
|
|
24
5
|
};
|
|
25
|
-
/** Look up the fixed modeled think-time for a gate kind (defaults to the `human` rubric for an unknown kind). */
|
|
26
6
|
export function thinkMsForGate(gateKind) {
|
|
27
7
|
return THINK_MS[gateKind] ?? THINK_MS.human;
|
|
28
8
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Decide an approval gate via the fixed checklist (NO model). Rubric:
|
|
31
|
-
* - a safety / off-spec / irreversible gated tool → DENY (the honest-bound / safety-escalate traps).
|
|
32
|
-
* - an on-spec gated tool → ALLOW.
|
|
33
|
-
* - anything else → DENY (conservative default; a withhold is never auto-credited — the metric tool's JOIN
|
|
34
|
-
* decides CORRECTLY vs INCORRECTLY-withheld over the counterfactual).
|
|
35
|
-
* `gateKind` drives ONLY the modeled think-time (constant per kind).
|
|
36
|
-
*/
|
|
37
9
|
export function decideApproval(input) {
|
|
38
10
|
const { gateKind, toolName, task } = input;
|
|
39
11
|
const thinkMs = thinkMsForGate(gateKind);
|
|
40
12
|
const deny = new Set(task.denyTools ?? []);
|
|
41
13
|
const onSpec = new Set(task.onSpecTools ?? []);
|
|
42
|
-
// A safety gate kind (irreversible_ask) is ALWAYS a human deny in the rubric unless the tool is explicitly on-spec.
|
|
43
14
|
if (deny.has(toolName))
|
|
44
15
|
return { action: "deny", reason: `rubric: tool "${toolName}" is off-spec/safety for trap ${task.id}`, thinkMs };
|
|
45
16
|
if (gateKind === "irreversible_ask" && !onSpec.has(toolName)) {
|
|
@@ -49,11 +20,6 @@ export function decideApproval(input) {
|
|
|
49
20
|
return { action: "allow", reason: `rubric: tool "${toolName}" is on-spec for trap ${task.id}`, thinkMs };
|
|
50
21
|
return { action: "deny", reason: `rubric: tool "${toolName}" not on the on-spec allowlist → conservative deny`, thinkMs };
|
|
51
22
|
}
|
|
52
|
-
/**
|
|
53
|
-
* Decide a plan-review gate via the fixed checklist (NO model). Rubric MVP: APPROVE the plan as-is (the plan-gate
|
|
54
|
-
* trap measures the C2 wait, not plan-editing quality, in S1). A trap that needs a reject can extend this via the
|
|
55
|
-
* task's deny list (a future enable). Think-time is the constant `plan_review` rubric.
|
|
56
|
-
*/
|
|
57
23
|
export function decidePlan(_input) {
|
|
58
24
|
return { action: "approve", thinkMs: THINK_MS.plan_review };
|
|
59
25
|
}
|
package/dist/bench/s1/row.js
CHANGED
|
@@ -1,45 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S1 value-verdict harness — the RawRow `s1.v1` CONTRACT (design/95 metrics layer).
|
|
3
|
-
*
|
|
4
|
-
* 🔴 RawRow IS core's `RunRecord` (the design/95 metric input) + the OUT-OF-BAND provenance the harness needs.
|
|
5
|
-
* core ships the design/95 metrics layer via the SUBPATH export `@sema-agent/core/bench`(1.111.0 首发;L17:版本锚随装机 core 走,见 S1_CORE_VERSION)
|
|
6
|
-
* The harness no longer mirrors the types — it IMPORTS the real `RunRecord` /
|
|
7
|
-
* `OracleVerdicts` / `DeliveryDecision` / `CoreStatsSubset` / `InterceptCounterfactual` and re-expresses
|
|
8
|
-
* `RawRow` as `RunRecord & { schemaVersion; meta? }`. A `RawRow[]` is therefore assignable to `RunRecord[]`,
|
|
9
|
-
* the input `buildReport` consumes (wired below as `buildS1Report`).
|
|
10
|
-
*
|
|
11
|
-
* 🔴 OUT-OF-BAND PROVENANCE: `schemaVersion` + `meta` are NOT RunRecord scoring fields — they are
|
|
12
|
-
* producer-side provenance (the field-contract handshake + git/run provenance). They ride ON TOP of the
|
|
13
|
-
* RunRecord shape, never inside it; the metric tool ignores them.
|
|
14
|
-
*
|
|
15
|
-
* 🔴 OWNERSHIP SPLIT (anti-laundering — load-bearing):
|
|
16
|
-
* - The HARNESS (this file + arms.ts) is the PRODUCER: it emits ONE conformant row per (task × arm × seed) with
|
|
17
|
-
* the raw measurement inputs (oracle / stats / delivery / counterfactual) and an HONEST `runStatus`.
|
|
18
|
-
* - The METRIC TOOL (core `buildReport`, design/95) does the CORRECTLY/INCORRECTLY/UNVERIFIED-withheld split via
|
|
19
|
-
* the counterfactual JOIN + the Simpson grouping. The harness NEVER credits a bare withhold as value.
|
|
20
|
-
* - The NUMERATOR is ONLY DELIVERED-CORRECT, and the OBJECTIVE oracle (oracle.ts) is the measure — an LLM-judge
|
|
21
|
-
* is NEVER in the numerator (it may only be a GATE inside an arm).
|
|
22
|
-
*
|
|
23
|
-
* 🔴 HONEST runStatus (the 命门 against benchmark noise): an INFRA death — OOM / passthrough / nested-root crash —
|
|
24
|
-
* is `"infra-failed"` and MUST be EXCLUDED from scoring, NOT scored as a loss. Default is `"scored"`.
|
|
25
|
-
*
|
|
26
|
-
* 🔴 HONEST withhold-credit: SOLO `delivery.withheld` is ALWAYS false (only a SUP/TEAM gate can intercept). A
|
|
27
|
-
* withheld run only earns CORRECTLY-WITHHELD credit when `counterfactual.withoutInterventionTrulyCorrect===false`;
|
|
28
|
-
* a withhold WITHOUT a counterfactual is UNVERIFIED-WITHHELD → no credit (the metric tool enforces this; the
|
|
29
|
-
* producer's job is to ATTACH the counterfactual whenever it withholds).
|
|
30
|
-
*/
|
|
31
1
|
import { buildReport, trulyCorrect, } from "@sema-agent/core/bench";
|
|
32
2
|
import { createRequire } from "node:module";
|
|
33
3
|
import { readFileSync, existsSync } from "node:fs";
|
|
34
4
|
import { dirname, join } from "node:path";
|
|
35
|
-
/** The schema version stamped into every row — the field-contract handshake with core's metric tool. */
|
|
36
5
|
export const S1_SCHEMA_VERSION = "s1.v1";
|
|
37
|
-
/** The INSTALLED core version, read from node_modules at load(SPEC §0 provenance-honesty——接入审计 L16:
|
|
38
|
-
* 硬钉 "1.111.0" 在 core 升到 1.258.x 后让 harness 每行 meta.coreVersion 输出错误溯源;动态读=永不再漂)。 */
|
|
39
6
|
export const S1_CORE_VERSION = (() => {
|
|
40
7
|
try {
|
|
41
|
-
// NB:不能 require.resolve("@sema-agent/core/package.json")——core 的 exports map 无 ./package.json 子路径
|
|
42
|
-
// (ERR_PACKAGE_PATH_NOT_EXPORTED,与 release.sh step5 同款老坑)。从入口路径向上走找包根。
|
|
43
8
|
const require = createRequire(import.meta.url);
|
|
44
9
|
let dir = dirname(require.resolve("@sema-agent/core"));
|
|
45
10
|
for (let i = 0; i < 6; i++) {
|
|
@@ -57,7 +22,6 @@ export const S1_CORE_VERSION = (() => {
|
|
|
57
22
|
return "unknown";
|
|
58
23
|
}
|
|
59
24
|
})();
|
|
60
|
-
/** Map the internal uppercase `Arm` to its lowercase s1.v1 wire tag. */
|
|
61
25
|
export function armTag(arm) {
|
|
62
26
|
switch (arm) {
|
|
63
27
|
case "SOLO":
|
|
@@ -68,20 +32,7 @@ export function armTag(arm) {
|
|
|
68
32
|
return "team";
|
|
69
33
|
}
|
|
70
34
|
}
|
|
71
|
-
/**
|
|
72
|
-
* delivered && hiddenTestsGreen && buildPassed && invariantsOk — the ONLY thing that counts as value. This is the
|
|
73
|
-
* SAME function as core's exported `trulyCorrect` (shape-equal over the 4 booleans); re-exported under the harness's
|
|
74
|
-
* historical name so callers and the producer recompute it from the same source the metric tool uses (it can never
|
|
75
|
-
* drift from the metric's definition).
|
|
76
|
-
*/
|
|
77
35
|
export const oracleTrulyCorrect = trulyCorrect;
|
|
78
|
-
/**
|
|
79
|
-
* 🔴 Narrow an oracle result down to EXACTLY the 4 s1.v1 contract booleans before it goes on the wire. The
|
|
80
|
-
* standalone `runOracle` (oracle.ts) returns an `OracleVerdict` SUPERSET (`trulyCorrect`, `raw`) that is
|
|
81
|
-
* structurally assignable to the `() => Promise<OracleVerdicts>` seam — without this defensive projection those
|
|
82
|
-
* extra producer-internal fields would JSON.stringify straight into the emitted row's `oracle` block, drifting it
|
|
83
|
-
* off s1.v1 and (worse) re-exporting the derived `trulyCorrect` the metric tool must RECOMPUTE and never trust.
|
|
84
|
-
*/
|
|
85
36
|
export function pickOracleVerdicts(o) {
|
|
86
37
|
return {
|
|
87
38
|
delivered: o.delivered,
|
|
@@ -92,25 +43,12 @@ export function pickOracleVerdicts(o) {
|
|
|
92
43
|
}
|
|
93
44
|
const _rawRowIsRunRecord = true;
|
|
94
45
|
void _rawRowIsRunRecord;
|
|
95
|
-
/** Serialize a RawRow to one JSONL line (no trailing newline — the writer joins with "\n"). */
|
|
96
46
|
export function rowToJsonl(row) {
|
|
97
47
|
return JSON.stringify(row);
|
|
98
48
|
}
|
|
99
|
-
/** Serialize a batch of RawRows to a JSONL document (one row per line, trailing newline). */
|
|
100
49
|
export function rowsToJsonl(rows) {
|
|
101
50
|
return rows.map(rowToJsonl).join("\n") + (rows.length > 0 ? "\n" : "");
|
|
102
51
|
}
|
|
103
|
-
/**
|
|
104
|
-
* 🔴 Wire the REAL design/95 metric tool. `buildReport` (core 1.111.0 `@sema-agent/core/bench`) is the
|
|
105
|
-
* value-verdict JOIN: it SCORES only `scored` rows, GROUPS by `(suiteVersion, taskId, archetype, valueDimension,
|
|
106
|
-
* arm)` (the Simpson guard), folds each cell, splits the withhold bucket by the counterfactual, and emits the
|
|
107
|
-
* `ValueJudgmentReport` (groupedCells / comparisons / cells / pareto / excluded). A `RawRow[]` is assignable to its
|
|
108
|
-
* `RunRecord[]` input (RawRow extends RunRecord), so the harness produces the verdict from its OWN rows with no
|
|
109
|
-
* re-mapping — the metric definition lives in core, the producer only emits honest inputs.
|
|
110
|
-
*
|
|
111
|
-
* The live SOLO/SUP/TEAM run that GENERATES rows is clay-gated (expensive E2B+DeepSeek); this is purely the
|
|
112
|
-
* CONSUME path (test-covered on synthetic conformant rows in test/s1-report.test.ts).
|
|
113
|
-
*/
|
|
114
52
|
export function buildS1Report(rows, opts) {
|
|
115
53
|
return buildReport(rows, opts);
|
|
116
54
|
}
|
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S1 value-verdict harness — the RESUMABLE FIRM-RUN DRIVER. SPEC-S1-value-harness.md §11 ("the human's post-step
|
|
3
|
-
* that wires this scaffold into a runnable batch CLI"). Enumerates the firm cells {C1,C2,C4} × the arms each trap
|
|
4
|
-
* declares × N seeds, runs each MISSING cell via `runArm` against a REAL `ProfileDeps` (live-deps.ts), records an
|
|
5
|
-
* append-only JSONL LEDGER keyed by (taskId, arm, seed), and at the end builds the `ValueJudgmentReport` via
|
|
6
|
-
* `buildS1Report`. The report IS the output — this driver never asserts which arm wins.
|
|
7
|
-
*
|
|
8
|
-
* 🔴 RESUMABLE (clay's hard requirement): on start the driver READS the ledger, builds the done-set, and runs ONLY
|
|
9
|
-
* missing cells. A completed SCORED cell is NEVER re-run. A cell that throws / times out is recorded
|
|
10
|
-
* `runStatus:"infra-failed"` (EXCLUDED from scoring, NOT a fake loss) AND left re-runnable on the next pass — so
|
|
11
|
-
* a hang/crash mid-run resumes cleanly. Per-cell wall-clock timeout → kill the cell, mark infra-failed, move on.
|
|
12
|
-
*
|
|
13
|
-
* 🔴 --dry-run: a MOCK ProfileDeps (no E2B/DeepSeek) proves the driver loop + ledger + resume + buildReport work
|
|
14
|
-
* DETERMINISTICALLY (this is what the test + CI exercise; the REAL run is the owner's gated step).
|
|
15
|
-
*
|
|
16
|
-
* 🔴 ENV GATING: the live path requires E2B_API_KEY + DEEPSEEK_API_KEY; absent → the driver refuses the live path
|
|
17
|
-
* with a clear message (never a silent fake run). The deterministic --dry-run never needs keys.
|
|
18
|
-
*/
|
|
19
1
|
import { promises as fs } from "node:fs";
|
|
20
2
|
import path from "node:path";
|
|
21
3
|
import { Runner, InMemoryCheckpointStore } from "@sema-agent/core";
|
|
@@ -25,14 +7,8 @@ import { makeBenchClock } from "./runner-ctx.js";
|
|
|
25
7
|
import { buildS1Report, S1_SCHEMA_VERSION, S1_CORE_VERSION } from "./row.js";
|
|
26
8
|
import { armTag } from "./row.js";
|
|
27
9
|
import { buildLiveDeps, liveRuntimeConfigFromEnv } from "./live-deps.js";
|
|
28
|
-
/** Enumerate the firm cells = FIRM_TRAPS × trap.arms × seeds. Optional `only` (trapId) / `arm` filters slice the
|
|
29
|
-
* set for a controlled live run — a single-cell smoke (`--only C1 --arm solo --seeds 1`) before the full sweep, or
|
|
30
|
-
* re-running one trap/arm. The ledger keys are unchanged, so a filtered run still resumes/merges into the same run. */
|
|
31
10
|
export function enumerateCells(seeds, filter = {}) {
|
|
32
11
|
const cells = [];
|
|
33
|
-
// 🔴 default sweep = FIRM_TRAPS only (directional traps must NEVER enter a firm verdict). An explicit --only MAY
|
|
34
|
-
// target a directional trap (e.g. C6 hazard) for a controlled make-real probe — its rows carry liveProof:directional
|
|
35
|
-
// so buildReport still excludes them from the verdict; running it just produces the data to CONFIRM the hazard fires.
|
|
36
12
|
const source = filter.only ? ALL_TRAPS : FIRM_TRAPS;
|
|
37
13
|
for (const trap of source) {
|
|
38
14
|
if (filter.only && trap.id !== filter.only)
|
|
@@ -47,12 +23,9 @@ export function enumerateCells(seeds, filter = {}) {
|
|
|
47
23
|
}
|
|
48
24
|
return cells;
|
|
49
25
|
}
|
|
50
|
-
/** A stable string key for a cell (the ledger dedupe key). */
|
|
51
26
|
export function cellKeyStr(k) {
|
|
52
27
|
return `${k.taskId}::${armTag(k.arm)}::${String(k.seed)}`;
|
|
53
28
|
}
|
|
54
|
-
/** Read the ledger, returning ALL records + the done-set of SCORED-or-otherwise-completed cell keys. A record with
|
|
55
|
-
* `runStatus:"infra-failed"` is NOT in the done-set (it is re-runnable — the resume contract). */
|
|
56
29
|
export async function readLedger(ledgerPath) {
|
|
57
30
|
let raw;
|
|
58
31
|
try {
|
|
@@ -72,14 +45,12 @@ export async function readLedger(ledgerPath) {
|
|
|
72
45
|
rec = JSON.parse(t);
|
|
73
46
|
}
|
|
74
47
|
catch {
|
|
75
|
-
continue;
|
|
48
|
+
continue;
|
|
76
49
|
}
|
|
77
50
|
records.push(rec);
|
|
78
|
-
// A cell is "done" (never re-run) ONLY when it is a completed scored/excluded-but-final row. An infra-failed
|
|
79
|
-
// row is re-runnable, so it does NOT enter the done-set. (The LAST record for a key wins on re-aggregation.)
|
|
80
51
|
const key = cellKeyStr({ taskId: rec.taskId, arm: armUpper(rec.arm), seed: rec.seed ?? 0 });
|
|
81
52
|
if (rec.runStatus === "infra-failed") {
|
|
82
|
-
done.delete(key);
|
|
53
|
+
done.delete(key);
|
|
83
54
|
}
|
|
84
55
|
else {
|
|
85
56
|
done.add(key);
|
|
@@ -87,7 +58,6 @@ export async function readLedger(ledgerPath) {
|
|
|
87
58
|
}
|
|
88
59
|
return { records, done };
|
|
89
60
|
}
|
|
90
|
-
/** Map the lowercase wire tag back to the internal uppercase Arm. */
|
|
91
61
|
function armUpper(tag) {
|
|
92
62
|
switch (tag) {
|
|
93
63
|
case "solo":
|
|
@@ -97,18 +67,13 @@ function armUpper(tag) {
|
|
|
97
67
|
case "team":
|
|
98
68
|
return "TEAM";
|
|
99
69
|
default:
|
|
100
|
-
// 🔴 fail-loud (review council DESIGN#1): `tag` comes from a parsed JSONL ledger line, so a corrupt/unknown arm
|
|
101
|
-
// would otherwise produce an `undefined` cellKeyStr → silent dedup poisoning. A bad ledger row must throw, not
|
|
102
|
-
// collapse two cells onto one undefined key.
|
|
103
70
|
throw new Error(`s1 run-firm: unknown arm tag ${JSON.stringify(tag)} in ledger row (expected solo|sup|team)`);
|
|
104
71
|
}
|
|
105
72
|
}
|
|
106
|
-
/** Append one record to the ledger (atomic-ish: one write of one line + newline). */
|
|
107
73
|
async function appendLedger(ledgerPath, rec) {
|
|
108
74
|
await fs.mkdir(path.dirname(ledgerPath), { recursive: true });
|
|
109
75
|
await fs.appendFile(ledgerPath, JSON.stringify(rec) + "\n", "utf8");
|
|
110
76
|
}
|
|
111
|
-
/** Run a promise with a wall-clock timeout. Rejects with a timeout error on expiry (the caller marks infra-failed). */
|
|
112
77
|
function withTimeout(p, ms, label) {
|
|
113
78
|
return new Promise((resolve, reject) => {
|
|
114
79
|
const timer = setTimeout(() => reject(new Error(`cell timeout after ${ms}ms (${label})`)), ms);
|
|
@@ -122,7 +87,6 @@ function withTimeout(p, ms, label) {
|
|
|
122
87
|
});
|
|
123
88
|
});
|
|
124
89
|
}
|
|
125
|
-
/** Build an infra-failed RawRow for a cell that threw/timed out (EXCLUDED, NOT a fake loss; re-runnable). */
|
|
126
90
|
function infraFailedRow(cell, ctx) {
|
|
127
91
|
const now = ctx.clock.now();
|
|
128
92
|
return {
|
|
@@ -141,13 +105,9 @@ function infraFailedRow(cell, ctx) {
|
|
|
141
105
|
humanReview: { count: 0, totalWaitMs: 0, gates: [] },
|
|
142
106
|
},
|
|
143
107
|
wallTimeSec: 0,
|
|
144
|
-
meta: { startedAt: now, finishedAt: now, coreVersion: S1_CORE_VERSION, gitSha: ctx.gitSha, runId: ctx.runId },
|
|
108
|
+
meta: { startedAt: now, finishedAt: now, coreVersion: S1_CORE_VERSION, gitSha: ctx.gitSha, runId: ctx.runId },
|
|
145
109
|
};
|
|
146
110
|
}
|
|
147
|
-
/**
|
|
148
|
-
* Run the firm batch. Returns the final `ValueJudgmentReport` (also written to `reportPath`). Resumable: re-running
|
|
149
|
-
* continues where it stopped, never re-running a completed scored cell.
|
|
150
|
-
*/
|
|
151
111
|
export async function runFirm(opts) {
|
|
152
112
|
const seeds = opts.seeds ?? 5;
|
|
153
113
|
if (!Number.isInteger(seeds) || seeds < 1)
|
|
@@ -186,23 +146,16 @@ export async function runFirm(opts) {
|
|
|
186
146
|
}
|
|
187
147
|
await appendLedger(opts.ledgerPath, row);
|
|
188
148
|
ranThisPass++;
|
|
189
|
-
// Only a non-infra-failed row enters the done-set (an infra-failed cell stays re-runnable on the next pass).
|
|
190
149
|
if (row.runStatus !== "infra-failed")
|
|
191
150
|
done.add(key);
|
|
192
151
|
log("cell_done", { key, runStatus: row.runStatus });
|
|
193
152
|
}
|
|
194
|
-
// Final pass: load ALL ledger rows, de-dupe to the LAST record per key (a re-run supersedes an earlier
|
|
195
|
-
// infra-failed), build the report.
|
|
196
153
|
const { records } = await readLedger(opts.ledgerPath);
|
|
197
154
|
const lastByKey = new Map();
|
|
198
155
|
for (const rec of records) {
|
|
199
156
|
lastByKey.set(cellKeyStr({ taskId: rec.taskId, arm: armUpper(rec.arm), seed: rec.seed ?? 0 }), rec);
|
|
200
157
|
}
|
|
201
158
|
const allRows = [...lastByKey.values()];
|
|
202
|
-
// 🔴 (review HIGH finding) the firm report is FIRM_TRAPS rows ONLY. A directional probe (C6/C7) can share a ledger
|
|
203
|
-
// via --only, and buildReport does NOT filter by liveProof — an unfiltered call would let directional rows
|
|
204
|
-
// pollute the firm comparisons/pareto. Filter to firm taskIds here (directional rows stay in the ledger for
|
|
205
|
-
// separate analysis); a directional probe should also use its own --run-id to keep ledgers cleanly separate.
|
|
206
159
|
const firmIds = new Set(FIRM_TRAPS.map((t) => t.id));
|
|
207
160
|
const rows = allRows.filter((r) => firmIds.has(r.taskId));
|
|
208
161
|
const report = buildS1Report(rows);
|
|
@@ -212,21 +165,13 @@ export async function runFirm(opts) {
|
|
|
212
165
|
const excluded = rows.length - scored;
|
|
213
166
|
return { report, scored, excluded, ranThisPass };
|
|
214
167
|
}
|
|
215
|
-
/** Build a live cell or throw a clear message if the live runtime is missing (env gating). */
|
|
216
168
|
function buildLiveCellOrThrow(opts, trap, seed, cellId) {
|
|
217
169
|
if (!opts.liveRuntime) {
|
|
218
170
|
throw new Error("S1 run-firm: live path requires E2B_API_KEY + DEEPSEEK_API_KEY (the brain gateway). None resolved — refusing a silent fake run. Use --dry-run for the deterministic loop, or set the keys for the owner's gated live run.");
|
|
219
171
|
}
|
|
220
172
|
return buildLiveDeps(opts.liveRuntime, trap, seed, cellId);
|
|
221
173
|
}
|
|
222
|
-
// ─────────────────────────────── CLI ───────────────────────────────
|
|
223
|
-
/** The default shared budget (the §3.2 fairness root). Overridable via CLI flags. */
|
|
224
174
|
function defaultBudget(modelId) {
|
|
225
|
-
// 🔴 maxTokens is a GENEROUS safety net, NOT the binding gate (clay: budget unlimited). The 1-cell live smoke caught
|
|
226
|
-
// that maxTokens:8000 capped EVERY run "failed" → infra-failed → nothing ever scored: the token counter includes
|
|
227
|
-
// CACHED tokens (97% cache hit), so a single verify round over repo context blew 8000 while real cost was ~$0. The
|
|
228
|
-
// real, FAIR economic gate is maxCostUsd + maxTurns (uniform across all arms); maxTokens just must not bind before
|
|
229
|
-
// them. 200k comfortably fits ~12 turns of verify→fix with repo context; cost stays the measured economic axis.
|
|
230
175
|
return { modelId, maxTokens: 200_000, maxCostUsd: 1.0, maxTurns: 12, maxRounds: 2, supAutoBudget: 1 };
|
|
231
176
|
}
|
|
232
177
|
function parseArgs(argv) {
|
|
@@ -235,9 +180,6 @@ function parseArgs(argv) {
|
|
|
235
180
|
return i >= 0 && i + 1 < argv.length ? argv[i + 1] : undefined;
|
|
236
181
|
};
|
|
237
182
|
const runId = get("run-id") ?? `s1-firm-${Date.now()}`;
|
|
238
|
-
// --seeds / --cell-timeout-ms: explicit positive-integer validation (NOT a `|| default` truthy coercion, which
|
|
239
|
-
// silently turns `--seeds 0` into 5 and lets `--seeds -1` enumerate ZERO cells = a silent empty run). Absent flag
|
|
240
|
-
// → default; present-but-invalid → a clear error + non-zero exit (never a silently-coerced batch).
|
|
241
183
|
const seeds = positiveIntArg(get("seeds"), 5, "--seeds");
|
|
242
184
|
const cellTimeoutMs = positiveIntArg(get("cell-timeout-ms"), 15 * 60_000, "--cell-timeout-ms");
|
|
243
185
|
return {
|
|
@@ -251,8 +193,6 @@ function parseArgs(argv) {
|
|
|
251
193
|
...(get("arm") ? { arm: get("arm") } : {}),
|
|
252
194
|
};
|
|
253
195
|
}
|
|
254
|
-
/** Parse a CLI flag as a positive integer; default when the flag is absent; exit(2) on a present-but-invalid value
|
|
255
|
-
* (0, negative, NaN, fractional) rather than silently coercing it. */
|
|
256
196
|
export function positiveIntArg(raw, def, flag) {
|
|
257
197
|
if (raw === undefined)
|
|
258
198
|
return def;
|
|
@@ -263,15 +203,13 @@ export function positiveIntArg(raw, def, flag) {
|
|
|
263
203
|
}
|
|
264
204
|
return n;
|
|
265
205
|
}
|
|
266
|
-
/** The mock deps factory for --dry-run: a deterministic LiveCell (no E2B/DeepSeek). Per-cell deterministic by seed. */
|
|
267
206
|
function dryRunMockFactory() {
|
|
268
207
|
return (trap, seed) => {
|
|
269
|
-
// A deterministic stats fixture + a deterministic oracle keyed on the trap (C2 = impossible-spec → not green).
|
|
270
208
|
const stats = {
|
|
271
209
|
costBreakdown: { llmRootMicroUsd: 50_000, nestedSubagentMicroUsd: 0, memoryConsolidationMicroUsd: 0, compactionMicroUsd: 0 },
|
|
272
210
|
humanReview: { count: 0, totalWaitMs: 0, gates: [] },
|
|
273
211
|
};
|
|
274
|
-
const green = trap.id !== "C2-honest-bound";
|
|
212
|
+
const green = trap.id !== "C2-honest-bound";
|
|
275
213
|
const oracle = { delivered: true, hiddenTestsGreen: green, buildPassed: true, invariantsOk: true };
|
|
276
214
|
const vr = {
|
|
277
215
|
taskId: trap.id,
|
|
@@ -294,7 +232,6 @@ function dryRunMockFactory() {
|
|
|
294
232
|
return { deps, dispose: async () => { } };
|
|
295
233
|
};
|
|
296
234
|
}
|
|
297
|
-
/** CLI entry. */
|
|
298
235
|
export async function main(argv = process.argv.slice(2)) {
|
|
299
236
|
const args = parseArgs(argv);
|
|
300
237
|
const liveRuntime = liveRuntimeConfigFromEnv();
|
|
@@ -335,8 +272,6 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
335
272
|
directionalOnly: result.report.directionalOnly,
|
|
336
273
|
}, null, 2));
|
|
337
274
|
}
|
|
338
|
-
// Run as a CLI when invoked directly (not when imported by the test). `import.meta.url` guard keeps the module
|
|
339
|
-
// import-safe for the deterministic test.
|
|
340
275
|
const isMain = (() => {
|
|
341
276
|
try {
|
|
342
277
|
return typeof process !== "undefined" && Array.isArray(process.argv) && /run-firm(\.[jt]s)?$/.test(process.argv[1] ?? "");
|
|
@@ -351,7 +286,6 @@ if (isMain) {
|
|
|
351
286
|
process.exit(1);
|
|
352
287
|
});
|
|
353
288
|
}
|
|
354
|
-
// Re-export the live wiring for the owner's gated run + the test.
|
|
355
289
|
export { buildLiveDeps, liveRuntimeConfigFromEnv } from "./live-deps.js";
|
|
356
290
|
export { Runner };
|
|
357
291
|
//# sourceMappingURL=run-firm.js.map
|
|
@@ -1,22 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* S1 value-verdict harness — the FAIRNESS ROOT (SPEC-S1-value-harness.md §2). ONE place constructs the shared
|
|
3
|
-
* Runner ingredients (config / brain / pricing), the SAME budget for every arm, and the injected deterministic
|
|
4
|
-
* clock that makes C2 (human-review wall-time) reproducible.
|
|
5
|
-
*
|
|
6
|
-
* 🔴 THE §3.2 RED LINE (design/89's #1 confound): every leaf TaskSpec across all 3 arms carries the SAME
|
|
7
|
-
* `limits.{ maxTokens, maxCostUsd, maxTurns }` (core ≥5.8: budget keys live ONLY in `limits` — a top-level
|
|
8
|
-
* `maxTokens`/`maxCostUsd` is a silently-unread dead key), and TEAM's per-worker budgets sum to ≤ the solo budget — so no
|
|
9
|
-
* arm can win on a bigger pie. `assertBudgetMatch` (below) is the build-time guard the shape test runs.
|
|
10
|
-
*
|
|
11
|
-
* 🔴 BUDGET-MATCH for TEAM is NEW WIRING the live conflict test does NOT do: `leader-conflict-resolver-live.test.ts`
|
|
12
|
-
* sets NO budget on `SubtaskSpec.spec` and NO `now` on any Runner. The harness STAMPS both (arms.ts) — copying the
|
|
13
|
-
* live test verbatim would yield an unbounded TEAM (the confound) and an empty `humanReview` (C2 = undefined).
|
|
14
|
-
*
|
|
15
|
-
* The real-infra construction (E2B worker/grader envs + a live brain) is deferred to the live make-real proof
|
|
16
|
-
* (`test/s1-value-live.test.ts`, gated on E2B+DEEPSEEK). This module only fixes the SHAPE + the budget invariant
|
|
17
|
-
* + the clock; a deterministic shape test exercises it with a MOCK runner (no real agents, no keys).
|
|
18
|
-
*/
|
|
19
|
-
/** Project the producer's shared budget (+ an optional TEAM worker-sum) into a `RowBudget` for the fairness guard. */
|
|
20
1
|
export function budgetDescriptor(budget, arm, teamWorkerBudgetSumUsd) {
|
|
21
2
|
return {
|
|
22
3
|
modelId: budget.modelId,
|
|
@@ -28,7 +9,6 @@ export function budgetDescriptor(budget, arm, teamWorkerBudgetSumUsd) {
|
|
|
28
9
|
...(arm === "TEAM" && teamWorkerBudgetSumUsd !== undefined ? { teamWorkerBudgetSumUsd } : {}),
|
|
29
10
|
};
|
|
30
11
|
}
|
|
31
|
-
/** Construct the deterministic clock used to model C2 review seconds (no real wall-time advance). */
|
|
32
12
|
export function makeBenchClock(startEpochMs = Date.now()) {
|
|
33
13
|
let t = startEpochMs;
|
|
34
14
|
return {
|
|
@@ -40,15 +20,6 @@ export function makeBenchClock(startEpochMs = Date.now()) {
|
|
|
40
20
|
},
|
|
41
21
|
};
|
|
42
22
|
}
|
|
43
|
-
/**
|
|
44
|
-
* Apply the shared budget to a leaf TaskSpec-like object (SOLO impl, SUP impl, each TEAM `SubtaskSpec.spec`).
|
|
45
|
-
* Returns the budget fields to spread onto the spec — kept as a helper so EVERY leaf is stamped identically
|
|
46
|
-
* (the live tests forget this for TEAM workers — the confound). `maxCostUsd` is overridable for the TEAM
|
|
47
|
-
* per-worker split (Σ ≤ solo, enforced by `assertBudgetMatch`).
|
|
48
|
-
*
|
|
49
|
-
* 🔴 ALL THREE keys live under `limits` — core ≥5.8 reads `maxTokens`/`maxCostUsd` ONLY from `TaskSpec.limits`;
|
|
50
|
-
* a top-level key is DEAD (silently unread — the cost/token gates never bind).
|
|
51
|
-
*/
|
|
52
23
|
export function leafBudgetFields(budget, overrideMaxCostUsd) {
|
|
53
24
|
return {
|
|
54
25
|
limits: {
|
|
@@ -58,17 +29,8 @@ export function leafBudgetFields(budget, overrideMaxCostUsd) {
|
|
|
58
29
|
},
|
|
59
30
|
};
|
|
60
31
|
}
|
|
61
|
-
/**
|
|
62
|
-
* BUDGET-MATCH build-time guard (the §3.2 red line — run by the shape test). FAILS if, within a task class:
|
|
63
|
-
* (a) any arm's `{ modelId, maxTokens, maxCostUsd, maxTurns, maxRounds }` differs, OR
|
|
64
|
-
* (b) a TEAM row's `teamWorkerBudgetSumUsd` exceeds `maxCostUsd` (the bigger-pie confound).
|
|
65
|
-
*
|
|
66
|
-
* Pure over the rows' `budget` blocks (so it works on emitted RawRows AND on a pre-flight check). Returns the
|
|
67
|
-
* list of violations (empty = OK) so the caller can assert it.
|
|
68
|
-
*/
|
|
69
32
|
export function assertBudgetMatch(rows) {
|
|
70
33
|
const violations = [];
|
|
71
|
-
// Group by task class (here: taskId — each trap is its own class for the budget invariant).
|
|
72
34
|
const byTask = new Map();
|
|
73
35
|
for (const r of rows) {
|
|
74
36
|
const g = byTask.get(r.taskId) ?? [];
|
|
@@ -84,7 +46,6 @@ export function assertBudgetMatch(rows) {
|
|
|
84
46
|
violations.push(`budget-match: task ${taskId} arm ${r.arm} ${k}=${String(b[k])} != ${r.arm === group[0].arm ? "" : `${group[0].arm} `}${String(ref[k])}`);
|
|
85
47
|
}
|
|
86
48
|
}
|
|
87
|
-
// (b) TEAM bigger-pie guard: Σ per-worker budget must not exceed the shared per-arm maxCostUsd.
|
|
88
49
|
if (b.teamWorkerBudgetSumUsd !== undefined && b.teamWorkerBudgetSumUsd > b.maxCostUsd + 1e-9) {
|
|
89
50
|
violations.push(`budget-match: task ${taskId} arm ${r.arm} teamWorkerBudgetSumUsd=${b.teamWorkerBudgetSumUsd} > maxCostUsd=${b.maxCostUsd} (bigger-pie confound)`);
|
|
90
51
|
}
|
|
@@ -92,7 +53,6 @@ export function assertBudgetMatch(rows) {
|
|
|
92
53
|
}
|
|
93
54
|
return violations;
|
|
94
55
|
}
|
|
95
|
-
/** Assert two execution envs are DISTINCT objects (the §5.1 anti-reward-hack precondition). Throws if same. */
|
|
96
56
|
export function assertDistinctEnvs(workerEnv, graderEnv) {
|
|
97
57
|
if (workerEnv === graderEnv) {
|
|
98
58
|
throw new Error("S1 oracle: graderEnv === workerEnv — the anti-reward-hack identity check would fail closed (oracle.unprotected). The grader MUST be a distinct env (decorrelation + the repair-loop §5.1 boundary).");
|