Post hoc walk-forward analysis of finished per-window studies.
``walkforward(windows, sources, *, metric, direction, space=None, max_work=None)``
reads the caller's ordered plan and one finished study per supplied window. It runs
no window, evaluates nothing, writes no file, keeps no state and changes no native
result. v1 analyses finished studies; native in-loop walk-forward comes later.
Contract ``pineforge-hpo-walkforward/v1``, algorithm ``exact_per_window_v1``:
Only ``ok`` rows with finite metric cells compete. Other statuses are excluded as
``status_<status>``, absent cells as ``metric_not_recorded`` and null cells as
``metric_unavailable``, in that order. An invalid cell on an ok row, or a non-finite
or JSON-unwritable cell on any row, or an integer too large for binary64 on any
row, refuses the call. Numeric cells are binary64;
booleans are not numbers. The metric is ``objective`` or an exact recorded name.
Selection minimises ``(sign * value, trial_id)``, with sign -1.0 for maximize and
+1.0 for minimize. A supplied window with no eligible row has no selection; none
anywhere refuses. Missing sources appear in ``never_run`` in plan order. Gaps
between consecutive supplied windows appear in ``chain_breaks``.
For adjacent supplied windows whose first has a selection, its exact parameter
key is looked up in the target's rows. Every such pair appears, including a target
without eligible rows. Eligible matches must have one value; unequal values refuse,
otherwise the lowest id is reported with ``row_found`` true. Its mid-rank is
``better + (equal + 1) / 2`` among target eligible rows. Without an eligible match,
``row_found`` is false, numeric fields are null, and the reason is that of the
lowest-id matching row, or ``no_row``. When ``row_found`` is true, parameters belong
to the matching row; when false, they are the source window's selected parameters
(the vector looked up). No value is inferred.
Stability lists selected parameters as recorded, in plan order, with distinct
typed-scalar counts and exact numeric minimum and maximum for both integer and real
dimensions, keeping the first recorded value on equality. Boolean and categorical
extremes are null. Real identity equates integer and real spellings and signed zeros.
There is no tolerance, averaging, interpolation, threshold or robustness verdict.
The shared reader checks each supplied study and its context separately. Recorded
spaces and row space hashes must agree across windows; bar and timeframe counters
are compared only inside a window. Top-level result hashes are not compared. For
objective, the recorded common space's direction is checked first, then source
directions; a passed space's direction is not compared.
Hash-mismatch ``ids`` ascend: one id per differing row, so an id that occurs in
several windows is listed once for each.
Refusals raise ``WalkforwardError`` with its refused ``document()``. The first
defect decides: missing options before invalid options; unknown labels; no source;
reading and each window's context; recorded spaces then row hashes; direction;
metric name; cells; every row's parameters; carried duplicates; no eligible row;
admission figure. The figure is rows read + sum e(e-1)/2 + sum target eligible
counts over carry-over pairs, bounded only by a caller-supplied ``max_work``.
The document and digest ignore row and mapping insertion order. The digest is
SHA-256 of sorted raw per-row SHA-256 digests of compact, key-sorted ASCII JSON
``[window label, trial_id, status, cell]``. It covers every status, normalises numeric
cells to binary64, writes absent/null as null, and preserves other JSON cells on
excluded rows. It omits metric name, direction and plan position. Listings follow
the plan, dimensions follow code-point name order, exclusion status reasons precede the
missing and null metric reasons, and ids ascend. ``interpretation`` is fixed.