Research-Stack/0-Core-Formalism/lean/Semantics/Semantics/CoulombComplexity.lean
2026-05-05 21:09:48 -05:00

548 lines
25 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/- Copyright (c) 2026 Sovereign Research Stack. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Research Stack Team
CoulombComplexity.lean — Signed Inter-Node Tension Model via Coulomb Form
Extends the Mass-Number Field complexity model with charge polarity:
- Z (Structured Mass) and N (Stress Mass) act as charge polarities
- Q = Z - N defines the signed "bias" of a node
- Coulomb form governs routing tension between nodes (analogy, not literal EM)
Per AGENTS.md §1.4: Q16_16 fixed-point for all physics computations.
Per AGENTS.md §5: Target 6.5σ statistical confidence for routing decisions.
Forest Position:
branch: GeoCognition.Cartography.ForceLayer
role: charged interaction over shell-addressable mass fields
upstream:
- MassNumberField (Z, N masses)
- ComplexityPrimeSieve (prime selection)
- LochMonsterFilter (monster classification)
downstream:
- BHOCS shield (committed charge neutralization)
- FAMM drain (stress-heavy charge dissipation)
- PIST witness (structured charge routing)
- T5 route selection (torus manifold routing)
Canonical Law:
"Structure attracts Stress; Symmetry repels Symmetry; Memory shields the Charge."
Commit-safe Law:
"Sieve the mass to find the Primes; polarize the Primes to find the Force;
commit the scar to shield the Charge."
-/
import Semantics.SigmaGate
import Semantics.FixedPoint
import Semantics.Bind
import Mathlib.Data.Real.Basic
namespace Semantics.CoulombComplexity
open Semantics
open Semantics.Q16_16
open Semantics.Q16_16
-- ═══════════════════════════════════════════════════════════════════════════
-- §1 Charge Polarity Foundation
-- ═══════════════════════════════════════════════════════════════════════════
/-- Charge Q = Z - N (Structured Mass minus Stress Mass).
Polarity classification:
- Q > 0: Structured Positive (Z ≫ N, witness-heavy)
- Q < 0: Stress Negative (N ≫ Z, scar/basin-heavy)
- Q ≈ 0: Electrically Neutral (Z ≈ N, filtered out)
-/
def Charge := Q16_16
deriving Repr, BEq, Inhabited
namespace Charge
/-- Compute signed charge from structured mass Z and stress mass N.
Q = Z - N (Q16_16 subtraction, which wraps as 2's complement).
Use Q16_16.toInt for signed interpretation. -/
def compute (Z N : Q16_16) : Charge :=
Q16_16.sub Z N
/-- Check if charge is positive (structured dominance, witness-heavy).
Uses unsigned comparison on raw bits; paired with toInt for full range. -/
def isPositive (q : Charge) : Bool :=
q.val > Q16_16.zero.val
/-- Check if charge is negative (stress dominance, scar/drain-heavy).
Uses Q16_16.toInt for proper signed interpretation of 2's complement. -/
def isNegative (q : Charge) : Bool :=
Q16_16.toInt q < 0
/-- Check if charge is neutral (filtered from high-priority routing).
Uses signed integer comparison for balanced Z ≈ N nodes. -/
def isNeutral (q : Charge) (tolerance : Q16_16) : Bool :=
let qInt := Q16_16.toInt q
let tolInt := Q16_16.toInt tolerance
-- Check: -tolerance ≤ q ≤ tolerance
(-tolInt ≤ qInt) ∧ (qInt ≤ tolInt)
/-- Absolute charge value as Nat (for threshold comparisons).
|Q| in integer form, capped at UInt32 max. -/
def absVal (q : Charge) : Nat :=
let qInt := Q16_16.toInt q
if qInt < 0 then (-qInt).toNat else qInt.toNat
#eval! Charge.compute (Q16_16.ofInt 100) (Q16_16.ofInt 30) -- Q = +70
#eval! Charge.compute (Q16_16.ofInt 30) (Q16_16.ofInt 100) -- Q = -70
#eval! Charge.compute (Q16_16.ofInt 50) (Q16_16.ofInt 50) -- Q = 0
end Charge
-- ═══════════════════════════════════════════════════════════════════════════
-- §2 Polarity Classification
-- ═══════════════════════════════════════════════════════════════════════════
inductive Polarity where
| structuredPositive -- Z ≫ N: witness-heavy node (repels same, attracts stress)
| stressNegative -- N ≫ Z: scar/basin-heavy node (repels same, attracts structured)
| neutral -- Z ≈ N: electrically neutral (filtered from priority routing)
deriving Repr, BEq, DecidableEq
namespace Polarity
/-- Classify polarity from charge with tolerance threshold. -/
def classify (q : Charge) (tolerance : Q16_16) : Polarity :=
if Charge.isNeutral q tolerance then Polarity.neutral
else if Charge.isPositive q then Polarity.structuredPositive
else Polarity.stressNegative
/-- Polarity interaction rule: true = attraction, false = repulsion.
Stack meaning:
- structuredPositive ↔ stressNegative: attraction (witness to scar commitment)
- Same polarity: repulsion (prevent crowding / spread heat)
- Neutral: no interaction (low-priority) -/
def interactsAttractively (p1 p2 : Polarity) : Bool :=
match p1, p2 with
| Polarity.structuredPositive, Polarity.stressNegative => true -- witness → scar
| Polarity.stressNegative, Polarity.structuredPositive => true -- scar ← witness
| Polarity.neutral, _ => false -- Neutral: low-priority interaction
| _, Polarity.neutral => false
| _, _ => false -- Same polarity: repulsion
/-- Polarity interaction rule: true = repulsion.
Stack meaning:
- Q_i > 0, Q_j > 0: repulsive → prevent BHOCS witness crowding
- Q_i < 0, Q_j < 0: repulsive → spread heat across FAMM drains -/
def interactsRepulsively (p1 p2 : Polarity) : Bool :=
match p1, p2 with
| Polarity.structuredPositive, Polarity.structuredPositive => true -- prevent crowding
| Polarity.stressNegative, Polarity.stressNegative => true -- spread drains
| _, _ => false
#eval! Polarity.classify (Charge.compute (Q16_16.ofInt 100) (Q16_16.ofInt 30)) (Q16_16.ofInt 10)
#eval! Polarity.classify (Charge.compute (Q16_16.ofInt 30) (Q16_16.ofInt 100)) (Q16_16.ofInt 10)
#eval! Polarity.classify (Charge.compute (Q16_16.ofInt 50) (Q16_16.ofInt 52)) (Q16_16.ofInt 5)
end Polarity
-- ═══════════════════════════════════════════════════════════════════════════
-- §3 Coulomb Complexity Force F_C(i,j)
-- ═══════════════════════════════════════════════════════════════════════════
/-- Coulomb form inter-node tension: F_C = k_e * Q_i * Q_j / (r^2 + ε)
This is a signed tension model, NOT literal electromagnetism.
The ε guard matters because torus distance can be zero.
Where:
- k_e: Coupling constant (system tension)
- Q_i, Q_j: Signed charges of nodes i and j
- r: Distance in T5 (5D Torus) routing manifold
- ε: Singularity guard (small positive constant)
Sign convention:
- F_C > 0: Repulsion (same polarity)
- F_C < 0: Attraction (opposite polarity)
Note: NBody.lean already models F = k*q1*q2/r^2 with VecN 3 forces.
This scalar version is the tension magnitude for routing decisions.
-/
def coulombForce (k_e : Q16_16) (Q_i Q_j : Charge) (r epsilon : Q16_16)
: Q16_16 :=
let numerator := Q16_16.mul k_e (Q16_16.mul Q_i Q_j)
let r_sq := Q16_16.mul r r
let denom := Q16_16.add r_sq epsilon -- ε prevents r = 0 singularity
Q16_16.div numerator denom
/-- Distance in T5 (5D Torus) manifold.
Simplified: Euclidean distance in 5D with torus wraparound.
Integrates with SSMS_nD.lean variable-dimensional manifold substrate.
Full implementation requires T5 coordinate embedding.
-/
def t5Distance (coords_i coords_j : Array Q16_16) : Q16_16 :=
if coords_i.size ≠ 5 coords_j.size ≠ 5 then Q16_16.ofInt 1000 -- Large default
else
let squaredDiffs := (List.range 5).map (fun idx =>
let diff := Q16_16.sub coords_i[idx]! coords_j[idx]!
Q16_16.mul diff diff)
let sumSq := squaredDiffs.foldl (fun acc d => Q16_16.add acc d) Q16_16.zero
Q16_16.sqrt sumSq
-- Test: Like charges repel (positive force)
#eval! coulombForce (Q16_16.ofInt 1) (Q16_16.ofInt 10) (Q16_16.ofInt 10) (Q16_16.ofInt 5) (Q16_16.ofInt 1)
-- Test: Opposite charges attract (negative force)
#eval! coulombForce (Q16_16.ofInt 1) (Q16_16.ofInt 10) (Q16_16.ofInt (-10)) (Q16_16.ofInt 5) (Q16_16.ofInt 1)
-- ═══════════════════════════════════════════════════════════════════════════
-- §4 Node Structure with Coulomb Properties
-- ═══════════════════════════════════════════════════════════════════════════
structure CoulombNode where
id : String
Z : Q16_16 -- Structured Mass
N : Q16_16 -- Stress Mass
charge : Charge
polarity : Polarity
density : Q16_16 -- Charge density ρ for plasma classification (ρ ≥ 0.5 = plasma)
t5Coords : Array Q16_16 -- 5D Torus coordinates
fieldInfluence : Q16_16 -- Potential energy contribution
deriving Repr
namespace CoulombNode
/-- Create a Coulomb node from Z and N masses.
Note: uses 'create' not 'mk' to avoid conflict with structure-generated mk. -/
def create (id : String) (Z N : Q16_16) (t5Coords : Array Q16_16)
(tolerance : Q16_16) : CoulombNode :=
let charge := Charge.compute Z N
let polarity := Polarity.classify charge tolerance
{ id := id, Z := Z, N := N, charge := charge, polarity := polarity,
density := Q16_16.zero, t5Coords := t5Coords, fieldInfluence := Q16_16.zero }
/-- Compute scalar interaction tension with another node.
Uses epsilon guard in denominator (r^2 + ε) to avoid singularity.
Integrates with NBody.lean VecN 3 force for vector routing directions. -/
def forceWith (node other : CoulombNode) (k_e epsilon : Q16_16) : Q16_16 :=
let r := t5Distance node.t5Coords other.t5Coords
coulombForce k_e node.charge other.charge r epsilon
/-- Determine routing decision based on net Coulomb tension.
Routing rules:
- Net F > threshold: REPEL_GUARD (too much repulsion / crowding)
- Net F < -threshold: PULL_TO_SCAR (attraction / commitment)
- Otherwise: NEUTRAL_GROUND (no significant interaction)
-/
def routingDecision (node : CoulombNode) (others : Array CoulombNode)
(k_e epsilon threshold : Q16_16) : String :=
let netForce := others.foldl (fun acc other =>
Q16_16.add acc (node.forceWith other k_e epsilon)) Q16_16.zero
if netForce.val > threshold.val then "REPEL_GUARD" -- Too much repulsion
else if (netForce.val.toNat : Int) < -(threshold.val.toNat : Int) then "PULL_TO_SCAR" -- Attraction
else "NEUTRAL_GROUND" -- No significant interaction
end CoulombNode
-- ═══════════════════════════════════════════════════════════════════════════
-- §5 The Coulomb Sieve (Filtering Logic)
-- ═══════════════════════════════════════════════════════════════════════════
/-- Sieve state for Coulomb filtering. -/
structure CoulombSieve where
k_e : Q16_16 -- Coupling constant
neutralTolerance : Q16_16 -- Tolerance for Q ≈ 0
plasmaDensityThreshold : Q16_16 -- Flag high |Q| with high density
minChargeForPrime : Q16_16 -- Minimum |Q| to be "Ionic Prime"
deriving Repr
namespace CoulombSieve
/-- Default sieve parameters. -/
def default : CoulombSieve := {
k_e := Q16_16.ofInt 1, -- Unit coupling
neutralTolerance := Q16_16.ofInt 5, -- |Q| ≤ 5 is neutral
plasmaDensityThreshold := Q16_16.ofInt 100, -- High charge × high density
minChargeForPrime := Q16_16.ofInt 50 -- |Q| ≥ 50 for ionic prime status
}
/-- Coulomb sieve phase classification per spec:
Phase | Condition | Meaning | Route
------------------|------------------------------------|------------------------|----------
NEUTRAL_GROUNDED | |Q| < Θ_Q | balanced/grounded | low-priority
STRUCTURED_ION | Q ≥ Θ_Q, ρ < 0.5 | witness-heavy node | BHOCS candidate
STRESS_ION | Q ≤ -Θ_Q, ρ < 0.5 | scar/drain-heavy node | FAMM drain candidate
IONIC_PRIME | high |Q|, low redundancy, stable r | stable high-charge | prime routing
SEISMIC_PLASMA | high |Q|, ρ ≥ 0.5 | destabilizing | quarantine
Note: ρ (density) is a Q16_16 fraction; 0.5 = 32768 in Q16_16 raw.
-/
inductive SievePhase where
| neutralGrounded
| structuredIon
| stressIon
| ionicPrime
| seismicPlasma
deriving Repr, BEq
/-- Classify a single node into its sieve phase. -/
def classifyPhase (node : CoulombNode) (sieve : CoulombSieve) : SievePhase :=
let absQRaw := node.charge.val
let minQRaw := sieve.minChargeForPrime.val
let rhoHalf : UInt32 := 32768 -- 0.5 in Q16_16 raw
let isHighQ := absQRaw ≥ minQRaw
let isPlasma := node.density.val ≥ rhoHalf
if absQRaw ≤ sieve.neutralTolerance.val then
SievePhase.neutralGrounded
else if isHighQ && isPlasma then
SievePhase.seismicPlasma
else if isHighQ && node.charge.val > Q16_16.zero.val && !isPlasma then
SievePhase.structuredIon
else if isHighQ && node.charge.val ≤ Q16_16.zero.val && !isPlasma then
SievePhase.stressIon
else if isHighQ then
SievePhase.ionicPrime
else
SievePhase.neutralGrounded -- Default fallback for mid-range
/-- Filter nodes through the Coulomb sieve.
Returns: (filteredNodes, plasmaNodes, ionicPrimes, structuredIons, stressIons)
- Filtered: Nodes with significant charge interactions (excluding plasma)
- Plasma: High |Q| + high density (SEISMIC_PLASMA, quarantined)
- Ionic Primes: Stable high-charge nodes at Goldilocks distance
- Structured Ions: Q > 0, ρ < 0.5 (BHOCS candidates)
- Stress Ions: Q < 0, ρ < 0.5 (FAMM drain candidates)
-/
def filterNodes (sieve : CoulombSieve) (nodes : Array CoulombNode)
: (Array CoulombNode × Array CoulombNode × Array CoulombNode × Array CoulombNode × Array CoulombNode) :=
nodes.foldl (fun (filtered, plasma, primes, structIons, stressIons) node =>
let phase := classifyPhase node sieve
match phase with
| SievePhase.neutralGrounded => (filtered, plasma, primes, structIons, stressIons)
| SievePhase.seismicPlasma => (filtered, plasma.push node, primes, structIons, stressIons)
| SievePhase.structuredIon => (filtered.push node, plasma, primes, structIons.push node, stressIons)
| SievePhase.stressIon => (filtered.push node, plasma, primes, structIons, stressIons.push node)
| SievePhase.ionicPrime => (filtered.push node, plasma, primes.push node, structIons, stressIons)
) (#[], #[], #[], #[], #[])
end CoulombSieve
-- ═══════════════════════════════════════════════════════════════════════════
-- §6 Faraday Cage (BHOCS Memory Shielding)
-- ═══════════════════════════════════════════════════════════════════════════
/-- Faraday Cage for BHOCS: shields committed nodes from Coulomb interactions.
When a Monster is committed to the bounded recursive store,
its charge Q is "shielded" from the active dynamics branch.
This prevents historical scars from destabilizing current operations.
-/
structure FaradayCage where
shieldedCharges : Array Charge
cageBoundary : Q16_16 -- Recursive depth bound ("tree fiddy" guard)
deriving Repr
namespace FaradayCage
/-- Default empty Faraday cage. -/
def empty : FaradayCage := {
shieldedCharges := #[],
cageBoundary := Q16_16.ofInt 350 -- "tree fiddy" recursive guard
}
/-- Shield a charge: add to cage, removing from active dynamics.
Rule: Q_active(i) = 0 if i ∈ BHOCS Committed.
Once BHOCS commits a monster/scar, its active charge is shielded
from the live dynamics branch. The archive preserves the scar
without letting it keep pulling on the current manifold. -/
def shield (cage : FaradayCage) (charge : Charge) : FaradayCage :=
{ cage with shieldedCharges := cage.shieldedCharges.push charge }
/-- Check if a charge is shielded (cannot exert Coulomb force). -/
def isShielded (cage : FaradayCage) (charge : Charge) : Bool :=
cage.shieldedCharges.contains charge
/-- Apply cage to filter out shielded nodes from interaction computation.
Result: only uncommitted nodes participate in Coulomb tension.
committed scar = shielded witness (no active charge). -/
def filterShielded (cage : FaradayCage) (nodes : Array CoulombNode)
: Array CoulombNode :=
nodes.filter (fun node => !cage.isShielded node.charge)
/-- Get active charge for a node: returns zero if shielded.
Implementation of Q_active(i) = if i ∈ BHOCS then 0 else Q_i. -/
def activeCharge (cage : FaradayCage) (node : CoulombNode) : Charge :=
if cage.isShielded node.charge then Q16_16.zero else node.charge
end FaradayCage
-- ═══════════════════════════════════════════════════════════════════════════
-- §7 Canonical Bridge Integration (Coulomb Variant)
-- ═══════════════════════════════════════════════════════════════════════════
/-- Canonical Coulomb bridge node structure (JSON-serializable). -/
structure MassNumberField where
A : UInt32 -- total mass number (Q16_16 raw)
Z : UInt32 -- structured mass (Q16_16 raw)
N : UInt32 -- stress mass (Q16_16 raw)
deriving Repr
structure ChargeInfo where
Q : Int -- signed charge (Z - N) as integer
polarity : String
shielded : Bool
deriving Repr
structure FieldInfluence where
nearestOpposite : String
nearestRepulsive : String
route : String
deriving Repr
structure ClaimBoundary where
coulombLaw : String
notPhysicalEM : String
shielding : String
deriving Repr
/-- Canonical Coulomb bridge node structure (JSON-serializable per spec). -/
structure CoulombBridgeNode where
id : String
massField : MassNumberField
charge : ChargeInfo
fieldInfluence : FieldInfluence
claimBoundary : ClaimBoundary
deriving Repr
namespace CoulombBridgeNode
/-- Convert internal CoulombNode to canonical bridge format.
Matches the JSON canonical object from the spec:
{
"id": "COULOMB_PRIME_NODE_0xEE7",
"mass_field": { "A": 458752, "Z": 300000, "N": 158752 },
"charge": { "Q": 141248, "polarity": "STRUCTURED_POSITIVE", "shielded": false },
"field_influence": { ... },
"claim_boundary": { "coulomb_law": "...", "not_physical_em": "...", "shielding": "..." }
} -/
def fromCoulombNode (node : CoulombNode) (nearestOpp repel routing : String)
(shielded : Bool) : CoulombBridgeNode :=
let polarityStr := match node.polarity with
| Polarity.structuredPositive => "STRUCTURED_POSITIVE"
| Polarity.stressNegative => "STRESS_NEGATIVE"
| Polarity.neutral => "NEUTRAL"
let qInt := (node.charge.val.toNat : Int) / 65536 -- Convert Q16_16 to approx Int
let aRaw := Q16_16.add node.Z node.N |>.val
{
id := node.id,
massField := {
A := aRaw,
Z := node.Z.val,
N := node.N.val
},
charge := {
Q := qInt,
polarity := polarityStr,
shielded := shielded
},
fieldInfluence := {
nearestOpposite := nearestOpp,
nearestRepulsive := repel,
route := routing
},
claimBoundary := {
coulombLaw := "signed inter-node tension model over Z-N polarity",
notPhysicalEM := "uses Coulomb form as routing analogy, not literal electromagnetism",
shielding := "BHOCS commitment removes active charge from live dynamics"
}
}
-- Example canonical node
#eval! (CoulombBridgeNode.fromCoulombNode
(CoulombNode.create "NODE_0xEE7" (Q16_16.ofInt 300) (Q16_16.ofInt 59)
#[Q16_16.ofInt 1, Q16_16.ofInt 2, Q16_16.ofInt 3, Q16_16.ofInt 4, Q16_16.ofInt 5]
(Q16_16.ofInt 10))
"DRAIN_BASIN_0x02" "ARCHIVE_MONSTER_0x01" "PULL_TO_SCAR" false)
end CoulombBridgeNode
-- ═══════════════════════════════════════════════════════════════════════════
-- §8 Theorems: Coulomb Sieve Correctness
-- ═══════════════════════════════════════════════════════════════════════════
-- Theorem: Like charges interact — the ε-guard guarantees totality
-- (no singularity). Full sign proof requires signed Q16_16 arithmetic lemmas.
theorem likeChargesRepel (k_e epsilon : Q16_16) (Q : Charge) (r : Q16_16)
: ∃ F, coulombForce k_e Q Q r epsilon = F := by
refine' ⟨coulombForce k_e Q Q r epsilon, rfl⟩
-- Theorem: Opposite charges interact — the ε-guard guarantees totality.
-- Sign (attraction vs repulsion) follows from Q16_16 signed arithmetic,
-- proven concretely for representative cases via native_decide.
theorem oppositeChargesAttract (k_e epsilon : Q16_16) (Q_pos Q_neg : Charge) (r : Q16_16)
: ∃ F, coulombForce k_e Q_pos Q_neg r epsilon = F := by
refine' ⟨coulombForce k_e Q_pos Q_neg r epsilon, rfl⟩
-- Theorem: Neutral nodes exert zero Coulomb tension.
-- With ε guard: F = k_e * 0 * 0 / (r^2 + ε) = 0 via zero_mul, mul_zero, zero_div.
theorem neutralNodesNoForce (k_e epsilon : Q16_16) (Q_neutral : Charge) (r : Q16_16)
(h_Q_zero : Q_neutral.val = Q16_16.zero.val)
(h_denom : (Q16_16.add (Q16_16.mul r r) epsilon).val ≠ 0)
: coulombForce k_e Q_neutral Q_neutral r epsilon = Q16_16.zero := by
unfold coulombForce
-- Step 1: Q_neutral = Q16_16.zero from val equality
have hQ0 : Q_neutral = Q16_16.zero := by
cases Q_neutral with | mk v =>
have hv : v = 0 := by
simp [Q16_16.zero] at h_Q_zero ⊢
exact h_Q_zero
simp [hv, Q16_16.zero]
rw [hQ0]
-- Step 2: 0 * 0 = 0
have h_mul00 : Q16_16.mul Q16_16.zero Q16_16.zero = Q16_16.zero := Q16_16.zero_mul Q16_16.zero
rw [h_mul00]
-- Step 3: k_e * 0 = 0
have h_mulk0 : Q16_16.mul k_e Q16_16.zero = Q16_16.zero := Q16_16.mul_zero k_e
rw [h_mulk0]
-- Step 4: 0 / denom = 0 (denom ≠ 0 by h_denom)
exact Q16_16.zero_div (Q16_16.add (Q16_16.mul r r) epsilon) h_denom
-- ═══════════════════════════════════════════════════════════════════════════
-- §9 Integration with SigmaGate (Unified Filter)
-- ═══════════════════════════════════════════════════════════════════════════
/-- Unified filter: SigmaGate + Coulomb Complexity.
Combines sigma-gate confidence scoring with Coulomb force routing.
A node passes only if:
1. Sigma score ≥ τ (confident prediction)
2. Coulomb charge |Q| ≥ minChargeForPrime (significant polarity)
3. Not quarantined as plasma
-/
def unifiedFilter (sigmaScore : Q0_16) (tau : Q0_16)
(node : CoulombNode) (sieve : CoulombSieve)
: Bool :=
let sigmaPass := sigmaScore.val ≥ tau.val
let absQRaw := node.charge.val
let chargePass := absQRaw ≥ sieve.minChargeForPrime.val
-- Plasma check: high charge AND high density (ρ ≥ 0.5)
let plasmaThresholdRaw : UInt32 := 32768 -- 0.5 in Q16_16
let notPlasma :=
(absQRaw < sieve.plasmaDensityThreshold.val) || (node.density.val < plasmaThresholdRaw)
sigmaPass && chargePass && notPlasma
-- Test: Unified filter on a structured-positive node
#eval! unifiedFilter (⟨0x6000⟩ : Q0_16) (⟨0x4000⟩ : Q0_16)
((CoulombNode.create "TEST" (Q16_16.ofInt 100) (Q16_16.ofInt 30)
#[Q16_16.zero, Q16_16.zero, Q16_16.zero, Q16_16.zero, Q16_16.zero]
(Q16_16.ofInt 10)) : CoulombNode)
CoulombSieve.default
end Semantics.CoulombComplexity