# Ribbon Garden: training and evaluation

Wisp uses a fitted **`pytoolz.wsrf.WSRFRegressor`** to rank legal directions. This is supervised action-value learning from a visible route-and-escape score and simulated continuations. It does not retrain in the browser. Grid rules, flood fills, collisions, seed placement, and ribbon growth are explicit game code.

## A model with a little memory

The first prototype sometimes circled without reaching the next pod. The released model receives two additional inputs: visits to the candidate square since the last pod, and steps since the last pod. These are ordinary recorded history, not a separate learned memory system. They reset when a pod is collected. The fitted forest learns how those inputs affect a direction's value.

Inputs, in order: `collecting a pod, reachable space, next exits, tail route open, path to pod, pod distance after, pod distance before, ribbon length, growth pending, pods gathered, pods remaining, distance from edge, horizontal move, vertical move, pod priority, space priority, extra growth, visits since last pod, steps since last pod`. Route space and distances use the visible grid after a candidate move. No collision action is offered to the model. The tail's old square is legal when it will vacate this move; pending growth keeps it occupied. Longer-ribbon mode adds a pending segment after a pod. Seven pods wins; a trapped head, unreachable replacement pod, or 180 turns ends the attempt.

## Target and training procedure

The reference score rewards a pod, an open route to the tail, nearby exits and reachable space. It penalizes distance, insufficient room, a dead end, and repeated visits to a square. Focus inputs change the pod, route, and visit weights. A six-step reference continuation supplies a discounted return (0.9 per step): pods earn 30 or 36, each move costs 1, a win adds 160, a loss subtracts 220, and the final state receives a visible space/distance potential. This continuation value is clipped to ±100 and multiplied by 0.06 before being added to the immediate reference score. This bounded adjustment keeps progress and escape evidence useful when future pod locations differ.

`pt.indexrng.Index("ribbon-garden-v3", backend="blake2b")` creates distinct train, recovery, validation, test and guided streams. Actual qrand arithmetic generates hedges, pods and exploratory choices. The initial dataset combines 256 reference episodes (an exploratory legal move every eleventh turn) with 128 guided episodes from the previous 17-feature model. Those parent-model trajectories are relabeled using the new 19-feature target and visit history. The parent forest is retained in [parent-forest.json](training/parent-forest.json).

An early model uses 12 trees per zone and depth 12. Another 48 guided episodes from that model are relabeled and added before a 32-tree-per-zone, depth-18 refit. Both use leaf size 2, all features, seed 2026, one worker, no adaptive complexity, no zone prior and no calibration. The selected model has **40,235 action rows** and **64 trees**. The two zones are calm and extra-growth conditions.

Both candidates play the same 32 validation seeds. Selection compares wins, mean pods, then mean turns. Validation selected **final**. Test data is evaluated only afterward and is not used for fitting or model selection. Both candidates won 21/32 validation games; the selected model collected more pods on average. The early model subsequently won more held-out test games than the selected model; that result is retained below. Development v1/v2 reports are historical experiments on other seed namespaces, not same-seed evidence of improvement. The final release uses the fresh v3 namespace.

## Measured results

| Policy | Completed gardens | Mean pods | Mean turns |
| --- | --- | --- | --- |
| Early model | 45/64 | 5.98/7 | 35.25 |
| Selected model | 41/64 | 5.88/7 | 31.94 |
| Selected model, guided | 18/32 | 5.88/7 | 45.94 |
| Reference route strategy | 34/64 | 5.42/7 | 36.84 |
| Random legal moves | 0/64 | 1.53/7 | 78.17 |

Solo evaluation starts at balanced focus with a seeded mix of normal and longer ribbons. Guided evaluation changes focus and ribbon conditions every seven turns. These small deterministic evaluations are not a guarantee of perfect play or strength on other garden sizes. Wisp can still choose a bad route; undo and replay branching are part of the game. Mean turns includes losses, so shorter is not automatically better.

Held-out target MAE: **1.781428**; R²: **0.999449**. These are errors on the designed action score, not probabilities of winning. All **515,373 Python/JavaScript predictions** agree within `1e-9` (observed maximum error: `0`). Fixtures include held-out visited inputs and float32 neighbors around every exported split threshold. [Download the gzip-compressed fixtures](training/validation.json.gz); [decoded-data checksum](training/fixture-package.json).

The brain panel lets you select any legal direction, inspect its actual inputs and tree path, compare early/current models, and preview one rule-based move on a copy. Looking ahead never advances the game. Smooth movement is presentation only and respects reduced-motion preferences. The route and growth rules do not depend on animation timing.

## Reproduction

From the arcade source root with the local pytoolz/WSRF environment:

```sh
/home/wiliamrocha/.spenv/bin/python -B tools/ribbon/train.py
/home/wiliamrocha/.spenv/bin/python -B tools/ribbon/document.py
node tools/test-ribbon.cjs
npm run build
```

The retained parent forest is an input to reproducing the recovery dataset. `tools/ribbon/data.cjs` evaluates the old model using its original named features and records the new features and labels alongside that play. The full selected and early models, per-seed outcomes, parameters, source hashes and estimator version are in [report.json](training/report.json). Model SHA-256: `75c0ee894ea52326a115ddadcddb0e60ea22a08d7c7b1dd5743eb99a5ef0fb01`. [Actual indexrng/qrand source provenance](training/library-sources.json) supplements the estimator provenance in the report.

Normal builds need no Python. The static website serves the fitted model locally, with no external model API. Tests reproduce all 96 recorded selected-policy outcomes, verify collision and growth invariants, validate the tail-vacating case, and check every saved Python prediction. Browser checks exercise play, guidance, inspection, previews, undo, branching, named sharing, motion preferences, and phone/tablet/desktop layouts.
