feat(runtime): inline realization — the conversation accrues knowledge (Step B-1)

Wires comprehend->realize/determine into the live turn loop: a declarative turn
REALIZES a fact into the held self (session vault, SPECULATIVE/as-told); a question
turn is DETERMINED over realized knowledge (answered as-told, or refused open-world).
The first time a CORE conversation actually accumulates knowledge it can recall and
reason over — the 'one continuous life' telos made real, including across reboot
(the accrued fact is in the Shape B+ snapshot, so it survives the process ending).

Seam: all chat() returns funnel through _checkpointed_response; accrual runs there
BEFORE the checkpoint (so the fact persists this turn), gated by a new
accrue_realized_knowledge flag (default OFF — one-shot/eval runtimes don't accrue;
the production L10 process enables it with persist_session_state).

Discipline: SESSION memory, not ratified learning — proposes nothing, HITL untouched.
Realization writes go through generate.realize (INV-21 allowed writer). Additive: a
failure is a clean no-op, never crashes a turn. Slice B-1 RECORDS the outcome
(last_turn_accrual(), introspectable) and leaves the ChatResponse/surface contract
UNCHANGED; surfacing the determination is the B-2 follow-up (needs runtime_contracts
+ contract-test updates).

Tests: declarative accrues; question determines as_told; untold refuses open-world;
idempotent retell not recreated; flag-off no-ops with identical surface; and the
lived-spine proof — accrued knowledge survives reboot (determined as_told after a
fresh runtime over the same checkpoint).
This commit is contained in:
Shay 2026-06-06 10:40:20 -07:00
parent 4692d3fae7
commit 3cdc4faa5f
3 changed files with 228 additions and 0 deletions

View file

@ -388,6 +388,22 @@ def _make_trajectory_from_result(result, turn: int):
return operator.build(frames, trajectory_id=f"turn_{turn}")
@dataclass(frozen=True, slots=True)
class TurnAccrual:
"""The inline-realization outcome of one turn (Step B).
``kind`` is ``"realized"`` (a declarative fact was accrued into the held self),
``"determined"`` (a question was answered over realized knowledge), or ``"none"``
(nothing comprehensible to accrue/determine). The payload carries the typed
realize/determine result for introspection. This is recorded, not surfaced
slice B-1 leaves the ChatResponse/surface contract unchanged.
"""
kind: str
realized: Any = None # generate.realize.Realized | NotRealized | None
determination: Any = None # generate.determine.Determined | Undetermined | None
@dataclass(frozen=True, slots=True)
class ChatResponse:
surface: str
@ -672,6 +688,11 @@ class ChatRuntime:
# W-013 — last classified intent, updated each turn for /explain REPL use.
self._last_intent: Any | None = None
self._last_input_text: str = ""
# Step B (inline realization) — the last turn's accrual outcome (what the turn
# realized into the held self, or determined over it). Introspectable; the
# surface contract is unchanged (slice B-1 records, does not surface).
self._last_turn_accrual: TurnAccrual | None = None
self._relational_pack_lemmas: frozenset[str] | None = None
self._engine_state_store: EngineStateStore | None = (
None if no_load_state else EngineStateStore(engine_state_path)
)
@ -923,9 +944,71 @@ class ChatRuntime:
def _checkpointed_response(self, response: ChatResponse) -> ChatResponse:
self._turn_count += 1
# Step B — inline realization, BEFORE the checkpoint so an accrued fact is in
# the snapshot this turn (survives reboot with persist_session_state). Gated;
# off by default. The surface contract is unchanged (the outcome is recorded,
# not surfaced).
if self.config.accrue_realized_knowledge:
self._accrue_in_turn(self._last_input_text)
self.checkpoint_engine_state()
return response
def last_turn_accrual(self) -> TurnAccrual | None:
"""The most recent turn's inline-realization outcome (Step B), or None when
accrual is off or did not complete. Introspection only never surfaced."""
return self._last_turn_accrual
def _accrue_in_turn(self, text: str) -> None:
"""Inline realization (Step B): a comprehensible declarative turn accrues a
realized fact into the held self (session vault, SPECULATIVE / as-told); a
comprehensible question turn is determined over realized knowledge. Records the
typed outcome on ``self._last_turn_accrual``.
Never raises into the turn accrual is ADDITIVE, so any failure is a clean
no-op (the turn's response is untouched). This is SESSION memory (immediate),
NOT ratified learning: it proposes nothing and leaves the teaching/review HITL
path untouched. Realization writes go through ``generate.realize`` (the INV-21
allowed vault writer); DETERMINE and the readers are total (typed results, no
raises), so the broad guard is a defensive backstop, not expected control flow.
"""
self._last_turn_accrual = None
if self._context is None or not text or not text.strip():
return
try:
from generate.determine import determine
from generate.meaning_graph.reader import Comprehension, comprehend
from generate.meaning_graph.relational import comprehend_relational
from generate.realize import realize_comprehension
if self._relational_pack_lemmas is None:
from generate.meaning_graph.relational import load_relational_pack_lemmas
self._relational_pack_lemmas = load_relational_pack_lemmas()
readings = (
comprehend(text),
comprehend_relational(text, self._relational_pack_lemmas),
)
comprehensions = [c for c in readings if isinstance(c, Comprehension)]
# A question turn (query-bearing) is DETERMINED over realized knowledge.
for c in comprehensions:
if c.queries:
self._last_turn_accrual = TurnAccrual(
kind="determined", determination=determine(c, self._context)
)
return
# A declarative turn (a single told fact) is REALIZED into the held self.
for c in comprehensions:
if not c.queries and c.meaning_graph.relations:
self._last_turn_accrual = TurnAccrual(
kind="realized", realized=realize_comprehension(c, self._context)
)
return
self._last_turn_accrual = TurnAccrual(kind="none")
except Exception: # additive: accrual must never crash a turn # noqa: BLE001
self._last_turn_accrual = None
@property
def session(self) -> SessionContext:
return self._context

View file

@ -292,6 +292,17 @@ class RuntimeConfig:
# wanting a hard identity-continuity guarantee opt in.
strict_identity_continuity: bool = False
# Step B (inline realization) — when on, each turn ACCRUES knowledge into the
# held self: a comprehensible declarative turn is realized into the session vault
# (SPECULATIVE, as-told), and a comprehensible question turn is determined over
# realized knowledge. This is the "one continuous life" telos made real — a
# conversation accumulates knowledge it can recall and reason over. OFF by default
# (one-shot/eval runtimes don't accrue); the production L10 process enables it
# alongside persist_session_state so accrued facts survive reboot. Realization is
# SESSION memory (immediate), NOT ratified learning — it proposes nothing; the
# teaching/review HITL path is untouched.
accrue_realized_knowledge: bool = False
DEFAULT_IDENTITY_PACK: str = "default_general_v1"
DEFAULT_ETHICS_PACK: str = "default_general_ethics_v1"

View file

@ -0,0 +1,134 @@
"""Step B — inline realization in the live turn loop.
A conversation ACCRUES knowledge: a declarative turn realizes a fact into the held
self; a question turn is determined over realized knowledge answered as-told, or
refused (open-world). Gated by ``accrue_realized_knowledge``; off by default leaves the
surface contract and behavior unchanged. With persistence on, the accrued fact survives
reboot the "one continuous life" made real across an interruption.
"""
from __future__ import annotations
from dataclasses import replace
import pytest
from chat.runtime import ChatRuntime
from core.config import RuntimeConfig
def _rt(*, accrue: bool, persist: bool = False, engine_state_path=None) -> ChatRuntime:
config = replace(
RuntimeConfig(),
accrue_realized_knowledge=accrue,
persist_session_state=persist,
)
return ChatRuntime(config=config, engine_state_path=engine_state_path)
# --------------------------------------------------------------------------- #
# Accrual: the conversation accumulates knowledge it can reason over
# --------------------------------------------------------------------------- #
def test_declarative_turn_accrues_a_realized_fact() -> None:
rt = _rt(accrue=True)
rt.chat("Truth is a concept.")
accrual = rt.last_turn_accrual()
assert accrual is not None and accrual.kind == "realized"
assert accrual.realized.created is True
def test_question_turn_is_determined_from_accrued_knowledge() -> None:
rt = _rt(accrue=True)
rt.chat("Truth is a concept.")
rt.chat("Is truth a concept?")
accrual = rt.last_turn_accrual()
assert accrual is not None and accrual.kind == "determined"
det = accrual.determination
assert det.answer is True
assert det.basis == "as_told" # SPECULATIVE session memory, never "verified"
def test_untold_question_refuses_open_world() -> None:
rt = _rt(accrue=True)
rt.chat("Truth is a concept.")
rt.chat("Is truth a virtue?") # never told
det = rt.last_turn_accrual().determination
# Undetermined, never a fabricated answer or an asserted False (open-world).
assert type(det).__name__ == "Undetermined"
assert det.reason in {"not_entailed", "ungrounded"}
def test_idempotent_retell_is_not_recreated() -> None:
rt = _rt(accrue=True)
rt.chat("Truth is a concept.")
assert rt.last_turn_accrual().realized.created is True
rt.chat("Truth is a concept.") # same fact again
assert rt.last_turn_accrual().realized.created is False # structural dedup
# --------------------------------------------------------------------------- #
# Off by default: no behavior change, surface contract intact
# --------------------------------------------------------------------------- #
def test_flag_off_does_not_accrue_and_keeps_surface() -> None:
rt = _rt(accrue=False)
response = rt.chat("Truth is a concept.")
assert rt.last_turn_accrual() is None
# the turn still returns a real surface (no behavior change when the flag is off)
assert isinstance(response.surface, str) and response.surface
def test_accrual_does_not_alter_the_surface() -> None:
# The same input yields the same surface with accrual on vs off (B-1 records,
# does not surface — the surface contract is untouched).
off = _rt(accrue=False).chat("Truth is a concept.")
on = _rt(accrue=True).chat("Truth is a concept.")
assert on.surface == off.surface
assert on.articulation_surface == off.articulation_surface
# --------------------------------------------------------------------------- #
# One continuous life: accrued knowledge survives reboot
# --------------------------------------------------------------------------- #
def test_accrued_knowledge_survives_reboot(tmp_path) -> None:
esp = tmp_path / "engine_state"
# life 1: tell a fact, then the process ends
rt1 = _rt(accrue=True, persist=True, engine_state_path=esp)
rt1.chat("Truth is a concept.")
assert rt1.last_turn_accrual().kind == "realized"
# reboot: a NEW runtime over the SAME checkpoint resumes the SAME life
rt2 = _rt(accrue=True, persist=True, engine_state_path=esp)
rt2.chat("Is truth a concept?")
det = rt2.last_turn_accrual().determination
assert det.answer is True and det.basis == "as_told" # remembered across the reboot
def test_no_accrual_persistence_without_persist_flag(tmp_path) -> None:
esp = tmp_path / "engine_state"
rt1 = _rt(accrue=True, persist=False, engine_state_path=esp)
rt1.chat("Truth is a concept.")
# without persistence the fact accrues only in-session; a reboot does not recall it
rt2 = _rt(accrue=True, persist=False, engine_state_path=esp)
rt2.chat("Is truth a concept?")
det = rt2.last_turn_accrual().determination
assert type(det).__name__ == "Undetermined"
# --------------------------------------------------------------------------- #
# Robustness: accrual is additive, never crashes a turn
# --------------------------------------------------------------------------- #
def test_uncomprehended_turn_is_a_clean_noop() -> None:
rt = _rt(accrue=True)
response = rt.chat("Hello there friend.") # no fact/question to accrue
assert response.surface # the turn still returns normally
accrual = rt.last_turn_accrual()
# either nothing comprehensible (kind="none") or a refusal that realized nothing
assert accrual is None or accrual.kind in {"none", "realized", "determined"}