From 9be12b9a144c24debef9238be467c62612d8878e Mon Sep 17 00:00:00 2001 From: Shay Date: Thu, 14 May 2026 13:10:00 -0700 Subject: [PATCH] identity: add CharacterProfile.from_manifold() factory + TurnEvent provenance record MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CharacterProfile.from_manifold() populates traits/theological grounding directly from a live IdentityManifold — no longer orphaned. - TurnEvent is a frozen, append-only provenance record for one chat turn. Carries: turn index, dialogue role, IdentityScore, CycleCost, vault hit count, walk surface, and articulation surface. Enables full determinism tracing across every turn without mutation. - IdentityCheck.check() is unchanged in contract. --- core/physics/identity.py | 70 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/core/physics/identity.py b/core/physics/identity.py index 6a88a12f..c8907f22 100644 --- a/core/physics/identity.py +++ b/core/physics/identity.py @@ -13,7 +13,7 @@ CORE's identity is not a description of CORE. It is CORE, expressed geometricall from __future__ import annotations from dataclasses import dataclass -from typing import Dict, FrozenSet, Tuple +from typing import Dict, FrozenSet, Optional, Tuple @dataclass(frozen=True) @@ -74,8 +74,74 @@ class CharacterProfile: This is not the identity itself. The identity is geometric. The CharacterProfile is a representation of it — a map, not the terrain. """ - traits: Dict[str, str] # trait name → description + traits: Dict[str, str] # trait name → description drive_summaries: Dict[str, float] # drive name → current gradient magnitude fatigue_index: float boundary_commitments: Tuple[str, ...] theological_grounding: Dict[str, str] # axis name → scriptural/philosophical note + + @classmethod + def from_manifold( + cls, + manifold: IdentityManifold, + drive_summaries: Optional[Dict[str, float]] = None, + fatigue_index: float = 0.0, + ) -> "CharacterProfile": + """Populate a CharacterProfile directly from a live IdentityManifold. + + Derives traits and theological grounding from the manifold's value_axes + so the profile always reflects the current geometric identity — not a + manually maintained parallel description. + """ + traits: Dict[str, str] = {} + theological_grounding: Dict[str, str] = {} + for axis in manifold.value_axes: + traits[axis.name] = ( + f"Fixed geometric direction {axis.direction} " + f"in versor manifold — non-negotiable." + ) + if axis.theological_note: + theological_grounding[axis.name] = axis.theological_note + + return cls( + traits=traits, + drive_summaries=drive_summaries or { + axis.name: 0.0 for axis in manifold.value_axes + }, + fatigue_index=fatigue_index, + boundary_commitments=tuple(sorted(manifold.boundary_ids)), + theological_grounding=theological_grounding, + ) + + +@dataclass(frozen=True) +class TurnEvent: + """Append-only provenance record for one chat turn. + + Every field is deterministically derivable from the turn's execution. + No inference, no approximation — each value is the exact output of the + corresponding operator as it ran. The log of TurnEvents over a session + is a complete, reproducible trace of the model's internal state evolution. + + Fields: + turn — zero-based turn index within the session + input_tokens — tokens as ingested (after OOV filtering) + walk_surface — syntactically guarded token sequence from manifold walk + articulation_surface — proposition-level surface from realize() + dialogue_role — DialogueRole classification for this turn + identity_score — IdentityScore from IdentityCheck (None if not run) + cycle_cost_total — total CycleCost.total for this turn + vault_hits — number of vault recall hits that fired during generate() + versor_condition — versor_condition(final_state.F) after generation + flagged — True if identity_score.flagged (shortcut for filtering) + """ + turn: int + input_tokens: Tuple[str, ...] + walk_surface: str + articulation_surface: str + dialogue_role: str + identity_score: Optional[IdentityScore] + cycle_cost_total: float + vault_hits: int + versor_condition: float + flagged: bool