Store the refusals, so the chips and the model can see them
`world_delta_of` wrote `delta` and `applied` only. Every consumer that tells a refused change from a successful one reads the two lists it dropped: `Action.world_changes` marks a clamped chip from `clamped` and builds its refusal chips from `rejected`, and `worldstate.refusals` reads both. So no chip could report a limit, no rejection chip could appear, and no correction ever reached the next prompt. The three mechanisms merged last session were live in the code and unreachable in production. Found by playing the Pokemon demo. Turn 3's snapshot held two clamped entries with correct `fix` text, both chips came back `clamped: false`, and turn 4's prompt carried no correction, so the model repeated the same mistake. The 21 tests passed because `action()` built the column by hand with every list present. It now fills the column through `world_delta_of`. Removing the two new lines fails 9 of the 23 tests; that was checked by sabotage. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PacdRuPXSkQQy4ZYdH32hF
This commit is contained in:
co-authored by
Claude Opus 5
parent
abbfc61263
commit
1988979aeb
@@ -528,16 +528,27 @@ def world_delta_of(snapshot: dict | None) -> dict | None:
|
||||
"""Returns the bulk-read slice of a context snapshot, for `Action.world_delta`.
|
||||
|
||||
`context_snapshot` is deferred because it holds the whole assembled prompt.
|
||||
The two parts that every action needs, the world-change chips and the emit
|
||||
block replayed into history, get their own small column instead. Update this
|
||||
function wherever a snapshot is written.
|
||||
The parts that every action needs get their own small column instead: the
|
||||
world-change chips, the emit block replayed into history, and the refusal
|
||||
note fed back to the model. Update this function wherever a snapshot is
|
||||
written.
|
||||
|
||||
Carry all three report lists, not just `applied`. `Action.world_changes`
|
||||
marks a chip from `clamped` and builds its refusal chips from `rejected`,
|
||||
and `worldstate.refusals` reads both. Storing `applied` alone left every
|
||||
consumer unable to tell a refused change from one that worked, which is the
|
||||
distinction this column exists to carry. The two extra lists are subsets of
|
||||
one turn's block, so they cost a few hundred bytes per action at most.
|
||||
"""
|
||||
ws = (snapshot or {}).get("world_state")
|
||||
if not isinstance(ws, dict):
|
||||
return None
|
||||
report = ws.get("report") or {}
|
||||
return {
|
||||
"delta": ws.get("delta") or {},
|
||||
"applied": (ws.get("report") or {}).get("applied") or [],
|
||||
"applied": report.get("applied") or [],
|
||||
"clamped": report.get("clamped") or [],
|
||||
"rejected": report.get("rejected") or [],
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user