The original design, and why it broke
The first implementation ofset delegation and policy used a single
Interpreter-global stack: entering a session or starting an agent
pushed a copy of the current rules, and exiting popped it. It worked, and
it was simple — right up until agent pause/resume
needed to exist.
The problem: a stack models exactly one thing correctly — a single,
uninterrupted sequence of nested scopes, entered and exited in strict
order. Pause/resume breaks that assumption on purpose. When an agent
pauses mid-body, its delegation/policy frame is still logically “open” —
but control has been handed back to whatever called start(), which has
its own, completely different notion of “current scope.” With a shared
global stack, “top of stack” stops reliably meaning “the right scope” the
moment two independent logical contexts — a paused agent, and whatever
resumed it — can each expect their own current scope at the same time.
The fix: attach state to Environment, not the interpreter
Environment — the same object that already holds a scope’s
variables — gets three more optional slots: model (a set delegation
override), policy (a dict of capability → allowed), and agent (set
only on an agent’s own scope, so pause() can find “which agent am I
inside”).
Looking up “the current model” walks the parent chain exactly the way
Environment.get(name) already does for variables — first non-None
value wins, defaulting to None (no model configured) if nothing in the
chain ever set one. set delegation = x mutates only the current
env’s own model slot — never a parent’s — so it’s automatically scoped to
wherever it’s written and automatically visible to anything nested inside,
with zero explicit push/pop/copy bookkeeping anywhere.
Environment object reachable from
wherever execution currently is, on whichever thread), not in a single
mutable structure shared across every context that happens to be
interpreting Sense code at once.
A side effect worth knowing about
Because every scope — including an ordinary function call’s own environment — now gets its own optional override for free, a plain function’sset delegation no longer leaks to its caller either. Under
the old stack-based design, only session and agent bodies got their own
frame; a function call didn’t push one, so delegation set inside a
function used to affect the caller too. That was a documented limitation.
It disappeared as a consequence of fixing the pause/resume bug, without
anyone writing function-call-specific scoping logic — every scope just
follows the same one rule now.
Policy uses the identical mechanism
.verify()/.commit() each call this independently rather than
caching a result.
Continue
Agent concurrency model
The pause/resume mechanism this redesign was made to support.
Sessions
The user-facing behavior this architecture produces.

