approaches/fair-expectimax/fair-policy/README.mdxMDX198 lines · 10.6 KB
---
title: The fair leaf evaluator
family: fair-expectimax
summary: The hand-written board evaluator every search in this family uses at the bottom of its look-ahead, and the tuning bench its coefficients came from.
status: completed
evidence: ledger-recorded
reads: public
kind: strategy
technique: heuristic-evaluation
featured: true
---

## The problem

A search that looks four moves ahead still has to guess what happens after the
fourth move. If that guess is "how many points did I score", the policy cashes
in every chain the moment it can and leaves itself an empty board with nothing
prepared; the [chance-and-choice walkthrough](/learn/concepts/chance-vs-choice)
shows that losing to a quieter move on a real position.

Whatever number the search puts on the boards at the bottom of its tree is the
number the whole decision rests on. Every search on the neighbouring pages
shares one such number. This page is about where it comes from and what is
known about it.

## Proposed solution

Write the evaluator in terms of what the board can still do. The heaviest
positive term is direct build readiness, structures that will fire soon,
weighted 1,600. Latent chain potential, structure one step further away, is
weighted 700. Cover access rewards buried gray discs that can still be
reached, since revealing them is how the board keeps producing usable numbers.
Against those stand penalties for height, for covered discs sitting high up,
for low numbers clogging the board, for danger with a rise imminent, and for
other public risks (the weights are in the ledger's
[historical fair-only horizon evaluator section](/docs/research/history)).

One deliberate choice stands out in the recovery notes. The roughness penalty,
a tidiness term that discourages uneven column heights, was set to zero. The
evaluator is allowed to build spiky, awkward-looking boards, because that is
what a board holding a loaded chain looks like. The ledger describes the
resulting behaviour as "knife-edge chain-building": able to enter a
self-sustaining clear-and-reveal regime, and high variance.

The evaluator reads only the visible board, the visible next disc, and the
drops remaining before the next rise. The tuning bench around it has an
optional mode that imitates a perfect-information
[oracle](/learn/concepts/oracles-and-teachers), a planner allowed to read the
hidden gray-disc numbers; that mode produces training labels only, its output
carries the banner "oracle teacher (UNFAIR, training only)", and no run
through it is recorded anywhere.

<GameTreeFigure seed={0x5eed1004} moves={12} caption="The evaluator at work: every outcome board at the bottom of the tree gets one number from it, and the search averages those numbers over chance and takes the best column. The browser solver uses the TypeScript combined leaf, a playground analogue of the frozen fair leaf." />

## How it works

1. Read the visible position: the board, the visible next disc, and the drops
   remaining before the next rise. Nothing in the feature set can see a
   hidden value, the seed, the score, or the move number.
2. Extract the features: readiness, latent potential, cover access and
   altitude, height load, low-number congestion, and rise danger.
3. Multiply each feature by its frozen weight and add. The sum is the board's
   leaf value; a modelled game over is a flat −1,000,000 instead.
4. Hand that one number to the search. The evaluator chooses nothing; the
   searches on the neighbouring pages consume its values and pick the column.
5. The tuning bench can also play, as a one-move sampled policy, so a
   coefficient vector can be scored by complete games. Its planner samples are
   a pure function of the observable position and a fixed policy seed, so
   neither training nor play can peek at the game's future randomness. A
   separate sweep tool tests coefficient values the caller names up front,
   every candidate on the same game seeds, so each comparison is paired.

## What happened

The [experiment index](/docs/research/experiment-index) records these runs as
completed, ledger-recorded: "these runs produced the fair reference weights."
Nothing more about the fitting is retained. The ledger records the recovery of
the resulting weight vector into the native depth-3 evaluator and the gameplay
results of the searches that used it; it keeps no result record for the tuning
runs themselves, no cohort, no objective value, and no before-and-after
comparison. How strong the weights are is answered by the reference search's
numbers on the [reference page](/approach/fair-expectimax/reference).

The one direct piece of evidence about the leaf's own behaviour is a two-game
pilot on two already-used training seeds. The games ran 155 and 160 moves and
cleared and revealed discs at rates the task record associates with long games
([ledger](/docs/research/history), historical fair-only horizon evaluator
section; the counts are in the results table below). The ledger's own verdict
is that two non-independent training seeds show that the mechanism exists and
say nothing reliable about a mean.

## What we learned

The durable lesson is the shape of the evaluator. It rewards what the board
can still do, what can still fire and what can still be revealed, ahead of
points already banked, and one conventional tidiness term had to be switched
off before the policy would build anything at all.

The provenance of the frozen coefficients is thin. They are recorded as the
output of these runs, but the runs' own protocol and cohort never reached the
ledger, so anyone re-deriving them faces a fresh fitting problem. They have
also never been refitted under corrected scoring or at the depth they are
used at, and every later attempt to adjust them
([machine tuning](/approach/fair-expectimax/cem),
[transition rewards](/approach/fair-expectimax/transition-rewards),
[vertical-ladder energy](/approach/fair-expectimax/vertical-ladder)) failed
on fresh games. That says the vector is hard to improve by small adjustments.
It says nothing about how far it sits from the best possible leaf.

The open question is whether a refit under corrected scoring, at depth 4, on
fresh whole-origin data, would keep these coefficients or replace them.

<AgentContext summary="Records and provenance">

- Status: completed; ledger-recorded, in the
  [experiment index](/docs/research/experiment-index) row "Fair policy
  tuning: tune.ts, weight-sweep.ts", verdict "these runs produced the fair
  reference weights."
- Where the weights are pinned. The native depth-3 evaluator
  (`approaches/fair-expectimax/reference/fair-only-horizon.cpp`) recovers the
  fair-only leaf from `tune.ts` together with five frozen overrides exported
  as `FAIR_PHASE_BASELINE_WEIGHTS` from
  [`phase-fair-combination/main.ts`](/approach/fair-expectimax/phase-fair-combination):
  direct potential 1,600, latent chain potential 700, height load −20,
  roughness 0, revealed-cover value 300. The 300-point revealed-cover term is
  a transition feature and is inert when the model is used only as a leaf.
  The standalone native policy is full-width iterative depth 3 with five
  stratified chance samples, a one-million-work limit, a 40,000-entry LRU
  cache, and the same observable-state policy seed and −1,000,000 terminal
  utility as the TypeScript experiment.
- Recovery verification: three deterministic TypeScript fixtures, identical
  best actions, root expected scores, node/work/cache counts and completed
  depth, with maximum leaf and root-value errors of `3.64e-12` and
  `1.82e-12`. Reflection and public-state metadata checks pass; optimised
  `-Werror` and ASan/UBSan builds pass the self-tests.
- Seed roles declared in the source: training `0x1d70_0000`, validation
  `0x7d70_0000`, reserved final `0xd700_0000`. Defaults: 10 generations,
  population 24, six elites, 16 training games, 64 validation games, three
  policy samples, 500-move cap.
- The oracle mode. `tune.ts` imports `planOracleMove` from
  `approaches/oracle-curriculum/perfect-information-oracle/`, runs only on
  training seeds, prints the banner "oracle teacher (UNFAIR, training only)",
  and executes only the seed-blind student's move during roll-outs. Any
  distillation run through this path is a teacher/diagnostic result and never
  a policy result. No such run is recorded in the ledger.
- Files: `tune.ts` is the fair-policy laboratory for a one-move sampled
  policy; the environment seed is deliberately absent from the move chooser.
  `weight-sweep.ts` runs fast paired coordinate ablations; the caller chooses
  the tested values up front and every candidate plays the same seeds. It is
  deliberately not a tuner.

</AgentContext>

<AgentContext summary="Full results table">

The two-game pilot, from the ledger's "Historical fair-only horizon
evaluator" section. Both games are on already-used, non-independent training
seeds.

| Pilot game | Moves | Numbered discs cleared | Covers revealed | Clears per move | Reveals per move | Longest chain |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| first training seed | 155 | 331 | 186 | 2.14 | 1.20 | 7 |
| second training seed | 160 | 351 | 201 | 2.19 | 1.26 | 9 |

The ledger adds that adding any tested phase residual broke the two historical
trajectories, reducing them to 55–110 moves.

</AgentContext>

<AgentContext summary="Validity, gates and limitations">

- No ledger section, result record or artifact exists for the tuning runs
  themselves: no cohort, no objective value, no before-and-after comparison
  for the fitting process. The frozen coefficients are recorded only as the
  output of these runs.
- The pilot used two non-independent training seeds. The ledger's verdict:
  "Because the pilot used only two non-independent training seeds, it was
  evidence for a mechanism, not a reliable performance mean."
- The oracle mode of `tune.ts` reads hidden gray-disc numbers; anything
  produced with it is a teacher or diagnostic label, never a deployable
  policy. The evaluator itself reads only the visible board, the visible next
  disc, and the drops remaining before the next rise.
- The coefficients have never been refitted under corrected scoring or at
  depth 4; the later adjustment attempts linked above each failed on fresh
  games.

</AgentContext>

<AgentContext summary="Scoring mode">

The pilot figures on this page are move, clear and reveal counts, so no score
enters them. The ledger keeps the pilot in its historical fair-only section,
whose later eight-game screen and sixteen-game confirmation are historical
7,000-point scoring, archival; none of those scores appears on this page. The
recovered evaluator is the leaf of the reference search, which is measured
under corrected 17,000-point Hardcore scoring on the reference page.

</AgentContext>