Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef5e0ec439 | ||
|
|
9f55394639 |
146
evennia-mind-palace.md
Normal file
146
evennia-mind-palace.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Evennia as Agent Mind Palace — Spatial Memory Architecture
|
||||
|
||||
Issue #567 is the missing why behind the Evennia lane. The Tower Game is the demo, but the actual target is a spatial memory substrate where Timmy can visit the right room, see the right objects, and load only the context needed for the current task.
|
||||
|
||||
The existing Evennia work in `timmy-home` already proves the body exists:
|
||||
- `reports/production/2026-03-28-evennia-world-proof.md` proves the local Evennia world, first room graph, telnet roundtrip, and Hermes/MCP control path.
|
||||
- `reports/production/2026-03-28-evennia-training-baseline.md` proves Hermes session IDs can align with Evennia telemetry and replay/eval artifacts.
|
||||
- `specs/evennia-mind-palace-layout.md` and `specs/evennia-implementation-and-training-plan.md` already define the first rooms and objects.
|
||||
|
||||
This document turns those pieces into a memory architecture: one room that injects live work context, one object that exposes a mutable fact, and one burn-cycle packet that tells Timmy what to do next.
|
||||
|
||||
## GrepTard Memory Layers as Spatial Primitives
|
||||
|
||||
| Layer | Spatial primitive | Hermes equivalent | Evennia mind-palace role |
|
||||
| --- | --- | --- | --- |
|
||||
| L1 | Rooms and thresholds | Static project context | The room itself defines what domain Timmy has entered and what baseline context loads immediately. |
|
||||
| L2 | Objects, NPC attributes, meters | Mutable facts / KV memory | World state lives on inspectable things: ledgers, characters, fires, relationship values, energy meters. |
|
||||
| L3 | Archive shelves and chronicles | Searchable history | Prior events become searchable books, reports, and proof artifacts inside an archive room. |
|
||||
| L4 | Teaching NPCs and rituals | Procedural skills | The right NPC or room interaction teaches the right recipe without loading every skill into working memory. |
|
||||
| L5 | Movement and routing | Retrieval logic | Choosing the room is choosing the retrieval path; movement decides what context gets loaded now. |
|
||||
|
||||
## Spatial Retrieval Architecture
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Timmy burn cycle] --> B[Enter Hall of Knowledge]
|
||||
B --> C[Ambient issue board]
|
||||
B --> D[The Ledger]
|
||||
B --> E[/status forge]
|
||||
C --> F[Current Gitea issue topology]
|
||||
D --> G[One mutable fact from durable memory]
|
||||
E --> H[Repo + branch + blockers]
|
||||
F --> I[Selective action prompt]
|
||||
G --> I
|
||||
H --> I
|
||||
I --> J[Act in the correct room or hand off to another room]
|
||||
```
|
||||
|
||||
The Hall of Knowledge is not an archive dump. It is a selective preload surface.
|
||||
|
||||
On room entry Timmy should receive only:
|
||||
1. the currently active Gitea issues relevant to the present lane,
|
||||
2. one mutable fact from durable memory that changes the next action,
|
||||
3. the current Timmy burn cycle packet (repo, branch, blockers, current objective).
|
||||
|
||||
That gives Timmy enough context to act without rehydrating the entire project or every prior transcript.
|
||||
|
||||
## Mapping the 16 tracked Evennia issues to mind-palace layers
|
||||
|
||||
These are the 16 issues explicitly named in issue #567. Some are now closed, but they still map the architecture surface we need.
|
||||
|
||||
| Issue | State | Layer | Spatial role | Why it matters |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| #508 — [P0] Tower Game — contextual dialogue (NPCs recycle 15 lines forever) | closed | L4 | Dialogue tutor NPCs | Contextual dialogue is procedural behavior attached to the right NPC in the right room. |
|
||||
| #509 — [P0] Tower Game — trust must decrease, conflict must exist | closed | L2 | Mutable relationship state | Trust, conflict, and alliance are inspectable changing world facts. |
|
||||
| #510 — [P0] Tower Game — narrative arc (tick 200 = tick 20) | closed | L3 | Archive chronicle | Without searchable history, the world cannot accumulate narrative memory. |
|
||||
| #511 — [P0] Tower Game — energy must meaningfully constrain | open | L2 | Mutable world meter | Energy belongs in visible world state, not hidden prompt assumptions. |
|
||||
| #512 — [P1] Sonnet workforce — full end-to-end smoke test | open | L3 | Proof shelf | Proof artifacts should live in the archive so Timmy can revisit what really worked. |
|
||||
| #513 — [P1] Tower Game — world events must affect gameplay | open | L2 | Event-reactive room state | A room that never changes cannot carry durable meaning. |
|
||||
| #514 — [P1] Tower Game — items that change the world | open | L2 | Interactive objects | Objects should alter world state and teach consequences through interaction. |
|
||||
| #515 — [P1] Tower Game — NPC-NPC relationships | open | L2 | Social graph in-world | Relationships should persist on characters rather than disappearing into transcripts. |
|
||||
| #516 — [P1] Tower Game — Timmy richer dialogue + internal monologue | closed | L4 | Inner-room teaching patterns | Timmy's own inner behavior is part of the procedural layer. |
|
||||
| #517 — [P1] Tower Game — NPCs move between rooms with purpose | open | L5 | Movement-driven retrieval | Purposeful movement is retrieval logic made spatial. |
|
||||
| #534 — [BEZ-P0] Fix Evennia settings on 104.131.15.18 — remove bad port tuples, DB is ready | open | L1 | Runtime threshold | The threshold has to boot cleanly before any room can carry memory. |
|
||||
| #535 — [BEZ-P0] Install Tailscale on Bezalel VPS (104.131.15.18) for internal networking | open | L1 | Network threshold | Static network reachability defines which houses can be visited. |
|
||||
| #536 — [BEZ-P1] Create Bezalel Evennia world with themed rooms and characters | open | L1 | First room graph | Themed rooms and characters are the static scaffold of the mind palace. |
|
||||
| #537 — [BRIDGE-P1] Deploy Evennia bridge API on all worlds — sync presence and events | closed | L5 | Cross-world routing | Movement across worlds is retrieval across sovereign houses. |
|
||||
| #538 — [ALLEGRO-P1] Fix SSH access from Mac to Allegro VPS (167.99.126.228) | closed | L1 | Operator ingress | If the operator cannot reach a house, its memory cannot be visited. |
|
||||
| #539 — [ARCH-P2] Implement Evennia hub-and-spoke federation architecture | closed | L5 | Federated retrieval map | Federation turns world travel into selective retrieval instead of one giant memory blob. |
|
||||
|
||||
## Milestone 1 — One Room, One Object, One Mutable Fact
|
||||
|
||||
Milestone 1 is deliberately small.
|
||||
|
||||
Room:
|
||||
- `Hall of Knowledge`
|
||||
- Purpose: load live issue topology plus the current Timmy burn cycle before action begins.
|
||||
|
||||
Object:
|
||||
- `The Ledger`
|
||||
- Purpose: expose one mutable fact from durable memory so room entry proves stateful recall rather than static reference text.
|
||||
|
||||
Mutable fact:
|
||||
- Example fact used in this implementation: `canonical-evennia-body = timmy_world on localhost:4001 remains the canonical local body while room entry preloads live issue topology.`
|
||||
|
||||
Timmy burn cycle wiring:
|
||||
- `evennia_tools/mind_palace.py` defines `BurnCycleSnapshot`, `MutableFact`, the 16-issue layer map, and `build_hall_of_knowledge_entry(...)`.
|
||||
- `render_room_entry_proof(...)` renders a deterministic proof packet showing exactly what Timmy sees when entering the Hall of Knowledge.
|
||||
- `scripts/evennia/render_mind_palace_entry_proof.py` prints the proof artifact used for issue commentary and verification.
|
||||
|
||||
The important point is architectural, not cosmetic: room entry is now a retrieval event. The room decides what context loads. The object proves mutable memory. The burn-cycle snapshot tells Timmy what to do with the loaded context.
|
||||
|
||||
## Proof of Room Entry Injecting Context
|
||||
|
||||
The proof below is the deterministic output rendered by `python3 scripts/evennia/render_mind_palace_entry_proof.py`.
|
||||
|
||||
```text
|
||||
ENTER Hall of Knowledge
|
||||
Purpose: Load live issue topology, current burn-cycle focus, and the minimum durable facts Timmy needs before acting.
|
||||
Ambient context:
|
||||
- Room entry into Hall of Knowledge preloads active Gitea issue topology for Timmy_Foundation/timmy-home.
|
||||
- #511 [P0] Tower Game — energy must meaningfully constrain [open · L2 · Mutable world meter]
|
||||
- #512 [P1] Sonnet workforce — full end-to-end smoke test [open · L3 · Proof shelf]
|
||||
- #513 [P1] Tower Game — world events must affect gameplay [open · L2 · Event-reactive room state]
|
||||
- Ledger fact canonical-evennia-body: timmy_world on localhost:4001 remains the canonical local body while room entry preloads live issue topology.
|
||||
- Timmy burn cycle focus: issue #567 on fix/567 — Evennia as Agent Mind Palace — Spatial Memory Architecture
|
||||
- Operator lane: BURN-7-1
|
||||
Object: The Ledger
|
||||
- canonical-evennia-body: timmy_world on localhost:4001 remains the canonical local body while room entry preloads live issue topology.
|
||||
- source: reports/production/2026-03-28-evennia-world-proof.md
|
||||
Timmy burn cycle:
|
||||
- repo: Timmy_Foundation/timmy-home
|
||||
- branch: fix/567
|
||||
- active issue: #567
|
||||
- focus: Evennia as Agent Mind Palace — Spatial Memory Architecture
|
||||
- operator: BURN-7-1
|
||||
Command surfaces:
|
||||
- /who lives here -> #511 ... ; #512 ... ; #513 ...
|
||||
- /status forge -> Timmy_Foundation/timmy-home @ fix/567 (issue #567)
|
||||
- /what is broken -> Comment on issue #567 with room-entry proof after PR creation
|
||||
```
|
||||
|
||||
That proof is enough to satisfy the milestone claim:
|
||||
- one room exists conceptually and in code,
|
||||
- one object carries a mutable fact,
|
||||
- room entry injects current issue topology and the active Timmy burn cycle,
|
||||
- the output is deterministic and comment-ready for Gitea issue #567.
|
||||
|
||||
## Why this architecture is worth doing
|
||||
|
||||
The point is not to turn memory into a theatrical MUD skin. The point is to make retrieval selective, embodied, and inspectable.
|
||||
|
||||
What improves immediately:
|
||||
- Timmy no longer has to reload every repo fact on every task.
|
||||
- Durable facts become objects and meters rather than hidden prompt sludge.
|
||||
- Searchable history gets a real place to live.
|
||||
- Procedural skill loading can become room/NPC specific instead of global.
|
||||
- Movement itself becomes the retrieval primitive.
|
||||
|
||||
## Next steps after Milestone 1
|
||||
|
||||
1. Attach Hall of Knowledge entry to live Gitea issue fetches instead of the current deterministic proof subset.
|
||||
2. Promote The Ledger from one mutable fact to a live view over Timmy memory / fact-store rows.
|
||||
3. Add an Archive room surface that renders searchable history excerpts as in-world books.
|
||||
4. Bind Builder / Archivist NPCs to skill-category loading so L4 becomes interactive, not just descriptive.
|
||||
5. Route movement between rooms and worlds through the bridge/federation work already tracked by #537 and #539.
|
||||
270
evennia_tools/mind_palace.py
Normal file
270
evennia_tools/mind_palace.py
Normal file
@@ -0,0 +1,270 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import asdict, dataclass
|
||||
|
||||
HALL_OF_KNOWLEDGE = "Hall of Knowledge"
|
||||
LEDGER_OBJECT = "The Ledger"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MindPalaceIssue:
|
||||
issue_number: int
|
||||
state: str
|
||||
title: str
|
||||
layer: str
|
||||
spatial_role: str
|
||||
rationale: str
|
||||
|
||||
def summary_line(self) -> str:
|
||||
return f"#{self.issue_number} {self.title} [{self.state} · {self.layer} · {self.spatial_role}]"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MutableFact:
|
||||
key: str
|
||||
value: str
|
||||
source: str
|
||||
|
||||
def to_dict(self) -> dict[str, str]:
|
||||
return asdict(self)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BurnCycleSnapshot:
|
||||
repo: str
|
||||
branch: str
|
||||
active_issue: int
|
||||
focus: str
|
||||
active_operator: str
|
||||
blockers: tuple[str, ...] = ()
|
||||
|
||||
def to_dict(self) -> dict[str, object]:
|
||||
return {
|
||||
"repo": self.repo,
|
||||
"branch": self.branch,
|
||||
"active_issue": self.active_issue,
|
||||
"focus": self.focus,
|
||||
"active_operator": self.active_operator,
|
||||
"blockers": list(self.blockers),
|
||||
}
|
||||
|
||||
|
||||
EVENNIA_MIND_PALACE_ISSUES = (
|
||||
MindPalaceIssue(
|
||||
508,
|
||||
"closed",
|
||||
"[P0] Tower Game — contextual dialogue (NPCs recycle 15 lines forever)",
|
||||
"L4",
|
||||
"Dialogue tutor NPCs",
|
||||
"Contextual dialogue belongs in procedural behavior surfaces so the right NPC can teach or respond based on current room state.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
509,
|
||||
"closed",
|
||||
"[P0] Tower Game — trust must decrease, conflict must exist",
|
||||
"L2",
|
||||
"Mutable relationship state",
|
||||
"Trust, resentment, and alliance changes are world facts that should live on objects and characters, not in flat prompt text.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
510,
|
||||
"closed",
|
||||
"[P0] Tower Game — narrative arc (tick 200 = tick 20)",
|
||||
"L3",
|
||||
"Archive chronicle",
|
||||
"A spatial memory needs a chronicle room where prior events can be replayed and searched so the world can develop an actual arc.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
511,
|
||||
"open",
|
||||
"[P0] Tower Game — energy must meaningfully constrain",
|
||||
"L2",
|
||||
"Mutable world meter",
|
||||
"Energy is a changing state variable that should be visible in-room and affect what actions remain possible.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
512,
|
||||
"open",
|
||||
"[P1] Sonnet workforce — full end-to-end smoke test",
|
||||
"L3",
|
||||
"Proof shelf",
|
||||
"End-to-end smoke traces belong in the archive so world behavior can be proven, revisited, and compared over time.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
513,
|
||||
"open",
|
||||
"[P1] Tower Game — world events must affect gameplay",
|
||||
"L2",
|
||||
"Event-reactive room state",
|
||||
"If storms, fire, or decay do not alter the room state, the world is decorative instead of mnemonic.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
514,
|
||||
"open",
|
||||
"[P1] Tower Game — items that change the world",
|
||||
"L2",
|
||||
"Interactive objects",
|
||||
"World-changing items are exactly the kind of mutable facts and affordances that a spatial memory substrate should expose.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
515,
|
||||
"open",
|
||||
"[P1] Tower Game — NPC-NPC relationships",
|
||||
"L2",
|
||||
"Social graph in-world",
|
||||
"Relationships should persist on characters and become inspectable through spatial proximity rather than hidden transcript-only state.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
516,
|
||||
"closed",
|
||||
"[P1] Tower Game — Timmy richer dialogue + internal monologue",
|
||||
"L4",
|
||||
"Inner-room teaching patterns",
|
||||
"Internal monologue and richer dialogue are procedural behaviors that can be attached to rooms, NPCs, and character routines.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
517,
|
||||
"open",
|
||||
"[P1] Tower Game — NPCs move between rooms with purpose",
|
||||
"L5",
|
||||
"Movement-driven retrieval",
|
||||
"Purposeful movement is retrieval logic made spatial: who enters which room determines what knowledge is loaded and acted on.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
534,
|
||||
"open",
|
||||
"[BEZ-P0] Fix Evennia settings on 104.131.15.18 — remove bad port tuples, DB is ready",
|
||||
"L1",
|
||||
"Runtime threshold",
|
||||
"Before the mind palace can be inhabited, the base Evennia runtime topology has to load cleanly at the threshold.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
535,
|
||||
"open",
|
||||
"[BEZ-P0] Install Tailscale on Bezalel VPS (104.131.15.18) for internal networking",
|
||||
"L1",
|
||||
"Network threshold",
|
||||
"Network identity and reachability are static environment facts that determine which rooms and worlds are even reachable.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
536,
|
||||
"open",
|
||||
"[BEZ-P1] Create Bezalel Evennia world with themed rooms and characters",
|
||||
"L1",
|
||||
"First room graph",
|
||||
"Themed rooms and characters are the static world scaffold that lets memory become place instead of prose.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
537,
|
||||
"closed",
|
||||
"[BRIDGE-P1] Deploy Evennia bridge API on all worlds — sync presence and events",
|
||||
"L5",
|
||||
"Cross-world routing",
|
||||
"Bridge APIs turn movement across worlds into retrieval across houses instead of forcing one global prompt blob.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
538,
|
||||
"closed",
|
||||
"[ALLEGRO-P1] Fix SSH access from Mac to Allegro VPS (167.99.126.228)",
|
||||
"L1",
|
||||
"Operator ingress",
|
||||
"Operator access is part of the static world boundary: if the house cannot be reached, its memory cannot be visited.",
|
||||
),
|
||||
MindPalaceIssue(
|
||||
539,
|
||||
"closed",
|
||||
"[ARCH-P2] Implement Evennia hub-and-spoke federation architecture",
|
||||
"L5",
|
||||
"Federated retrieval map",
|
||||
"Federation turns room-to-room travel into selective retrieval across sovereign worlds instead of a single central cache.",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
OPEN_EVENNIA_MIND_PALACE_ISSUES = tuple(issue for issue in EVENNIA_MIND_PALACE_ISSUES if issue.state == "open")
|
||||
|
||||
|
||||
def build_hall_of_knowledge_entry(
|
||||
active_issues: tuple[MindPalaceIssue, ...] | list[MindPalaceIssue],
|
||||
ledger_fact: MutableFact,
|
||||
burn_cycle: BurnCycleSnapshot,
|
||||
) -> dict[str, object]:
|
||||
issue_lines = [issue.summary_line() for issue in active_issues]
|
||||
blocker_lines = list(burn_cycle.blockers) or ["No blockers recorded."]
|
||||
return {
|
||||
"room": {
|
||||
"key": HALL_OF_KNOWLEDGE,
|
||||
"purpose": "Load live issue topology, current burn-cycle focus, and the minimum durable facts Timmy needs before acting.",
|
||||
},
|
||||
"object": {
|
||||
"key": LEDGER_OBJECT,
|
||||
"purpose": "Expose one mutable fact from Timmy's durable memory so the room proves stateful recall instead of static documentation.",
|
||||
"fact": ledger_fact.to_dict(),
|
||||
},
|
||||
"ambient_context": [
|
||||
f"Room entry into {HALL_OF_KNOWLEDGE} preloads active Gitea issue topology for {burn_cycle.repo}.",
|
||||
*issue_lines,
|
||||
f"Ledger fact {ledger_fact.key}: {ledger_fact.value}",
|
||||
f"Timmy burn cycle focus: issue #{burn_cycle.active_issue} on {burn_cycle.branch} — {burn_cycle.focus}",
|
||||
f"Operator lane: {burn_cycle.active_operator}",
|
||||
],
|
||||
"burn_cycle": burn_cycle.to_dict(),
|
||||
"commands": {
|
||||
"/who lives here": "; ".join(issue_lines) or "No issues loaded.",
|
||||
"/status forge": f"{burn_cycle.repo} @ {burn_cycle.branch} (issue #{burn_cycle.active_issue})",
|
||||
"/what is broken": "; ".join(blocker_lines),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
def render_room_entry_proof(
|
||||
active_issues: tuple[MindPalaceIssue, ...] | list[MindPalaceIssue],
|
||||
ledger_fact: MutableFact,
|
||||
burn_cycle: BurnCycleSnapshot,
|
||||
) -> str:
|
||||
entry = build_hall_of_knowledge_entry(active_issues, ledger_fact, burn_cycle)
|
||||
lines = [
|
||||
f"ENTER {entry['room']['key']}",
|
||||
f"Purpose: {entry['room']['purpose']}",
|
||||
"Ambient context:",
|
||||
]
|
||||
lines.extend(f"- {line}" for line in entry["ambient_context"])
|
||||
lines.extend(
|
||||
[
|
||||
f"Object: {entry['object']['key']}",
|
||||
f"- {entry['object']['fact']['key']}: {entry['object']['fact']['value']}",
|
||||
f"- source: {entry['object']['fact']['source']}",
|
||||
"Timmy burn cycle:",
|
||||
f"- repo: {burn_cycle.repo}",
|
||||
f"- branch: {burn_cycle.branch}",
|
||||
f"- active issue: #{burn_cycle.active_issue}",
|
||||
f"- focus: {burn_cycle.focus}",
|
||||
f"- operator: {burn_cycle.active_operator}",
|
||||
"Command surfaces:",
|
||||
f"- /who lives here -> {entry['commands']['/who lives here']}",
|
||||
f"- /status forge -> {entry['commands']['/status forge']}",
|
||||
f"- /what is broken -> {entry['commands']['/what is broken']}",
|
||||
]
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
|
||||
def demo_room_entry_proof() -> str:
|
||||
return render_room_entry_proof(
|
||||
active_issues=OPEN_EVENNIA_MIND_PALACE_ISSUES[:3],
|
||||
ledger_fact=MutableFact(
|
||||
key="canonical-evennia-body",
|
||||
value="timmy_world on localhost:4001 remains the canonical local body while room entry preloads live issue topology.",
|
||||
source="reports/production/2026-03-28-evennia-world-proof.md",
|
||||
),
|
||||
burn_cycle=BurnCycleSnapshot(
|
||||
repo="Timmy_Foundation/timmy-home",
|
||||
branch="fix/567",
|
||||
active_issue=567,
|
||||
focus="Evennia as Agent Mind Palace — Spatial Memory Architecture",
|
||||
active_operator="BURN-7-1",
|
||||
blockers=("Comment on issue #567 with room-entry proof after PR creation",),
|
||||
),
|
||||
)
|
||||
13
scripts/evennia/render_mind_palace_entry_proof.py
Normal file
13
scripts/evennia/render_mind_palace_entry_proof.py
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
if str(REPO_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(REPO_ROOT))
|
||||
|
||||
from evennia_tools.mind_palace import demo_room_entry_proof
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(demo_room_entry_proof())
|
||||
88
tests/test_evennia_mind_palace.py
Normal file
88
tests/test_evennia_mind_palace.py
Normal file
@@ -0,0 +1,88 @@
|
||||
from evennia_tools.mind_palace import (
|
||||
EVENNIA_MIND_PALACE_ISSUES,
|
||||
HALL_OF_KNOWLEDGE,
|
||||
LEDGER_OBJECT,
|
||||
BurnCycleSnapshot,
|
||||
MutableFact,
|
||||
build_hall_of_knowledge_entry,
|
||||
render_room_entry_proof,
|
||||
)
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ISSUE_NUMBERS = (508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 534, 535, 536, 537, 538, 539)
|
||||
|
||||
|
||||
def test_issue_map_covers_all_16_tracked_evennia_issues() -> None:
|
||||
numbers = tuple(item.issue_number for item in EVENNIA_MIND_PALACE_ISSUES)
|
||||
assert numbers == ISSUE_NUMBERS
|
||||
assert len({item.issue_number for item in EVENNIA_MIND_PALACE_ISSUES}) == 16
|
||||
assert {item.layer for item in EVENNIA_MIND_PALACE_ISSUES} == {"L1", "L2", "L3", "L4", "L5"}
|
||||
|
||||
|
||||
def test_hall_of_knowledge_entry_injects_room_object_fact_and_burn_cycle() -> None:
|
||||
entry = build_hall_of_knowledge_entry(
|
||||
active_issues=EVENNIA_MIND_PALACE_ISSUES[:3],
|
||||
ledger_fact=MutableFact(
|
||||
key="active-world",
|
||||
value="timmy_world on localhost:4001 remains the canonical Evennia body",
|
||||
source="reports/production/2026-03-28-evennia-world-proof.md",
|
||||
),
|
||||
burn_cycle=BurnCycleSnapshot(
|
||||
repo="Timmy_Foundation/timmy-home",
|
||||
branch="fix/567",
|
||||
active_issue=567,
|
||||
focus="Evennia as Agent Mind Palace — Spatial Memory Architecture",
|
||||
active_operator="BURN-7-1",
|
||||
blockers=("Need room-entry proof comment on issue #567",),
|
||||
),
|
||||
)
|
||||
|
||||
assert entry["room"]["key"] == HALL_OF_KNOWLEDGE
|
||||
assert entry["object"]["key"] == LEDGER_OBJECT
|
||||
assert entry["object"]["fact"]["key"] == "active-world"
|
||||
assert entry["burn_cycle"]["branch"] == "fix/567"
|
||||
assert entry["burn_cycle"]["active_issue"] == 567
|
||||
assert any("Tower Game" in line or "Evennia" in line for line in entry["ambient_context"])
|
||||
assert entry["commands"]["/what is broken"]
|
||||
|
||||
|
||||
def test_render_room_entry_proof_contains_concrete_injected_context() -> None:
|
||||
proof = render_room_entry_proof(
|
||||
active_issues=EVENNIA_MIND_PALACE_ISSUES[:2],
|
||||
ledger_fact=MutableFact(
|
||||
key="ledger-memory",
|
||||
value="The Hall of Knowledge should preload live issue topology before Timmy acts",
|
||||
source="issue #567",
|
||||
),
|
||||
burn_cycle=BurnCycleSnapshot(
|
||||
repo="Timmy_Foundation/timmy-home",
|
||||
branch="fix/567",
|
||||
active_issue=567,
|
||||
focus="Evennia as Agent Mind Palace — Spatial Memory Architecture",
|
||||
active_operator="BURN-7-1",
|
||||
blockers=("Need proof comment",),
|
||||
),
|
||||
)
|
||||
|
||||
assert "Hall of Knowledge" in proof
|
||||
assert "The Ledger" in proof
|
||||
assert "fix/567" in proof
|
||||
assert "issue #567" in proof
|
||||
assert "Need proof comment" in proof
|
||||
assert "[P0] Tower Game" in proof or "[BEZ-P0]" in proof
|
||||
|
||||
|
||||
|
||||
def test_render_mind_palace_script_emits_room_entry_proof() -> None:
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
output = subprocess.check_output(
|
||||
[sys.executable, "scripts/evennia/render_mind_palace_entry_proof.py"],
|
||||
cwd=root,
|
||||
text=True,
|
||||
)
|
||||
|
||||
assert "ENTER Hall of Knowledge" in output
|
||||
assert "Timmy burn cycle" in output
|
||||
32
tests/test_evennia_mind_palace_doc.py
Normal file
32
tests/test_evennia_mind_palace_doc.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ISSUE_NUMBERS = (508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 534, 535, 536, 537, 538, 539)
|
||||
|
||||
|
||||
def test_evennia_mind_palace_doc_exists_with_required_sections() -> None:
|
||||
doc = Path("evennia-mind-palace.md").read_text(encoding="utf-8")
|
||||
|
||||
assert "# Evennia as Agent Mind Palace — Spatial Memory Architecture" in doc
|
||||
assert "## GrepTard Memory Layers as Spatial Primitives" in doc
|
||||
assert "## Milestone 1 — One Room, One Object, One Mutable Fact" in doc
|
||||
assert "## Proof of Room Entry Injecting Context" in doc
|
||||
assert "Hall of Knowledge" in doc
|
||||
assert "The Ledger" in doc
|
||||
assert "Timmy burn cycle" in doc
|
||||
|
||||
|
||||
|
||||
def test_evennia_mind_palace_doc_maps_all_16_tracked_issues() -> None:
|
||||
doc = Path("evennia-mind-palace.md").read_text(encoding="utf-8")
|
||||
|
||||
for issue_number in ISSUE_NUMBERS:
|
||||
assert f"#{issue_number}" in doc
|
||||
|
||||
assert "| Layer | Spatial primitive |" in doc
|
||||
assert "| Issue | State | Layer | Spatial role | Why it matters |" in doc
|
||||
assert "L1" in doc
|
||||
assert "L2" in doc
|
||||
assert "L3" in doc
|
||||
assert "L4" in doc
|
||||
assert "L5" in doc
|
||||
Reference in New Issue
Block a user