Skip to content

Commit a37d66f

Browse files
committed
feat: enforce portable experiment execution envelopes
1 parent 6be74b2 commit a37d66f

21 files changed

Lines changed: 3452 additions & 109 deletions

TODO.md

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,36 @@ Usage rules:
1010

1111
## Now
1212

13-
- Make live-validation temp workspace builders emit `run_status.json` with `validation_scope=live_fixture`.
14-
- Current temp workspaces can still look noisier than intended in `/doctor` because older fixtures do not emit the new scope marker.
15-
- Keep this additive; do not weaken the default governed-run validator.
16-
1713
- Decide whether to add an additive backfill helper for older runs that predate `run_status.json`.
1814
- Current behavior is honest fallback projection.
1915
- Follow-up is whether a bounded backfill would improve operator surfaces without pretending old runs had artifacts they never wrote.
2016

21-
- Add a per-run completeness checklist artifact.
22-
- Summarize presence of `run_record.json`, `events.jsonl`, checkpoints, key node artifacts, and public mirrors.
23-
- Keep this separate from harness validation and do not turn it into a new gate by default.
17+
- Validate CPU and explicitly selected NVIDIA GPU isolation on a host that
18+
permits user namespaces.
19+
- The Local ACI now binds CPU/NVIDIA device policy, mounts only declared
20+
numeric GPU IDs plus required NVIDIA control devices, and emits `enforced`
21+
only after an in-sandbox start marker.
22+
- This workstation rejects the required namespace setup, so its live runs
23+
remain honestly `partial` even though the device policy is now implemented.
24+
25+
- Validate the Docker execution adapter against a real purpose-built runtime
26+
container on another host.
27+
- The adapter now fails closed, clears the command environment, verifies the
28+
strict container boundary before and after execution, and checks exact
29+
CPU/NVIDIA exposure.
30+
- Unit and fake-CLI integration coverage pass locally; a real Docker daemon
31+
and selected NVIDIA device run are still required for cross-host evidence.
32+
- Remote execution still requires a dedicated enforced adapter.
33+
34+
## Completed Recently
35+
36+
- Added portable execution envelopes, hash-bound receipts, automatic
37+
`bubblewrap` isolation, strict inspected Docker execution, explicit GPU
38+
device policy, and fail-closed paper-grade execution grounding.
39+
- Live-validation fixture builders emit `run_status.json` with
40+
`validation_scope=live_fixture`.
41+
- Per-run completeness checklists summarize canonical run artifacts without
42+
replacing harness validation or becoming a default gate.
2443

2544
## Next
2645

docs/architecture.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,51 @@ manager entry, and `run_experiments` all consume the same recomputed execution
397397
authorization. Persisted pre-probe booleans and estimator status are diagnostic
398398
components and must never be treated independently as execution permission.
399399

400+
Every command launched by `run_experiments`, including preflight, primary,
401+
retry, and supplemental commands, crosses the shared execution-envelope
402+
boundary. The portable envelope binds the command template and hash, workspace
403+
relative working and writable roots, an environment-name allowlist, network
404+
policy and purpose, timeout, declared seeds, explicit CPU/NVIDIA device policy,
405+
input hashes, dependency-lock hashes, and expected outputs. Per-attempt envelopes and receipts remain under
406+
`execution/{envelopes,receipts}/`; the latest primary pair is projected as
407+
`execution/execution_envelope.json` and `execution/execution_receipt.json`.
408+
409+
An ACI adapter must report which controls it actually enforced. The local ACI
410+
first probes the Linux `bubblewrap` adapter. For local CPU execution, no GPU
411+
device is exposed. For NVIDIA execution, the requested GPU count and concrete
412+
numeric visible-device IDs must agree; only those device nodes plus required
413+
NVIDIA control nodes are mounted. When the host permits namespace creation and
414+
the device policy is enforceable, the adapter exposes only the
415+
declared workspace, overlays the explicit writable roots, clears the host
416+
environment, applies the network policy, and reports `enforcement=enforced`
417+
only after an in-sandbox start marker is observed. A failed setup does not
418+
silently rerun the command outside the sandbox.
419+
420+
For `executionProfile=docker`, the ACI uses a dedicated `docker_exec` path
421+
instead of embedding a second Docker command in the experiment command. Before
422+
execution it inspects the selected container and requires a stable running
423+
state, a non-root user, a read-only root filesystem, dropped capabilities,
424+
`no-new-privileges`, non-privileged mode, identity bind mounts restricted to
425+
the declared workspace and writable roots, the requested network mode, and an
426+
exact CPU/NVIDIA device match. The command runs through `/usr/bin/env -i` with
427+
only the managed allowlist and device visibility variables. A second inspect
428+
must reproduce the same boundary fingerprint before the receipt can report
429+
`enforcement=enforced`. An inspect or policy failure blocks the command rather
430+
than falling back to host execution.
431+
432+
If `bubblewrap` is missing or forbidden by host policy, GPU IDs are absent or
433+
unsupported, or required device nodes are unavailable, local execution strips
434+
non-allowlisted environment variables and verifies the command, input hashes,
435+
and timeout. It does not claim workspace, mount, device, or blocked-network
436+
isolation and therefore reports `enforcement=partial` with a reason code.
437+
Remote and plan-only profiles fail closed until they have dedicated adapters.
438+
An adapter without the envelope API reports
439+
`enforcement=compatibility`. Neither level is paper-grade. The existing
440+
`execution_grounding` research-process check requires a hash-valid
441+
`enforcement=enforced` receipt with every environment, workspace, input,
442+
timeout, network, mount, and device assurance flag and required output
443+
present before experimental output can be paper-ready eligible.
444+
400445
`analyze_papers` revalidates the collection generation, query plan, reviewer
401446
input hash, pair judgments, retained paper IDs, family counts, and semantic
402447
precision floors. A retired quality artifact, a changed judgment, or a corpus

docs/experiment-quality-bar.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ When execution is recorded as successful:
6464
- `run_manifest.json` should exist and summarize what was run.
6565
- `experiment_portfolio.json` or an equivalent design artifact should exist and describe the planned trial groups.
6666
- At least one concrete run record must exist under the run artifact tree.
67+
- `execution/execution_envelope.json` and
68+
`execution/execution_receipt.json` must exist, bind each other by SHA-256,
69+
and name the actual assurance level. Runtime success may use a `partial` or
70+
`compatibility` receipt, but paper-scale promotion may not.
71+
- `bubblewrap` availability alone is insufficient: an `enforced` receipt
72+
requires a successful host probe and an adapter-controlled marker proving
73+
that the experiment command started after namespace and mount setup.
74+
- GPU-backed paper-scale execution must bind a positive requested GPU count and
75+
the same number of concrete numeric visible-device IDs. Missing IDs, UUID-only
76+
device selectors, unavailable device nodes, and Docker/remote execution through
77+
the local adapter remain `partial` until a dedicated enforced adapter exists.
6778

6879
### B. `analyze_results` success expectations
6980
When `analyze_results` is completed:
@@ -121,6 +132,12 @@ For an experiment result to count as paper-scale candidate evidence, all of the
121132
6. The experiment output is connected to the stated research question.
122133
7. The run is not merely a smoke test of the workflow itself.
123134
8. The evidence goes beyond a single thin run by including repeated trials/folds/seeds or explicit robustness evidence such as confidence intervals, stability metrics, or effect estimates.
135+
9. The primary execution has a hash-valid `enforcement=enforced` receipt whose
136+
environment, workspace, input-hash, timeout, network-policy, and mount-
137+
isolation and device-policy assurances all pass, whose dependency lock is
138+
present, and whose required outputs are hash-bound. Docker receipts require
139+
matching pre/post container-boundary inspection; an uninspected
140+
`docker exec` is not paper-grade execution evidence.
124141

125142
If any of the above is missing, the result may still be valid runtime output,
126143
but it must not be treated as paper-worthy experimental evidence.

docs/reproducibility.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ Reproducibility claims must be backed by concrete artifacts.
2828
or public output
2929
- Planned portfolio / trial-group structure (`experiment_portfolio.json`)
3030
- Run manifest (`run_manifest.json`)
31+
- Portable primary execution envelope and hash-bound receipt
32+
(`execution/execution_envelope.json`,
33+
`execution/execution_receipt.json`), plus immutable per-attempt records under
34+
`execution/envelopes/` and `execution/receipts/`
3135
- Matrix trial-group index when managed bundle execution materializes dataset/profile slices (`trial_group_matrix.json`)
3236
- Per-slice managed trial-group metrics when present (`trial_group_metrics/*.json`)
3337
- Raw or summarized metrics (`metrics.json`, supplemental metrics)
@@ -49,6 +53,38 @@ For each run, preserve:
4953
- key gate/recovery artifacts (`transition_recommendation.json`, `collect_background_job.json` when present)
5054
- key generated artifacts in `.autolabos/runs/<run_id>/...`, including trial-group matrix artifacts when present
5155

56+
Execution-envelope reproducibility requires more than the files being present:
57+
58+
- Recompute `envelope_sha256` after removing only `envelope_id` and
59+
`envelope_sha256`, and require `envelope_id` to match that digest.
60+
- Recompute `receipt_sha256` after removing only `receipt_sha256` and require
61+
its run, phase, attempt, envelope ID, and envelope hash to match the envelope.
62+
- Keep command paths portable through `${WORKSPACE_ROOT}` and store artifact
63+
paths relative to the workspace. Never persist environment values or secrets.
64+
- Bind `devices.policy`, `requested_gpu_count`, and concrete visible device IDs
65+
in the envelope. CPU-only execution exposes no GPU device. NVIDIA execution
66+
is paper-grade eligible only when the declared count and IDs agree and the
67+
adapter mounts exactly the selected GPU device nodes plus required control
68+
nodes.
69+
- Treat `partial` and `compatibility` receipts as development diagnostics, not
70+
paper-grade execution evidence. A paper-facing execution requires an
71+
`enforced` adapter receipt, verified dependency locks, required outputs, and
72+
all environment, workspace, input, timeout, network, mount, and device
73+
assurances.
74+
- The local ACI may issue `enforced` only when its `bubblewrap` probe succeeds
75+
and the command emits the adapter-controlled in-sandbox start marker. Missing
76+
namespace permission, setup failure, or an incomplete GPU device declaration
77+
must remain visible as a reason-coded non-paper-grade receipt.
78+
- The Docker ACI may issue `enforced` only when pre/post
79+
`docker container inspect` observations match and both satisfy the envelope: stable non-root
80+
and non-privileged execution, read-only root filesystem, dropped
81+
capabilities, `no-new-privileges`, bounded identity bind mounts, requested
82+
network mode, and exact CPU/NVIDIA device exposure. The process environment
83+
must be rebuilt through `env -i`. Inspection or policy failure blocks the
84+
command; it must not fall back to host execution.
85+
- Remote and plan-only profiles remain fail-closed until a dedicated adapter
86+
can emit equivalent independently checkable assurances.
87+
5288
## 3) Model-review reproducibility
5389

5490
Model-assisted review is reproducible only when its inputs, topology, and

src/core/evaluation/evalHarness.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ async function evaluateRun(runsDir: string, run: RunRecord): Promise<EvalHarness
338338
const policyBlocked = implementFailureType === "policy" || runVerifierStage === "policy";
339339
const storedStatus = await readRunOperatorStatus(runDir);
340340
const researchProcess = storedStatus?.research_process || await buildRunResearchProcessProjection({
341+
workspaceRoot: path.resolve(runsDir, "..", ".."),
341342
runDir,
342343
run
343344
});

0 commit comments

Comments
 (0)