identity: add CharacterProfile.from_manifold() factory + TurnEvent provenance record

- 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.
This commit is contained in:
Shay 2026-05-14 13:10:00 -07:00
parent 541b1646b2
commit 9be12b9a14

View file

@ -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