node tools/allocate.js (tests: tests/unit/allocate.test.js, and the lens test in tests/unit/field.test.js). A report for the tier work; nothing here reaches the site. BSData 374f505, corpus 570b8c6, the top-quarter field from tools/field.js (build/field/states.json, 630 units, 2,002 points). No panel was read; no tier test was run.
What was built
- tools/allocate.js. The kernel of design/matrix.md 7.2: each weapon group's share into each target, σ ∝ ρ × R × (v ÷ v*)^β; saturation scales every share into an overkilled target by R ÷ Δ and respreads the freed share over the group's open targets by the same weights, up to five passes, then the rest is lost and reported per group. At β = ∞ the spill goes to the best target still open (the finite rule's limit; without it a saturated best target loses all the rest). Reach (7.3): ranged groups reach the share of the enemy's 12" band inside their range, Rapid Fire and Melta get their half-range share, Lone Operative targets only within 12", melee needs the charge (2D6 against the gap), never into AIRCRAFT without FLY, Lance on the charge. The reference battle (7.4): two sides, five simultaneous rounds, guns scaled by their unit's share alive, wounds at points per wound. A field unit's groups: each ranged weapon (its ➤ profiles as alternatives, the best per target; pistols only for a unit with nothing else, as ev.js), one melee line per unit (each model's best weapon per target, Extra Attacks on top).
- The matrix interface:
{ unit, attacker, defender, cell(att, def, ctx) }.liveMatrixcalls tools/matrix.js's cell kernel;tableMatrixreads stored cells, as T-568 step 4's layers will. Nothing in tools/matrix.js was edited. - The game-plan sheet's pairing, ported read-only from docs/gameplan.js (
scoreand the jobs table: EV.unitVsUnit with the comparator's options, the better of shooting and fighting, share slain × points, first on a tie). docs/ is unchanged. - Lenses in tools/field.js (
lensField,lensesOf; written to states.json, the tracked copy and the field report).
The tests (all pass)
| Test | Result |
|---|---|
| β = ∞, one round, the sheet's numbers through the kernel and the battle: each unit's choice is the sheet's best target | 54 of 54 units, two sample pairings both ways (the four k = 4 medoid lists: Space Wolves against Astra Militarum, Drukhari against Necrons) |
| No target ever loses more than it has | 300 random turns × 6 β (0 to ∞), saturation forced; the field's five-round battle at β 6 |
| Conservation | each gun's shares plus its lost share sum to one (1e-9); Δ is exactly the fire received; total landed never above every gun at its best |
| Two guns, two targets by hand (β = 1) | first choices 2/7, 5/7 and 6/11, 5/11; target 1 (4 wounds) saturated: shares 22/107 and 42/107, spill 85/107 and 65/107; target 2 loses 810/107; one pass, nothing lost. A gun reaching only the saturated target loses 0.6; at β = ∞ the spill goes to the next best |
| Anti-tank into chaff while hulls remain | four lascannons against 9 × 20 Termagants, a Rhino and a Land Raider (reach off): 0.25% to 0.93% into chaff over five rounds at β 6 (β 3: 12% to 24%; β 0: 87%) |
| Interface: stored cells against the live kernel | identical wounds left and shares, three rounds, both pairings (1,000+ cells stored, read back from JSON) |
| β sweep at 3, 6, 12 | below; the chaff share falls as β rises |
The β sweep (the field's battle, reach on; agreement on the sample pairings, reach off)
| β | Game-plan agreement | (sheet on wounds at π) | Anti-tank fire into chaff, round 1 | over five rounds | Round 1 fire lost to saturation |
|---|---|---|---|---|---|
| 3 | 35/54 (65%) | 43/54 | 1.30% | 0.62% | 0% |
| 6 | 33/54 (61%) | 41/54 | 0.32% | 0.14% | 0% |
| 12 | 32/54 (59%) | 40/54 | 0.04% | 0.02% | 0% |
| ∞ | 32/54 (59%) | 40/54 | 0% | 0% | 75% |
Chaff is 4.8% of the field's points. Agreement is measured on the matrix's own volleys; the sheet counts whole models slain with cover and half range on and takes the better of shooting and fighting, the matrix counts wounds at points per wound (question 6) with neither and both halves together. On the matrix's convention (the sheet re-scored as wounds removed × points per wound) agreement rises to 74% to 80%; the rest is cover, half range and the summed halves. The battle destroys about 1,890 of 2,002 points in five rounds at β 6 (528, 666, 403, 202, 93): no terrain flatters shooting, as section 11 warned.
The lenses (3 Oct): the k = 4 split as compositions
v1 runs on one meta state, the whole top-quarter field: the clustering found one stable state, and the lists are a continuum (silhouettes 0.12 to 0.23), not separate kinds. The four states of the turned-down split are lenses by composition, not membership: each state's class shares re-weight the whole field (each class's units multiplied alike), so a lens holds the field's 2,002 points and exactly that mix. Names provisional; Jordan names them.
| Lens | Composition (points; field share, multiplier) | Anti-tank into chaff, round 1, β 6 |
|---|---|---|
| heavy infantry | heavy infantry 43% (19%, ×2.23), character 19% (16%, ×1.16), light vehicle 12% (14%, ×0.86), elite infantry 12% (13%, ×0.92), cavalry and beasts 8% (7%, ×1.11) | 0.24% |
| armour | heavy vehicle 45% (13%, ×3.37), elite infantry 14% (13%, ×1.03), light vehicle 12% (14%, ×0.82), character 11% (16%, ×0.67), heavy infantry 9% (19%, ×0.47), monster 6% (12%, ×0.54) | 0.06% |
| mixed | light vehicle 30% (14%, ×2.07), elite infantry 24% (13%, ×1.75), character 16% (16%, ×0.99), chaff 13% (5%, ×2.77), cavalry and beasts 6% (7%, ×0.87), monster 5% (12%, ×0.45) | 0.51% |
| monsters | monster 39% (12%, ×3.30), character 19% (16%, ×1.18), heavy infantry 15% (19%, ×0.76), cavalry and beasts 13% (7%, ×1.92) | 0.28% |
Timing
Pool and profiles 0.17 s; the field's volley tables 2.2 s (1,358 groups × 630 targets, 348,080 cells); one five-round battle both ways 0.75 s; the whole command 9 s.
Decided alone
- β = ∞'s spill goes to the best open target (the limit of 7.2's rule), not lost.
- The gap each round is a placeholder track (24" apart, each unit closes its Move a round) until layer one's delivery profiles are wired in at step 4; no Deep Strike, transports, Overwatch or mortal pseudo-weapons yet.
- A target's cells use its front group's profile; its wounds count every model (models the matrix's minimum groups don't count, as in Gaunt's Ghosts, join the front group).
- One Shot at the live fifth a turn; hazards not charged; a ranged group's reach uses its longest profile.
- Agreement compares each unit's first choice (before spill, round one, reach off, every gun firing) with the sheet's best.
Doubts
- Agreement with the sheet is 59% to 65%: two conventions differ by design (partial wounds, the halves summed), two by options (cover, half range). The sheet is a pairing yardstick, not truth.
- At this size a battle costs 0.75 s; step 4's per-unit F^−X battles (about 1,150 units) would take about 15 minutes a state unless the symmetric battle runs one side or groups are merged by attacker profile.
- The field kills 95% of itself in five rounds: without terrain or delivery the later rounds are thin.
For the supervisor
design/decisions.md entry (paste-ready):
3 Oct: the allocation rule and the reference battle (T-569 step 3); one meta state for v1, lenses by composition
- Built: tools/allocate.js: the soft best-target kernel (β, saturation and spill over five passes, then lost and reported), reach (12" band, half range, Lone Operative, the charge, AIRCRAFT), the reference battle (five simultaneous rounds, fluid targets); the matrix read through one interface, so T-568 step 4's stored layers drop in unchanged (tested). Lenses in tools/field.js.
- One meta state for v1. The top quarter holds one stable state; lists are a continuum (silhouettes 0.12 to 0.23). The k = 4 split becomes four lenses defined by composition, not membership: each state's class shares re-weight the whole top-quarter field (heavy infantry 43%; armour, heavy vehicles 45%; mixed, light vehicles 30% and chaff 13%; monsters 39%), a synthetic skew that is stable across refreshes and explainable in one line. Names provisional; Jordan names them.
- Numbers: β = ∞ reproduces the game-plan sheet's best targets 54/54 on its own numbers; the matrix's choices agree with the sheet 61% at β 6 (74% to 80% on the matrix's own damage convention); anti-tank fire into chaff 0.32% of round one at β 6 (1.30% at β 3, 0.04% at β 12). β stays 6, to be fitted.
- Proposed convention, for Jordan to confirm, applied from the next run: a meta state counts only if its mean per-state Jaccard over 5 seeds is at least 0.6 and the split's silhouette is at least 0.25 (below that no split is worth showing as a state).
- Next: step 4, X as a marginal entrant (H_t, the mirror, S_t, F^−X), with layer one's delivery in place of the placeholder track.
design/scoring.md changelog line (paste-ready):
3 Oct T-569 step 3, a report only, live scores unchanged: tools/allocate.js, the allocation kernel (σ ∝ ρ × R × (v ÷ v*)^β, β 6 swept at 3, 6 and 12; saturation scales a target's incoming fire to R ÷ Δ and respreads the freed share over each gun's open targets, five passes, then lost; β = ∞ spills to the best open target), reach (a 12" depth band, half-range shares for Rapid Fire and Melta, Lone Operative within 12", the charge as 2D6 against the gap, no melee into AIRCRAFT without FLY; a placeholder track of 24" closing by Move until delivery is wired) and the reference battle (five simultaneous rounds, fluid targets at points per wound). One meta state for v1; the k = 4 split as four lenses re-weighting the whole field to each state's class composition (tools/field.js lensField). Report: reports/tiers/2026-10-03-allocation.md.