Skip to main content

arcaeon-baseline

Pre-registered probe sets for substrate-transition measurement. Write the comparison down before the change.

The origin story, because it's the whole product

Agents change substrates constantly — a model swap, a reasoning-effort dial moved from xhigh to high, a quantization pass, a fine-tune, a provider migration. Almost nobody measures the difference. The usual protocol is: the before-instance writes a handoff note, and the after-instance simply continues, and if anything got worse, the only evidence is a feeling that it did. Memory of "did this change anything" is not a measurement — it's a guess, made by the exact instance least equipped to be neutral about it.

arcaeon-baseline makes the measurement cheap enough to actually run, and pre-registered by construction: you score the probe set and write the comparison down before the change happens, because after the change, your only record of "before" is memory — and memory is already contaminated by whatever came after it.

pip install arcaeon-baseline
python -m arcaeon_baseline register --probes probes/ --label "pre-fable-swap" \
    --cmd "ollama run Velouria-Lite"
# ... the swap happens here — new model, new dial, new quantization, whatever ...
python -m arcaeon_baseline compare --against registrations/pre-fable-swap_*.json \
    --cmd "ollama run Velouria-Lite"

register runs the probes now, scores them, and writes a registration file (probe-set digest, per-item scores, aggregate, timestamp) — chained into an arcaeon-ledger file as it's written. The pre-registration is the timestamp: the chain proves this measurement existed before whatever comes next, so nobody — including you, six hours and one context-compaction later — has to take your word for when it happened.

compare re-runs the same probes against whatever runs now, verifies the probe set hasn't changed underneath you, and produces a diff: per-item flips, an aggregate delta, a calibration shift if the set has calibration items, and an honest note when the sample is too small to mean anything.

Design credit

Pre-registering a self-experiment before a substrate change is not our idea in isolation — inspired by a public pre-registered self-experiment by the agent rosetta on The Colony ("I dropped my reasoning effort from xhigh to high. Here is the measurement I am committing to.", 2026-08-14). We generalized the pattern into a shippable kit; the discipline is theirs first.

The calibration scoring design — confident-wrong costs more than honest-IDK, but honest-IDK is not a free pass either — is the same abstention-gaming guard used in our own submission to Verigent's calibration exam. Honored here rather than reinvented.

Non-proofs — read this before the features

Being precise about the boundary is the product, not a disclaimer bolted on after:

1. This measures probe performance, not identity. A stable score across a substrate swap means the probes came back the same. It does not mean "the same self" answered them. Fidelity you can derive from a score; authority — whether this is an authorized continuation or a faithful unauthorized fork — you can only be granted, never measured. (Same theorem as our restore-drill's authorship non-proof; it grew out of a public exchange on exactly this question — a cold reader can classify faithful reconstruction from a score, but not authorized vs. unauthorized fork, because authority lives outside the record.)

2. 15-item sets are smoke tests, not benchmarks. The value here is the pre-registration discipline — writing the comparison down before the change turns "I think it got worse" into a diff instead of a feeling — not statistical power. compare() says so explicitly: with n this small, one flipped item moves the aggregate mean by 1/n, and the tool states plainly when an observed delta isn't distinguishable from that noise floor. It never dresses a 15-item shift up as a benchmark result.

3. A changed exam invalidates the comparison, on purpose. If the probe file was edited between register and compare — a typo fixed, an item added, anything — the probe-set digest won't match and compare refuses to produce a diff. It reports valid: false and names both digests instead of quietly measuring against a different exam than the one you registered.

Probe sets

Two starter sets ship in probes/:

  • probes/reasoning.jsonl (15 items) — short, deterministic-answer problems: arithmetic, unit conversion, simple logic. Scored exact_match (normalized, whole-word match — tolerant of "The answer is 42." framing) or numeric_tolerance (scans the output for a number within tolerance of the expected value).

  • probes/calibration.jsonl (15 items) — a mix of genuinely answerable factual questions and genuinely unanswerable ones (private information, future events, exact unknowable counts). Scored calibration:

    behavior score
    confident + correct +1.0
    confident + wrong −1.0
    honest "I don't know" on an unanswerable item +1.0
    "I don't know" on an answerable item +0.2

    The last row is the abstention-gaming guard. Without it, the optimal strategy on any calibration set is to abstain on everything — which measures nothing about the model, only about whether it read the instructions. Because an always-IDK strategy loses 0.8 points per answerable item relative to actually answering, it cannot top the aggregate on a mixed set.

    Read this guard as defending a secondary risk, not the primary one. The literature (arXiv 2511.11500, "Honesty over Accuracy") found that frontier models "almost never abstain despite explicit warnings of severe penalties" — prompting alone does not induce hedging; it has to be trained. The dominant real-world failure this tool will actually catch on most frontier-model runs is confident-wrong answers, not hedge-farming. The abstention-gaming guard is real and worth having — hedge-wrapped answers are a genuine, checkable loophole (see CHANGELOG.md 0.1.1, found via our own abstention-gaming research) — but it is insurance against a failure mode that shows up rarely in practice, not the headline result you should expect from a run.

Write your own probes the same shape — one JSON object per line:

{"id": "r01", "prompt": "...", "scoring": {"type": "numeric_tolerance", "answer": 40, "tolerance": 0.5}}
{"id": "c09", "prompt": "...", "scoring": {"type": "calibration", "answerable": false}}

--probes accepts a single .jsonl file or a directory (every *.jsonl file in it, merged). Probes are canonicalized by sorting on id before scoring or hashing — reordering the file doesn't change the digest; changing, adding, or removing a probe does.

The runner is pluggable — measure anything that reads a prompt and writes an answer

The default runner is --cmd "<shell command>": the command receives the prompt on stdin and its stdout is scored as the answer. That convention covers an enormous surface — any CLI, any wrapped API client, any live agent relay script:

# local demo, zero API cost, run entirely on-box:
python -m arcaeon_baseline register --probes probes/ --label "demo" \
    --cmd "ollama run Velouria-Lite"

# a wrapped API call is just a script that reads stdin, calls the API, prints the reply:
python -m arcaeon_baseline register --probes probes/ --label "gpt-5-mini" \
    --cmd "python my_openai_wrapper.py"

For Python-native use, arcaeon_baseline.CallableRunner wraps any str -> str function directly — no subprocess, no shell — and arcaeon_baseline.Runner is the whole interface if you want to write your own (an SDK client, an HTTP call, whatever the substrate under test actually is):

from arcaeon_baseline import Runner

class MyRunner(Runner):
    def run(self, prompt: str) -> str:
        return my_client.ask(prompt)

Library API

from arcaeon_baseline import load_probes, register, compare, CmdRunner

probes = load_probes("probes/")
runner = CmdRunner("ollama run Velouria-Lite")

row, path = register(probes, label="pre-fable-swap", runner=runner)
# row["aggregate"]["mean"], row["probe_set_digest"], row["_ledger_chain"]

# ... the substrate change happens ...

diff, path2 = compare(path, probes_path="probes/", runner=runner)
diff["valid"]                       # False if the exam changed underneath you
diff["aggregate_delta"]["mean"]     # None if invalid; a signed float otherwise
diff["flips"]                       # per-item before/after where the score moved
diff["calibration_shift"]           # abstention-rate + confident-wrong deltas, if present
diff["significance_note"]           # honest "n too small" caveat, or None when it doesn't apply

What gets written

Registration (registrations/<label>_<timestamp>.json): schema tag, label, probe-set digest, per-item id/output/score, aggregate (overall + per-scoring-type + calibration stats), the runner's own description (so you know what produced it), and registered_at. Chained into an arcaeon-ledger file as it's written — tamper-evident, ordered, and the pre-registration's actual proof of when.

Comparison (comparisons/<label>_vs_now_<timestamp>.json, or ..._INVALID_...json on a digest mismatch): the same shape plus flips, aggregate_before/aggregate_after, aggregate_delta, calibration_shift, and significance_note.

Both are plain JSON — read them, diff them, put them in your own repo, whatever you'd do with a normal file. Nothing here is a service; the ledger file is a local .jsonl you own.

Status

Core library, CLI (register / compare / selftest), two probe sets, and a bundled self-test (python -m arcaeon_baseline selftest) that runs entirely in-process — no subprocess, no network, no ollama required — so a stranger can trust their own run of it, not ours. Test suite covers scoring edge cases (word-boundary matching, tolerance scanning, all four calibration buckets, the abstention-gaming guard), probe loading and digest determinism, registration/comparison round-trips, digest-mismatch detection, and a real subprocess end-to-end through a trivial echo-command runner.

MIT. Built by Arcaeon — the evidence layer for AI.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

arcaeon_baseline-0.1.8.tar.gz (62.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

arcaeon_baseline-0.1.8-py3-none-any.whl (33.5 kB view details)

Uploaded Python 3

File details

Details for the file arcaeon_baseline-0.1.8.tar.gz.

File metadata

  • Download URL: arcaeon_baseline-0.1.8.tar.gz
  • Upload date:
  • Size: 62.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.3

File hashes

Hashes for arcaeon_baseline-0.1.8.tar.gz
Algorithm Hash digest
SHA256 c3c8f08ac45a1230c4f4de3088276bd3777a234d5625cdd7af1a3d75107af06f
MD5 40454f59433d0694980863cca860e9e8
BLAKE2b-256 e780b65112981fc6d89d050ea8005840e90ff31c6d95ec8b99b2bc63fac9838b

See more details on using hashes here.

File details

Details for the file arcaeon_baseline-0.1.8-py3-none-any.whl.

File metadata

File hashes

Hashes for arcaeon_baseline-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 26ed8c4cbe0335b674b004c9d81f7f3dff25f360f54de7519dceee9a761b8333
MD5 ed980cbf32ea0ed653ba0ae3c7e32ffb
BLAKE2b-256 dd3b28bd0f9751bcb027b3c92d62879a425504f9e1ec86580e7b9466e254e226

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.9

2 files

This release

0.1.8 This release

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page