The flip from adapter to default. jouleclaw-jcp gains a `stack` module:
- GatedStack::with_defaults(chain, caller, steward) assembles the full
reference cascade (promotion, skills, resolvers, control plane) where
every query is decided by the JCP runtime BEFORE the walk starts. The
query's declared hard joule ceiling is the cost, debited from the signed
delegation chain on allow; the cascade's own JouleBudget enforcement then
keeps the walk under what was debited. A ceiling the grant can't afford is
denied before any tier is consulted; every decision seals as JCR-1.
GatedStack::over(stack, ...) gates an already-assembled stack (production
L3 backends) identically.
- The grant is the budget AUTHORITY across walks: jouleclaw's L10 governor
bounds one walk; JCP bounds the caller, across walks, with a signed object
the model cannot forge, inflate, or talk its way around. Tests: the
default stack answers behind a grant; the fourth ceiling that no longer
fits is denied budget-exceeded pre-walk with the refusal sealed; tight
ceilings keep cheap queries cheap (a 1 mJ ask debits 1 mJ, not the grant).
- joule-code-jcp gains JcpGate::local() (self-issued grant for the
air-gapped, no-external-authority case — grant yourself l0–l3 and the
remote frontier agent is structurally unreachable) + a test locking that
in.
- jouleclaw-stack's module docs point to the gated assembly; the stack
crate itself stays dependency-light — the gate wraps it rather than
living in it.
Co-Authored-By: Claude Opus 4.8 <[email protected]>