- 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.
13 KiB
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
Nisifori < N/2, otherwisei-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:
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:
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 0–7:
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 0–7, 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:
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 0–7 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:
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
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::StageStateis the default: every relaxation stage usesS(stage)-stage.Rk4RelaxationReference::StepOriginis the retained historical option:k1=S(A0)-A0; intermediatek2..k4compute neighborhoods/targets from their clamped stage but subtractA0.- 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 by1/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 correctionsqrt(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×Kactive faces, legacy defaultK=128, internal radiusR=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 widths1;- 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 ofcell_area*kernel_weight, preserving a constant field.Legacy: original six-face atlas geometry, side gutters with masked corner sectors, analytic disk normalizationcap(ri), analytic ring normalizationcap(ra)-cap(ri), original radius conversion/search stencil, and original discrete/fixed-0.1smooth 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 widths1, sampled stencil normalization;headis the next layer to overwrite andlatest=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, seed1, 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 toStageState. - 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, seed1, cleared base-style splats, and palette 7. - Sphere:
K=128,R=K/2, seed1, cleared then seeded overlays, and palette 1. Generate a corrected-default preset and a separately namedSphereModel::Legacypreset from the historical row. - DT: no historical fixed shape existed because it followed the window; choose and record
512², depth 16, causal delay, seed1, 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); countfloor(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 2–7, and random binary value.
- DT boxes: build one seeded field from 1,000 rectangles with width and height independently 10–19, 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/nextfields 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
- Hash every consulted legacy source/config file and store the hashes in
docs/legacy-source-map.md. - Record source paths and relevant line ranges.
- Mark the specification plus the new contract as the implementation authority.
- Future legacy consultation requires a concrete discrepancy, and its finding must be copied back into the contract with provenance.
- 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.