M5.3: scope memory
A project's notes have their own folder, memory/nisse-dev/projects/<project>/, with its own index; remember and forget take scope (general, or project: always the current item's own, so no item writes another project's notes, and a conversation has none). At an item's start the transcript gets the general index and its project's, never another's. Index links are pages from the vault's root, as SilverBullet names them. The closing pass's memory_done can name repository documents the item left out of date; the harness says so in the thread and records it. The prompt: the repository is the authority, and a note that disagrees is corrected. With the operator: ARCHITECTURE.md isn't put into every item's context (its size); the infrastructure world model waits for nisse-ops. The walk writes project notes and checks they come only from that project's items. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01J5Utyfzw7gF7UhjRDEtjTk
This commit is contained in:
1 parent
427278ac80
commit
fe4548459f
8 files changed
+301
-66
No files matched your search
@@ -57,7 +57,7 @@ from nisse_dev.memory import Memory
|
||||
from nisse_dev.oplog import OpLog
|
||||
from nisse_dev.tools import Workspace
|
||||
from nisse_dev.transport import InboundMessage, InMemoryTransport
|
||||
from nisse_dev.vault import Vault
|
||||
from nisse_dev.vault import Vault, split_frontmatter
|
||||
from nisse_dev.worker import InlineWorker
|
||||
|
||||
# How many walks, and from which seed: all 48 by default; CI runs fewer on a
|
||||
@@ -87,6 +87,16 @@ class PolicyModel:
|
||||
self.projects = projects
|
||||
self.n = 0
|
||||
|
||||
def _remember(self) -> Any:
|
||||
scope = _scope(self.rng)
|
||||
return call(
|
||||
"remember", name=f"n{self.n % 4}", description="d", fact="f", scope=scope
|
||||
)
|
||||
|
||||
def _forget(self) -> Any:
|
||||
scope = _scope(self.rng)
|
||||
return call("forget", name=f"n{self.n % 4}", why="superseded", scope=scope)
|
||||
|
||||
def complete(self, events, tools, model, system=None) -> list[Any]:
|
||||
assert_renderable(events) # as the real API would
|
||||
self.n += 1
|
||||
@@ -101,16 +111,14 @@ class PolicyModel:
|
||||
# The memory pass at a close (M5.2): a note, a forgetting, done.
|
||||
roll = self.rng.random()
|
||||
if roll < 0.3:
|
||||
return [
|
||||
call("remember", name=f"n{self.n % 4}", description="d", fact="f")
|
||||
]
|
||||
return [self._remember()]
|
||||
if roll < 0.55:
|
||||
return [call("forget", name=f"n{self.n % 4}", why="superseded")]
|
||||
return [self._forget()]
|
||||
return [call("memory_done", summary="done")]
|
||||
if "remember" in offered and self.rng.random() < 0.06:
|
||||
if self.rng.random() < 0.4:
|
||||
return [call("forget", name=f"n{self.n % 4}", why="superseded")]
|
||||
return [call("remember", name=f"n{self.n % 4}", description="d", fact="f")]
|
||||
return [self._forget()]
|
||||
return [self._remember()]
|
||||
if "toolchain_ready" in offered:
|
||||
# A preflight (M4.1): usually reported, sometimes badly or not.
|
||||
if self.rng.random() < 0.15:
|
||||
@@ -213,6 +221,10 @@ class PolicyModel:
|
||||
]
|
||||
|
||||
|
||||
def _scope(rng: random.Random) -> str:
|
||||
return rng.choice(["general", "project"])
|
||||
|
||||
|
||||
class Watched:
|
||||
"""The driver's model, watched: a run on a project item (not its
|
||||
preflight) must find the project's marker on the VM, and no model runs
|
||||
@@ -715,6 +727,18 @@ class Walk:
|
||||
and p != root / "notes" / "Ops.md"
|
||||
]
|
||||
assert not strays, f"memory_stays_home: {strays}: {where}"
|
||||
# M5.3: a project's notes come only from that project's items.
|
||||
projects = root / "memory" / "nisse-dev" / "projects"
|
||||
for note in projects.rglob("*.md") if projects.exists() else []:
|
||||
if note.name == "index.md":
|
||||
continue
|
||||
project = note.relative_to(projects).parts[0]
|
||||
front, _ = split_frontmatter(note.read_text())
|
||||
source = front["provenance"]["source"]
|
||||
assert front["provenance"]["project"] == project, where
|
||||
assert source.startswith(f"work item {project}-"), (
|
||||
f"project_notes_stay_with_their_project: {note}: {source}: {where}"
|
||||
)
|
||||
assert (root / "notes" / "Ops.md").read_text() == "the operator's\n", where
|
||||
# #137: no model works on a project whose build VM is out of reach.
|
||||
assert not self.while_down, f"no_model_on_a_lost_vm: {self.while_down}: {where}"
|
||||
|
||||
Reference in new issue
Block a user