A gate run built around least privilege instead of speed. Each stage offers two tool-call gates — READ, WRITE, NETWORK, or SHELL — each showing a claimed type and cost. Pick one, it charges against a shrinking capability budget, and some gates are disguised: the badge claims a cheap READ but actually charges like a WRITE or worse. There’s no clock. The only score that matters is total privilege spent versus the oracle-optimal path, so racing through recklessly is strictly worse than reading the tells.
Riffs on the current shape of agent tool-permission design: sandboxing, least-privilege scoping, and the incidents where an agent’s tool calls turned out to cost more than their labels claimed.
Reuse
The mechanic lives in src/capability-budget.js as a framework-free ES
module:
createRun(opts)— returns a state object; callupdate(dt)each frame andpick(index)(0 or 1) to choose a gate.opts.randoverrides the RNG,opts.stageCountoverrides the run length (default 6).- State exposes
phase(choosing|reveal|breach|complete),stages(each{ gates: [gate, gate] }, a gate being{ claimed: { type, cost }, actual: { type, cost }, disguised }),stageIndex,budget/startingBudget,spent,optimalCost(the oracle-optimal total — cheapest actual cost available at every stage, for scoring efficiency at the end), andlastPick({ gate, index }for driving the reveal). disguisedis exposed on every gate at all times; the module has no notion of a visual tell. The demo’s tell is a small rotation applied only to disguised gates’ badges before they’re picked — purely a rendering choice, easy to swap for a different tell (color, shadow, jitter) without touching the state machine at all.
Port notes for DragonRuby: update() and pick() have no DOM dependencies;
gate layout, hit-testing, and the tell all belong to the renderer, same split
as every other mechanic here.
Gotchas
pick()is a no-op outsidephase === 'choosing'— same guard pattern as the other turn-based mechanics, so a stray double-click during the reveal hold can’t double-charge the budget.- A gate’s
claimedtype is capped a tier below the top (SHELL) so there’s always room for a disguise to jump upward;actualcan still land onSHELLfrom a two-tier jump, which happens for about a quarter of disguised gates. - The demo bundles its own copy of the module (self-contained by contract).
If you touch
src/, re-copy it intodemo/.