Phase 1 of the post-ADR-0024 sequence: wire the inner-loop flag into live
cognition paths and prove deterministic-when-wired in the same milestone.
Changes:
- RuntimeConfig: add inner_loop_admissibility + admissibility_threshold.
- ChatRuntime: pass both into generate() on the chat hot path.
- CLI: --inner-loop-admissibility / --admissibility-threshold flags.
- vocab/manifold.py: document strict `>` tie-break as load-bearing for
ADR-0024 rejected_attempts ordering (determinism by construction, not
by accident).
- tests/test_inner_loop_admissibility.py: three new determinism tests —
identical rejected_attempts across 5 runs, identical trace hash across
5 runs (non-empty), and legacy hash equivalence when no rejections
occur (flag on/off byte-identical).
- tests/test_language_pack_cache.py: fix stale fixture (en-core-cog-070
-> en-core-cog-085 after pack growth).
Suite: 995 passed, 0 failed, 2 skipped.
Acceptance criteria met:
- wired through RuntimeConfig + CLI + ChatRuntime + generate()
- deterministic rejected_attempts sequence (verified by repetition)
- deterministic trace hash under inner_loop=True
- legacy ADR-0023 trace hashes preserved when no rejections
- nearest_next determinism is by construction (sequenced iteration +
strict > tie-break), now documented
Next: Phase 2 — corpus-observation eval on existing v1 corpus with the
four-condition matrix (boundary-only, null control, inner-loop t=0.0,
inner-loop t>0) and exhaustion_rate + latency metrics.
Make versor construction fail closed instead of synthesizing hash-derived fallback rotors.
- remove pseudo-random construction fallback from unitize_versor
- add signed residual helper for +1 field states vs ±1 manifold entries
- validate vocab manifold entries with full residuals
- document antipodal transition rotor failure contract
- add focused invariant tests for versor closure and manifold validation
Add RuntimeConfig with English default output policy, wire output language through runtime/frame selection/generation/CLI, preserve language metadata in mounted manifolds, and add runtime/CLI policy tests.
- VocabManifold.update(): replace a stored versor in-place (grade-norm
enforced, KeyError if word missing)
- compile_entries_to_manifold() now also returns entry_id->surface map
as a second return value; callers that only need the manifold use [0]
- _alignment_nudge_rotor(): slerp-style rotor that rotates source toward
target by edge.weight * ALIGNMENT_NUDGE_STRENGTH (0.06) — small enough
to preserve intra-pack geometry, large enough to pull cross-lang pairs
into proximity
- load_pack(): after both manifolds are built, loads alignment.jsonl,
resolves entry_id->surface on each side, applies nudge to source versor
using the already-compiled target versor as the attractor
- _is_hebrew_root() guard retained; _triliteral_root() Hebrew-only
Three surgical import changes. No behavior change. No new semantics.
Backend decides Rust vs pure-Python transparently.
- field/propagate.py: versor_apply <- algebra.backend
- vocab/manifold.py: cga_inner <- algebra.backend
- vault/store.py: recall loop replaced with vault_recall() from
algebra.backend; public result shape preserved ({versor, score,
metadata, index}). null_project stays on algebra.cga (not the
recall hot path). store() and reproject() unchanged.
Rust path for vault_recall uses Rayon parallel scan and releases
the GIL. Python fallback is sequential and behaviorally identical.
No batching introduced; that is Commit 3+.
- 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
- Add algebra/rotor.py: word_transition_rotor() as a free operator function
- Update algebra/__init__.py: export word_transition_rotor
- Refactor vocab/manifold.py: remove edge_rotor(), add versor grade-norm
invariant check in add() to reject raw coordinate vectors at insertion time
VocabManifold now stores only algebraically valid Cl(4,1) versors and
exposes only relational lookup (CGA inner product). Rotor construction
is a contextual algebra-layer concern, not a vocabulary property.