Development record
A failed fix round escalates one tier, and a provider route stays on its allowlist
Summary
spc-2609251028149555 delivers what spc-2609180535002478 could not for
itd-2609170822093401. That spec shipped the routing table, its resolution,
--route on the delegating verbs, the request block, the receipt and the
install consent. Two acceptance criteria wait on records that do not exist yet,
and the provider halves of two more wait on the same adapter. This spec holds
all four:
- AC 10: a lane whose fix round failed runs its next round one tier up, and the state file records the switch. The intent's Decision 1 rules this a rule, not a router.
- AC 11: a route through a provider adapter is one that provider's allowlist admits, or the proposal names the refusal. This is Decision 2 and adr-2609221009491186.
- AC 3, the dispatch half: a step whose route resolves to a configured, reachable provider is sent to that provider directly. The resolution half shipped; no verb can send a step anywhere but the harness until the adapter exists.
- AC 8, the adapter half: a setting the provider's adapter does not accept is
refused before the step runs, never dropped. The merge and the receipt's
settings_sentshipped; the set of accepted settings is the adapter's.
Scope
- Escalation. The implement loop's state file records, per lane and round,
the tier the round ran at. When a round's gates fail, the next round's route
for the lane's role is
oracle.Resolve's row with the tier moved one step up the ladderlocal→economy→frontier.host-decidesandfrontierdo not move. The state file records the round, the failing gate output and the switch, and the receipt names the escalated tier as the tier asked. - The allowlist.
oracle.Connectionsgains the adapter's allowlist. A tier the bundled proposal, a table row or a--routewould send to a provider is checked against it before dispatch. A route the allowlist does not admit is refused, naming the provider and the route, instead of being sent. - Provider dispatch. A delegating verb whose route names a provider
connection sends the step through that connection instead of handing it to
the host, and the receipt's
connection_usednames the provider. - Accepted settings. The adapter's
Connectiondeclares the settings it accepts, andResolverefuses a merged setting outside that set before dispatch, naming the setting and the provider.
Approach
- Once the implement loop's state file exists, add a
Roundrecord carryingtier,gate_outputandescalated_from, and a pureEscalate(tier)besideoracle.ParseTier. Table-test the ladder and its two fixed points. - Once the API adapter (itd-2609081951381895) implements
Connections, extend its interface with the allowlist and refuse an unlisted route insideResolve, before any settings merge. Test it with an in-memory adapter. - With the same adapter, route a provider-leg step through its connection in
the delegating verbs, and refuse a setting its
Connectiondoes not accept insideResolve, after the merge and before dispatch.
How the Acceptance Criteria are satisfied
- A route whose connection is a provider is dispatched through that provider's adapter, and the receipt names it as the connection used.
Resolverefuses a merged setting the connection's adapter does not accept, before the step runs.- A lane whose round N failed resolves round N+1 through
Escalate, and the state file carries the round, the gate output and the switch. Resolveconsults the connection's allowlist before it returns a provider leg. An unlisted route is an error that names the refusal. A--route <agent>=<tier>@<conn>whose agent'soracle.roles.<agent>does not point at that connection is refused, naming the one setting to add (the product thinker's ruling BR1 of 2026-09-29, which took the refusal as built in e1c4e38ad and 35100512e), so AC 11 is complete as built.
Tests
internal/core/oracle: the escalation ladder; an allowlist refusal naming the provider and the route.- The implement loop: a failed round followed by an escalated round, with the state file's record read back.
internal/core/oracleand one delegating verb: a provider-leg route sent through an in-memory adapter, and a setting outside the adapter's accepted set refused before dispatch.
Blocked on
- The implement loop's per-lane state file, for AC 10.
AC 3 is met and blocks nothing: a delegating verb whose route names a provider
sends the step through that provider's adapter and its receipt names the
provider as the connection used (APIConfig.Dispatch, called by intent audit, intent consistency, intent audit --owed, launch ship, spec close's review re-emit and reading ingest --dispatch; the product thinker's
ruling DR5 of 2026-09-29 admits only self-contained agents to a provider that
holds a key). The spec stays open for AC 10.
Frontmatter
| id | spc-2609251028149555 |
|---|---|
| type | spec |
| lifecycle | closed |
.abcd/development/specs/closed/spc-2609251028149555-tier-escalation-and-provider-allowlist.md
open on GitHub ↗ · commit history ↗
References1
- itd-2609170822093401abcd proposes the model each agent deserves, and facilitates it where it canimplements
mentions6
- adr-2609221009491186A provider adapter serves only the models it lists, under a vendor denylist no listing overrides; everything else runs on the host
- itd-2609081951381895abcd ships an OpenAI-compatible API adapter, and a provider serves only the models it lists
- itd-2609221017023290abcd keeps every external credential the same way
- itd-2609301918174237A remote provider takes a file-reading agent only as a fixed, blanked, capped bundle
- spc-2609180535002478abcd proposes the model each agent deserves, and facilitates it where it can
- spc-2610281649196051consult-only-advisor-role