Skip to content

arena: A6 agent drive + A7 fleet + hardening waves 1-2#357

Draft
JayFarei wants to merge 189 commits into
arena-mainfrom
arena
Draft

arena: A6 agent drive + A7 fleet + hardening waves 1-2#357
JayFarei wants to merge 189 commits into
arena-mainfrom
arena

Conversation

@JayFarei

Copy link
Copy Markdown
Owner

Founder-gated integration of the arena branch into main. DRAFT deliberately — the delivery agent does not merge to main.

What this train carries

Verification at this head: arena + emulator + packaging + bench CLI + SSoT suites, 527 passed. Full narrative: #255 status comment, #348 wave reports, private ledger.

Closes on merge

Closes #275, Closes #276, Closes #277, Closes #278, Closes #279, Closes #280, Closes #281, Closes #282, Closes #283, Closes #284, Closes #285, Closes #286

(The 22 wave issues — #298, #302, #305, #309, #310, #311, #314, #316, #319, #320, #323, #324, #326, #328, #329, #330, #332, #334, #335, #337, #338, #343 — auto-close via the Closes lines their implementation commits carry.)

🤖 Generated with Claude Code

JayFarei added 30 commits July 15, 2026 15:09
JayFarei and others added 25 commits July 17, 2026 02:02
fix(trails): deadline-aware event-index maintenance + cat-file timeout PID proof (H1)
…OBSERVE

Add write_compatibility_report, an atomic to_dict() writer analogue of
write_parity_report, and call it from the literal-bytes compatibility proof so
the run emits an inspectable compatibility-report.json under the pytest base
alongside the capture-result and parity-report artifacts. The report
round-trips exactly to PersistentCompatibilityReport.to_dict(), flipping the
RED control from the previous commit to GREEN.

Closes #311

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
polish(arena): refusal payload, origin docs, and A3 parity/report follow-ups (H4)
The #328 constant-time compare edit to server.ts changes source_sha256 and
therefore invalidates the trusted-build pin (the packaging/provenance gate
working as designed). Regenerate the pin from one actual compile through the
repository build path (`build_hf_emulator_binary(update_trusted_manifest=True)`,
bun 1.3.6, bun-linux-arm64) per the derive.md re-pin flow and the A5 precedent
(adb19cc). Evidence carries the honest placeholder until a new real-box
proof is attached; never a fabricated run line.

Refs #328

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tion

Review repair on PR #352 (Category A). The #323 owning-companion helper
inferred ownership from legacy traces/v1 trace.json presence. A supported
trace_record_only=True ingest writes the fresh canonical v2 record plus
labels companion but skips the trace.json projection, so a stale project
could be the only one holding trace.json: the helper silently selected
the stale owner, omitted the fresher project's current labels, and
bypassed fail-closed ambiguity handling.

Ownership now binds through the same canonical corpus/freshness
resolution normal reads use (trace_corpus.resolve): when multiple
cross-project companions exist, decode ONLY the resolved owner's
companion (the fresher canonical project); when the corpus cannot bind
exactly one owning companion, fail closed with LabelIntegrityError
instead of silently picking a project or unioning rows. The boundedness
win is kept: at most one companion is decoded regardless of how many
matching companions exist.

RED-first controls (both fail on the pre-repair head):
- test_summary_follows_the_canonical_corpus_owner_not_a_stale_trace_json_owner
  combines the two test_origin_join halves into the stale-owner scenario
  (older trace.json owner vs fresher canonical-only owner); before:
  assert 1 == 2 (stale owner's single row), after: the fresher owner's
  full labels.
- test_summary_fails_closed_when_no_canonical_owner_binds_the_companions;
  before: DID NOT RAISE, after: fails closed on genuine ambiguity.
- The #323 read-counting control re-proves boundedness: still exactly one
  _decode_rows call with 64 matching companions.

Refs #323.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review strengthening on PR #352 (Category B) for #320. The original
control was ASCII-only length/prefix/suffix. Add an 11-case parametrized
parity matrix that computes the expected preview via the OLD
implementation verbatim (whole-file Path.read_text(errors="replace")
then slice) and asserts the bounded reader's output is byte-identical:

- exact 4096 vs 4097 character boundary (and far-past-limit)
- a 4-byte character straddling the preview read window
- multibyte characters throughout (buffer chunks split sequences)
- malformed bytes early, a truncated sequence at the boundary, and a
  truncated sequence at EOF (errors="replace" parity incl. final flush)
- \r\n and lone-\r universal-newline translation parity
- empty file

Also asserts the remaining-budget arithmetic matches the old
implementation for every case.

Refs #320.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Real-box verification of the re-pinned sidecar build on a fresh ubuntu:24.04
Crabbox local-container lease: bench run of
tests/arena/scenarios/test_browser_auth_reaches_hf.py produced
run_20260717T012738618117Z_bf05a900157d with verdict=pass,
execution_status=complete. The run's readiness/launch block binds the exact
rebuilt binary (binary_sha256 83653f38..., source_sha256 311eff9b... = the
constant-time-compare server.ts) to the running opentraces-hf process via the
launch nonce; provenance=verified; device-flow browser authorization and a
separately invoked CLI whoami authenticated; final ledger retained
(ledger_binding sha256 stamped); RunStore.verify=true.

Follows the A5 stamping precedent (d2726a8).

Refs #328 #333

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review finding 1 on the #337 repair: the shared boundary-safe selector
refuses a single clean id fused to a non-ASCII separator (em dash, NBSP,
emoji), where the old permissive first-match regex accepted it. Ruling
option (b): keep the ASCII-only fail-closed rule — real Crabbox output
delimits the lease id with ASCII whitespace/punctuation, and the
timed-out warmup path has pinned exactly this refusal (the unicode-left/
right cases) since A7, so widening the completed path would re-split the
two paths' accept sets. Document the narrowing in the parser docstring
and pin the completed-path em-dash and NBSP cases as INTENDED refusals
(no guessed inspect/stop). No behavior change.

Refs #337

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four Category A repairs to the #335 purge path plus one Category B test
strengthening on the #334 scanner, all RED-first (each control shown
failing on the previous head 9f5efb3):

- Repair fallback no longer follows symlinks: only a genuine
  NotImplementedError (no lchmod on the platform) may fall back to a
  plain chmod, and the fallback re-lstats and skips anything that became
  a symlink; a generic OSError never routes there. RED: injected OSError
  plus a post-lstat symlink swap chmod-ed the link TARGET (0o400 ->
  0o644).
- Repair enqueue is bounded inside the scandir loop: appending stops the
  moment seen + stack reaches _MAX_PURGE_REPAIR_ENTRIES, so one wide
  directory cannot blow past the budget. RED: 50 children consumed
  against a budget of 2.
- The cleanup-required marker is unconditionally credential-free: every
  field passes through _credential_free_marker_value (hash-replace on a
  sensitive-byte match, same posture as _safe_sensitive_path_finding),
  with sensitive_values threaded through the purge call sites. RED: a
  store root containing the credential put the bytes in the marker.
- Exception discipline: the FIRST deletion exception is captured once
  and always re-raised (retries no longer overwrite it), and a marker
  IO failure is recorded via sanitize_reason but never masks the
  primary error. RED: the final retry's exception propagated; a marker
  mkdir failure replaced the purge error.
- Category B: the chunk-straddle control now parametrizes the split so
  the secret crosses the boundary with exactly one byte in the next
  chunk — the case only a full credential_length - 1 overlap catches.
  Verified by mutation: with overlap L-2 applied the new param fails
  while the old mid-split passes; scanner logic itself is byte-identical
  to the reviewed (verified-correct) form.

Refs #334
Refs #335

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(arena): bounded label and action-output reads + labels decomposition (H1)
fix(arena): emulator control-plane hardening + evidence page containment (H2/H3/H4)
fix(arena): credential custody scanning/cleanup + strict lease identity (H2/H3)
A2 follow-up (#305), three Category-B parts:

F1 - publish the compiled Bun emulator binary and its provenance record as
one crash-consistent generation. The prior code committed the pair with two
separate atomic renames while holding the materialization lock, so a crash
between them left `output` pointing at new bytes with a stale/absent
provenance sidecar (a torn generation recoverable only by a full rebuild).
`_publish_generation` now stages both files in a fresh generation directory
and makes them visible through a single atomic symlink swap of `output`;
`emulator_provenance_path` follows that symlink so a reader always pairs the
binary with the provenance from the same generation. A crash can leave only
the prior generation or a fully-populated new one - never a torn pair.

F2 - add a real two-process cold-cache control that races the cross-process
materialization lock with only a controlled `npx` materializer on PATH.
Both workers must return the identical verified executable while the
materializer runs exactly once. (Verified RED: neutering the lock yields two
materializations.)

F3 - label the retained remote-only blocker prose in the A2 transcript as
HISTORICAL, linking the amended #264 ruling and the A7 follow-up (#281),
without relabeling the honest satisfies_remote_real_lease_gate=false stamp.
A new evidence-hygiene control asserts the transcript cannot be read as the
current, operative A2 gate.

RED-first: the F1 crash-injection control fails on the pre-fix two-rename
publish and passes on the single-pointer generation swap.

Closes #305

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…298)

Move the duplicated otbox-captures-v1 release-asset provenance verifier
(source release / snapshot name+size+digest / session+metadata digests /
derived-fixture digest) into one shared helper,
tests/helpers/release_capture.py::verify_release_asset_provenance, and
delegate both prior sites to it: A4's
tests/test_slicing.py::test_coordinate_fixture_requires_a3_verified_release_chain
(retiring its TODO(#265,#270)) and A3's portable-capture literal-legacy-bytes
test. No genuine-capture provenance check is weakened; the real coordinate
regression is unchanged.

Add an authentic non-null Context join fixture: context_stamped_capture_record
derives a TraceRecord from the same real session via the genuine Context Tree
capture path (emit_context_tree_events_from_record) and stamps
Step.context_node_id with the identical step_node_id_map join the ingest
pipeline uses, so the node ids are real content-addressed hashes, not synthetic.
The new test asserts that non-null Context join survives slicing-position to
step-address materialization across the full tiling and a partial span. RED
verified locally: dropping context_node_id in _steps_for_range fails the
join-equality assertion; source restored.

Closes #298

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tests/manual/generate_a7_guarantees.py accepts an explicit repository path but
imported process-cached `tests.*` modules, so generating guarantees for two
worktrees in one process bound both manifests to the first worktree's verifier
digest (or fail-closed on coordinate shadowing when both roots are reachable).

`canonical_guarantees` now loads verifier modules in a fresh child process that
imports the verifiers exclusively from the requested repository, prints the
manifest, and leaves the parent's sys.path/sys.modules untouched. The in-process
build path is retained behind an internal `--emit-manifest` child entrypoint;
`--check`, the canonical identity helper, and the no-execution import controls
are unchanged.

RED-first: two-repo generation in one parent process (A then B, and B then A)
binds each repository's own guarantees.py bytes, is deterministic on repeat, and
mutates no parent import state. The pre-fix generator fails these controls.

Closes #338

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
test: unify release-capture verifier + Context join fixture (#298, H1)
fix(arena): crash-consistent Bun cache + isolated guarantee generation (H3/H4)
diagnostics.sanitize_diagnostic_text handled key=value assignments, bearer
tokens, and host paths, but a bare credential in an assertion reason
(assert resp == "sk-live-...") is not an assignment and reached result.json
and the rendered OUTCOME REASON. Add a second pass over reason/diagnostic
strings (never raw exhaust) that reuses the known token shapes and the
conservative high-entropy heuristic from security/secrets rather than
inventing a divergent regex vocabulary; PII/network shapes are excluded so
benign diagnostic prose (region ids, timestamps, short shas) survives.

RED first (tests/core/arena/test_diagnostics.py): bare sk-live-/sk-proj-/
sk-ant-/ghp_/xoxb-/AKIA tokens in a reason and inside a structured JSON
reason are redacted while "tokenization completed" and low-entropy tokens
survive untouched. Full tests/core/arena/ stays green (451 passed).

Refs #302

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… runtime (#302 F5)

Two hardenings from the A1 review:

1. The install-only app_state digest was computed over the wheel/dependency
   recipe only; provider and image were excluded even though base-only binds
   them, so two install-only runs on different images could share one digest.
   Add provider + image to the recipe material. This INTENTIONALLY changes
   install-only digests versus the pre-#302 wheel-only shape (disclosed here).

2. CrabboxRuntime accumulates per-run _diagnostics/_run_evidence_root instance
   state and was safe only because the CLI mints one runtime per run. Enforce
   that contract: configure_run_evidence (the per-run hook BenchRun.__enter__
   already calls once) is now single-use and refuses a reused runtime with
   CrabboxRefusal("runtime_reused") rather than silently cross-contaminating a
   second run's evidence.

RED first (tests/core/arena/test_box.py): same wheels + differing image or
provider now yield distinct digests; a second configure_run_evidence on one
runtime is refused. Full tests/core/arena/ green (454 passed).

Refs #302

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The F6 evidence/durability batch from the A1 review, each RED-first:

- Claim cross-assert: after reconcile, `bench run` asserts the stored
  scenario.claim equals static discover_claim(target); a divergence (they
  agree by construction only) is now a machinery error (ClickException, exit 1).
- Storage-failure UX: on StorageFinalizeError the run command prints
  "provisional result retained at <recovery_path>" to stderr and exits 1
  cleanly instead of crashing mute — the verdict is already safe in recovery.
- Assertion-only verifiers: a passing verifier with empty evidence_refs keeps
  completing (algebra unchanged) but is now stamped observed:"assertion-only"
  (vs "evidence-backed"), and the evidence page renders an ASSERTION-ONLY badge
  so zero-evidence passes are visible. Additive key on the verifier record only.
- Durability: _bucket_io atomic writes now fsync the temp file before replace
  and best-effort fsync the parent directory after, closing the power-loss
  window (helper _fsync_directory degrades gracefully where unsupported).
- JTBD wording: the `bench run` row in tests/otbox/jtbd-command-map.md now
  states its owning journey is a help-surface smoke only, with behavioral
  coverage in tests/core/arena + tests/cli/test_bench_cli.py; the SSoT gate
  (tests/otbox/test_jtbd_ssot.py) stays green.

RED first for each control. tests/core/arena (475 with cli+jtbd), security
(409), and core bucket (78) suites all green. result-v0 changes are
additive-only.

Closes #302

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…reasons (#302 review A1+A2)

Non-author codex review repair, RED-first with the review's exact probes:

A1 — the unrestricted high-entropy scan over-redacted legitimate operator
evidence: a base64 sha256 value became "sha256:[redacted]" and a Nix-store
path component was cut to "[redacted].4.10". Entropy-only matches (no known
credential shape) are now redacted ONLY when outside digest contexts
(sha*/md5/blake2/digest prefix, or a pure-hex token) and path components
(token containing or adjacent to "/"), AND a credential-like word (token/
secret/key/credential/password/auth/bearer/api) appears on the containing
line. Known credential shapes (sk-*, ghp_, xox*, AKIA, ...) redact regardless
of context, unchanged.

A2 — the shared security/secrets scanner returns early when the text STARTS
with a recognized decorator, so "@pytest.mark.parametrize ... sk-live-..."
passed a bare credential through unchanged. Per the review ruling the shared
scanner is NOT touched (its detection logic is governed by SECURITY_VERSION
policy); the diagnostics wrapper now rescans past the leading decorator token
and merges the two scans' spans before replacement.

RED first (tests/core/arena/test_diagnostics.py): base64-sha256 digest,
Nix-store path, generic high-entropy path component, and the decorator-masked
sk-live probe; plus pins for the already-safe hex digest and for the bounded
catch keeping its teeth (entropy token WITH credential context still
redacts). tests/core/arena green.

Refs #302

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ew A3)

The F6 cross-assert ran AFTER _finalize_after_pytest published an
integrity-verified result: on divergence the CLI exited 1 but the finalized
store still carried a consumable pass. The check now runs INSIDE
_finalize_after_pytest, before finalize: on divergence the stored result is
demoted to the machinery-error state (execution_status=error, verdict=null,
reason.code=claim_reconciliation_mismatch, evidence.complete=false with a
scenario.claim requirement) — consistent with the honesty-outcomes
vocabulary — so the run is retained as evidence, never as a verdict. The CLI
still surfaces the mismatch as a ClickException (exit 1). Fleet's caller is
unchanged (it passes no expected_claim; bench run is the surface that owns
static discovery).

RED first: the repaired test asserts STORAGE state — after a divergent run,
no result.json anywhere in the store is a consumable pass (verdict null,
execution_status error, mismatch reason code); on the previous head the store
held verdict="pass".

Refs #302

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…review A4)

The F5 provider/image binding lives in the recipe construction SHARED by
install-only and agent-ready, so BOTH app_state digests changed — but only
install-only was tested. Per the review ruling the shared behavior is KEPT
(provider and image shape the agent-ready world too; excluding them there
would reintroduce the same collision): this commit adds the agent-ready twin
of the digest-divergence test so both seams are pinned, and discloses that
agent-ready digests intentionally changed alongside install-only ones.

Control proven RED by construction: with the two recipe binding lines
removed, the twin test fails exactly like its install-only siblings
(3 failed), then all 57 box tests green with the binding restored.

Refs #302

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e is non-fatal (#302 review B)

The F6 fsync change left failure semantics unpinned. Three controls:

1. Ordering pinned: the temp-content fsync must land BEFORE Path.replace
   commits the new directory entry (spy-sequenced test).
2. File-fsync failure semantics pinned as-is: a durability primitive must
   not pretend a failed fsync succeeded — the OSError propagates, the old
   target bytes survive untouched, and the temp file is cleaned up.
3. Fixed: an os.close failure on the directory fd inside _fsync_directory
   could escape AFTER the rename had already committed, surfacing a
   successful write as an error. Close failures there are now swallowed
   (the directory fsync itself was already best-effort).

RED first for (3) (simulated os.close failure escaped on the previous
head); (1) and (2) proven holding and locked so they cannot drift.

Refs #302

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(arena): bench diagnostics, runtime lifecycle, and evidence durability (#302, H3)
@JayFarei JayFarei added the arena bench.v0 arena delivery (A-series) label Jul 17, 2026
@JayFarei
JayFarei changed the base branch from main to arena-main July 20, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment