- field/state.py: FieldState is now frozen+slotted; constructor copies and
enforces float32 shape (32,); advance() updated to pass raw arrays.
np.ndarray inside frozen dataclass is ref-frozen — copy() at construction
is the explicit contract boundary.
- generate/result.py: NEW — GenerationResult frozen dataclass carrying
tokens + final_state. Async variant yields tokens and exposes final_state
on completion.
- generate/stream.py: generate() now returns GenerationResult, not list[str].
vocab.edge_rotor() call replaced with:
A = vocab.get_versor_at(current.node)
B = vocab.get_versor_at(word_idx)
V = word_transition_rotor(A, B)
agenerate() updated to yield tokens and surface final_state.
- vocab/manifold.py: added get_versor_at(idx) and get_word_at(idx) indexed
accessors. VocabManifold stores points; algebra constructs operators.
normalize_to_versor() call-site in docstring clarified: callers must call
unitize_versor() (algebra construction primitive) before add(), not
normalize_to_versor() directly.
- algebra/versor.py: unitize_versor() added as the explicit construction-time
primitive. normalize_to_versor() kept but marked internal/gate-only.
Distinction encoded in docstrings and __all__.
- persona/motor.py + ingest/gate.py: SessionContext.respond() is not yet in
the repo as a separate file; gate.py docstring updated to reflect the
three-tier normalization doctrine:
unitize_versor() — algebra construction only
inject() — gate, once per raw input
normalization — forbidden in propagate/generate/vault recall
41 lines
1.6 KiB
Python
41 lines
1.6 KiB
Python
"""
|
|
FieldState — the complete cognitive field at one moment.
|
|
|
|
Invariant: versor_condition(F) < 1e-6 always.
|
|
This is checked at injection and maintained structurally by versor_apply().
|
|
|
|
FieldState is immutable by design (frozen=True, slots=True).
|
|
The np.ndarray F is copied and validated at construction — the copy() call
|
|
is the explicit contract boundary. Callers must not retain a mutable
|
|
reference to the array passed in and expect coherence.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
from dataclasses import dataclass
|
|
import numpy as np
|
|
|
|
_EXPECTED_COMPONENTS = 32
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class FieldState:
|
|
F: np.ndarray # shape (32,) float32 — Cl(4,1) multivector on the versor manifold
|
|
node: int = 0 # current node index in the vocabulary manifold
|
|
step: int = 0 # number of propagation steps taken
|
|
|
|
def __post_init__(self) -> None:
|
|
# Enforce copy + dtype + shape at the construction boundary.
|
|
# frozen=True prevents reassignment, but ndarray contents are still
|
|
# mutable via the array object; copy() here is the defence.
|
|
F = np.array(self.F, dtype=np.float32).copy()
|
|
if F.shape != (_EXPECTED_COMPONENTS,):
|
|
raise ValueError(
|
|
f"FieldState.F must have shape ({_EXPECTED_COMPONENTS},), "
|
|
f"got {F.shape}."
|
|
)
|
|
# Bypass frozen to store the validated copy.
|
|
object.__setattr__(self, "F", F)
|
|
|
|
def advance(self, new_F: np.ndarray, new_node: int) -> FieldState:
|
|
"""Return a new FieldState after one propagation step."""
|
|
return FieldState(F=new_F, node=new_node, step=self.step + 1)
|