Restore FieldState slots in determinism proof

This commit is contained in:
Shay 2026-05-13 14:26:24 -07:00
parent 4e7c29b84a
commit f8113a38ba
2 changed files with 5 additions and 3 deletions

View file

@ -4,7 +4,7 @@ FieldState — the complete cognitive field at one moment.
Invariant: versor_condition(F) < 1e-6 always. Invariant: versor_condition(F) < 1e-6 always.
This is checked at injection and maintained structurally by versor_apply(). This is checked at injection and maintained structurally by versor_apply().
FieldState is immutable by design (frozen=True). FieldState is immutable by design (frozen=True, slots=True).
The np.ndarray F is copied and validated at construction the copy() call The np.ndarray F is copied and validated at construction the copy() call
is the explicit contract boundary. Callers must not retain a mutable is the explicit contract boundary. Callers must not retain a mutable
reference to the array passed in and expect coherence. reference to the array passed in and expect coherence.
@ -17,7 +17,7 @@ import numpy as np
_EXPECTED_COMPONENTS = 32 _EXPECTED_COMPONENTS = 32
@dataclass(frozen=True) @dataclass(frozen=True, slots=True)
class FieldState: class FieldState:
F: np.ndarray # shape (32,) float32 — Cl(4,1) multivector on the versor manifold F: np.ndarray # shape (32,) float32 — Cl(4,1) multivector on the versor manifold
node: int = 0 # current node index in the vocabulary manifold node: int = 0 # current node index in the vocabulary manifold
@ -28,6 +28,7 @@ class FieldState:
# Enforce copy + dtype + shape at the construction boundary. # Enforce copy + dtype + shape at the construction boundary.
# frozen=True prevents reassignment, but ndarray contents are still # frozen=True prevents reassignment, but ndarray contents are still
# mutable via the array object; copy() here is the defence. # mutable via the array object; copy() here is the defence.
# slots=True closes __dict__ so no incidental attributes can be added.
F = np.array(self.F, dtype=np.float32).copy() F = np.array(self.F, dtype=np.float32).copy()
if F.shape != (_EXPECTED_COMPONENTS,): if F.shape != (_EXPECTED_COMPONENTS,):
raise ValueError( raise ValueError(

View file

@ -63,6 +63,7 @@ import hashlib
import json import json
import struct import struct
from copy import deepcopy from copy import deepcopy
from dataclasses import fields
from typing import Any from typing import Any
import numpy as np import numpy as np
@ -498,7 +499,7 @@ class TestDET10FieldStateIsSingleMultivector:
"""FieldState must not hold a copy of the input tokens.""" """FieldState must not hold a copy of the input tokens."""
state = inject(["in", "the", "beginning"], _PinVocab()) state = inject(["in", "the", "beginning"], _PinVocab())
# No attribute should store the original token list # No attribute should store the original token list
for attr in vars(state).values(): for attr in (getattr(state, field.name) for field in fields(state)):
if isinstance(attr, (list, tuple)): if isinstance(attr, (list, tuple)):
# Allow small metadata tuples but not token-length sequences # Allow small metadata tuples but not token-length sequences
assert len(attr) <= 4, ( assert len(attr) <= 4, (