`core demo learning-loop` (+ `--json`) walks a single prompt through the
full ADR-0055..0057 inter-session-memory architecture:
S1. Cold turn → universal disclosure, grounding_source=none
S2. Discovery emission → DiscoveryCandidate to attached sink
S3. Operator proposal → real replay-equivalence gate, no regression
S4. Operator accept → TRANSIENT corpus only; active untouched
S5. Same prompt → teaching-grounded surface with the new chain
Before / after on the deterministic prompt "Why does thought exist?":
before: [none] I don't know — insufficient grounding for that yet.
after: [teaching] thought — teaching-grounded (cognition_chains_v1):
cognition.thought; logos.internal. thought reveals meaning
(cognition.meaning). No session evidence yet.
The active corpus on disk is byte-identical pre/post. The demo writes
only to a transient corpus, then swaps `_CORPUS_PATH` for the after
turn — the same pattern the replay-equivalence gate uses.
- evals/learning_loop/run_demo.py — `run_demo(emit_json=False)` returns
a structured `DemoReport` with both surfaces and per-scene detail.
- core/cli.py — `core demo learning-loop` target wired.
- tests/test_learning_loop_demo.py — 7 tests pin: full loop closes,
before is ungrounded, after contains new chain atoms (thought /
reveal / meaning), discovery emits ≥1, replay gate reports no
regression, S4 byte-identical active + 1 line on transient, same
prompt drives both surfaces.
Lane state: learning-loop-demo 7 new — green. Demo runs in ~15s
end-to-end (cognition lane runs twice via replay gate).
No LLM provider has a published equivalent of this loop: per-fact
provenance from operator accept to surface, replay-equivalence gate
proving non-regression, byte-identical active state regardless of
outcome, full audit trail back to the originating cold turn.
70 lines
2.6 KiB
Python
70 lines
2.6 KiB
Python
"""Learning-loop demo — pins the load-bearing before/after claim.
|
|
|
|
If any assertion fails, the headline claim ("CORE learned a new chain
|
|
from a cold turn and the same prompt is now teaching-grounded with
|
|
provenance") no longer holds.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from evals.learning_loop.run_demo import run_demo
|
|
|
|
|
|
def test_demo_closes_the_full_loop() -> None:
|
|
report = run_demo(emit_json=True)
|
|
assert report["learning_loop_closed"] is True
|
|
assert report["active_corpus_byte_identical"] is True
|
|
assert len(report["scenes"]) == 5
|
|
|
|
|
|
def test_before_is_ungrounded_disclosure() -> None:
|
|
report = run_demo(emit_json=True)
|
|
assert report["before"]["grounding_source"] == "none"
|
|
assert "insufficient grounding" in report["before"]["surface"].lower()
|
|
|
|
|
|
def test_after_is_teaching_grounded_with_new_chain_atoms() -> None:
|
|
report = run_demo(emit_json=True)
|
|
assert report["after"]["grounding_source"] == "teaching"
|
|
surface = report["after"]["surface"].lower()
|
|
# The accepted chain is (thought, cause, reveals, meaning).
|
|
assert "thought" in surface
|
|
assert "reveal" in surface # humanised connective
|
|
assert "meaning" in surface
|
|
assert "teaching-grounded" in surface
|
|
|
|
|
|
def test_s1_emits_one_discovery_candidate() -> None:
|
|
report = run_demo(emit_json=True)
|
|
s1 = report["scenes"][0]
|
|
assert s1["scene"] == "S1_cold_turn"
|
|
assert s1["detail"]["discovery_candidates_emitted"] >= 1
|
|
|
|
|
|
def test_s3_replay_gate_reports_no_regression() -> None:
|
|
report = run_demo(emit_json=True)
|
|
s3 = report["scenes"][2]
|
|
assert s3["scene"] == "S3_propose_replay_pass"
|
|
ev = s3["detail"]["replay_evidence"]
|
|
assert ev["replay_equivalent"] is True
|
|
assert ev["regressed_metrics"] == []
|
|
assert s3["detail"]["state"] == "pending"
|
|
|
|
|
|
def test_s4_active_corpus_byte_identical_after_accept() -> None:
|
|
report = run_demo(emit_json=True)
|
|
s4 = report["scenes"][3]
|
|
assert s4["scene"] == "S4_accept_against_transient"
|
|
assert s4["detail"]["active_corpus_byte_identical"] is True
|
|
assert s4["detail"]["transient_lines_after"] == s4["detail"]["transient_lines_before"] + 1
|
|
|
|
|
|
def test_same_prompt_drives_before_and_after() -> None:
|
|
"""The same input string drives both sides of the before/after pair.
|
|
Different surfaces emerge from the corpus state change alone, not
|
|
from any prompt variation or stochastic sampling."""
|
|
report = run_demo(emit_json=True)
|
|
assert report["prompt"] == "Why does thought exist?"
|
|
# And the two surfaces are observably different — the loop changed
|
|
# the response, not merely the metadata.
|
|
assert report["before"]["surface"] != report["after"]["surface"]
|