Skip to content

Slice 028: context can tighten the gate, and can never loosen it - #88

Merged
HackTuah merged 1 commit into
mainfrom
slice/028-tighten-only-policy-state
Sep 24, 2026
Merged

HackTuah merged 1 commit into
mainfrom
slice/028-tighten-only-policy-state

Conversation

@HackTuah

Copy link
Copy Markdown
Member

From the connectome research report's A7: neuromodulators are global gain, not rewiring. The wiring is fixed and the gain is state. Trinity's wiring is the tier, a function of the tool's name; this is the gain.

This is the second axis of attenuation in the tree. Slice 070 caps by surface (a channel approves less than the desktop). This caps by context. Both apply after the gate's own decision, never instead of it, and both name what tightened in the basis.

The constraint is in the types

requires/1 returns :ask or :deny and has no clause that can return :allow, so no state is ever a licence. tighten/2 takes the strictest of the gate's decision and every active state, so adding a state moves the result one way only.

One-way is the design, not a preference. Every state derives from something an attacker may be able to influence: whether the turn read untrusted content, whether a budget is exhausted, whether anyone is at the machine. If any could widen authority, the useful move would be to arrange the state rather than argue with the gate, and arranging state is quieter.

The test is exhaustive, not sampled

Every decision against every subset of the state set in every ordering: 195 cases. No seed, nothing to be unlucky with, and order-independence asserted directly rather than probably. An example test would pass on a modifier that happened to tighten for the cases someone thought of.

End to end: a real $0.01 day budget, a real usage_events row of $0.05, a real fs_read through the runner. Denied, with state:over_budget in the basis, and the tool's tier unmoved.

AC5 is amended, not met

It asked for a state-tightened approval on the permissions page. Of the four states, only :over_budget has a producer here and it floors at :deny; the two that floor at :ask have none. The approval column and page rendering would have displayed a reason that cannot occur, which is the decoration slice 027 declined for per-edge confidence scores. Original text kept in SLICE.md; lift condition is the first :ask-floor state gaining a producer.

One bug worth reading

The gate test's setup restored a previously-unset config key with Application.put_env(key, nil), which sets the key to nil rather than removing it. get_env/3 then returns the stored nil instead of the default, so impl() became nil and every later test called nil.decide/4. The file passed alone and took four MCP tests down in the full suite: same-run-only, not reproducible in isolation, which looks exactly like R26. R26's own counter-example entry says the signature is not the diagnosis, and that is twice in two days it has been right.

Verification

mix gate
Result: 700 passed, 18 excluded
trinity.coverage: 027 80.31% vs 090 80.31%: OK

🤖 Generated with Claude Code

From the connectome research report's A7: neuromodulators are global gain, not
rewiring. The wiring is fixed and the gain is state. Trinity's wiring is the tier,
which is a function of the tool's name, and this is the gain.

A state raises what a call requires. It cannot change what the tier is, and it
cannot turn a refusal into a permission. The constraint is in the types rather
than in a review: requires/1 returns :ask or :deny and has no clause that can
return :allow, so no state is ever a licence, and tighten/2 takes the strictest of
the gate's decision and every active state, so adding a state moves the result one
way only.

One-way is the design and not a preference. Every state is derived from something
an attacker may be able to influence: whether the turn read untrusted content,
whether a budget is exhausted, whether anyone is at the machine. If any of those
could widen authority, the useful move would be to arrange the state rather than
argue with the gate, and arranging state is quieter.

The test is exhaustive rather than sampled: every decision against every subset of
the state set in every ordering, 195 cases, so there is no seed and order
independence is asserted directly. Over the budget, a real fs_read call through
the runner is denied and the basis names over_budget, against a real ledger row
and a real configured budget.

This is the second axis of attenuation in the tree. Slice 070 caps by surface, a
channel approving less than the desktop; this caps by context. Both apply after
the gate's decision rather than instead of it.

Two names collided with Kernel, and the rename improved them: tighten/2 says at
every call site which direction the seam runs in, which is the whole property.

AC5 is amended rather than met, with the original text kept. It asked for a
state-tightened approval on the permissions page, and of the four states only
over_budget has a producer here and it floors at deny; the two that floor at ask
have none. The column and the rendering would have displayed a reason that cannot
occur, which is the decoration slice 027 declined for confidence scores. The lift
condition is the first ask-floor state gaining a producer.

mix gate: 700 passed, 18 excluded; coverage 80.31%, unchanged.

Signed-off-by: Ayla Croft <aylacroft@proton.me>
@HackTuah
HackTuah merged commit 4c44b8d into main Sep 24, 2026
8 checks passed
@HackTuah
HackTuah deleted the slice/028-tighten-only-policy-state branch September 24, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant