Say which memories the model can actually see
Retrieval has been path-scoped since SP3: a memory on a branch this story never travelled is never sent to the AI. The drawer listed every memory alike, so on a fork you read "Fell down the cellar stairs; badly hurt" and reasonably concluded the model knew it. It does not. That is worse than either hiding the row or retrieving it — it is the screen claiming something the engine contradicts. Hiding them is not the answer either; that was the original comment's point, and it stands. A memory nobody can list is a memory nobody can delete, in a phase whose rule is that nothing is removed automatically. So the whole bank still lists, and the rows off the current path are set back, dashed, and labelled "another branch". MemoryOut.on_path carries it, computed from the predicate retrieval itself uses rather than a second spelling of the same idea — two spellings drift, and the failure mode here is a badge that says the opposite of what the model gets. Pinning does not override it: the path clause runs before pinning is considered. The relationship is asymmetric and there is now a test that says so. A fork borrows its ancestors, so a memory written on the parent is on the fork's path too; the reverse never is. Worth pinning before somebody makes it symmetric on the grounds that it looks wrong. 399 tests, three new, egress ceilings intact — the flag costs one id-only query. Verified in a browser on tools/branch_fixture.py. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015H5qiyiR7gtFQaoDphHZ3g
This commit is contained in:
committed by
Parth
co-authored by
Claude Opus 5
parent
811368d048
commit
1d1367ce3a
@@ -4,7 +4,7 @@ import threading
|
||||
|
||||
from fastapi import APIRouter, Body, Depends, HTTPException, Request
|
||||
from fastapi.responses import StreamingResponse
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy.orm import Session, load_only, undefer
|
||||
from sqlalchemy.orm.attributes import set_committed_value
|
||||
|
||||
@@ -1874,7 +1874,7 @@ def action_context(
|
||||
def list_memories(
|
||||
adventure_id: int, db: Session = Depends(get_db), user: models.User = CurrentUser
|
||||
):
|
||||
get_adventure_or_404(adventure_id, db, user)
|
||||
adventure = get_adventure_or_404(adventure_id, db, user)
|
||||
# A query naming its columns, not a walk of `adventure.memories`. The walk
|
||||
# is what retrieval used to do, and it is the reason a turn cost megabytes:
|
||||
# a relationship load takes whole entities, so it picks up whatever the
|
||||
@@ -1885,13 +1885,32 @@ def list_memories(
|
||||
# the story being played, the drawer manages the bank. Hiding a branch's
|
||||
# memories from the drawer would mean memories nobody can find to delete,
|
||||
# in a phase whose rule is that nothing is ever removed automatically.
|
||||
return (
|
||||
rows = (
|
||||
db.query(models.Memory)
|
||||
.options(load_only(*MEMORY_LIST_COLUMNS))
|
||||
.filter(models.Memory.adventure_id == adventure_id)
|
||||
.order_by(models.Memory.id)
|
||||
.all()
|
||||
)
|
||||
# ...but listing them alike would be its own lie. A memory on a branch this
|
||||
# story never travelled is never retrieved, so showing it beside one that is
|
||||
# tells the player the model remembers something it cannot see. The ids come
|
||||
# from **the predicate retrieval itself uses**, deliberately: two spellings
|
||||
# of "on this path" would eventually disagree, and the failure would be a
|
||||
# badge that says the opposite of what the model gets.
|
||||
on_path = {
|
||||
row[0] for row in db.execute(
|
||||
select(models.Memory.id).where(
|
||||
models.Memory.adventure_id == adventure_id,
|
||||
lineage.path_of(db, adventure).clause(
|
||||
models.Memory, unanchored=True
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
for row in rows:
|
||||
row.on_path = row.id in on_path
|
||||
return rows
|
||||
|
||||
|
||||
@router.post("/{adventure_id}/memories", response_model=schemas.MemoryOut, status_code=201)
|
||||
|
||||
@@ -289,6 +289,12 @@ class MemoryOut(ORMModel):
|
||||
last_used_at: datetime | None
|
||||
source_start: int | None
|
||||
source_end: int | None
|
||||
# Whether this memory is on the story currently being read (Phase 14, SP7).
|
||||
# The drawer lists the whole bank so nothing becomes impossible to find and
|
||||
# delete, but a memory belonging to another branch will never be retrieved
|
||||
# into context — and a list that showed the two alike would be telling the
|
||||
# player the model knows something it cannot see.
|
||||
on_path: bool = True
|
||||
created_at: datetime
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user