Add detailed phase plans for foundational macrosteps

- Macrostep 00: Model contract and retained historical options.
- Macrostep 01: Project foundation and configuration, including schema, presets, CLI, and CI setup.
- Macrostep 02: Mathematical core implementation and deterministic oracles.
- Macrostep 03: CPU-based planar simulation engine, FFT backend, and headless runner.

Provides exhaustive objectives, phase breakdowns, validation policies, and deliverables for each macrostep.
This commit is contained in:
2026-07-14 16:50:54 +02:00
parent 7a414db1d3
commit 51cff7b0f3
13 changed files with 2122 additions and 0 deletions

View File

@@ -0,0 +1,244 @@
# Macrostep 00 — Model contract and retained historical options
## Objective
Create the permanent in-repository source of truth for the rewrite. Freeze the new deterministic behavior and exactly three retained historical options: RK4 relaxation reference, packed-unitary FFT, and sphere model. After this macrostep, normal implementation work must not depend on repeatedly reading `/home/fpasqua/Nextcloud/VecchiProgetti/SmoothLifeAll`.
## Dependencies
None.
## Required outputs
- `docs/model-contract.md`: exact mathematics and update semantics.
- `docs/historical-options.md`: the three retained options, their exact semantics, constraints, and rejected historical behavior.
- `docs/legacy-source-map.md`: provenance with source file, line range, and source-file hash.
- `tests/fixtures/legacy/preset_rows.jsonl`: schema-neutral bootstrap capture of every accepted legacy row.
- `tests/fixtures/contract/`: small deterministic scalar/field fixtures.
## Phase 0.1 — Freeze the shared mathematical contract
### Substep 0.1.1 — State, topology, and indexing
Record these invariants verbatim in `docs/model-contract.md`:
- State is a scalar `A ∈ [0,1]` after every committed update.
- Base domains are periodic: a 1-D circle, 2-D torus, or 3-D torus.
- Storage is x-fast row-major. Define and test one canonical index mapping.
- Signed periodic offset for even extent `N` is `i` for `i < N/2`, otherwise `i-N`.
- Sphere is a closed spherical surface; delayed time is a 2-D spatial torus with circular temporal history.
### Substep 0.1.2 — Sampled kernels
Freeze the exact base construction:
```text
ri = ra / rr
w = ra / rb
L(r;a,w) = 0 when r < a-w/2
1 when r > a+w/2
(r-a)/w + 1/2 otherwise
KD(r) = 1 - L(r;ri,w)
KR(r) = L(r;ri,w) * (1-L(r;ra,w))
M = circular_convolution(A,KD) / sum(KD)
N = circular_convolution(A,KR) / sum(KR)
```
Document that weights are sampled at lattice points. Generate the complete nonzero support and warn when radii are unsuitable for the domain. The historical component cutoff is not retained.
Record the known 2-D check for `ra=10, rr=3, rb=10`:
```text
sum(KR) ≈ 279.216312
sum(KD) ≈ 35.524035
```
### Substep 0.1.3 — All rule curves
Use conventional `TAU = 2π`; the legacy shader variable called `pi` actually stores tau.
Freeze rising curves 07:
```text
0 hard: x >= a ? 1 : 0
1 linear: compact linear transition over a±e/2
2 Hermite: u²(3-2u), u=(x-a+e/2)/e, compactly clamped
3 sine: 0.5*sin((TAU/2)*(x-a)/e)+0.5, compactly clamped
4 logistic: 1/(1+exp(-4(x-a)/e))
5 atan: atan((x-a)*(TAU/2)/e)/(TAU/2)+0.5
6 atan/cos: (1.1*atan((x-a)/e)/(TAU/4)*cos(1.4(x-a))+1)/2
7 overshoot: (logistic-0.5)*(1+exp(-(x-a)²/e²))+0.5
```
For types 07, `W(n;a,b)=P(n,a,sn)*(1-P(n,b,sn))`. Hard windows are exactly `[a,b)`. Types 8 and 9 are complete windows:
```text
base = logistic(n,a,sn) * (1-logistic(n,b,sn))
mid = (a+b)/2
type 8 = base*(1-0.2*exp(-(20*(n-mid))²))
type 9 = base*(1+0.2*exp(-(20*(n-mid))²))
```
The mixer uses only curves 07 at center `0.5` and width `sm`. Curves 6/7 and resulting targets may overshoot; clamp only at the integration/commit points specified below.
### Substep 0.1.4 — Four rule constructions
Freeze:
```text
B = W(N;b1,b2)
D = W(N;d1,d2)
Q = selected mixer at M
1: S = mix(B,D,M)
2: S = mix(B,D,Q)
3: S = W(N, mix(b1,d1,M), mix(b2,d2,M))
4: S = W(N, mix(b1,d1,Q), mix(b2,d2,Q))
```
## Phase 0.2 — Freeze dynamics and integration
### Substep 0.2.1 — Base dynamics
```text
mode 0 / Discrete: A' = clamp(S)
mode 1 / Growth: dA/dt = 2S-1
mode 2 / Relaxation: dA/dt = S-A
```
The base discrete path ignores `dt` and selected integrator. Modes 3/4 found in old keyboard code are experimental and excluded from the supported contract unless later added with explicit names.
### Substep 0.2.2 — Integrators and clamp points
- Euler: `clamp(A + dt*k1)`.
- AB3: deterministic Euler first step, AB2 second step, AB3 thereafter: `(23k_n-16k_{n-1}+5k_{n-2})/12`.
- RK4: clamp every intermediate state and the final state.
- `Rk4RelaxationReference::StageState` is the default: every relaxation stage uses `S(stage)-stage`.
- `Rk4RelaxationReference::StepOrigin` is the retained historical option: `k1=S(A0)-A0`; intermediate `k2..k4` compute neighborhoods/targets from their clamped stage but subtract `A0`.
- The RK4 reference field exists structurally only inside relaxation+RK4 configuration. It is absent for discrete, growth, Euler, and AB3 rather than carried and ignored.
- Preserve AB history only for presentation, inspection, pause, and scheduler changes.
- Invalidate it for reset, ordinary state load, initializer/seed, rule, dynamics, timestep, integrator, kernel geometry, historical-option selection, topology, shape, variant, or backend changes. Switching away from and later back to AB3 never revives old derivatives.
- An exact continuation checkpoint may restore AB history only when its complete validated model/backend-independent arithmetic descriptor matches.
Undefined AB history is discarded. This list is the authoritative history-invalidation policy used by every later macrostep.
### Substep 0.2.3 — FFT algorithms
Freeze one local `FftAlgorithm` option for planar and multiscale convolution:
- `Standard` (default): conventional unscaled forward transform, inverse scaled by `1/sample_count`, then sampled-kernel normalization.
- `LegacyPackedUnitary`: power-of-two 1-D/2-D/3-D GPU path retaining adjacent-real packing, half-width x complex spectra, historical bit-reversal/twiddle plan stages, unitary butterfly scaling, real/complex conversion, and spectral correction `sqrt(sample_count)/kernel_sum`.
The legacy FFT is a complete algorithm backend, not a global compatibility mode. It uses the same complete kernels and safe ping-pong resource layer as the new implementation. Old OpenGL compatibility syntax, working-directory shaders, framebuffer feedback, and resource behavior are discarded. An explicit legacy FFT request on CPU or unsupported GPU hardware fails clearly; it never silently substitutes `Standard`. A small CPU stage oracle and fixtures validate its packing, plans, scaling, spectra, and convolution.
## Phase 0.3 — Freeze variant contracts
### Substep 0.3.1 — Multiscale
Record all six combinations in a 2×3 matrix:
- Independent inputs: each scale receives `(ring_i(A), disk_i(A))`.
- Chained inputs: `(ring_0,ring_1)`, `(ring_1,ring_2)`, `(ring_2,disk_2)`.
- Sequential: update and clamp between scales, recomputing from the current state.
- Ordered clamped sum: evaluate all responses from one snapshot, add/clamp each in scale order.
- Mean increment: evaluate from one snapshot, add the arithmetic mean once, then clamp.
The new implementation supports growth and corrected relaxation. It rejects discrete dynamics because the three composition names do not define an unambiguous target aggregator; adding it later requires an explicit target-aggregation enum and fixtures.
Sequential composition always recomputes every required input from the current state. Shared-snapshot methods always use one original state. Relaxation names that current or original reference state explicitly. Additive mode-0 responses, stale chained fields, texture feedback, and undefined mode-2 sources are discarded.
### Substep 0.3.2 — Sphere
Freeze:
- six `K×K` active faces, legacy default `K=128`, internal radius `R=K/2`;
- direction map `normalize(face_normal + tan(uπ/4)face_u + tan(vπ/4)face_v)`;
- area-weighted sample accumulation;
- distance `R*acos(clamp(dot(a,b),-1,1))`;
- `ri=ra/3`, transition widths `1`;
- planar-to-geodesic conversion `R*acos(1-ra²/(2R²))`;
- spherical cap area `2πR²(1-cos(r/R))`;
- direct replacement and fixed `A+0.1(2S-1)` modes.
Freeze one local `SphereModel` option:
- `Corrected` (default): complete edge/corner mapping and per-center normalization by the actual sum of `cell_area*kernel_weight`, preserving a constant field.
- `Legacy`: original six-face atlas geometry, side gutters with masked corner sectors, analytic disk normalization `cap(ri)`, analytic ring normalization `cap(ra)-cap(ri)`, original radius conversion/search stencil, and original discrete/fixed-`0.1` smooth dynamics.
Both models use clamped dot products, explicit initialization, and ping-pong writes. Unclamped `acos`, texture feedback, and undefined atlas contents are discarded.
### Substep 0.3.3 — Delayed time
Freeze:
- periodic x/y field and history depth 16;
- `ri=ra/3`, both transition widths `1`, sampled stencil normalization;
- `head` is the next layer to overwrite and `latest=wrap(head-1,depth)`;
- causal nearest-layer selection is `wrap(latest-floor(distance+0.5),depth)`, so delay zero reads the latest committed state;
- direct replacement or `latest+0.1(2S-1)`, then clamp.
The historical head anomaly is discarded and has no configuration option.
## Phase 0.4 — Preset and fixture capture
### Substep 0.4.1 — Schema-neutral bootstrap capture
Before the Rust schema exists, use a tiny reviewed extraction script to copy accepted source rows verbatim into JSONL with source path, line number, parsed columns, description, and source hash. This is evidence capture, not the final application importer. Expected counts are:
- main catalogue: 188 valid rows;
- SDL catalogue: 187 rows, largely duplicate and containing drift;
- multiscale catalogue: 12 rows = 4 triplets;
- sphere catalogue: 1 row;
- DT catalogue: 29 rows.
Do not deduplicate the evidence and do not run legacy executables. Macrostep 01 converts this frozen capture into the versioned schema and performs deliberate deduplication.
### Substep 0.4.2 — Freeze migration defaults absent from rows
Commit a mapping table so every imported row becomes a complete run:
- Base: shape `1024`/`512²`/`64³` by dimension, Euler, standard FFT, seed `1`, cleared C++-inspired periodic splats, palette 2, and 3-D volume style 2. Because Euler is selected, no RK4-reference field is stored; creating relaxation+RK4 later defaults that newly applicable field to `StageState`.
- SDL rows: same model mapping, source-tagged and deduplicated against main rows; no separate backend.
- Multiscale: `512²`, sequential composition, independent kernels, growth/relaxation only, standard FFT, seed `1`, cleared base-style splats, and palette 7.
- Sphere: `K=128`, `R=K/2`, seed `1`, cleared then seeded overlays, and palette 1. Generate a corrected-default preset and a separately named `SphereModel::Legacy` preset from the historical row.
- DT: no historical fixed shape existed because it followed the window; choose and record `512²`, depth 16, causal delay, seed `1`, a seeded box field replicated into all layers, and palette 7. Record this initializer/shape as an intentional modern replacement.
The table must distinguish source facts from chosen deterministic replacements.
### Substep 0.4.3 — Freeze initializer algorithms
- Base splats: clear to zero; choose continuous uniform centers; radius uniform in `[0.5ra,ra)`; count `floor(domain_volume / product(min(2ra,axis_extent)))+1`; paint periodic interval/disk/ball samples to one. Use ChaCha with a specified draw order.
- Sphere overlays: clear first; perform 1,000 draws with random face/center, radius 27, and random binary value.
- DT boxes: build one seeded field from 1,000 rectangles with width and height independently 1019, then replicate it to all history layers. Use one documented boundary policy; do not retain gradual filling or undefined layers.
Commit exact seeded fixture arrays so later PRNG upgrades cannot silently change tests.
### Substep 0.4.4 — Golden fixtures
Commit compact fixtures for:
- scalar curve boundaries and overshoot;
- a rule-surface grid spanning all valid enum combinations;
- small asymmetric 1-D/2-D/3-D fields;
- raw and normalized kernels;
- direct convolution outputs plus legacy packed plans/stages/unitary scaling;
- Euler/AB/RK synthetic derivatives, including both RK4 relaxation references;
- all six corrected multiscale combinations;
- source-frozen corrected/legacy sphere `M/N/S/next` fields at face centers, edges, and masked corners for both update modes, in addition to face transforms, normalization, and area totals;
- DT layer-coded history and radial delay shells.
Use explicit arrays for essential goldens, not only PRNG seeds.
## Phase 0.5 — Source retirement protocol
1. Hash every consulted legacy source/config file and store the hashes in `docs/legacy-source-map.md`.
2. Record source paths and relevant line ranges.
3. Mark the specification plus the new contract as the implementation authority.
4. Future legacy consultation requires a concrete discrepancy, and its finding must be copied back into the contract with provenance.
5. The application, build, tests, and importer outputs must not require the legacy path.
## Exit gate
- Every formula, constant, mode, topology, retained historical option, and discarded defect has a local documented decision.
- Preset counts/grouping reconcile with the source catalogues.
- Fixtures are readable without legacy tools.
- A new implementer can build any mandatory backend using only this repository.