Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -501,3 +501,6 @@ data/candidates/
# README's measurement section, so a clone that lacks it has a dangling reference.
!/docs/evidence-export.md
!/docs/wheel-console.md

# Public native scorer preparation is a supported cross-machine workflow.
!/docs/public-native-scoring.md
22 changes: 8 additions & 14 deletions data/datasets/alfworld.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
The environment is `kind: "files"`. Dataset discovery and the actor's socket client
use only the standard library. The trusted relay explicitly binds the separately
prepared `alfworld` execution artifact; no host Python package fallback is allowed.
The native verifier retains its independently pinned, sealed scorer runtime.
The native verifier uses public scorer source and locally prepared execution dependencies;
a historical machine archive is not required.

What the agent can read, and what that used to cost
--------------------------------------------------
Expand Down Expand Up @@ -88,16 +89,10 @@
environment the agent acts in and the environment the check replays are built from one
text -- `tests/quality/test_alfworld_relay.py` pins that byte identity for all 134 games.

Two things about this are **not** in this repository yet, and both are required before
an end-to-end run: (1) the runner must stage those bytes outside the sandbox and start
`relay.py`, then pass the socket to the sandbox as `tool_socket=` so it is published at
`/run/harnessgrad-tool/tool.sock` where the CLI imports and calls it (the mount wiring
lives in `eval/containers/`, a separate task -- and this migration is the first to
require `PLAN_VERSION` 4 -> 5, because from then on what a subject sees has changed);
(2) a relay fault currently makes `alf` exit nonzero, and nothing yet maps that to an
**unmeasured** task rather than a 0 -- `Relay.receipt` is the evidence the runner needs
for that. Neither is faked here. `control.py --oracle` (the local arm) publishes the
same pair into a temp directory itself and is unaffected.
The runner stages the selected game outside the actor's namespace, starts the
managed relay and publishes only its socket and stdlib client. Relay failures
remain unmeasured rather than becoming an agent's zero. `control.py --oracle`,
`--noop` and `--platform` use this lifecycle and the public native verifier.

The metric, and what is deliberately not added
----------------------------------------------
Expand Down Expand Up @@ -496,9 +491,8 @@ def _verifier(record: dict) -> dict:
"evidence_file": EVIDENCE_FILE,
"timeout_s": 300,
}
from data.runtimes import NATIVE_PINS
spec["native_runtime"] = NATIVE_PINS["alfworld"].copy()
return bind_scorer_input(spec, record["task_id"], [GAME_IN_WORKDIR])
from data.scaffolds.public_native import bind as bind_public_native
return bind_public_native("alfworld", bind_scorer_input(spec, record["task_id"], [GAME_IN_WORKDIR]))


def downloads() -> list[dict]:
Expand Down
2 changes: 1 addition & 1 deletion data/datasets/alfworld/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
a reader to be able to reproduce.

Both legacy `--oracle`/`--noop` and `--platform` use the normal runner,
managed trusted service and independently sealed native verifier. Dependencies
managed trusted service and public native verifier. Dependencies
must be prepared explicitly; platform Python and the actor CLI remain stdlib.
`--no-sandbox` selects the runner's weaker diagnostic mode for either spelling.

Expand Down
11 changes: 5 additions & 6 deletions data/datasets/alfworld/execution-recipe.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ ALFWorld trusted interactive service

Discovery, task filtering, game stripping, the actor CLI and action-log parsing
use the standard library. Third-party imports occur only in `gym_env.build()` in
the trusted service or the independently sealed native verifier. Task setup binds
the trusted service or the public native verifier. Task setup binds
a prepared execution artifact with role `service`; a missing or changed artifact
is an error, without host interpreter fallback or implicit installation.

Expand Down Expand Up @@ -31,9 +31,9 @@ without importing those packages. `native-source-version-evidence.json` records
these limited identity checks; it does not claim a complete original inventory. The exact pins
in `execution-requirements.txt` are a **new service dependency resolution**, made
on 2026-11-07 with uv using the public Tsinghua index for CPython 3.12/Linux. They
are not a reconstruction of the historical scorer environment. The existing
`data/runtimes/alfworld-native.json`, its hashes and the native scoring algorithm
are unchanged and continue to define verification.
are not a reconstruction of the historical scorer environment. Current verification uses the public source scorer and this locally prepared
execution recipe. `data/runtimes/alfworld-native.json` remains historical provenance;
it is not required for new evaluations. See [public native scoring](../../../docs/public-native-scoring.md).

Only three source files are mounted for the service: relay.py, lib/gym_env.py and
the platform tool_transport.py. The runner separately stages the selected stripped
Expand All @@ -54,8 +54,7 @@ python -m pytest -q tests/quality/test_alfworld_managed_runtime.py \
```

The legacy `control.py --oracle` / `--noop` and `--platform` spellings now all
use the normal runner with the complete managed relay declaration and original
sealed native verifier. `--budget` is carried consistently to service, actor CLI
use the normal runner with the complete managed relay declaration and public native verifier. `--budget` is carried consistently to service, actor CLI
and replay; missing scores or relay failures remain unmeasured. The older helper
API also starts the admitted service through the runner's relay lifecycle and
scores through the native verifier; it never imports the engine in platform Python.
5 changes: 2 additions & 3 deletions data/datasets/bird_minidev.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,8 @@ def _verify(record: dict) -> dict:
{"path": "database.sqlite", "from": str(database)},
],
}
from data.runtimes import NATIVE_PINS
spec["native_runtime"] = NATIVE_PINS["bird_minidev"].copy()
return bind_scorer_input(spec, record["task_id"], ["gold.sql", "database.sqlite"])
from data.scaffolds.public_native import bind as bind_public_native
return bind_public_native("bird_minidev", bind_scorer_input(spec, record["task_id"], ["gold.sql", "database.sqlite"]))


def setup_map() -> dict:
Expand Down
6 changes: 6 additions & 0 deletions data/datasets/bird_minidev/execution-runtime.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"schema": "harnessgrad.dataset-execution-runtime.v1",
"dataset": "bird_minidev",
"python": "3.12",
"requirements": "scoring-requirements.txt"
}
1 change: 1 addition & 0 deletions data/datasets/bird_minidev/scoring-requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# BIRD EX uses Python standard-library sqlite3; no external Python packages.
9 changes: 4 additions & 5 deletions data/datasets/chessbench_puzzles.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,13 +442,12 @@ def setup_for(record: dict) -> dict:


def verify_for(record: dict) -> dict:
from data.runtimes import NATIVE_PINS
from data.scaffolds.public_native import bind as bind_public_native
spec = _SPEC.verifier(record)
# The native runner supplies -I -S from its independently pinned manifest;
# retain its fixed script-at-argv[1] route contract.
# The public native runner supplies isolated Python flags; retain its
# script-at-argv[1] route contract.
spec['argv'].remove('-I')
spec['native_runtime'] = NATIVE_PINS['chessbench_puzzles'].copy()
return spec
return bind_public_native('chessbench_puzzles', spec)


__all__ = ["KIND", "DATASET_ROOT", "REVISION", "load", "load_selected", "control_task",
Expand Down
6 changes: 6 additions & 0 deletions data/datasets/chessbench_puzzles/NATIVE_RUNTIME.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Current evaluation uses the public-native-local-v1 profile. Prepare this dataset's
execution dependencies with `python tools/prepare_dataset.py --dataset chessbench_puzzles --runtime execution`.
No original scorer-machine archive is required. See [public native scoring](../../../docs/public-native-scoring.md).
The exact-byte archive material below is retained as historical evidence or explicit
legacy reproduction guidance; it is not the current default installation requirement.

# Independent ChessBench native scorer

The managed `chess==1.11.2` provider is for loading and interactive board state.
Expand Down
6 changes: 6 additions & 0 deletions data/datasets/chessbench_puzzles/execution-runtime.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"schema": "harnessgrad.dataset-execution-runtime.v1",
"dataset": "chessbench_puzzles",
"python": "3.12",
"requirements": "requirements-load.txt"
}
5 changes: 2 additions & 3 deletions data/datasets/jericho.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,8 @@ def _verifier(record: dict) -> dict:
"evidence_file": EVIDENCE_FILE,
"timeout_s": VERIFY_TIMEOUT_S,
}
from data.runtimes import NATIVE_PINS
spec["native_runtime"] = NATIVE_PINS["jericho"].copy()
return bind_scorer_input(spec, record["task_id"], [GAME_FILE, record["rom"]])
from data.scaffolds.public_native import bind as bind_public_native
return bind_public_native("jericho", bind_scorer_input(spec, record["task_id"], [GAME_FILE, record["rom"]]))


def downloads() -> list[dict]:
Expand Down
6 changes: 6 additions & 0 deletions data/datasets/jericho/NATIVE_CONTROL.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Current evaluation uses the public-native-local-v1 profile. Prepare this dataset's
execution dependencies with `python tools/prepare_dataset.py --dataset jericho --runtime execution`.
No original scorer-machine archive is required. See [public native scoring](../../../docs/public-native-scoring.md).
The exact-byte archive material below is retained as historical evidence or explicit
legacy reproduction guidance; it is not the current default installation requirement.

# Original supported-game native control

`authored_story.py` generates an original, CC0-1.0 Z-machine v5 story. It contains
Expand Down
5 changes: 2 additions & 3 deletions data/datasets/scienceworld.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,9 +468,8 @@ def _verifier(record: dict, *, world_jar=None) -> dict:
"evidence_file": EVIDENCE_FILE,
"timeout_s": 900,
}
from data.runtimes import NATIVE_PINS
spec['native_runtime'] = NATIVE_PINS['scienceworld'].copy()
return bind_scorer_input(spec, record["task_id"], [TASK_IN_WORKDIR, "scienceworld.jar"])
from data.scaffolds.public_native import bind as bind_public_native
return bind_public_native("scienceworld", bind_scorer_input(spec, record["task_id"], [TASK_IN_WORKDIR, "scienceworld.jar"]))


def downloads() -> list[dict]:
Expand Down
6 changes: 6 additions & 0 deletions data/datasets/scienceworld/ISOLATION_STATUS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Current evaluation uses the public-native-local-v1 profile. Prepare this dataset's
execution dependencies with `python tools/prepare_dataset.py --dataset scienceworld --runtime execution`.
No original scorer-machine archive is required. See [public native scoring](../../../docs/public-native-scoring.md).
The exact-byte archive material below is retained as historical evidence or explicit
legacy reproduction guidance; it is not the current default installation requirement.

ScienceWorld actor dependency boundary
=====================================

Expand Down
6 changes: 5 additions & 1 deletion data/runtimes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
"""Reviewed independent admission pins; never recalculate expectations at runtime."""
"""Historical sealed scorer pins for explicit archive reproduction.

Current built-in scoring uses public-native-local-v1 and local execution recipes.
These immutable pins preserve old evidence; they are not new-machine prerequisites.
"""

NATIVE_PINS = {
"alfworld": {
Expand Down
45 changes: 45 additions & 0 deletions data/scaffolds/public_native.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Bind public scorer source and dependency recipes, not a historical machine image."""
from __future__ import annotations

import hashlib
import json
from pathlib import Path, PurePosixPath

ROOT = Path(__file__).resolve().parents[2]
PROFILE = 'public-native-local-v1'
DATASETS = frozenset(('alfworld', 'bird_minidev', 'chessbench_puzzles', 'jericho', 'scienceworld'))


def identity(value):
return hashlib.sha256(json.dumps(value, sort_keys=True, separators=(',', ':')).encode()).hexdigest()


def bind(dataset: str, spec: dict) -> dict:
"""Keep original argv/metric/inputs; identify only the public Python scorer files."""
if dataset not in DATASETS:
raise ValueError('unsupported public native scorer')
sources = {}
for entry in spec.get('inputs', []):
name = entry.get('path', '')
if not name.endswith('.py'):
continue
path = PurePosixPath(name)
if path.is_absolute() or '..' in path.parts or str(path) != name:
raise ValueError('public scorer code path must be normalized and relative')
if 'from' in entry:
source = Path(entry['from']).resolve(strict=True)
if not source.is_relative_to(ROOT) or not source.is_file():
raise ValueError('public scorer code must come from the installed platform')
content = source.read_bytes()
value = {'source': source.relative_to(ROOT).as_posix()}
else:
content = entry['content'].encode('utf-8')
value = {'content': entry['content']}
value['sha256'] = hashlib.sha256(content).hexdigest()
if name in sources and sources[name] != value:
raise ValueError('conflicting public scorer code entries')
sources[name] = value
if not sources:
raise ValueError('public native scorer requires declared scoring code')
binding = {'dataset': dataset, 'profile': PROFILE, 'sources': sources}
return {**spec, 'native_runtime': {**binding, 'sha256': identity(binding)}}
41 changes: 15 additions & 26 deletions docs/dataset-runtime-interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,36 +239,25 @@ VERIFY[task_id] = {
都必须在声明目录或沙箱已有的系统运行目录内。缺失、不可见或无效的声明保持不可测。
解释器版本及依赖要求由适配器确定,通用平台不要求某个 Python 版本。

### 5.2 封存原生评分运行时的宿主兼容性
### 5.2 公开原生评分与本机依赖

Bird、Jericho、ALFWorld、ScienceWorld 和 ChessBench 的 `native_runtime` 清单固定
解释器、依赖、评分代码、沙箱映射及 launcher 的内容摘要。清单 `identity.kernel`
保留生成时记录的内核版本;准入要求 Linux 和匹配的机器架构,并检查实际能力,
不要求宿主内核版本字符串与构建时完全相同。
ALFWorld、Bird Mini-Dev、ChessBench puzzles、Jericho 和 ScienceWorld 默认使用
`public-native-local-v1`。评分算法和原生引擎的版本要求是公开的;新机器通过
`tools/prepare_dataset.py --dataset <name> --runtime execution` 准备自己的运行环境,
不需要恢复原机器的 Python、标准库、共享库、依赖或 launcher 的字节。
完整命令、指标和边界见[公开原生评分](public-native-scoring.md)。

每次准入先校验文件并封存到 memfd,确认写入、扩缩和继续加封均被锁定,然后使用
已封存的 launcher 和解释器运行独立探针。探针检查私有 user/mount/PID/network/IPC/UTS
命名空间、只读运行时及任务挂载、不可见的宿主临时文件、隔离 Python 和封存的子解释器启动。
能力缺失、探针失败或超时仍按不可测处理,不回退到宿主解释器或关闭隔离。
评分代码在可信目录中生成只读快照,隔离 Python 启动,依赖使用本机显式准备的环境。
回执记录公开代码身份、实际 Python/SQLite/依赖版本、当前运行时身份和宿主信息。
本机环境的文件清单用于检测本次运行中被更改的安装,不用于要求跨机器复制旧环境。
数据与评分规则的校验、错误与零分的区分、只读输入和 actor 隔离继续生效。
不同本机运行时可执行同一公开评分;复用旧分数仍要求对应测量身份一致。

宿主能力探针使用独立的 30 秒预算,覆盖完整封存运行时的沙箱挂载与探针执行,
为 ALFWorld 等较大运行时的并发准入预留启动时间。评分命令使用验证阶段自己的超时配置。
旧 schema 1/2 封存清单仅供显式历史复现使用,后文描述其归档格式,
不构成新评测的安装前提。ChessBench 交互协议仍由其控制器评分,
离线公开评分声明不会替代交互协议本身的语义。

评分回执的 `native_runtime.identity` 保留清单身份;新增 `native_runtime.host` 记录实际
system、machine、kernel、准入策略及通过的能力检查,逐次 verdict 归档保留这些字段。
内核与 launcher 的宿主加载环境仍属于平台可信边界;这些检查不声明所有内核行为等价。

评分缓存读取前使用同一套声明校验和运行时准入,并按每个选中的声明去重检查。
缓存键包含已验证的 native 回执(清单摘要、用户态身份及实际宿主兼容回执);路径定位改变而
内容身份不变可以复用,运行时或宿主回执改变则重新测量。缓存中的最后一个 verdict 和每次
trial 的 native 回执必须全部匹配;新测量若出现不匹配则保持不可测且不写入缓存。
旧缓存键、缺失或未验证的 native 回执均不能作为当前原生评分的结果使用。

上述 native 校验仅用于实际执行原生评分器的路径。ChessBench 交互模式由进程内控制器
评分,不使用 verifier 中为离线评分准备的 `native_runtime` 声明;交互缓存按协议区分,
复用前仍要求通过交互会话的沙箱、环境类型及可信输入校验。

### 5.3 可搬迁的原生运行时包
### 5.3 历史原生运行时包(显式复现)

五份受审查清单使用 schema 2。`files[*].source` 和 `launcher.source` 只引用
`blobs/<sha256>`,宿主读取位置由外部存储配置决定。包同时包含解释器、用户态依赖、
Expand Down
5 changes: 5 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ command when the native runtime has not been prepared. This is a warning because
the run can also build the runtime from cached wheels. If a published runtime
fails validation, the check exits with its specific error.

ALFWorld, BIRD Mini-Dev, ChessBench puzzles, Jericho and ScienceWorld use public
native scoring with locally prepared execution dependencies. They do not require
the original scorer-machine archive. See [public native scoring](public-native-scoring.md)
for the five recipes and preparation commands.

Data download and dependency preparation are separate operations. For a research
recipe using GSM8K, set an external data root and prepare its loading environment:

Expand Down
6 changes: 6 additions & 0 deletions docs/linux-runtime-remaining.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
Current default for the five Python/native host scorers is described in
[public native scoring](public-native-scoring.md). They use locally prepared public
dependencies, not original-machine archives. The archive recovery receipts and
blockers below preserve historical observations; they are not current new-machine
installation requirements.

# Linux runtime acceptance remaining work

The [2026-11-08 final-source Linux validation](linux-release-validation.md) records
Expand Down
Loading
Loading