repl: enforce budget per Norris step, not just post-loop (closes #51)

PHASE3.md §2 specifies sliding-window eviction "including mid-Norris-
session if the loop runs long". Implementation only called
enforce_budget() once, after the planning loop exited — so for a tight
max_turns with a multi-step Norris session the model saw the FULL
conversation throughout, defeating context budgeting and preventing
R-C3 (NORRIS suffix goal anchor surviving eviction) from being
exercised end-to-end.

Move status_evictions(ctx:enforce_budget()) inside the while loop so
it runs after every safety.norris_step return. Drop the now-redundant
post-loop call.

Surfaced during TC #38 (Qwen3-30B-A3B, max_turns=4) where the
"oldest 4 turns evicted" status arrived AFTER NORRIS DONE.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 21:05:34 +00:00
parent 0c93e31186
commit 0700dce881
+5 -1
View File
@@ -690,6 +690,11 @@ function M.run(config)
max_steps = max_norris_steps,
cfg = config,
})
-- Issue #51: enforce budget after every step (was post-loop only).
-- PHASE3.md §2 specifies sliding-window eviction mid-Norris-session
-- when the loop runs long; this is what makes R-C3 (NORRIS suffix
-- goal anchor surviving eviction) observable end-to-end.
status_evictions(ctx:enforce_budget())
if result.status == "continue" then
step_n = step_n + 1
else
@@ -701,7 +706,6 @@ function M.run(config)
ctx.norris_active = false
ctx.norris_goal = nil
renderer.norris_end(final_status, final_reason)
status_evictions(ctx:enforce_budget())
end
-- Meta dispatch table.