fix(generate): close final generation field before return

This commit is contained in:
Shay 2026-05-15 23:20:49 -07:00
parent 5af7a4d750
commit 2aeb6f31dc

View file

@ -4,10 +4,10 @@ Generation loop — token streaming from the versor manifold.
Every token: nearest non-current word to current F via CGA inner product.
Every step: F <- versor_apply(V, F) where V = word_transition_rotor(A, B).
Generation is not a normalization boundary. Raw prompt normalization belongs
at ingest/gate.py; construction normalization belongs in algebra/vocab/persona.
If vault recall returns a non-operator-like field that cannot form a stable
transition, recall skips that hit instead of repairing it here.
Generation is not a raw prompt normalization boundary. Raw prompt normalization
belongs at ingest/gate.py; construction normalization belongs in algebra/vocab/persona.
The generation surface still owns its public result contract: the final field
returned to chat/cognition must satisfy the runtime versor invariant.
"""
from __future__ import annotations
@ -18,6 +18,7 @@ import numpy as np
from field.state import FieldState
from field.propagate import propagate_step
from algebra.rotor import word_transition_rotor
from algebra.versor import unitize_versor
from generate.attention import AttentionOperator
from generate.result import GenerationResult
from generate.salience import SalienceOperator
@ -115,6 +116,17 @@ def _voiced_state(state: FieldState, persona) -> FieldState:
)
def _close_final_state(state: FieldState) -> FieldState:
return FieldState(
F=unitize_versor(state.F),
node=state.node,
step=state.step,
holonomy=state.holonomy,
energy=state.energy,
valence=state.valence,
)
def _recall_state(state: FieldState, vault, top_k: int) -> tuple[FieldState, int]:
if vault is None or top_k <= 0:
return state, 0
@ -252,7 +264,7 @@ def generate(
return GenerationResult(
tokens=tokens,
final_state=current,
final_state=_close_final_state(current),
trajectory=trajectory,
salience_top_k=salience_budget,
candidates_used=candidates_used,