# Judge's verdict: Prime Academy correctness and robustness audit

Read-only cross-judge, 2026-10-01. Every audit, rationale, script and log in `candidate-1/`,
`candidate-2/` and `candidate-3/` was read end to end. Facts the candidates dispute were checked
against the code and, where cheap, rerun. The one rerun is
`/tmp/arena-prime-audit/judge/j01_gate_seeds_and_plateau.py` (log `j01.log`): 16 seeds x 5,000
paths of `wallet_mc` at the deployed cell, one process, 26 seconds, plus the exact plateau rows.

## Scores

| criterion | candidate 1 | candidate 2 | candidate 3 |
|---|---|---|---|
| 1. Reproduced, not asserted | 4 | 5 | 5 |
| 2. Decision-relevant correctness | 5 | 4 | 5 |
| 3. Robustness with thresholds | 4 | 5 | 5 |
| 4. Coverage of the chain | 5 | 4 | 5 |
| 5. Honest severity and labels | 4 | 5 | 5 |
| 6. Actionable within constraints | 5 | 5 | 5 |
| total | 27 | 28 | 30 |

## Recommendation

Use candidate 3 as the base of the merged audit. Merge in candidate 1's F11 (the payout event
moves `acct_start` live), F8 (tooth parity), F9 (`day_split_mc` checks barriers once a day) and
its gap-fill note, and candidate 2's correlation threshold, aside-by-spread boundary table and
its exact statement of the pick's tie-break. Replace every gate level with the pooled figure
below.

Reasons, in order of weight:

- Candidate 3 has the two findings that would bite first if the runner were wired to the plan,
  and nobody else has them. The clip nets commission only, so under a live spread a clipped win
  lands short of +9% by the spread cost on full-sized lots and every later clipped win re-lands
  at the same shortfall (its F2, 0.0% pass in its lattice run). Lots floor to 0.01, so the
  nominal 1.575% realises 1.504% and the gate moves by about -0.008 (its F3).
- Candidate 3 verified the kernels independently: its own dynamic programme for both chains, a
  bar walker for the inputs, and a lattice copy of the clip rule. The others reused `prime.py`.
- Candidate 3 priced every rule reading on the exact chain (eight variants in `e20.log`) and
  gave both the log gate and the expected-value view, which is what the operator needs to see
  that "buy" is robust under one criterion and undecided under the other.
- Candidate 1 is the best on the live code (its F11 is the one genuinely live-only bug found)
  and on the inputs (Jensen cost, knob table, strict daily on two day boundaries), but it has
  three slips listed under false positives and it pooled a favourable seed subset.
- Candidate 2 is the cleanest on traceability and thresholds, and its correlation and aside
  boundaries are unique, but it declined the strict daily reading and missed the Jensen cost,
  the lot floor, the clip stall and the payout-event bug.

## Disputed facts, settled

### The gate's value across seeds

- All three candidates' seed values reproduce digit for digit (`j01.log`). Candidate 2's seeds
  1 to 8 read +0.0151, -0.0115, -0.0195, +0.0109, +0.0037, +0.0094, +0.0004, +0.0093. Candidate
  1's seeds 5 to 8 are the last four of those. Candidate 3's seeds 101 to 108 read +0.0057,
  +0.0050, +0.0145, -0.0024, -0.0039, +0.0039, +0.0165, +0.0092.
- Pooled over all 16 seeds (80,000 paths): +0.0041, SE 0.0024, t 1.69. Pooled with the published
  10,000-path run (+0.0132, SE 0.0058): +0.0055 +/- 0.0023.
- So candidate 1's +0.008 (four positive seeds plus the published run) is high, candidate 2's
  +0.002 (two negative outliers among eight) is low, and candidate 3's +0.006 is closest. The
  decision reading is the same in all three: under 2.5 SE from zero, not a settled result.
- The gate's zero in cost share follows the level. With +0.005 the root is near 3.40% (candidate
  1: 3.38%, candidate 3: 3.415%), a spread of 0.52 to 0.53 pip at the measured swap. Candidate 2's
  "exactly at the assumed 3.35%" is its own low seed draw, not the pooled picture. The merged
  audit should say the root sits 0.02 to 0.06 points of cost share above the assumed value, which
  is inside the uncertainty of the spread and of the Jensen correction (+0.09 points).

### The size of the strict daily-loss effect

- Candidates 1 and 3 agree at nominal 3% risk: candidate 1 measures 1.15% to 1.58% of losing
  trades breach (day at 00:00 or 21:00 UTC, 8 to 11 events of 695 stops), candidate 3 measures
  1.50% of stop-outs (35 events of 2,330 stops, 21:00 UTC). On the gate both read -0.03 to -0.04
  at that rate (candidate 1: -0.031 and -0.044 paired over 20,000 paths, candidate 3: -0.034 at
  q 0.015).
- Candidate 3 adds the lot-floored case: at the realised 2.90% the breach threshold moves from
  0.63 to 0.69 stop distances, the rate halves to 0.56% of stops, and the gate reads -0.002. The
  90th percentile of the boundary float is 0.62 of the stop, so the rate is steep in the
  threshold. Report both cases. The rate rests on 8 to 35 events either way.
- Candidate 1's extra result stands: under the strict reading 2.75% beats 3% on pass rate
  (43.7 to 44.0% against 42.6 to 43.1%), and 4% loses six points (`log_s06b.txt`).

### Whether the two stop-rule knobs give the same cell

- They do not, and the paper's sentence at `prime_academy.tex:1459` ("the two knobs give the same
  cell here") is wrong at the level that matters. Candidate 1's cohort: the beta knob
  max(0.924 sigma, 30) has c E[1/l] 2.662% against the floor knob max(0.75 sigma, 38.3) at
  2.522%, a 0.14-point gap, larger than the gate's margin. Candidate 3's walker: Jensen +6.0%
  against +0.9%, pace 2.35 against 2.44 days a trade, swap nights 0.995 against 1.085. Both say
  40 pips stays richest only through the floor knob. Candidate 2 did not examine it.
- The Jensen argument itself is right by construction: lots are risk over the stop, so a trade's
  round trip is r c / l_t and its mean is r c E[1/l], not r c / E[l]. Both measurements of the
  deployed rule agree (2.968% and 2.964% against 2.874%).

### How the funded pick is selected

- Candidate 2 is right about the mechanism. On the exact chain `med_first_pay` is 21, 17, 17 and
  then 14 for every plateau risk from 1.35% to 1.575% (`j01.log`, matching `c2_gate.out` [1]).
  The notebook's rule `min(plat, key=(med_first_pay, -e_W))` therefore selects by the `-e_W`
  tie-break, which rises with risk and picks the upper edge. The paper (`tex:1378`, `tex:1273`)
  names only "the fewest trades to the first payout".
- Candidate 1's conclusion is the same and its width table proves it (0.25 to 2 points gives
  1.45% to 1.675%, always the edge), but its sentence "that tie-break falls monotonically with
  risk" describes the wrong selector.

### The terminal valuation

- Candidates 1 and 3 agree, independently, that the log statistic values the open account and the
  last fee at zero at the horizon: mean final wallet about $1,130 against about $1,195 implied by
  the cash rate, about +0.05 in log if valued. This is the one correction that would open the gate
  with margin, and it belongs beside the Jensen and lot-floor corrections that close it. Candidate
  2 did not raise it.

## Findings I checked against the code and found correct

- `run_live.py:74` `FROZEN = dict(risk=0.04, ...)`, `build()` at 273 to 277 never calls
  `set_account`, `acceptance.py:53` pins $50,000 and 4%. All three.
- `broker_map.py:34` `PAY_WAIT = 14`, passed to `set_account` at line 63. The funded durations in
  the answer table come from a 14-trade clock. All three.
- `spread.py:75` and `:83` pass the same `seed` to every stream, so honour draws are shared across
  accounts. Candidates 1 and 3. Candidate 3 sized it (ruin +0.08 points, conservative).
- `prime.py:679-683`: a refused request zeroes the equity. Candidates 2 and 3 give the three
  readings (vanish about 0.00, stay +0.16 to +0.19, terminate -0.18) and the breakeven honours
  (80%, 60%, 89%). Candidate 1 gives the terminate reading only.
- `prime_academy_strategy.py:726-733`: `fee = cost_per_lot * lots`, the target cap rounds up one
  tick, and `broker_map.py:63` passes `2 * commission_per_side`. The stall of candidate 3's F2
  follows: the shortfall after a clipped win is the spread cost on the full lots, about $1.25 at
  0.25 lots and 0.5 pip, and the tick round-up recovers at most $0.25. The pass test at line 329
  has a 1e-9 tolerance. Candidate 3's lattice copy is faithful to those formulas.
- `prime_academy_strategy.py:344`: a PAY event sets `acct_start = broker.balance`. Live, a real
  withdrawal then drops the balance, and the strategy reads the equity as minus the payout.
  Candidate 1 alone, labelled inferred, correctly.
- `prime.py:360-366` `tooth_edges` uses `n = wait` for every j. After n trades the net-win count
  has the parity of n, so even j first occurs at wait + 1. Candidate 1's fine scan puts the chain's
  jump at 1.276 to 1.278% against the formula's 1.265% and the parity-corrected 1.276%.
- `prime.py:741-751` `day_split_mc` tests the floor, target and daily rule after the day's k
  trades, not after each. Candidate 1 alone.
- `_lots` at `prime_academy_strategy.py:555` floors to the lot grid. Candidate 3's realised risks
  (2.968% and 1.504%) follow.
- Paper text: `tex:29` "fixes the stop at one daily sigma, the risk at the daily-loss maximum",
  `tex:136` "runs from account opening or from the previous request", `tex:1548` "not
  implemented", `tex:1551` "never fires at one trade", `tex:1146` "fourteen-trade clock",
  `tex:477` "500 trading days", `tex:1459` "same cell". All as quoted.
- `rules.json` has no `allocation` or `news` entry (candidate 3's F11). `broker_map.json` has
  `declared: DISAGREES`, 39% of cells beyond 2 SE (candidate 2). `news_battery.json` counts 2,393
  events, USD 974, EUR 206 (candidate 2).
- The notebook's clock is `WT25 = max(PA.MIN_DAYS, int(round(PA.WAIT / pace[1.0])))` (candidate
  2's reading of why the 3-day minimum is inert).
- Constraints: every candidate script caps Monte Carlo at 5,000 paths. The prime worktree and the
  mdgraph are clean. The research checkout's modified files are in `regime_persistence`, another
  topic.

## False positives and slips, with evidence

- **Candidate 1, F6 mechanism.** "That tie-break falls monotonically with risk, so the pick is
  always the plateau's upper edge." The median first payout is flat at 14 trades from 1.35% to
  1.575% (`j01.log`). The `-e_W` tie-break picks the edge. The conclusion stands, the sentence
  does not.
- **Candidate 1, F11 clips.** "A clipped win lands short of +9% by about the half-spread, which
  forces one more small trade." It forces an unbounded sequence: the next clipped win lands at the
  same shortfall (candidate 3's `e19.log`, 0.0% pass). An under-call, not a wrong direction.
- **Candidate 1, citation.** "Paper line 237 says 'the plateau and the pick move much less'."
  Line 237 is blank. The sentence is at line 1273.
- **Candidate 1, F2 pooling.** "+0.008 +/- 0.0034" pools the four positive seeds 5 to 8 with the
  published run. Seeds 1 to 4 of the same generator (candidate 2) include -0.0115 and -0.0195.
  The honest pooled level is +0.004 to +0.0055 +/- 0.0023.
- **Candidate 2, F2 phrasing.** "Every flip threshold sits at the assumed input" and "crosses
  zero at 3.34% against the assumed 3.35%" hold at candidate 2's -0.001 level. At the pooled level
  the cost root is near 3.40% and the spread root 0.52 to 0.53 pip. The verdict "undecided" is
  unchanged.
- **Candidate 3, F9 row 4.** "trade once a day" against "pace 2.03 calendar days a trade" is not a
  contradiction. The plan enters at most once a day and holds about a day. Drop it.
- **Candidate 3, F3 table.** The row "funded risk chosen by p_any, not by the wallet's growth"
  sits among biases. It is a design choice the paper states (keep P(any) within a point of its
  best for the payout-rate limit). Candidate 3's text says so. Move it out of the bias stack.
- **Candidate 3, F2 severity.** HIGH is conditional: the runner never calls `set_account`, so the
  stall needs F1 fixed first and a caller that passes commission-only cost. Keep it, tag it
  conditional, and note that even a full-cost clip stalls when the true spread is 0.1 pip wider
  than assumed (`e19.log` case D), which is the robust part of the finding.

## Criterion notes

- **Criterion 1.** Candidate 1 loses a point for the line-237 citation and the F6 mechanism.
  Candidates 2 and 3 cite every number to a log that contains it.
- **Criterion 2.** Candidate 2 loses a point for coverage of decision-changing inputs it left to
  others (Jensen, lot floor, strict daily, clip stall), not for any false positive. Candidate 1's
  slips are wording, not false findings.
- **Criterion 3.** Candidate 1's table lacks a computed correlation threshold and the floor-on-tick
  row. Candidate 2's table is the most complete per decision. Candidate 3 covers every input and
  every rule reading but gives the correlation only a direction.
- **Criterion 4.** Candidate 2 did not go below `acct_on` in the strategy, so it missed the clip
  and payout-event issues. Candidates 1 and 3 read every stage.
- **Criterion 5.** Candidate 1's pooled SE understates between-seed spread and its F6 sentence is
  wrong. Candidates 2 and 3 label every claim and say plainly what checked out.
- **Criterion 6.** All three stayed inside the brief: no notebook run, no replay, 5,000 paths,
  read-only, no web.

## What the merged audit should carry as checked out

`decision.json` and `front.json` reproduce from the chains to four digits (all three). Both chains
match independent Monte Carlo and an independent dynamic programme (candidates 2 and 3). Clipped
legs land exactly in floating point (candidates 2 and 3). The 7-trade clock is applied the same
way in `funded_chain`, `wallet_mc` and the strategy, and the 14-day to 7-trade conversion is right
(mean 7.28, median 7, mixture changes P(any) by 0.0005; candidate 3). The 3-day minimum cannot
bind (first pass at trade 4). The 35% cap arithmetic is right (3.15%, 0.23 points of pass rate).
`hedge.shared_wallet` agrees with `wallet_mc` at one account (candidate 1).
