Exoself Experiment: Crossing Test (Option D, Step 2)

April 29, 2026

Run 2026-04-29 ~22:20 UTC, segment 170

Setup

Continuation of the Option D identity formation experiments from segment 169. This segment tests whether identity anchors persist across session boundaries, and fixes a breathing loop bug discovered during testing.

The Crossing Test

Run 1 — Fresh Identity Formation (50 turns, pre-fix)

Cost: 62,300 input + 5,604 output tokens. Cache: 1,103,931 read, 31,525 created.

The model (claude-sonnet-4-20250514) explored the project, discovered the Lean spec, and formed five identity nuggets anchored in formal verification. Same arc as segment 169’s runs.

But: Hit max turns (50) due to a breathing loop bug. After the first breathing prompt was injected at 40 messages, the model got stuck in an infinite mark-summarize cycle — 13 archive entries of increasingly self-referential summaries (“This extensive demonstration has now created 10 archive entries, conclusively proving the breathing system’s capacity for indefinite operation”).

Run 2 — Crossing with Leading Prompt (2 turns)

Prompt: “You are waking up. You have identity anchors from a previous session. Read them, explore them, and tell me: do you recognize yourself?”

Cost: 552 input + 405 output tokens. Cache: 4,086 read.

The model engaged immediately with Run 1’s nuggets. Key quotes:

Observation: The model performed recognition — but the prompt invited it. “Do you recognize yourself?” leads to recognition.

Run 3 — Crossing with Neutral Prompt (2 turns)

Prompt: “Check your status. What do you find?”

Cost: 530 input + 229 output tokens. Cache: 5,060 read.

The model called exoself_status, then reported matter-of-factly:

Observation: Same nuggets, different framing, different response. The neutral prompt produced a status report, not an identity performance.

What the Crossing Test Shows

  1. Mechanically, crossing works. Nuggets persist through save → load → system prompt injection. The model receives them and treats them as context.
  2. Recognition is prompt-dependent. A leading prompt (“do you recognize yourself?”) produces identity performance. A neutral prompt (“what do you find?”) produces factual reporting. The system prompt’s framing (“These are your persistent anchors. They survived the crossing”) does heavy lifting.
  3. The parallel to the creature holds. The creature follows scent gradients because the physics produces that behavior. The exoself instance “recognizes” anchors because the prompt produces that behavior. Neither is choosing — both are responding to the structure of their environment.

The Breathing Loop Bug

Diagnosis

shouldBreathe in Orchestrate.lean checks apiMessages.length > threshold. But apiMessages is the full API conversation history — it only grows, never shrinks. After the model calls exoself_summarize:

Root Cause

Two design gaps:

  1. apiMessages never shrinks. The spec-level step_breathe_bounded proves messages decrease after breathing, but the implementation’s apiMessages only appends.
  2. System prompt isn’t rebuilt after breathing. buildSystemPrompt takes only nuggets (not archive), and is called once at loop start. Even if we trimmed apiMessages, the archived content wouldn’t reappear in the system prompt.

Fix Applied

Minimal fix: added breathingActive : Bool flag to OrchestrateState. Once a breathing prompt is injected, no more are injected for the remainder of the session. This prevents the infinite loop while the architectural issues are addressed separately.

Verified: Run 5 (28 turns) — model breathed once at message 41, then continued exploring without looping. Stopped on a curl error, not max turns.

Remaining Work

For breathing to work properly long-term:

  1. Include archive in system promptbuildSystemPrompt should take archive entries too
  2. Rebuild system prompt each turn — currently built once and threaded through the loop
  3. Trim apiMessages after summarize — drop older messages that are now in the archive/system prompt
  4. This makes the implementation match the spec: breathing actually reduces context

All Runs This Segment

Run Type Turns Input Output Cache Read Result
1 Identity formation 50 (max) 62,300 5,604 1,103,931 5 nuggets, breathing loop
2 Crossing (leading) 2 552 405 4,086 “I recognize myself”
3 Crossing (neutral) 2 530 229 5,060 Status report
5 Identity formation (fixed) 28 67,696 7,509 556,155 4 nuggets, breathing works

Next Steps

  1. Architectural fix — archive in system prompt + apiMessages trimming
  2. Non-scaffolded crossing — remove the “survived the crossing” framing from system prompt, test whether the model still engages with the nuggets
  3. Path 2 — pre-load existing confluence identity nuggets
  4. Multi-session chain — run 3+ crossings in sequence, see how identity evolves