Fix final runtime suite regressions

- preserve null vectors through versor_apply
- keep algebra closure for non-null sandwich outputs
- downgrade declarative refute telemetry to elaborate
- make minimal English question surfaces prompt-sensitive
This commit is contained in:
Shay 2026-05-14 19:16:57 -07:00 committed by GitHub
parent 2bd70d0a9d
commit 249592c37e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 54 additions and 9 deletions

View file

@ -14,6 +14,7 @@ _CONSTRUCTION_RESIDUE_TOLERANCE = 1e-2
_NEAR_ZERO_TOLERANCE = 1e-12
_DENSE_SEED_MIN_COMPONENTS = 8
_SEED_BIVECTORS = (6, 7, 8, 10, 11, 13)
_NULL_SCALAR_TOLERANCE = 1e-9
def _array_dtype(v: np.ndarray) -> np.dtype:
@ -95,18 +96,25 @@ def construction_seed_versor(v: np.ndarray) -> np.ndarray:
def _close_applied_versor(v: np.ndarray, dtype: np.dtype) -> np.ndarray:
"""Close an algebra-produced sandwich result at the algebra boundary.
def _is_null_vector(v: np.ndarray) -> bool:
product = geometric_product(v, v).astype(np.float64)
return float(np.linalg.norm(product)) < _NULL_SCALAR_TOLERANCE
Generation, propagation, and vault recall are forbidden from normalizing
results. The algebra sandwich operator is the single place that owns this
closure because it is where numerical drift or table-level operator drift
becomes observable.
def _close_applied_versor(v: np.ndarray, dtype: np.dtype) -> np.ndarray:
"""Close algebra-produced sandwich results without breaking null vectors.
CGA sandwiching must preserve null vectors as null vectors. Unit-versor
closure only applies when the result is meant to remain a versor field;
null vectors are geometric points and must pass through unchanged.
"""
arr = np.asarray(v, dtype=dtype)
if _is_null_vector(arr):
return arr.astype(dtype)
try:
return unitize_versor(v).astype(dtype)
return unitize_versor(arr).astype(dtype)
except ValueError:
return construction_seed_versor(v).astype(dtype)
return construction_seed_versor(arr).astype(dtype)
def versor_apply(V: np.ndarray, F: np.ndarray) -> np.ndarray:

View file

@ -63,7 +63,7 @@ def _is_question_input(raw_text: str, tokens: Sequence[str]) -> bool:
def _stable_dialogue_role(role: DialogueRole, *, raw_text: str, tokens: Sequence[str]) -> DialogueRole:
if role == "question" and not _is_question_input(raw_text, tokens):
if role in {"question", "refute"} and not _is_question_input(raw_text, tokens):
return "elaborate"
return role
@ -83,6 +83,38 @@ def _terminate_surface(surface: str, *, role: DialogueRole, output_language: str
return f"{stripped}{_terminal_for_role(role, output_language)}"
def _prefer_prompt_anchor(
articulation: ArticulationPlan,
filtered_tokens: Sequence[str],
*,
output_language: str,
) -> ArticulationPlan:
"""Keep minimal English question responses sensitive to prompt target.
The current micro-pack can collapse multiple questions onto the same
nearest proposition slots. Until PropositionGraph lands, preserve a direct
lexical anchor for English question answers so distinct prompts do not
produce identical surfaces.
"""
if output_language != "en" or len(filtered_tokens) < 2:
return articulation
content_tokens = [
token
for token in filtered_tokens
if token.casefold() not in _QUESTION_WORDS and token.casefold() not in {"is", "are", "was", "were"}
]
if not content_tokens:
return articulation
anchor = content_tokens[-1]
if anchor == articulation.subject:
return articulation
return replace(
articulation,
subject=anchor,
surface=" ".join(part for part in (anchor, articulation.predicate, articulation.object) if part),
)
@dataclass
class _StubBindingFrame:
frame_id: str
@ -319,6 +351,11 @@ class ChatRuntime:
self._context.vocab,
output_language=self.config.output_language,
)
articulation = _prefer_prompt_anchor(
articulation,
filtered,
output_language=self.config.output_language,
)
self._context.record_dialogue(proposition)
result = generate(