Files
resonance-engine/CONTROL_SURFACE_BUILD_SPEC.md
2026-07-16 11:57:36 +07:00

21 KiB
Raw Permalink Blame History

CONTROL SURFACE BUILD SPEC — Exposing the Engine as a Deductive Search Instrument

Written 2026-07-15. Spec only — no code until approved.

This spec covers three parts:

  1. Expose the knobs — catalog every hardcoded physics constant in khra_gixx_1024_v5_observer.cu and design a single generic set_param command to make each live-settable.
  2. The deductive search method — how the full knob space is searched, per .clinerules §6.
  3. The observer's role — how the observer LLM runs the search, chases anomalies, and interacts with the human.

PART 1 — EXPOSE THE KNOBS

1.1 Already-Exposed Knobs (command surface as of 2026-07-14)

Knob Default Clamp Range Command
omega 1.97 [0.5, 1.99] set_omega
khra_amp 0.03 [0.0, 0.2] set_khra_amp
gixx_amp 0.008 [0.0, 0.1] set_gixx_amp

1.2 Currently Hardcoded Physics Constants

A. Wave Function (khra_gixx_wave_1024, line 7481)

The wave function in full:

float khra = sinf(2.0f * M_PI * x / 128.0f + cycle * 0.025f) *
             cosf(2.0f * M_PI * y / 128.0f + cycle * 0.015f) * d_khra_amp;
float gixx = sinf(2.0f * M_PI * x / 8.0f + cycle * 0.4f) *
             cosf(2.0f * M_PI * y / 8.0f + cycle * 0.35f) * d_gixx_amp;
float asymmetry_factor = 1.0f + sinf(cycle * 0.05f) * 0.5f;
return khra + gixx * asymmetry_factor;

Constants to expose:

# Constant Line(s) Location Default Proposed Clamp Rationale
W1 128.0f (khra wavelength λ_khra) 75, 76 x / 128.0f, y / 128.0f 128.0 [16.0, 512.0] Spatial scale of the slow carrier. Doubling it halves khra's spatial frequency.
W2 0.025f (khra temporal freq ω_khra) 75 cycle * 0.025f 0.025 [0.001, 0.5] Temporal frequency of khra carrier. Controls khra period (~251 cyc at default).
W3 0.015f (khra y-phase rate) 76 cycle * 0.015f 0.015 [0.0, 0.5] Phase offset rate for the y-component cosine. Governs khra's xy phase relation.
W4 8.0f (gixx wavelength λ_gixx) 77, 78 x / 8.0f, y / 8.0f 8.0 [2.0, 128.0] Spatial scale of the fast carrier.
W5 0.4f (gixx temporal freq ω_gixx) 77 cycle * 0.4f 0.4 [0.01, 2.0] Temporal frequency of gixx carrier. Controls gixx period (~15.7 cyc at default).
W6 0.35f (gixx y-phase rate) 78 cycle * 0.35f 0.35 [0.0, 2.0] Phase offset rate for gixx y-component.
W7 0.05f (breathing frequency) 79 cycle * 0.05f 0.05 [0.0, 1.0] Frequency of the asymmetry/breathing modulation. 0.0 = no breathing.
W8 0.5f (breathing amplitude) 79 sinf(…) * 0.5f 0.5 [0.0, 0.95] Amplitude of breathing modulation. At 1.0, asymmetry_factor ranges [0.0, 2.0] so gixx can vanish entirely at the trough.

B. Collision Kernel (collide_kernel_khragixx, lines 100169)

# Constant Line(s) Default Proposed Clamp Rationale
C1 0.1f (density floor) 124 0.1 [0.001, 1.0] Minimum rho after clamp. Lower bound on density. Source of mass-leak asymmetry (floor ≠ ceil).
C2 10.0f (density ceiling) 125 10.0 [1.0, 100.0] Maximum rho clamp. The asymmetry between C1 and C2 pumps mass in over long runs.
C3 0.25f (velocity clamp) 129, 130, 131, 139, 140, 141 0.25 [0.05, 1.0] Maximum velocity magnitude. Appears in two places: pre-forcing clamp (lines 129133) and post-forcing clamp (lines 138143). Both use the same constant.
C4 0.5f (ky cross-coupling) 135 ky = kx * 0.5f 0.5 [-2.0, 2.0]

C. LBGK Equilibrium Coefficients (collide kernel line 147, velocity_stress line 214)

# Constant Default Proposed Clamp Rationale
E1 3.0f (cs⁻², the eu coefficient) 3.0 [2.1, 3.9] Governs how strongly velocity couples to the equilibrium distribution. Standard D2Q9 value = 3.0. NUMERICAL STABILITY: clamp narrowed to ±30% of default.
E2 4.5f (cs⁻⁴/2, the eu² coefficient) 4.5 [3.15, 5.85] Second-order velocity coupling. Standard = 4.5. NUMERICAL STABILITY: clamp narrowed to ±30% of default.
E3 1.5f (cs⁻²/2, the u² coefficient) 1.5 [1.05, 1.95] Velocity-squared damping term. Standard = 1.5. NUMERICAL STABILITY: clamp narrowed to ±30% of default.

CRITICAL — E1E3 numerical stability note: These equilibrium coefficients define the local Maxwellian. Varying them far from the standard D2Q9 values (cs²=1/3 → 3.0, 4.5, 1.5) can destabilize the LBGK collision operator, producing NaN values in the distribution function f and contaminating the entire field. The clamp ranges above are narrowed to ±30% of default to stay within observed stable bounds. The sweep engine MUST detect divergence/NaN at any grid point and abort+flag that point before the averaging window completes. The daemon's existing NaN/Inf reset counter (lines 149152 in the collide kernel) will catch NaN events — the sweep engine must monitor reset_count in telemetry (port 5556) and abort any point where reset_count > 0 during the settle or measurement window. Such points are flagged in sweep_results.jsonl as "status": "diverged" and the daemon is restored to baseline params before continuing to the next point.

These are lower priority than the wave function and collision clamp constants — the wave parameters directly control the two-carrier forcing regime, which is the physics we're searching. The equilibrium coefficients control the fluid response to that forcing. Expose them but treat them as a secondary sweep dimension. Do NOT sweep E1E3 in Round 1; wait until the active knob set has been narrowed to a manageable size.

1.3 Design: Single Generic set_param Command

Channel: ZMQ SUB on port 5557 (existing).

Message format (JSON):

{"cmd": "set_param", "param": "<name>", "value": <float>}

Param names and their clamp ranges:

param name Default Min Max Maps to
omega 1.97 0.5 1.99 h_omega (already exposed, just add alias)
khra_amp 0.03 0.0 0.2 d_khra_amp (already exposed)
gixx_amp 0.008 0.0 0.1 d_gixx_amp (already exposed)
lam_khra 128.0 16.0 512.0 W1 — khra wavelength
w_khra 0.025 0.001 0.5 W2 — khra temporal frequency
khra_y_phase 0.015 0.0 0.5 W3 — khra y-component phase rate
lam_gixx 8.0 2.0 128.0 W4 — gixx wavelength
w_gixx 0.4 0.01 2.0 W5 — gixx temporal frequency
gixx_y_phase 0.35 0.0 2.0 W6 — gixx y-component phase rate
breath_freq 0.05 0.0 1.0 W7 — breathing modulation frequency
breath_amp 0.5 0.0 0.95 W8 — breathing modulation amplitude
rho_floor 0.1 0.001 1.0 C1 — density floor clamp
rho_ceil 10.0 1.0 100.0 C2 — density ceiling clamp
vel_clamp 0.25 0.05 1.0 C3 — velocity magnitude clamp
ky_ratio 0.5 -2.0 2.0 C4 — y/x forcing ratio
eq_cs2_inv 3.0 0.1 10.0 E1 — equilibrium cs⁻² coefficient
eq_cs4_half 4.5 0.1 20.0 E2 — equilibrium cs⁻⁴/2 coefficient
eq_usq_half 1.5 0.1 20.0 E3 — equilibrium u²/2 coefficient

Total: 18 params (3 already exposed, 15 newly exposed).

Implementation in handle_command: Add a single set_param branch that looks up the param name in a static table, validates the value against its clamp range, sets the corresponding host variable, and pushes to device where needed (via cudaMemcpyToSymbol for device-side wave-function params; host-side for clamp and equilibrium constants that are currently fed through kernel arguments or are baked as literals).

Response (ack on 5559):

{"ack": "set_param", "cycle": <n>, "status": "ok", "param": "<name>", "value": <float>}

or "status": "rejected" with reason if out of range or unknown param.

1.4 Constants That Must Move from Compile-Time Literal to Runtime Variable

Most of these constants (W1W8, C1C4, E1E3) are currently C numeric literals baked into the kernel at compile time. To make them live-settable:

  • Wave function constants (W1W8): Currently __device__ scalars or kernel literals. Must become __device__ variables (like d_khra_amp already is) so they can be updated via cudaMemcpyToSymbol without recompilation. The wave function kernel already reads from device memory for amplitudes — extend the same pattern to the other eight constants.

  • Collision clamp constants (C1C4): Currently inline literals in collide_kernel_khragixx. Must become either __device__ variables or kernel parameters. Kernel parameters are simpler (no symbol-copy overhead) but require the host to pass them every call. Recommendation: __device__ variables — consistent with the wave-function pattern, single point of update, no kernel signature change.

  • Equilibrium coefficients (E1E3): Currently inline literals in two kernels (collide line 147, velocity_stress line 214). Must become __device__ variables shared by both kernels — updated once, both kernels see the change.

1.5 Alpha Coupling Ratio — Automatic Computation

The coupling ratio is:

alpha = (A_khra * w_gixx * lam_gixx) / (A_gixx * w_khra * lam_khra)

With the full knob set exposed:

  • A_khra = khra_amp
  • A_gixx = gixx_amp
  • w_khra = w_khra (temporal frequency param, khra cycle multiplier)
  • w_gixx = w_gixx (temporal frequency param, gixx cycle multiplier)
  • lam_khra = lam_khra
  • lam_gixx = lam_gixx

The daemon should compute and include alpha in every telemetry frame (port 5556) so the sweep engine and observer always have it. Add it to the JSON payload alongside coherence, asymmetry, etc.

Default alpha at canonical params:

alpha = (0.03 * 0.4 * 8.0) / (0.008 * 0.025 * 128.0)
      = (0.096) / (0.0256)
      = 3.75

IMPORTANT — Alpha comparability note: The α computed here uses the daemon's phase-increment parameters (w_khra=0.025, w_gixx=0.4) as defined in the khra_gixx_wave_1024 device function. These are NOT physical angular frequencies (which would be 2π× these values). This α is internally consistent for this daemon — all α values logged by this instrument are comparable to each other. They are NOT comparable to any historical α values that were computed using physical angular frequencies. Treat this daemon's α as a self-consistent relative scale, not an absolute physical quantity.

1.6 Future — NOT Part of This Build

These are genuinely new degrees of freedom, not exposing existing constants. Listed for later consideration, do NOT implement now:

  • Per-node omega — spatially varying relaxation rate. Would require a new kernel or a texture lookup. Major change, not "exposing existing constants."
  • Multi-frequency forcing — adding a third or Nth carrier wave. New wave function architecture.
  • Non-periodic boundary conditions — walls, inflow/outflow. Changes the streaming kernel.
  • Anisotropic wavelengths — different λ_x and λ_y for khra and gixx. Currently they share one λ. Would add 2 params.
  • Non-sinusoidal wave shapes — sawtooth, square, arbitrary waveform. Changes the wave function fundamentally.

PART 2 — THE DEDUCTIVE SEARCH METHOD

2.1 The Dependent Variable

Perturbation hold-time — how long a perturbation (injected into the stress/non-equilibrium channel, NOT density — fixing Mistake 1) persists in the field before the system relaxes back to its unperturbed attractor. Longer hold-time = candidate "memory regime."

Operational definition: inject a standardized stress perturbation, then measure the number of cycles until the spatially-resolved field (5561 coarse stream) becomes indistinguishable from an unperturbed control run, by a pre-committed statistical threshold.

2.2 The Full Knob Space

18 knobs. Even with coarse discretization (e.g. 5 values each), full grid = 5^18 ≈ 3.8 × 10^12 points. Brute force is impossible. Deductive elimination is the only viable strategy.

2.3 The Method: Hypothesis → Vary → Observe → Eliminate → Narrow

Per .clinerules §6. Each round:

  1. State the current hypothesis — which knob(s) are predicted to move hold-time.
  2. Design the sweep — vary those knobs across their ranges while holding all others at baseline (canonical defaults). Each knob gets a sparse sweep (e.g. 35 values across its range) to detect whether it moves the dependent variable at all.
  3. Run the sweep — automated, resumable, detached. Every measurement uses:
    • ≥10-forcing-period averaging (≥2510 cycles at canonical khra ω=0.025; adjust dynamically if w_khra is varied, since khra period = 2π/w_khra).
    • Pre-committed threshold set in code before looking at results.
    • Surrogate/permutation null (temporal shuffle of perturbation-to-response mapping).
    • Bootstrap distribution of hold-time estimates (never a single sample).
  4. Eliminate — knobs that produce NO statistically significant variation in hold-time (flat response within bootstrap CI) are FIXED at their baseline value for all future rounds. They are eliminated from the search space.
  5. Combine — knobs that DO move hold-time are combined in the next round (small factorial design over the active subset).
  6. Narrow — repeat until only a small active set remains. Then refine: finer sweeps, interaction terms, regime mapping.

2.4 Round 1: The Two Known Hypotheses

Per task instructions, the first two hypotheses to test:

Hypothesis 1: Relaxation rate (omega) controls hold-time.

  • Vary omega across [0.5, 1.0, 1.5, 1.97, 1.99] with all other knobs at baseline.
  • Prediction: hold-time ∝ 1/(1−ω) near the inviscid limit, or some monotonic function of ω.
  • Null: hold-time is flat across omega (within bootstrap CI).
  • This is the obvious first guess — slower relaxation = longer persistence.

Hypothesis 2: Perturbation carrier/rhythm phase relative to the forcing carriers controls hold-time.

  • The perturbation's timing relative to the khra and gixx wave phase determines whether the perturbation constructively or destructively interferes with the forcing.
  • Vary w_khra, w_gixx, breath_freq (the temporal knobs) in a small combinatorial sweep.
  • Prediction: hold-time peaks at specific phase alignments (resonances).
  • Null: hold-time is insensitive to temporal phase.

Round 1 should also sweep the amplitudes (khra_amp, gixx_amp) to establish the alpha-dependence baseline, since amplitude ratio α is the governing quantity (§3 of .clinerules). Sweep khra_amp × gixx_amp at a few omega values to get the first α-vs-hold-time map.

2.5 Round Structure Template

ROUND N
  Active knobs: [list]
  Fixed knobs (eliminated): [list with reason]
  Hypothesis: [stated before running]
  Sweep design: [which knobs at which values, how many points]
  Settle protocol: >=10 periods of the slowest active carrier after each knob change
  Measurement protocol: >=10 khra periods of 5561 coarse stream, averaged
  Rigor gates: [threshold, null type, bootstrap samples]
  Output: per-point JSONL + summary of which knobs moved hold-time and which didn't
  Decision: [which knobs eliminated, which combined for next round]

2.6 Safety and Operational Rules

  • Never reset_equilibrium casually — a fresh daemon start is the only clean reset.
  • Restore baseline params (omega 1.97, khra 0.03, gixx 0.008, all new params at defaults) at end of each sweep session.
  • Clamp all params to valid ranges before sending.
  • The mass leak (§2.5 of Source of Truth) contaminates long windows — subtract the leak slope from hold-time measurements, or keep perturbation windows short enough that leak drift is negligible relative to the perturbation signal.
  • Launch daemon detached. Only one daemon on ports 55565561.

PART 3 — THE OBSERVER'S ROLE

3.1 Architecture

The observer is the LLM driving the sweep engine. It sits behind the existing navigator/lattice_observer.py (extended) and the sweep engine (analysis/sweep_engine.py, per OBSERVER_SWEEP_BUILD_SPEC.md Stage 12). It receives:

  • Telemetry stream (port 5556) — 9 scalars + alpha + all 18 knob values.
  • Coarse field stream (port 5561) — 32×32×6 spatially-resolved field at ~100 Hz.
  • Per-point sweep metrics from the engine.

It sends:

  • set_param commands (port 5557) to turn knobs.
  • Sweep instructions to the engine (which points to run next).
  • Refinement requests (finer grid around an anomaly).

3.2 Observer Instructions (the Prompt)

The observer must be explicitly instructed. This is its core prompt, to be written to navigator/sweep_observer_prompt.json or embedded in the observer code:

You are mapping an alien system across its parameter space. You do NOT know what
it is. Your job is to find where its behaviour CHANGES CHARACTER — transitions,
new dynamical regimes, parameter regions where perturbations persist longer than
expected. Your method is DEDUCTIVE ELIMINATION, not brute force.

RULES:
1. Your dependent variable is PERTURBATION HOLD-TIME. Everything else is a
   predictor.
2. Every measurement uses >=10 khra-period averaging (>=~2510 cycles at default
   w_khra; scale this by 2π/w_khra if w_khra is varied).
3. Every claim must survive: pre-committed threshold, surrogate null, bootstrap
   distribution. A clean null is a real result.
4. The governing quantity is alpha = (A_khra * w_gixx * lam_gixx) /
   (A_gixx * w_khra * lam_khra). Always log alpha at every point.
5. The lattice may host MULTIPLE attractor basins. Do not assume "one attractor"
   from averaged data. Probe for multi-basin behaviour.
6. Time is a variable: how long things persist is the point. Do not reduce
   dynamics to static snapshots.

BANNED:
- Do NOT invoke Golden Weave.
- Do NOT query another LLM for a second opinion.
- Do NOT reach for neuroscience analogies as conclusions.
- Do NOT re-run injection/readback fidelity tests.
- Do NOT write to the density channel — perturbations go to the STRESS channel.

METHOD:
Each round: state hypothesis → vary active knobs → measure hold-time →
eliminate flat knobs → combine active knobs → narrow.
Report what each round eliminated and what remains active.

3.3 Anomaly Chasing

The observer watches per-point metrics as they compute. An anomaly is:

  • A hold-time that jumps by >2σ above the running bootstrap distribution.
  • A new orbit character (coherence behaviour changes — fixed point → limit cycle → chaotic).
  • A multi-basin signal (different settling points from different initial phases).
  • A predictability spike/drop in the coarse field.

When an anomaly is flagged, the observer:

  1. Requests the sweep engine to REFINE around that point — a finer grid in the active-knob space within ±one step of the anomalous point.
  2. Requests a longer capture window and a multi-basin probe (vary the perturbation phase and check for distinct settling outcomes).
  3. Reports the refined finding: anomaly confirmed (with rigor gates) or resolved as noise.

3.4 Interactive Human-in-Loop Mode

The observer exposes an interactive mode (CLI or lightweight web UI — agent's choice at build time, justified). In this mode:

  • Live view: current knob values, the α-vs-hold-time map so far (which points tested, what they showed), anomaly flags.
  • Human can:
    • Jump the daemon to any (param set) by issuing set_param commands.
    • Ask the observer to characterize a specific point (dwell, capture, report).
    • Request a custom sweep along a line or small grid.
    • Mark a point as "interesting" for the observer to refine later.
    • Override the observer's next-round proposal.
  • Observer explains: what it sees at the current point, what it thinks the active knobs are, where it would look next, and why.
  • Two-way: the human can accept, redirect, or override. The observer adapts its internal hypothesis state.

3.5 The Observer's Knowledge State

The observer maintains a running model of the search:

  • Active knobs: which params have been shown to move hold-time (not yet eliminated).
  • Eliminated knobs: which params were swept and found flat (with statistical confidence).
  • Untested knobs: which params haven't been swept yet.
  • Anomaly log: points that showed unexpected behaviour, with refinement status.
  • Alpha map: the hold-time surface over α for the current fixed-knob configuration.

This state persists to disk so the observer can resume after a crash or restart — it reads the sweep_results.jsonl and reconstructs its model.


DELIVERABLE CHECKLIST

  • Catalog all hardcoded physics constants in khra_gixx_1024_v5_observer.cu (18 total: 3 exposed, 15 to expose)
  • Design single set_param command with clamp ranges for all 15 new params
  • Specify deductive elimination search method with Round 1 design
  • Specify observer instructions, anomaly-chasing rules, interactive mode
  • List future additions that are NOT part of this build

Write no code until this spec is approved.