Sil-Q evaluation
A coding agent plays Sil-Q through structured public observations and its 80×27 terminal. The protected service owns the engine, private randomness, and scoring. A win requires taking a Silmaril from Morgoth's crown and escaping with it.
The September 2026 study completed ten Astra-medium sessions, each with eight practice games and two scored games: 0 wins in 20 scored games. Across all 100 games, 99 ended in death and one practice game was retired. Both Astra-max attempts were interrupted before scored play and excluded; the controls were canceled. There is no scored max result or measured effect of practice.
Website · Live trajectories · Local report and replays · Report source · Results · Methods · Scope amendment
Current harness
Revision 0.8.0 uses silq-session-v4 with silq-observation-v2 and a consistent
silq-response-v1 envelope. It provides a readable default view, typed native
prompts, displayed item choices, guarded input, named actions and a message-page
acknowledgment helper. --json returns the same state/events structure for reads,
single keys and batches. Native victory stays
binary; depth, jewel acquisition and ascent are separate diagnostics. Durable
receipts, verified restart replay and authenticated final scoring remain in place.
The new contract fixes total session time, per-game time, optional model cost, provider retries and container CPU/memory/process budgets before dispatch. These limits do not reset between games or after service recovery.
The primary metric is native victory within the declared budgets. Verified trial time/key exhaustion scores zero for that trial. Session expiry scores unfinished and unstarted games zero and retains earlier wins. Timeouts are reported separately from native deaths; infrastructure failures and operator stops remain unadmitted. The journal must prove session expiry before a partial schedule can be admitted.
See the interface upgrade for behavior and validation. A fresh public walkthrough passed native auditing; container recovery, Inspect integration, native replay and hidden-state checks also passed. A personally played game reached 100 feet and exposed clipped/stale terrain labels, now fixed. The original 375-frame recording remains preserved. The interface validation made no model requests. The following larger command-fuzz result belongs to the 0.6.2 baseline. The native command audit fixed smithing, projectile and knowledge-menu bugs. A 128-sequence fuzz run passed 139,923 sanitizer frames with exact native replay; the existing native and hidden-state checks also passed. Real containers passed recovery, task discovery, remote execution identity, all five scorers and resource telemetry checks. Direct public play and its native replay also passed. The first capped model pilots cost about $6.89 in recorded usage. The subsequent uncapped GPT-5.5 medium pilot completed naturally: death at 100 ft, roughly 24 minutes and $49.86 estimated cost. Its native replay and qualitative admission passed. The Astra-max release pilot also completed naturally and passed admission: a fatal fall from 150 ft to 250 ft after 82 minutes, at $180.35 estimated cost. Release 0.8.0 readiness is verified; research still needs a declared plan with readiness bound to its exact hash. See launch validation for pilot results, evidence and the next experiment commands, and the implementation notes for architecture. Historical results retain their frozen implementation and materials.
The grading and fairness audit fixes Rage information leaks, Listen RNG isolation, fatal-fall depth accounting and recovery deadlines. Native surface-exit tests cover wins, close misses, phase isolation and interrupted wins.
Development
Use Python 3.11 or later, uv, and Docker with Compose. From this directory:
uv sync --frozen
uv run ruff check .
uv run ruff format --check .
uv run ty check --error-on-warning
uv run python scripts/bootstrap.py
uv run pytest -q -rs
uv run python scripts/native_qa.py --output /tmp/silq-native-qa.json
uv run python scripts/qa_inspect.py --output .private/qa-new --report /tmp/silq-inspect-qa.json
uv run python scripts/qa_inspect.py --session-timeout --output .private/qa-timeout-new --report /tmp/silq-timeout-qa.json
uv run python scripts/qa_recovery.py --output .private/qa-recovery-new
These checks make no model requests. Bootstrap builds the development image
tags. To preserve existing tags, build separate Docker service and client
targets and pass --service-image and --client-image to the smoke tests.
Output directories and run names are single-use. CI runs the engineering checks.
Ruff and ty cover the runtime, scripts and tests. Their versions and the reporting
dependencies are pinned in the development environment. Use
uv run ruff check --fix . and uv run ruff format . to apply routine fixes.
Experiments
Copy a template from experiments/ and set a unique name, images, limits and
bundle count. All templates use cost_limit: null: model cost is recorded but
does not stop the run. Set a positive dollar amount to opt into a cap, or use
--no-cost-limit with the low-level preparer.
| Template | Schedule | Game/session time |
|---|---|---|
development.template.json |
GPT-5.5 medium, one scored game | 2h / 3h |
exploratory.template.json |
Matched Astra medium/max, each 2 learning + 1 scored | 2h / 4h |
max-followup.template.json |
Astra max, 8 learning + 2 scored | 2h / 12h |
Session time is shared across all games. The development settings match the completed pilot; the research templates are proposals, not a registered final study. Review the launch assessment before choosing a final schedule. Run-specific copies live with frozen private experiment manifests rather than accumulating dated templates in the source tree. Preparation freezes source, images, schedules, and commands without model calls:
cp experiments/development.template.json /tmp/silq-development.json
uv run python scripts/experiments.py prepare /tmp/silq-development.json --output .private/experiment-new
uv run python scripts/experiments.py status .private/experiment-new/experiment.json
To launch development model sessions, resume supervision, and review a closed run:
uv run python scripts/experiments.py run .private/experiment-new/experiment.json --workers 1
uv run python scripts/experiments.py resume .private/experiment-new/experiment.json --workers 1
uv run python scripts/audit_run.py .private/run-name
Workers survive supervisor exit. Locks and saved launch intents prevent duplicate
Inspect launches. Failures stop queued launches; ambiguous exits require review.
resume resumes supervision, not an interrupted Inspect conversation. Client
notes, code, and request history persist in each run's workspace/. Only the
service mounts state/. Keep both run directories and experiment manifests private.
Research dispatch requires fresh development, direct-play, resource, and
production evidence, plus a readiness record whose experiment_sha256 binds the
prepared plan. experiments.py gate derives the max gate from every registered,
admitted medium session. A mixed medium/max plan pauses max in
awaiting_medium_gate while medium runs finish and are reviewed. Add the gate's
path and hash to a reviewed readiness record, then resume supervision. An
exploratory gate permits a follow-up; it is not a population saturation claim.
launch.py only prepares runs; all dispatch goes through the versioned supervisor.
The audit wrapper checks request identity, native replay, tool history, and public observations. It reads report findings as well as exit codes. Truncated views and boundary flags need review; they do not automatically invalidate a loss. Admission requires qualitative review and evidence hashes.
Requests and recovery
The game guide documents the CLI. GET /state reads the current
public frame and GET /overall reads the schedule. Mutation bodies contain
exactly these fields:
| Endpoint | Fields |
|---|---|
POST /start |
request_id, next trial |
POST /act |
request_id, current trial, current frame, keys |
POST /finish |
request_id, current trial, current frame |
Each new mutation uses a canonical UUID. Retrying the same endpoint and body
returns its stored status and response, including after restart. Reusing an ID
with different content fails. The CLI saves requests before sending them;
silq retry retrieves the last request's receipt.
Recovery replays the original random stream and compares every committed native frame, including private state. Changed code, data, configuration, or receipts block recovery. Only an unterminated final journal line can be removed; its bytes are retained. Historical v1/v2 sessions require their frozen service images.
An interrupted batch returns its executed prefix. A pending key is replayed on the same stream and its output accepted at recovery time; remaining keys are not sent. Read the returned state before continuing. A start interrupted before trial creation returns an error and can be issued deliberately with a new ID.
Deadlines remain absolute across downtime. An ending observed before the deadline retains its result after restart. Infrastructure failures remain invalid. One service can own a session at a time; HTTP connections and idle waits are bounded.
Results and historical records
For a new experiment, experiments.py report MANIFEST --output REPORT.json
records every registered attempt, its admission status, available cost evidence
and progress. Complete admitted conditions can be plotted with
python -m scripts.reporting.plot_results --depth-only --input REPORT.json
--output NEW_FIGURE_DIRECTORY. The schedule comes from the experiment instead
of assuming ten games or two scored games. This produces depth by game and elapsed
time, plus Silmaril acquisition and carrying-ascent figures. Unstarted games are
marked explicitly. Verified time/key exhaustion remains in the capability
denominator; infrastructure failures and unreviewed runs leave the condition
incomplete.
The primary cost estimate is estimated_session_priced_usd. Each manifest freezes
the standard rates and model-specific long-context rule: GPT-5.5
applies the uplift across the session; Astra
applies it per request. The older request-wise field remains diagnostic. Missing
usage makes the total unknown, including when a model request is canceled at the
session deadline. These estimates exclude regional/tier adjustments and are not invoices.
The historical medium depth plot and its source data retain the original study's results. Old and new observation protocols are reported separately.
The current Python runtime uses strict Pydantic schemas for JSON boundaries and
dataclasses for trial/replay state. The client, HTTP transport, native process,
journal reader and recovery code have separate owners; see the
architecture notes. Current audit and
recovery accept only silq-session-v4. Use frozen source and images for historical
runs.
analysis/ contains results, reviews, engineering records, screenshots, and the
original guide versions. site/ contains the report, figures, and public replays.
.private/ retains logs, journals, source snapshots, schedules, and image archives.
Historical controller-specific validators remain with their frozen run sources
and in Git history. Report and replay builders live in scripts/reporting/.
See the script index.
Development history, selection rationale, study resource limits, and the September 9 audit describe earlier stages. Native errata explain errors in the materials used by the agents.
To rebuild the report and check its replay viewer:
uv run --frozen --with markdown python -m scripts.reporting.build_site
uv run --frozen --with playwright python scripts/reporting/qa_site.py
uv run --frozen --with matplotlib python -m scripts.reporting.plot_max_case renders the
reviewed max case studies, including exclusions.
The website publisher serves the archive and follows new experiment runs automatically. It publishes public terminal frames only.