| PSP: | 000009 |
| Title: | Governed Agentic Platform: SRBN Tool Harness and Model Portfolio |
| Author: | Vikrant Rathore (@vikrantrathore), Ronak Rathore (@ronakrathore) |
| Status: | Final |
| Type: | Enhancement |
| Created: | 2026-07-26 |
| Discussion-To: | https://github.com/eonseed/perspt/discussions/PSP-9 |
| Extends: | 000005, 000007, 000008 |
Abstract
This PSP turns Perspt’s existing bundle-oriented coding pipeline into a governed agentic tool loop. Its distinctive property is not a particular model or a particular number of providers: every stochastic action is a proposal, every effect is mediated, every accepted state is measured, and every reliability claim is conditional on evidence recorded by the platform.
Two things are missing today, and they are missing together. First, the model
cannot choose a tool: perspt-core::llm_provider exposes only text-in /
text-out completion, perspt-agent::tools::get_tool_definitions() has no
callers, exposes only nine of the twelve names dispatched by AgentTools,
and live effects remain orchestrator-directed. Second, Perspt cannot hold more
than one provider at a time: the orchestrator owns a single
Arc<GenAIProvider> bound to a single genai adapter and a single
credential, so the four configured model tiers are four model names served by
one vendor.
This PSP adds a model-driven tool loop and a model plane that holds a
portfolio of providers, and it governs both with the SRBN trilogy’s contracts.
Every model-issued tool call becomes a Paper III proposal; a deterministic
admissibility kernel decides whether it may affect a candidate workspace;
verifier evidence becomes a Paper II residual vector scored by the
quadratic energy already defined in perspt-sdk and made authoritative here;
and an acceptance gate
admits an intermediate checkpoint only on hard pass or measured descent.
Following Paper I’s realizability interface (§12), the gate is evaluated on the
candidate workspace that would actually be checkpointed, never on the model’s
account of it. Perspt does not, however, claim a coding-domain
δr or Corollary 12.5 feasibility certificate until a domain
provides the paper’s proxy state, encoder, norm, and analytic constants.
The work is placed to respect Perspt’s existing layering rather than to bypass
it: the published srbn kernel keeps implementing Paper I, perspt-sdk
keeps owning the domain-neutral Paper II/III contracts, perspt-coding and
perspt-research extend it as domain packages, and perspt-core’s language
plugins keep supplying the runtime verifier bindings. Upgrading srbn from
0.1.1 to 0.3.0 is a prerequisite, because that is where the realizability
interface, the gate policy, and the Merkle helpers now live.
The model portfolio is operationally important for cost routing, confidential work, failover, and optional independent review. It is not itself a reliability certificate. Paper III Lemma 5.1 and Corollary 5.2 apply only to validators that form a conjunctive gate over the same labeled proposal population. Perspt may report ρeff only after it has delayed unsafe labels, matched pairwise samples, and conservative finite-sample upper bounds. Model family and vendor diversity are routing priors until that evidence exists.
Because the tool loop is the natural consumer of the Paper III machinery that
PSP 000008 implemented in perspt-sdk but never wired to the live path,
this PSP also closes PSP-8 Phases 2, 3, 4, 5, 7, 8, and 9. Where this PSP and
PSP-8 describe the same object, this PSP supersedes PSP-8’s roadmap for that
object; PSP-8’s SDK contracts are consumed, not replaced.
The existing bundle pipeline is retained only as an offline ablation baseline. The live agent has one authoritative typed tool-loop path. Tool-less providers remain usable for chat, exploration, and adjudication but are ineligible to act as coding actuators.
Motivation
The Reliability Objective
Perspt’s target is a useful coding agent whose model-driven exploration and editing remain subordinate to an explicit harness contract. The trilogy identifies two distinct reasons that repeated checking can help, and the PSP must not collapse them:
Paper III Lemma 5.1 / Corollary 5.2. For two non-degenerate validators evaluated on the same proposal population, the joint miss probability is exactly q1q2 + κσ1σ2. For a conjunctive gate, pairwise joint-miss upper bounds yield the conservative ensemble bound ρeff = mini < juij. This is a statement about labeled validator misses, not about provider count, proposer diversity, or model agreement.
Paper II Lemma 2 (spectral energy-slope). The same fact in its deterministic form: a check that adds no new transverse information adds rank-deficient redundancy and does not raise the spectral gap μ. Adding a ninth copy of the same self-critique does not improve the certificate; it only costs tokens.
The defensible claim is therefore narrower and stronger: Perspt produces a bounded, classified accepted trajectory under the measured Paper II gate; confines effects when every authority-changing operation passes the Paper III kernel; and emits only those analytic or probabilistic certificates whose hypotheses are represented by recorded evidence. A cheap exploration model, a stronger implementation model, a local confidential route, and a separate review route are practical policies layered on this contract. Their benefit is measured by internal ablation, never assumed from vendor identity.
Perspt Cannot Use Its Own Tools
Perspt ships twelve workspace tools in perspt-agent::tools — read_file,
search_code, list_files, write_file, apply_patch,
apply_diff, delete_file, move_file, sed_replace,
awk_filter, diff_files, run_command — and a
get_tool_definitions() function that describes nine of those names in a
provider-agnostic schema (it omits write_file, delete_file, and
move_file). That function has no callers anywhere in the workspace.
The definitions are never sent to a model.
The reason is one level down. perspt-core::llm_provider::GenAIProvider
exposes exactly three generation entry points —
generate_response_simple, generate_response_with_retry, and
generate_response_stream_to_channel — and none of them accepts a tool
list or returns tool calls. The underlying genai 0.6.5 client supports
tool calling (ChatRequest::with_tools, Tool, ToolCall,
ToolResponse, ToolChoice, and ChatOptions::with_capture_tool_calls
for streaming), but Perspt does not use any of it.
The consequence is that Perspt’s agent is a closed pipeline, not an agent loop:
architect → task plan (JSON)
actuator → ONE text bundle containing whole file contents
orchestrator → parses the bundle, calls tools itself
verifier → build/test/lint/LSP
correction → new prompt, regenerate the bundle
Every arrow above is Perspt’s code deciding. The model contributes text at two points and never observes a tool result mid-turn. This produces three failure modes that are visible in real runs and are structural, not model-quality problems:
Blind editing. The actuator must emit whole files without first reading neighbouring code, so on an existing repository it guesses APIs, import paths, and module layout. PSP-8 added a goal-presence sensor and directed corrections to catch the resulting damage after the fact; a tool loop lets the model avoid producing it.
No incremental evidence. A failing build is only observed at the end of a generation. The model cannot run one test, read one error, and edit one function; it regenerates the bundle. This is expensive and it is why correction rounds dominate cost in existing traces.
Fixed tool repertoire per node type. Which tools run is decided by the orchestrator’s node type, so the model cannot decide that this particular task needs
git log, a dependency addition, or a targeted grep.
Perspt Cannot Hold More Than One Provider
Perspt already advertises many providers — openai, anthropic,
gemini, vertex, groq, cohere, ollama, xai, deepseek
— but only one per process:
Configcarries a singleprovider, a singlemodel, and a singleapi_key.GenAIProvider::from_configresolves exactly oneAdapterKind, builds one boundgenai::Client, and returns oneResolvedProvider.Orchestratorstores oneArc<GenAIProvider>and hands the same handle toArchitectAgent,ActuatorAgent, and the verifier agents, varying only the model-name string.perspt-sdk::routing::ModelTierConfigtherefore types its four tiers asStringmodel names, andresolve_routereturns aModelRoutewhosemodelandfallback_modelare names resolved against that one client.
So the existing tier architecture — Speculator, Verifier, Actuator,
Architect — is a within-vendor routing scheme. Its role separation is a
useful starting point, but changing it requires provider ownership, routing,
conversation, tool transport, configuration, and ledger changes; as built it cannot express
“explore with a local model, implement with vendor A, adjudicate with vendor B,”
and it cannot survive one vendor’s outage. This limits optional model-validator
routes, but it does not prevent a Corollary 5.2 study over compiler, test, or
other deterministic validators. That certificate depends on matched labeled
verdicts and conservative joint-miss bounds, not provider count.
residual::IndependenceRoute already anticipates this. It distinguishes
SeparateModel from SameModelCritique, and
is_full_weight_eligible() classifies same-model critique as ineligible for
full weight. That current helper is a provenance heuristic with no live energy
consumer, not a Paper III risk certificate. This PSP retains the route
classification for attribution and stratification but removes the unsupported
attenuate_weight helper and prohibits correlation-driven changes to gate
energy (system 8).
PSP-8 Left the Platform Contract Unwired
PSP 000008 implemented the Paper III platform machinery in perspt-sdk
and unit-tested it, but its own Implementation Status table records that
much of it is never invoked during a real run:
PSP-8 Phase |
Status |
SDK contract that exists but has no live consumer |
|---|---|---|
2 — Scheduler |
Partial |
|
3 — Capability kernel |
Partial |
|
4 — Replay ledger |
Partial |
|
5 — Spectral / independence |
Not wired |
|
7 — Exploration + routing |
Not started |
|
8 — Conformal budgets |
Not wired |
|
9 — Observability |
Partial |
|
These are not coincidentally unwired. Each is a contract about effects, and Perspt currently has no effect proposals — the orchestrator performs effects directly. A capability kernel with nothing to mediate, a replay ledger with no recorded proposals, a scheduler with no footprints, and a conformal threshold with no acceptance decision to calibrate all have the same cause. Introducing the tool loop supplies the missing subject, which is why this PSP fuses the work instead of sequencing it.
independence::compute is unwired for a second, independent reason: it needs
VerdictRecords from validators that can actually disagree. That is the
model plane’s job.
What the Papers Require
Paper I supplies the state model and, in its §12, the piece a tool loop needs most. Its realizability interface (Definition 12.2) prices the fact that a model proposes in an idealized space while a system commits discrete artifacts: every proposal is projected to a realizable artifact and re-embedded before the barrier evaluates it, and the mismatch is the realizability residual rk. Assumption 6 bounds it by δr; Theorem 12.4 converts asymptotic decay into practical stability with a floor of order δ2r; Corollary 12.5 makes commit feasibility and the retry budget explicit, and states that when the floor exceeds the tolerance no amount of retrying converges and the correct action is task refinement. Paper I names the deployment shape Perspt most closely follows — Regime B, black-box APIs with artifact revision — and says of it that the effective δr must be measured, not assumed. Matching the regime does not by itself supply its proxy geometry.
Paper II gives the harness contract: measure residuals r_t from
independent verifiers, aggregate to energy
V = ∑ewe‖re‖2, direct correction at the dominant
residual, and accept a candidate only on hard pass or measured descent
V ≤ Vbest − ρ. Its Lemma 1 gives the property this PSP
most needs: a gate over a nonnegative energy with a descent tolerance and a
finite correction budget makes at most
⌊V0 ⁄ ρ⌋ + B + 1 decisions and always reaches a
classified terminal state. Its Theorem 3 states the converse: a harness that
admits arbitrarily long unchecked intervals has no horizon-independent
reliability certificate at all, however good its repairs are. A tool loop whose
configuration permits such intervals falls into that class.
Paper III governs the effects and the ensemble. Stochastic components emit proposals, never effects; a deterministic admissibility kernel checks authority, contract, effect scope, barrier increment, and risk budget before commitment; delegation can only attenuate authority (Theorem 1), and that survives self-modification (Theorem 2). Corollary 4.2 is the security claim that matters for a coding agent reading untrusted repository content: prompt injection can corrupt what the model proposes, never what it is authorized to do. Lemma 5.1 and Corollary 5.2 govern redundancy — “correlation among redundant validators is measured, never assumed away”. Theorem 5 calibrates risk budgets distribution-free from the platform’s own ledger. Theorem 6 makes recovery terminate; Theorem 7 makes replay exact; Theorem 8 says only conflicting commits need ordering; Theorem 9 lifts the per-loop gate to platform backlog stability.
Perspt has many domain-neutral mathematical primitives, but several are representative or telemetry-only rather than theorem-complete on the live path. This PSP supplies the loop and model plane while closing the following concrete gaps found in the current tree:
Surface |
Current code |
PSP-9 requirement |
|---|---|---|
Model tool transport |
|
Structured, recorded multi-turn tool request/response transport |
Provider ownership |
|
Typed |
Acceptance authority |
|
One authoritative measured gate and one budget accounting path |
Admissibility |
|
Explicit five-clause witness; absent barrier evidence fails closed for chance-safety claims |
Validator independence |
Pair correlations use joint candidates, marginal miss rates use all candidates, and zero variance maps to zero correlation |
Matched strata, direct degenerate joint misses, delayed labels, and conservative uncertainty bounds |
Work graph |
Live execution mutates a |
SDK revision/generation model is the single scheduler source of truth |
Language verifier extension |
|
|
Replay |
SDK ledger is in-memory and |
Durable canonical transition records and deterministic audit fold |
Paper I kernel |
Perspt pins |
Upgrade through the narrow adapter; coding remains unmeasured until a
valid |
Proposed Changes
Where This Lands: Foundations, SDK, Domains, Plugins
Perspt already has the layering this PSP needs, and the first requirement on every system below is that it lands in the layer that owns it rather than in the orchestrator. The existing stack, verified against the crate graph:
srbn 0.3.0 srbn-serde 0.3.0 Paper I kernel: stabilize /
srbn-ledger 0.3.0 srbn-regex 0.3.0 stabilize_realized, Realizer,
(published crates, not forked) Policy, BarrierResult, Status,
^ attempt traces, Merkle helpers
| perspt-sdk::kernel (narrow adapter)
|
perspt-sdk Papers II + III as executable
no Perspt dependencies contracts. Domain-neutral, publishable,
no transport, no vendor, no I/O.
^ ^
| |
perspt-coding perspt-research Domain packages:
perspt-<next> AgentDomainPackage impls.
depend on: perspt-sdk only Residual schema, energy model,
correction directions,
verifier-suite adapters.
^
|
perspt-agent (composition root) Runtime: orchestrator, tool loop,
depends on: core, sdk, coding, adapters between ports and drivers.
policy, sandbox, store
perspt-core Process host: config, provider
depends on: genai; NOT on the SDK transport, plugin registry, events.
Two facts about this graph constrain the whole PSP and were confirmed in the manifests rather than assumed:
perspt-sdkdepends onsrbnandsrbn-serdeand on no Perspt crate. It is a standalone, publishable SDK. Nothing in this PSP may give it a dependency onperspt-core,genai, the filesystem, or a network client. It is currently pinned atsrbn 0.1.1; this PSP requires the upgrade to0.3.0described below, which is where the realizability interface lives.perspt-coredoes not depend onperspt-sdk. It hostsgenaiand the language plugin registry, and it must keep serving plain chat mode without pulling in the agent control plane.
The consequence for the model plane is decided here rather than discovered during implementation: the SDK declares the port, ``perspt-core`` provides the driver, and ``perspt-agent`` supplies the adapter.
// perspt-sdk::model — pure data, no transport, no vendor.
pub type TransportFuture<'a, T> =
Pin<Box<dyn Future<Output = Result<T>> + Send + 'a>>;
pub trait ModelTransport: Send + Sync {
fn chat_turn<'a>(
&'a self,
model: &'a ModelId,
conversation: &'a Conversation,
tools: &'a [ToolSpec],
choice: ToolChoicePolicy,
) -> TransportFuture<'a, TurnOutput>;
fn capabilities(&self, model: &ModelId) -> ProviderCapabilities;
fn family_of(&self, model: &ModelId) -> ModelFamily;
}
// perspt-core::llm_provider — genai driver, SDK-free.
// perspt-agent::transport — impl ModelTransport for GenAiTransport.
This is not architectural bookkeeping. It makes Gate S structural rather than
aspirational: perspt-agent::toolloop is written against
dyn ModelTransport. The boxed-future signature is deliberate: an async
fn directly on the trait would not be object-safe on the Rust toolchain used by
this workspace. The loop may inspect provider-neutral capabilities and model
identity for routing and attribution, but it cannot inspect genai adapter
types or credentials. This keeps the SDK usable by a consumer who brings a
different transport and never links genai.
Kernel Upgrade: srbn 0.1.1 → 0.3.0
The SRBN kernel has moved with Papers I and II, and perspt-sdk is a release
behind. Upgrading is a prerequisite for this PSP rather than a chore, because
the new surface is exactly what a tool loop needs. The 0.3.0 family is built on
edition 2024 with rust-version = 1.85, and Perspt currently declares no
MSRV at all; this PSP therefore sets rust-version = "1.85" in
[workspace.package] so the toolchain floor is stated where Cargo enforces
it rather than discovered as a build failure.
New in |
Why this PSP requires it |
|---|---|
|
Paper I Definition 12.2. Every proposed state is realized before the barrier evaluates it, so “a candidate cannot pass the gate on evidence about an artifact that would not actually be committed.” This is the single most important correctness property of a tool loop, and it now has a kernel interface instead of an orchestrator convention (system 10). |
|
Assumption 6’s δr can become a measured deployment
quantity for domains that implement |
|
|
|
|
|
SHA-256 hash-chain helpers with generic |
|
Regex-backed |
Migration is concentrated in perspt-sdk::kernel, the adapter that already
exists for precisely this reason: it converts Perspt’s AgentBarrierResult
into the kernel’s BarrierResult and keeps Perspt’s WorkGraph, residual, and
capability types out of the kernel crate. Call sites and serialization fixtures
must also migrate to 0.3.0. The adapter absorbs the Policy and Status
additions; the Realizer is new surface that perspt-agent implements.
The rule is unchanged and restated because it will be tempting to break it
under deadline: Perspt does not fork the kernel. If a Paper I mechanism is
missing, it is added upstream in srbn and consumed here.
Three properties of the 0.3.0 surface constrain how it is consumed, and each is absorbed at the seam rather than worked around downstream:
The kernel is synchronous.
srbn::Realizer::realizeis a blocking call andstabilize_realizedis a synchronous loop, while Perspt’s realization re-reads an overlay and runs verifiers — async I/O on a tokio runtime. The live tool loop therefore performs realization asynchronously inperspt-agentand hands the already-realized value to a pure syncsrbn::Realizeradapter;stabilize_realizedis used as the conformance parity oracle, never as the live async path (system 10).State must be ``Clone``. The kernel clones every attempt into its trace, so
WorkspaceStateis a cheap content-addressed handle — hashes and ids, never file contents.Traces are export-only.
srbn-serdeserializes but does not deserialize, so Theorem 7’s deterministic fold cannot round-trip kernel types.perspt-storeowns its own versioned, deserializable transition envelope and embeds the kernel’s trace JSON as an opaque, hash-checked blob.
Theory → Mechanism → Consumer
Several mechanisms named by the trilogy already have SDK types or unit-tested
skeletons in the tree; others exist only in the published srbn crates or in
the papers. This PSP completes them and gives them one authoritative live
consumer. Stating the mapping explicitly is the trilogy’s own discipline —
every certificate names the predicate that would falsify it, and the predicate
runs.
Paper result |
Implementing mechanism |
Consumer added or completed here |
|---|---|---|
I: Lyapunov energy V = ∑ewe‖re‖2 |
|
System 9 scores turn boundaries; domain packages own the weights |
I: stabilization loop, barrier result |
|
System 6 preserves restore-best and measured-gate semantics while using Paper II’s separate descent/rejection accounting |
I: Def. 12.2 realized-state gate (Regime B construction) |
|
System 10 invokes the same realization boundary before its asynchronous tool-loop gate; coding uses an unmeasured realization initially |
I: Assumption 6, bounded δr |
|
Optional |
I: Thm 12.4 practical stability |
floor of order δ2r |
Enabled only for domains with a complete analytic |
I: Cor. 12.5 commit feasibility |
floor vs. tolerance inequality |
Optional analytic mechanism. Coding uses measured plateau/budget escalation and SHALL NOT label it Corollary 12.5 |
I/II: restore-best gate rule |
|
System 10 preserves and conformance-tests the kernel semantics while
|
I: Merkle-ized state (Def. 7.1, Thm C.1) |
|
System 14 makes it the live persistence model, with durability in
|
II: acceptance gate |
|
System 10; candidate becomes a turn boundary |
II: Lemma 1 finite decisions |
|
System 6 logs and enforces it; ensembles consume it (Gate M) |
II: Theorem 3 sparse feedback |
turn budget |
System 6 rejects unbounded-unverified configs and enforces |
II: Lemma 2 spectral slope |
|
System 17 answers “does this new verifier earn its cost” |
II: residual-directed correction |
|
System 10 gains tool- and route-naming corrections |
III: Def. 3.2 admissibility |
|
System 12 routes every model-issued call through it |
III: Thm 1–2 confinement |
|
Systems 12–13, including child-role leases, authority epochs, durable grant ceilings, and external tool registration |
III: Cor. 4.2 blast radius |
kernel tables outside proposal reach |
Systems 12–13; the |
III: Lemma 5.1 / Cor. 5.2 |
|
System 8 — risk reporting for labeled conjunctive validator gates; never a dynamic energy-weight rule (Gates R and T) |
III: Thm 5 conformal budgets |
|
System 16, keyed per complete stratum with shadow/audit epochs |
III: Def. 8.1, Thm 6 recovery termination |
|
System 11, extended to transport failures; one shared cascade pool and the four Theorem 6 terminal classes |
III: Thm 7 replay determinism |
|
System 14; credential-free replay and recorded context compaction |
III: Thm 8 commuting commits |
|
System 15; footprints finally have a source |
III: Def. 9.1 R1–R6 |
|
System 14’s obligation table |
III: Thm 9 platform stability |
|
System 17’s Φ(W) gauge |
What is deliberately not claimed. perspt-coding today returns
StabilityClaim with the continuous constants α, β, δ, L, η marked NotClaimed, because a coding workspace exposes no continuous
embedding coordinate: only the measured discrete gate and the spectral
μ apply. This PSP does not change that. A tool loop does not turn
Paper I’s Theorems 5.1/5.2 continuous-time decay into a coding-domain claim, and
any implementation that starts reporting an exponential-decay rate for a coding
node is wrong.
The realizability interface needs the same care. srbn defines
rk = E(ak + 1, sk + 1) − ~xk + 1 as a normed difference in
the analysis space. The coding domain currently has neither
~xk + 1 nor a validated encoder E. A fraction of
edits denied or rewritten is useful operational telemetry, but it is not that
residual and SHALL be named projection_mismatch, not
‖rk‖. Coding therefore uses
Realization::unmeasured while still obtaining Definition 12.2’s structural
property that the barrier runs on the realized candidate. Corollary 12.5 is
disabled for coding until a domain supplies ProxyGeometry and all constants
required by Theorem 12.4. Measured plateaus can still trigger node refinement,
but that is an empirical recovery policy rather than an analytic verdict.
The honest claims therefore remain conditional and independently activated: finite decisions (Paper II Lemma 1) once every descent and rejection consumes the stated budget; realized-state gating (Paper I Definition 12.2) as a construction; confinement (Paper III Theorems 1–2) once all authority-changing effects are mediated; exact replay (Theorem 7) once full transition inputs and observations are durable; calibrated budgets (Theorem 5) only for a valid calibration stratum; and ensemble risk (Corollary 5.2) only for a labeled conjunctive validator gate with conservative estimates.
Notation: Budgets and Tolerances That Are Not Interchangeable
Paper III states the hazard in its own words — the platform’s budgets “are related accounting devices, not interchangeable assumptions” — and the trilogy reuses ρ and δ for several distinct quantities. This PSP is the first document to wire all of them into one runtime, so it fixes the names here. An implementation that stores two of these in one configuration field has already lost the corresponding theorem.
Symbol |
Source |
What it is, and what it is not |
|---|---|---|
ρgate |
Paper II gate, Lemma 1 |
The measured descent tolerance ( |
B |
Paper II Lemma 1 |
The correction budget, consumed by rejections and not by descent-acceptances. |
b, k |
Paper III Def. 8.1, Thm 6 |
The shared non-replenishing cascade budget and the escalation depth
( |
cc |
Paper III Def. 3.2, Thm 4 |
A capability’s certified barrier increment. It is simultaneously the barrier-clause allowance and the exact risk-clause debit (system 12). |
ρcap |
Paper III Def. 3.2, risk clause |
The per-capability risk budget satisfying
spent(x) + cc ≤ ρcap ( |
ρt |
Paper III Thm 3 |
A conditional per-step chance bound along the ledger filtration,
giving the horizon-linear bound ∑tρt. Perspt does not
assert it directly; where a |
ρc |
Paper III Thm 5 |
The marginal accepted-unsafe budget calibrated conformally
( |
ρeff |
Paper III Cor. 5.2 |
An upper bound on a conjunctive validator ensemble’s joint miss probability. Not a budget, not configurable, and reportable only under system 8’s evidence conditions. |
δ |
Papers I–II |
The exogenous disturbance bound in the ISS tube
V∞ = δ2 ⁄ (2(α − β)2μ); present today as
|
δr |
Paper I Assumption 6 |
The realizability residual bound — a property of π and
E, not of the environment. It lives in |
How Domains and Plugins Extend This
The eighteen systems are domain-neutral. A domain package extends them through one required trait. Breaking the trait now prevents a domain from silently claiming agent support while exposing no governed tools or hard-gate policy:
pub trait AgentDomainPackage: Send + Sync {
fn domain_id(&self) -> DomainId;
fn detect(&self, workspace: &WorkspaceSnapshot) -> DomainDetection;
fn residual_schema(&self, scope: &DomainScope) -> ResidualSchema;
fn energy_model(&self, scope: &DomainScope) -> EnergyModel;
fn correction_directions(&self, r: &[ResidualEvent]) -> Vec<CorrectionDirection>;
fn tool_entries(&self, scope: &DomainScope) -> Vec<ToolEntry>;
fn hard_gate_policy(&self, scope: &DomainScope) -> HardGatePolicy;
fn verifier_suite(&self, scope: &DomainScope) -> VerifierSuiteSpec;
fn safety_barrier(&self, scope: &DomainScope) -> SafetyBarrierDisposition;
fn adjudication_brief(&self, _c: &CandidateRef) -> Option<AdjudicationBrief> { None }
fn proxy_geometry(&self, _scope: &DomainScope)
-> Option<&dyn ProxyGeometry> { None }
}
SafetyBarrierDisposition is required even when it contains
NotClaimed(reason). This prevents a domain from inheriting a vacuous barrier
default; autonomous certification requires Registered(BarrierSpec) and the
runtime evidence specified by system 12.
The division of labour, using the two domains that exist:
Layer |
Owns |
|---|---|
|
Tool contract: schema shape, |
|
Coding tool entries ( |
|
The second-domain conformance check. It inherits the tool loop, kernel,
ledger, portfolio, ensembles, and adjudication for free; it supplies
its own tool entries (source discovery, citation fetch), its residual
classes (unsupported claim, stale evidence, source mismatch, citation
gap), and its correction directions. If adding a research tool loop
requires editing |
|
The runtime half of language knowledge: |
The seam between perspt-coding::lang::LanguageAdapter and
perspt-core::plugin::LanguagePlugin is deliberate and this PSP preserves it:
the adapter parses output into residuals and never shells out, the plugin knows
commands and availability and never parses diagnostics, and the runtime joins
them. Tool entries are bound at catalog-assembly time by asking the plugin
registry for the profile, so a workspace with no cargo on PATH simply
does not offer run_build — and says why.
That last behaviour is not new, which is the point: VerifierProfile already
carries any_available() and fully_degraded(), and Perspt already records
a degraded verifier rather than pretending. System 2’s provider degradation
ladder is the same discipline applied to the model plane, and it should look
familiar to a reviewer of the plugin code because it is deliberately the same
shape.
Functional Specification
Perspt gains eighteen load-bearing systems in four layers. Layer A is the model plane and is new in this revision. Layer B is the Paper II harness. Layer C is the Paper III platform contract. Layer D is the product surface. Each system below names the layer of the crate graph that owns it.
Layer A — Model Plane
1. Provider Abstraction and the Model Portfolio
Owner: identity types in perspt-sdk::model; transport in
perspt-core::llm_provider.
Perspt gains a portfolio: several concurrently live provider handles,
addressed by a typed model identifier rather than a bare string. The identity
half is pure data and belongs to the SDK, because routing, toolset, and
independence all need to name a model and none of them may know what a
client is:
// perspt-sdk::model
/// A fully qualified model: which provider serves it, and which model.
pub struct ModelId {
pub provider: String, // "anthropic", "openai", "ollama", "vertex"
pub model: String, // provider-native model name
}
/// A model's training lineage, used only as a routing *prior*.
pub enum ModelFamily {
OpenAiGpt, AnthropicClaude, GoogleGemini, XaiGrok,
DeepSeek, CohereCommand, Llama, Qwen, Mistral, Other(String),
}
The transport half owns the credentials, the genai clients, and the rate
limiters, and stays SDK-free:
// perspt-core::llm_provider
pub struct ProviderHandle {
pub id: String,
pub adapter: AdapterKind,
pub client: Arc<genai::Client>,
pub caps: ProviderCapabilities, // system 2
pub limits: RateLimits,
}
pub struct ModelPortfolio { /* provider id -> handle */ }
impl ModelPortfolio {
pub fn from_config(config: &Config) -> Result<Self>;
pub fn resolve(&self, provider: &str) -> Result<&ProviderHandle>;
pub fn available(&self) -> Vec<(String, String)>;
pub fn family_of(&self, provider: &str, model: &str) -> &'static str;
}
perspt-agent::transport::GenAiTransport wraps the portfolio and implements
perspt_sdk::ModelTransport, translating the SDK’s ModelId and
ModelFamily to and from the core representation. Everything above the
transport — the turn loop, routing, adjudication, calibration — sees only the
SDK types.
Two distinctions carry weight and must not be collapsed:
Provider ≠ family.
groq,vertex,ollama, and several OpenAI-compatible gateways are hosts, not model families. Llama served by Groq and Llama served by Ollama are the same lineage and will miss the same defects; two different endpoints are not two opinions.family_ofexists so routing never mistakes an endpoint for a viewpoint.Family is a prior, not a measurement. Even a different family is not guaranteed decorrelated — training corpora overlap.
ModelFamilytherefore only seeds routing defaults; no numeric κ is inferred from it. Credited independence comes from matched labeled ledger statistics (system 8). This follows the paper’s own discipline: point estimates are diagnostics; publication-grade budgets use conservative estimates.
Config is replaced by a [providers] table so several credentials
coexist. Model tiers change from String to fully qualified ModelId:
[providers.anthropic]
api_key_env = "ANTHROPIC_API_KEY"
[providers.openai]
api_key_env = "OPENAI_API_KEY"
[providers.local]
adapter = "ollama"
base_url = "http://localhost:11434"
[models]
architect = "anthropic::<model>"
actuator = "openai::<model>"
verifier = "anthropic::<model>"
speculator = "local::<model>"
adjudicator = "openai::<model>" # system 8
A portfolio may contain one entry, but route values remain fully qualified so
identity, calibration, and replay never depend on an ambient default provider.
Provider records describe resolution policy, not embedded secrets. The
portfolio preserves GenAIProvider’s existing credential behavior: API-key
providers may name an environment variable; Vertex may omit a static key and
use its per-request ADC token resolver, project discovery, and global
location default. The portfolio must not snapshot a short-lived OAuth token at
startup or require project/location literals when the existing resolver can
discover them. Model names remain route configuration rather than SDK defaults.
2. Provider Capability Matrix and Honest Degradation
Owner: the record type in perspt-sdk::model; probing and the ladder in
perspt-core.
Providers differ in what they support, and a platform that hides those differences will silently violate its own contracts. Each handle carries a declared and probed capability record:
pub struct ProviderCapabilities {
pub tool_calling: bool,
pub strict_schema: bool,
pub parallel_tool_calls: bool,
pub streaming_tool_calls: bool,
pub prompt_caching: bool,
pub structured_output: bool,
pub max_context_tokens: u32,
}
The degradation ladder is explicit, ordered, and recorded:
Missing capability |
Degradation |
|---|---|
|
Send non-strict schemas; validate arguments locally; a violation is a
|
|
Issue one tool call per turn. Costs turns, changes no invariant. |
|
Non-streaming turn; the TUI shows turn-granular rather than token-granular progress. |
|
Route accounting marks the route as cache-cold; portfolio routing (system 3) weights it accordingly. |
|
Route is ineligible as an actuator; select an explicit tool-capable fallback or stop before session creation. |
context shorter than the node’s packed context |
Route is ineligible for that node; routing selects another or the node is split. |
Every degradation emits a ProviderDegraded ledger event and is visible in
perspt providers. Silent emulation is prohibited. A provider without
tool calling SHALL NOT be given a text protocol that imitates tool calls,
because emulated calls are not recorded structured observations and would break
the recording obligation (R2) that Theorem 7 depends on. This rule is Gate U.
3. Portfolio Routing, Failover, and Exploration
Owner: perspt-sdk::routing, entirely. Routing is a decision, not a
call, so it stays in the SDK and is unit-testable without a network.
routing::resolve_route is extended to resolve a ModelId rather than a
name, and to carry the objective it optimized:
pub struct RouteObjective {
pub max_cost_per_node: Option<Cents>,
pub max_latency: Option<Duration>,
pub require: ProviderCapabilityMask,
/// Prefer a family decorrelated from `decorrelate_from` (system 8).
pub decorrelate_from: Option<ModelId>,
}
pub struct ModelRoute {
pub phase: AgentPhase,
pub resolved_tier: ModelTier,
pub model: ModelId, // was: String
pub fallback: Vec<ModelId>, // was: Option<String>
pub budget: ModelBudget,
pub reason: String,
}
Routing policy, with defaults chosen to be cheap before they are clever:
ExploreandResearch→ cheapest capable route, local model preferred when one is configured. Exploration is read-only (system 12), so a weaker model is a cost decision, not a safety decision.ImplementandRepair→ strongest configured actuator route.VerifyandReview→ a route whose family differs from the actuator’s whenever the portfolio permits, because that is the verdict worth recording.Plan→ architect route.
Two engineering realities are specified rather than discovered later:
Cache locality. Prompt caching is per-provider and per-conversation. Switching vendors mid-node discards the cache and can cost more than the better model saves. Routing is therefore sticky within a node by default; cross-vendor moves happen at node and role boundaries, not per turn. The exception is the adjudication call of system 8, which is a separate short conversation by construction.
Failover is recovery, not retry. A provider error, rate limit, or capability mismatch escalates to recovery level 1 (system 11) and selects
fallback, which is preferentially a different provider. The switch, its cause, and the substitutedModelIdare ledger events, and any residual produced after the switch is attributed to the new route so calibration (system 16) is not contaminated.
Layer B — Harness (Paper II)
4. Provider Tool-Calling Surface
Owner: contract types and the ModelTransport port in
perspt-sdk::model; the genai driver in perspt-core; the
adapter in perspt-agent.
The wire-neutral types are SDK types, because ToolCatalog::specs_for
produces them and the turn loop consumes them:
// perspt-sdk::model
/// A provider-agnostic tool declaration sent with a chat request.
pub struct ToolSpec {
pub name: String,
pub description: String,
/// JSON Schema for the tool's arguments.
pub schema: serde_json::Value,
pub strict: bool,
}
/// One tool call requested by the model.
pub struct ProviderToolCall {
pub call_id: String,
pub name: String,
pub arguments: serde_json::Value,
}
/// The result of one assistant turn.
pub enum TurnOutput {
ToolCalls(Vec<ProviderToolCall>),
Text(String),
}
/// The message log the harness owns: system, user, assistant,
/// assistant-tool-calls, tool-response. Never a vendor type.
pub struct Conversation { /* … */ }
perspt-core implements the driver against genai with its own mirror of
these shapes, and perspt-agent::transport performs the one translation:
ToolSpecmaps togenai::chat::Tool::new(name).with_description(..) .with_schema(..).with_strict(..);ProviderToolCallmaps togenai::chat::ToolCall; tool results are returned asgenai::chat::ToolResponse::from_tool_call(..). Streaming usesChatOptions::with_capture_tool_calls(true)and readsStreamEnd::captured_tool_calls().Streaming adds
ModelTransport::chat_turn_stream_to_channelwith the same signature plus anEventSender, so the TUI path and the headless path share one contract.Because
Conversationis Perspt’s own log rather than a vendor type, it is re-rendered per provider on each turn. That is what makes a mid-run provider swap possible at all, and it is why no vendor’s wire format reaches the harness.Malformed tool arguments are not retried blindly. They are a
ToolArgumentInvalidresidual with a directed correction naming the offending field, consistent with PSP 000007’s fail-closed parse-validate discipline.
The duplication between the SDK’s ToolSpec and the core driver’s mirror is
accepted deliberately; see Practical Decisions.
5. Typed Tool Catalog
Owner: perspt-sdk::toolset for the contract; perspt-coding /
perspt-research for domain entries; perspt-core::plugin for the
command bindings.
A new perspt-sdk::toolset module owns the domain-neutral catalog. Each entry
binds a tool name to its argument schema, its PSP-8 EffectKind, its
RiskClass, and its scheduler Footprint. The catalog is data, so a domain
package — or an external tool server (system 13) — can extend it without forking
the harness.
pub struct ToolEntry {
pub name: String,
pub effect: EffectKind,
pub risk: RiskClass,
pub schema: serde_json::Value,
/// Declarative selectors mapping validated arguments to resources.
pub footprint: FootprintSpec,
/// Whether the tool mutates durable state (gates R5 bracketing).
pub durable: bool,
pub origin: ToolOrigin, // Builtin | Domain | External(ServerId)
}
pub enum ResourceSelector {
Literal(Resource),
PathArgument { field: String, access: AccessMode },
ParentManifestOf { field: String, access: AccessMode },
ProviderRateLimit { model_field: Option<String> },
OpaqueWorkspace,
}
pub struct FootprintSpec {
pub selectors: Vec<ResourceSelector>,
}
pub trait ToolCatalog {
fn entries(&self) -> &[ToolEntry];
fn specs_for(&self, caps: &[Capability]) -> Vec<ToolSpec>;
}
The footprint is data, not an executable function pointer. This matters for
serialization, replay, and external-tool registration: the kernel resolves a
FootprintSpec only after JSON-schema validation and path canonicalization,
and an unknown selector fails closed to OpaqueWorkspace. The base catalog
maps onto the EffectKind variants PSP-8 already declares. The Risk column holds
capability::RiskClass values (None/Low/Medium/High/
Critical); “privileged” is the separate EffectKind::is_privileged()
property, not a risk level.
Tool |
|
Risk |
Notes |
|---|---|---|---|
|
|
Low |
Host-side deferred-catalog discovery; matches activate on the next turn. |
|
|
Low |
Bounded pure-Starlark composition; every nested call returns to the five-clause kernel. |
|
|
Low |
One shell-free, read-only OS program in the inspection sandbox
( |
|
|
Low |
Offset/limit windows; returns line-numbered content. |
|
|
Low |
Respects ignore files. |
|
|
Low |
Pattern → paths, sorted by mtime. |
|
|
Low |
Replaces |
|
|
Low |
Definitions, references, hover, diagnostics via |
|
|
Low |
|
|
|
Medium |
Whole-file creation; the bundle path’s effect, now model-issued. |
|
|
Medium |
Exact-string replace with uniqueness check; fails closed on ambiguity. This is the tool the current pipeline most lacks. |
|
|
Medium |
Unified diff, existing implementation. |
|
|
Medium |
Existing implementations. |
|
|
Medium |
Domain-package commands, not free-form shell. Output is parsed into
residuals by the |
|
|
Medium |
Scripts declared in the project profile. |
|
|
Low |
The shipped system-explorer family, registered through the open
execution plane. Read-only; |
|
|
Low |
The shipped local-DB-explorer family. |
|
|
High |
|
|
|
High |
Requires an explicit |
|
|
High |
|
|
|
High |
Defaults to ask; domain allow-lists permitted. |
|
|
Low |
The model’s escalation channel (Theorem 6, level 3). |
|
|
Critical |
Privileged effect. Split/add/retire work-graph nodes; validated against PSP-8 revision rules. |
|
|
Critical |
Privileged effect. Delegation; capability MUST attenuate (Theorem 1). The child may be routed to a different provider. |
sed_replace and awk_filter are removed from the model-facing
catalog. Their current argument contracts do not provide the exact-match and
state-witness preconditions required for governed mutation; edit_file and
apply_diff cover their uses. They are removed rather than retained through
an internal bypass, because this PSP does not preserve an unmediated effect
path.
Catalog assembly is a three-way join, and each side keeps its existing job.
The SDK contributes the base entries and the effect/risk/footprint contract; the
active AgentDomainPackage contributes tool_entries for its domain; and
perspt-core::plugin::PluginRegistry supplies the VerifierProfile that
binds run_test / run_build / run_formatter / lsp_query to actual
commands for this workspace. A workspace whose profile reports
any_available() == false for a stage does not get that tool in the catalog,
and the omission is reported with its reason rather than silently swallowed —
the same rule VerifierProfile::fully_degraded() already expresses today.
The current coding side is not yet registry-shaped: CodingLanguage is a
closed Rust/Python/TypeScript enum, adapter_for is a match, and
sdk_bridge::coding_language_for repeats string matching in the agent. This
PSP replaces those with LanguageId(String) and a
CodingAdapterRegistry. perspt-core::plugin::LanguagePlugin continues to
own command discovery and availability; perspt-coding::LanguageAdapter owns
diagnostic normalization, hard-gate classification, runtime probes, and directed
correction. perspt-agent joins the two registries by LanguageId and has
no language match statement. Adding Go then means registering those two halves,
not editing the orchestrator.
The catalog offered to the model is then derived from the actor’s held
capabilities, via specs_for. A model that holds no RunShell capability
never sees run_shell in its tool list. This is defence in depth, not the
security boundary — the kernel is. It also normalizes across providers: the same
capability set yields the same tool list whichever vendor is serving the turn,
which is half of Gate S.
6. The Agentic Turn Loop
Owner: rules in perspt-sdk (gate, energy, budgets, certificates);
execution in perspt-agent::toolloop.
A new perspt-agent::toolloop module implements the SRBN harness contract of
Paper II §”Engineering Pattern” as an executable loop — the direct analogue of
Paper II Appendix A Algorithm 1, with tool calls substituted for bundle
generation.
Algorithm: SRBN tool loop (one node generation)
Input: goal G, conversation T, capabilities C, catalog K, verifier suite Q,
route R, descent tolerance rho_gate, correction budget B, turn budget N,
max tool calls per turn M, max unverified mutations H
Output: terminal checkpoint eligible for delivery, or residual certificate
1. c_best <- measured baseline checkpoint; V_best <- V(c_best)
if baseline is hard pass or declared floor: classify and return
2. c_work <- isolated candidate overlay forked from c_best; u <- 0
3. for turn = 1..N:
4. out <- transport.chat_turn(R.model, T, K.specs_for(C), choice)
5. record_observation(out) before inspecting it
6. for each tool call tc in out.tool_calls: # PROPOSE
7. p <- proposal_from(tc, state_witnesses(c_work))
8. pre <- if ordinal(tc) > M then deny(ToolCallBudgetExceeded)
else kernel.precheck_authority_input_effect(p, C, c_work)
9. if pre denied: o <- deny_residual(pre); record_observation(o); goto 12
10. candidate, o <- prepare_transition_in_child_overlay(p, c_work)
record_observation(o) before evaluating it
11. w <- kernel.check_contract_barrier_risk(p, c_work, candidate, o)
record proposal, observation, and complete witness
if w.allowed: c_work <- candidate; if mutating(p): u <- u + 1
else: discard(candidate)
12. T <- T + tool_response(tc, o)
13. if out requests more tools and turn < N and
u < H: continue
14. c_real <- reread_overlay_and_environment(c_work) # Paper I Def. 12.2
15. evidence <- Q.run(c_real) # MEASURE
16. residuals <- typed_residuals(evidence, turn_outcomes)
17. V <- score_candidate(residuals, fixed_energy_model)
18. decision <- gate(hard_pass(evidence), V, V_best, rho_gate,
declared_energy_floor)
19. if decision is hard pass:
20. checkpoint(c_real); finalize_delivery(c_real); return HardPass
21. if decision is declared floor:
22. checkpoint(c_real); return DeclaredFloor
23. if decision is accepted descent:
24. checkpoint(c_real); c_best <- c_real; V_best <- V
25. c_work <- fork(c_best)
26. T <- T + directed_correction(dominant(residuals)); continue
27. reject(c_real); c_work <- fork(c_best); B <- B - 1
28. T <- T + directed_correction(dominant(residuals))
29. if B == 0: break
30. return ResidualCertificate(residuals, V_best, routes, rejected,
projection_mismatch, ledger_head)
Lines 14–17 are not bookkeeping. They implement the deployable part of Paper I’s
realizability interface (Definition 12.2). The loop consumes
srbn::Realizer / Realization for that boundary and
perspt-sdk::AcceptedTrajectory for Paper II’s separate descent and rejection
budgets. It does not force the entire conversation through
srbn::stabilize_realized, whose 0.3 Policy has one total attempt budget.
The barrier is evaluated on the state that would actually be checkpointed,
never on the model’s account of it. System 10 specifies what realization can and cannot claim for a
coding workspace. Lines 23–26 are equally load-bearing: Paper II Lemma 1 counts
descent acceptances as non-terminal decisions. A descent checkpoint advances
the accepted trajectory; it is not task success and does not end the node.
Tool mutations occur in an isolated candidate overlay (the existing Perspt sandbox is the first driver), not directly in the user’s workspace. An accepted descent checkpoints that overlay for control and replay. Delivery to the user’s workspace is a distinct durable effect, normally allowed only after hard pass. A domain may define a deliverable declared floor, but it must do so explicitly and the UI may not report it as verified success. Irreversible external effects cannot be speculative overlay mutations; they require write-ahead intent and their own approval or compensation contract before execution.
Properties the implementation must preserve:
Gating on the realized state (Paper I Def. 12.2). No gate decision may read the model’s claimed diff. Measurement runs against the candidate overlay after admissibility filtering and effect application, and the difference between the requested and applied effects is recorded as
projection_mismatch. It is recorded as ‖rk‖ only when a domain provides the paper’s normed proxy geometry.Finite decisions (Paper II Lemma 1). Every accepted descent at line 23 decreases accepted energy by at least ρgate; every non-terminal rejection at line 27 decreases a finite budget. The loop makes at most ⌊V0 ⁄ ρgate⌋ + B + 1 gate decisions. The SDK exposes this as
gate::finite_decision_boundandAcceptedTrajectory::decision_bound; the tool loop SHALL log the bound at node entry and SHALL fail the run if the realised decision count exceeds it.Bounded unchecked interval (Paper II Theorem 3).
Nbounds model turns,Mbounds calls in one response, andHforces a verifier boundary after a finite number of mutating effects even if the model keeps requesting tools. Reaching any bound goes to line 14; it does not skip measurement. A configuration permitting an unbounded value is rejected at startup.Observed vs accepted trajectory. Every tool call, every route switch, and every rejected candidate stays in the ledger for audit, learning, and threshold tuning; only gate-accepted states enter the accepted trajectory. Perspt’s stability claims attach to the latter and must be reported as such.
Route-invariance. Changing
R.modelchanges cost, latency, proposal distribution, calibration stratum, and success probability. It never changes the gate formula, capability predicate, budget accounting, or terminal-state definitions. This is Gate S.
Coding uses a bounded adaptive verification cadence, not a fixed choice between “after every call” and “only at the end.” Three boundaries are normative:
Effect boundary, every mutation. Re-read changed artifacts, verify state witnesses and exact postconditions, recompute the operational safety barrier, and incrementally parse every touched source file. This boundary is part of realization/admissibility and is never debounced.
Interleaved evidence boundary. Run touched-file LSP/type diagnostics after at most
Hadmitted mutations, and immediately after a manifest or exported interface change, a high/critical-risk effect, a hand-off/spawn, or an explicit verifier request.H=1for high/critical risk. A domain may choose a smaller bound; runtime tuning may never raise it above the declared maximum.Gate boundary. Before every descent/hard-pass decision, checkpoint, delivery, or graph-revision decision, run the complete verifier suite required by
HardGatePolicy. Builds, tests, and runtime smoke normally live here.
perspt-sdk adds a serializable VerificationCadence to
VerifierSuiteSpec; perspt-coding supplies the language default and
perspt-core::plugin::VerifierProfile supplies available commands. LSP
servers are long-lived and receive incremental document changes; commuting
edits from one tool batch may share one LSP flush, but the batch counts each
mutation against H. Cadence telemetry records verifier latency, cache hits,
residuals discovered per boundary, and escaped defects. These measurements may
optimize work within the bounds; they cannot create an unbounded unchecked
interval. All boundaries emit the same versioned residual schema so energy
remains comparable.
7. Heterogeneous Proposal Ensembles
Owner: EnsemblePolicy in perspt-sdk::model; execution in
perspt-agent::ensemble.
For nodes that have already failed a gate, the harness may draw candidates from different model families instead of correcting one candidate repeatedly. This is an exploration policy, not Corollary 5.2: proposers do not form a conjunctive validator gate, and proposer diversity has no certified risk interpretation.
pub struct EnsemblePolicy {
pub trigger: EnsembleTrigger, // AfterGateFailure | RiskAtLeast(RiskClass) | Never
pub width: u8, // default 2, hard max 4
pub require_distinct_family: bool, // default true
pub budget: ModelBudget,
}
Rules that keep this an SRBN mechanism rather than a lottery:
Ensembles propose; they never decide. Each candidate is scored by the same deterministic verifier suite and admitted only through the ordinary gate (
hard_passor V ≤ Vbest − ρ). Paper III’s rule — stochastic components emit proposals, deterministic admissibility earns commitment — is preserved exactly.Each candidate costs one gate decision. N candidates consume N of the finite budget of Lemma 1. The bound is not weakened, and the loop is not allowed to “try more models” to escape it.
No majority voting. Corollary 5.2 does not certify proposer votes. Three models from overlapping lineages agreeing may be weak evidence, and there is no labeled conjunctive-validator statistic from which to infer otherwise. Selection is by measured energy, which is a compiler-and-test quantity, not a popularity one.
Distinct family required by default. Two samples from one model at different temperatures are a re-roll, not a heterogeneous proposal set. This is a cost and search heuristic whose benefit must survive ablation.
The product hypothesis is concrete and testable: if different lineages fail differently on unfamiliar APIs, the probability that at least one candidate achieves descent should be higher for a heterogeneous pair than for two samples of one model at comparable token cost. This is not assumed by the gate. The benchmark arm in Reference Implementation is designed to reject the policy if the measured benefit does not appear.
8. Adjudication and Measured Validator Dependence
Owner: perspt-sdk::independence (the module exists; this system corrects
its statistics and adds its first live consumer); the adjudicator brief comes
from the domain package.
This system may produce a certificate only after the required labeled data exists. Until then it produces diagnostics and routing priors.
Adjudication. After deterministic verifiers run, an optional adjudicator reviews the realized candidate and evidence and emits a structured pass/fail verdict with reasons. If it participates in a certified validator ensemble, it is conjunctive: its failure blocks the ensemble pass. If it is configured as advisory, it is plainly labeled advisory and has no Corollary 5.2 interpretation. The route may prefer a family different from the actuator’s, but family is only a prior. Two hard rules apply:
It cannot compensate for a failed deterministic hard check. Hard pass always requires the domain’s compiler/test/policy predicates. When a model validator is configured conjunctively, its pass is an additional necessary condition, never a sufficient one.
It does not dynamically change the quadratic energy weights. Energy weights are fixed by the domain contract for the run; changing them from the candidate history would make Vt incomparable across gate decisions.
Measurement. Every validator — compiler, LSP, test oracle, formal check, repo script, and model-validator route — records its contemporaneous pass/fail verdict. A separate audit or delayed oracle later records whether the candidate was actually unsafe. Only then can the platform derive the miss indicator Mi = 1 (validator passed an unsafe candidate). A rollback is evidence of an unsafe outcome only when its reason is linked to the candidate; user preference rollbacks are not miss labels.
For each validator pair, qi, qj, covariance, and joint miss rate SHALL be computed over the same jointly evaluated, identically stratified candidate set. Degenerate marginals qi ∈ {0, 1} use the empirical joint miss directly, as Lemma 5.1 requires; they are never assigned κ = 0. Point estimates are diagnostics. A reported certificate uses conservative upper confidence bounds for pairwise joint misses and records sample count, stratum, label source, and interval method.
The bound is exact only for a pair. Corollary 5.2 is exact at n = 2 and deliberately conservative for n > 2, where the minimum pairwise joint miss can be far larger than the true n-way joint miss. Perspt therefore reports ρeff as an upper bound and n alongside it, and SHALL NOT tighten it by inferring higher-order joint statistics from pairwise correlations — the paper rules that inference out explicitly, and a finite ledger cannot estimate the higher-order terms that would license it. A three-validator ensemble whose reported bound improved on its best pair would be a defect, not a better certificate.
Crediting. Correlation controls the reported risk bound of a conjunctive
validator ensemble. It does not attenuate V through
w(1-\kappa); that heuristic is not in Paper II or III and could make the
same candidate easier to accept merely because a redundant validator was
added. IndependenceRoute remains provenance used to define strata and
cold-start policy. Deterministic routes are the default hard-check backbone;
model routes supplement them unless a domain deliberately defines a
model-validator hard requirement.
Cold start is uncertified. Before a route pair has enough labeled joint
verdicts, Perspt reports insufficient evidence. It may use
κ = 1 as a conservative routing prior, but it SHALL NOT turn an
arbitrary cross-family prior such as 0.5 into a risk certificate. The value 0.5
in Paper III is a worked mechanism-check parameter, not a universal prior.
Reporting. perspt status reports either certified
ρeff with confidence level and sample metadata, or an
explicit uncertified status alongside point diagnostics. Perspt SHALL NOT display a validator count, a
provider count, or an “N models checked this” badge as a safety signal. Two
correlated validators are worth close to one, and saying otherwise is the exact
mistake Corollary 5.2 exists to prevent. This is Gates R and T.
9. Turn Residuals and Energy
Owner: classes in perspt-sdk::residual; weights and correction
directions in the domain package; V in perspt-sdk::energy.
The tool loop reuses PSP-8’s quadratic energy unchanged —
V = ∑ewe‖re‖2 via energy::score_candidate — and
adds residual classes for tool-loop and model-plane evidence:
Residual |
Component |
Emitted when |
|---|---|---|
|
|
Arguments violate the tool schema. |
|
|
A precondition hash no longer matches; the model edited a stale view. |
|
|
Same proposal (identical idempotency key) repeated without intervening evidence change — the tool-loop analogue of livelock. |
|
|
One provider turn requested non-commuting calls without an explicit dependency order; no conflicting mutation was executed. |
|
|
A file was mutated in this turn that was never read in this turn. |
|
|
Turn/token/capability budget consumed past a declared fraction. |
|
|
An advisory model-validator objected. Its fixed domain weight is declared before the run; a conjunctive adjudicator is represented separately as a gate verdict rather than converted into a dynamic energy weight. |
|
|
A configured route failed and failover was taken; sensor-availability
class, matching |
Kernel denials do not get a new class. They reuse
ResidualClass::CapabilityDenied and ResidualClass::BudgetExhausted,
which perspt-sdk::residual already flags via is_admissibility_outcome()
and which are recorded on a separate blocked channel and never summed into
V (PSP-8 System 6). That separation is load-bearing: an admissibility
outcome says the harness refused, not that the artifact is inconsistent, and
folding the two together would let a well-behaved refusal look like a broken
build. Repeated denial still reaches the energy — through ToolThrash and
BudgetPressure, which are genuine harness-progress failures — so a turn that
spends its budget re-proposing a denied effect is rejected without corrupting
the blocked-channel accounting.
projection_mismatch (system 10) is recorded but not summed into
V; it is operational telemetry about denied, stale, ambiguous, or
normalized edits. A future domain that implements ProxyGeometry may also
record the true ‖rk‖. Paper I Theorem 12.4 treats that true
residual as a bounded disturbance, not as another energy component, so it also
remains separate from V.
Existing residual sensors (syntax, build, type, test failure, runtime smoke, goal presence, sheaf consistency) are unchanged and continue to dominate the energy. The new classes exist so that harness and model-plane failures are measured in the same currency as task failures.
10. Realizability, Gate, and Certified Termination
Owner: perspt-sdk::{kernel, gate, certificate}; the realizer is a
perspt-agent implementation of the srbn::Realizer interface;
correction content from the domain package.
Perspt uses the Regime B control shape but does not invent its geometry. Paper I §12 describes closed APIs with artifact revision as Regime B. Perspt can implement the construction immediately: generate a proposed action, project it through admissibility and a candidate overlay, re-read the resulting artifact and environment, and evaluate the gate there. The paper’s numeric residual requires more:
Neither the current SDK nor perspt-coding exposes the proposed proxy vector
~xk + 1, an encoder E into the same vector space,
or a norm on that space. Re-running sensors yields residual evidence used to
construct V; it is not by itself the encoder from Definition 12.2.
Accordingly, the coding implementation starts with these identities:
Map |
Paper I |
Perspt realization |
|---|---|---|
artifact realization |
ak + 1 = π(~xk + 1) |
The admissibility kernel plus isolated overlay: allowed effect application, exact-match patching, state-witness checks, and formatter normalization. |
realized-state measurement |
evaluate at E(ak + 1, sk + 1) |
Re-read touched files and relevant environment state, then run the declared verifier suite against that exact overlay. This discharges the gate-grounding construction, but does not expose E numerically. |
projection telemetry |
not rk |
|
// perspt-agent: the live tool loop invokes this boundary before gating.
impl srbn::Realizer<WorkspaceState> for SnapshotRealizer {
fn realize(&mut self, proposed: WorkspaceState)
-> srbn::SrbnResult<srbn::Realization<WorkspaceState>>
{
let realized = self.materialize_and_reread_overlay(proposed)?;
Ok(srbn::Realization::unmeasured(realized))
}
}
An optional domain extension may activate the analytic path:
pub struct RealizabilityClaim {
pub coordinate_schema: String,
pub projection_id: String,
pub encoder_id: String,
pub norm_id: String,
/// Assumption 6's uniform bound, not a maximum fitted on this run.
pub delta_r_bound: CertifiedBound<f64>,
/// Assumption 6 admits deterministic, in-expectation, and
/// high-probability instantiations, and Theorem 12.4's conclusion
/// weakens to match. The mode is recorded so a certificate cannot be
/// read as deterministic when the bound was only in expectation.
pub delta_r_mode: BoundMode, // Deterministic | InExpectation | WithProbability(f64)
pub analysis_domain: AnalysisDomainRef,
pub invariant_domain_evidence: Vec<EvidenceRef>,
}
pub trait ProxyGeometry: Send + Sync {
fn proposed_proxy(&self, proposal: &CandidateRef) -> Result<Vec<f64>>;
fn encode_realized(&self, realized: &CandidateRef) -> Result<Vec<f64>>;
fn residual_norm(&self, proposed: &[f64], realized: &[f64]) -> Result<f64>;
fn stability_claim(&self) -> StabilityClaim;
fn realizability_claim(&self) -> RealizabilityClaim;
}
The runtime may use Realization::measured and evaluate Theorem 12.4 or
Corollary 12.5 only when the vectors have equal declared semantics, the norm is
fixed, RealizabilityClaim supplies Assumption 6’s certified uniform
δr bound, its instantiation mode, and forward-invariance evidence,
and StabilityClaim supplies validated α, β, L, η, μ on the
same active analysis domain. One further hypothesis is easy to omit and is
required: Theorem 12.4 inherits Theorem 12.1’s step-size bounds,
which is what makes c > 0 and places the contraction factor
q = 1 − ηcμ in (1 ⁄ 2, 1). The runtime SHALL check this
inequality from the claim’s own constants and refuse the analytic path when it
fails, rather than reporting a floor computed from an inadmissible step size.
The existing StabilityClaim.delta is the Papers I–II exogenous
disturbance parameter; it SHALL NOT be silently reused as δr.
The maximum residual observed in one run is useful validation telemetry, not a
uniform future bound. perspt-coding initially returns None for this
extension. If an observed residual exceeds the certified bound, or the realized
state leaves the declared analysis domain, the runtime invalidates the analytic
claim for that run and records the counterexample. It may continue under the
measured Paper II gate, but it may not emit a Theorem 12.4 floor or Corollary
12.5 retry certificate.
The core descent predicate is unchanged — measured against the best accepted
energy, as PSP-8’s gate::evaluate_gate specifies — but what a “candidate” is
changes twice over: it is the realized workspace state at a turn boundary
together with its residual vector, rather than a parsed bundle and rather than
the model’s claimed result.
The API is extended to make the already-declared floor outcome reachable. Gate
ordering is: hard pass; candidate energy at or below the declared floor;
descent by at least ρ; rejection. A floor decision checkpoints the
realized candidate as a classified terminal state but does not imply delivery.
Today GateDecision::StoppedAtDeclaredFloor exists while
evaluate_gate/AcceptedTrajectory::submit never emits it; Phase 3 closes
that gap and records the floor value and provenance.
Commit feasibility is conditional. When ProxyGeometry is present,
Paper I gives
where c = (α − β) − Lη(α + β)2 ⁄ 2 and C = (1 + Lη(α + β))2 ⁄ (2ηc) + L ⁄ 2; both are derived and validated rather than configured independently. The implementation treats k* = 0 when the initial realized state already satisfies the tolerance. The retry budget is defined only on the strict feasible branch Vdisc∞ < ϵ; on the infeasible branch there is no k* to clamp or extend, and emitting a finite retry budget there would invert the corollary’s actual content. Only that path may call node refinement a Corollary 12.5 design rule. The default coding path instead refines when the measured Paper II gate plateaus, the same dominant residual recurs, or the finite budget is exhausted. Splitting a node is often useful, but the PSP does not assert that it necessarily lowers δr.
Budget semantics are not collapsed. The 0.3 kernel’s
OnNoDescent::Reject supplies an executable restore-best reference used by
conformance tests, and its realizer and trace types remain canonical. However,
srbn::Policy::max_attempts is a total evaluation cap, while Paper II’s
B counts rejections but not descent acceptances. The live tool loop uses
AcceptedTrajectory to track both counters and sets any underlying total cap
to finite_decision_bound(V0, rho_gate, B). Mapping max_attempts = B is
prohibited because it misstates Lemma 1. A non-descending attempt remains in the
trace, correction restarts from the best checkpoint, and descent is measured
against the best accepted energy.
Correction is residual-directed (PSP 000007, PSP-8): the dominant residual
class selects a CorrectionDirection from the domain package, injected into
the conversation as a user message before the next turn. The tool loop improves
on the bundle path here because the correction can name a tool — “run grep
for the trait definition before editing” is a legal directed correction that the
bundle path could not express — and, in the multi-model plane, it can also name
a route: a correction may carry the node to a different family when the
dominant residual has recurred under the current one.
The SRBN crate’s Status and Perspt’s product outcome are related but not
identical. In srbn 0.3, Stable requires barrier.ok and score at or
below tolerance, Stopped means policy-stopped descent, and Exhausted
means the attempt budget ended. The crate has no distinct declared-floor
outcome. Perspt therefore keeps an explicit, ledgered NodeTerminalOutcome
rather than claiming a one-to-one enum mapping:
Perspt terminal state |
Kernel evidence |
Meaning |
|---|---|---|
|
|
Realized candidate is eligible for delivery. |
|
Explicit |
Best checkpoint reached the domain’s measured tolerance without a hard pass. It is not delivered unless the domain policy explicitly permits it, and it is never reported as verified success. |
|
|
Budgets exhausted; a |
The certificate carries final residuals, energy, budget references, verifier
and model routes, rejected attempts, correction directions, projection-mismatch
telemetry, and the ledger head. It carries ρeff,
maxk‖rk‖, or a Corollary 12.5 verdict only when the
corresponding evidence object reports a certified state; otherwise it records
not_claimed with the missing preconditions.
11. Recovery Lattice
Owner: perspt-sdk::scheduler (RepairAction,
recovery_is_total, repair_to_effects* exist; this system extends
their classification and wires them to live failures).*
Rejection is the steady state of a stochastic proposer, so recovery must
terminate by construction (Paper III Theorem 6). The tool loop implements a
finite escalation chain with a single shared, non-replenishing cascade budget
b:
Level |
Control |
Tool-loop meaning |
|---|---|---|
0 |
retry |
Re-propose after a directed correction. |
1 |
fallback |
Switch route: alternate tool, alternate provider or model family, or bundle mode for this node. This is where multi-provider pays for itself operationally — a vendor outage, rate limit, or capability mismatch is a route change, not a run failure. |
2 |
refine |
Topological Escalation. Split or revise the node through the mutable
work graph when measured residuals plateau or scope is too broad. For a
domain with certified |
3 |
escalate |
|
4 |
contain |
Revoke the actor’s mutating capabilities, freeze the node, restore the best accepted state, issue the residual certificate. Unconditionally terminating. |
Every failure class produced anywhere in the loop — including unmodelled ones, and including provider-transport failures — maps totally to a control; unknown classes map to level 4. The classifier and mapping are deterministic kernel code, not model-selected.
Definition 8.1’s well-formedness conditions are adopted literally, because the
b + k count is a consequence of them rather than of the table above:
One pool, every level.
bis a single non-replenishing budget shared across the whole cascade. Every horizontal repetition consumes one unit of it, not only a level-0 retry — a second fallback route, a second refinement, and a second escalation each cost one unit exactly as a re-proposal does. A per-level budget, including a separate “refinement depth” counter, would give a bound of ∑λbλ + k rather thanb + k, so refinement depth is expressed as a cap on level-2 repetitions within the shared pool, never as its own pool.Exhaustion forbids repetition. Whenever the remaining budget is zero and the current level is below
k, the next non-terminal control MUST strictly escalate. This is what makes budget exhaustion a well-founded descent rather than a stall.The top level is unconditionally terminating. Level 4 never returns control to the loop.
With escalation depth k = 4, every cascade therefore terminates within
b + k steps regardless of whether any forward action ever succeeds, and
b being shared across route switches is what stops failover from buying
unbounded retries.
Theorem 6 also requires the terminal state to be classified, and names four classes. Perspt maps them without inventing a fifth:
Theorem 6 class |
Perspt cascade outcome |
|---|---|
|
A recovery control succeeded and the node re-entered the gate, which then
reached |
|
An irreversible external effect was rolled back through its
|
|
Level 3 handed the node to the user and the user’s decision terminated it. |
|
Level 4: capabilities revoked, node frozen, best accepted state restored, residual certificate issued. |
These are cascade classifications and are recorded alongside — not in place of —
the node’s Paper II NodeTerminalOutcome from system 10. A cascade that ends
Committed still exits the node through the gate’s three-way classification;
Contained and HumanEscalation produce Escalated.
Layer C — Platform Contract (Paper III)
12. Proposal → Admissibility → Effect
Owner: perspt-sdk::{capability, command} for the decision;
perspt-policy for the contract clause; perspt-sandbox for the process
boundary; perspt-agent for the routing of every call through them.
This system replaces direct tool execution with one kernel and closes PSP-8 Phase 3 / Gate E. The kernel always mediates authority, contract, and effect scope. It reports Paper III Definition 3.2 conformance only when barrier and risk clauses are also certified; a product fallback is never promoted into a theorem by naming it admissible.
Each ProviderToolCall is canonicalized into an EffectProposal. The
implemented struct carries path, command, network_target, risk,
risk_cost, generation, idempotency_key, and preconditions, but
today exposes only with_path and with_command builders. This PSP adds
the missing scope/witness builders and removes caller-supplied risk_cost.
The certified increment cc and budget debit come from the registered
capability contract and BarrierWitness, never from model arguments:
fn proposal_from(tc: &ProviderToolCall, ctx: &TurnContext)
-> Result<EffectProposal>
{
let entry = ctx.catalog.lookup(&tc.name)?;
let mut p = EffectProposal::new(
ctx.actor.clone(), ctx.node_id.clone(), entry.effect,
)
.with_generation(ctx.generation) // new builder
.with_risk_class(entry.risk) // trusted catalog metadata
.with_idempotency_key(idempotency_key(ctx, tc)) // new builder
.with_preconditions(state_witnesses(entry, &tc.arguments)); // new builder
// Scope is expressed through the existing typed fields, so the kernel's
// path / command / network clauses stay checkable.
if let Some(path) = arg_path(entry, &tc.arguments) {
p = p.with_path(ctx.workspace.canonicalize_bounded(path)?);
}
if let Some(raw) = arg_command(entry, &tc.arguments) {
p = p.with_command(command::canonicalize(raw, ctx.cwd()));
}
if let Some(target) = arg_network_target(entry, &tc.arguments) {
p = p.with_network_target(canonicalize_target(target)?);
}
Ok(p)
}
The proposal deliberately does not carry which model produced it. Provenance
is recorded in the ledger, not in the kernel’s input, so no admissibility
decision can depend on a vendor’s identity — a kernel that trusted proposals
more because they came from a particular provider would forfeit Gate S and
weaken Theorem 1’s confinement argument to a trust argument. The residual
evidence that motivated the proposal is likewise linked through the turn’s
ResidualEmitted events rather than added to EffectProposal.
The existing capability::check_admissibility is a useful scope checker, but
it is not yet Definition 3.2: it hardcodes contract_ok and
barrier_increment_ok to true and equates risk_cost with a spent-budget
amount. This PSP replaces that shortcut with explicit evaluators:
pub trait ContractEvaluator: Send + Sync {
fn evaluate(&self, state: &KernelSnapshot, proposal: &EffectProposal,
candidate: &CandidateTransition) -> ContractWitness;
}
pub trait BarrierEvaluator: Send + Sync {
fn evaluate(&self, state: &KernelSnapshot, proposal: &EffectProposal,
candidate: &CandidateTransition) -> BarrierWitness;
}
pub struct BarrierWitness {
pub h_before: f64,
pub expected_h_after_upper: f64,
pub certified_increment: f64, // invocation c_t, bounded by capability c_c^max
pub unsafe_threshold: f64, // 1 in Paper III
pub evidence_refs: Vec<String>,
}
pub enum AdmissibilityProfile {
/// All five clauses of Paper III Definition 3.2 are satisfied.
SrbnCertified,
/// Authority/contract/effect hold, but chance safety is not claimed.
ConfinementOnly { missing: Vec<ClauseId> },
/// Human authorization does not manufacture missing theorem evidence.
HumanApproved { missing: Vec<ClauseId>, approval: EvidenceRef },
}
For deterministic coding transitions, the barrier clause becomes h(x’) ≤ h(x) + cc and h(x’) < 1; determinism does not make it vacuously true. A capability without a registered barrier either uses a domain-defined deterministic barrier whose witness is recorded, requires user approval under a non-certified profile, or is denied. A Boolean hard predicate can instantiate h ∈ {0, 1} only when its safe/unsafe interpretation is declared and the evaluator proves the candidate remains below 1. Setting cc = 0 is valid only when the evaluator actually proves non-increase. Human approval is evidence of authorization, not evidence that the barrier inequality holds.
The coding domain supplies a narrow, useful operational safety barrier rather than pretending to solve semantic correctness with h. Let hj(x) ∈ [0, ∞) be versioned policy channels whose unsafe boundary is 1, covering at least protected-path modification, sandbox escape, secret exposure, unapproved network reachability, dependency-policy violation, and repository-size/resource limits. Define
Correctness evidence such as compiler errors and test failures remains in
V; it is not duplicated into h. For a fully materialized
deterministic candidate, ct is the exact conditional increment. The
kernel requires h(x0) < 1, h(x’) < 1,
ct ≤ cmaxc from the registered capability contract, and
spent + c_t <= rho_h before promotion. Spending is monotone: later barrier
decrease does not refund budget and therefore cannot finance oscillation.
Read-only effects that leave all channels unchanged have ct = 0 by
measurement, not by declaration.
The ledger reports the Paper III bound in its complete form,
Thus ρh is an increment budget, not by itself a total-risk target. A policy targeting total bound ρtotal must require ρh ≤ ρtotal − h(x0). For exact deterministic Boolean channels, the stronger direct invariant h(xt) < 1 holds for every committed state; the probability bound matters when a registered channel has certified residual randomness.
Each channel records its policy version, evaluator version, inputs, value before
and after, and evidence references. Boolean invariants are the special case
hj ∈ {0, 1}. A stochastic channel may use an expected upper bound only
when its registered certificate supplies that bound over the active calibration
domain; otherwise the effect is ConfinementOnly, HumanApproved, or
denied. This barrier certifies only the declared operational unsafe set. It
does not claim that code below the boundary is correct, secure against every
vulnerability, or free of escaped defects. The old shortcut “deterministic
transition, therefore cc = 0” is explicitly prohibited.
The full kernel produces an AdmissibilityWitness that records authority,
contract, effect, barrier, and risk clauses plus their certification states.
No durable effect may occur without a complete witness; an absent clause is
recorded as absent, never as true. Autonomous SrbnCertified commitment
requires all five clauses. ConfinementOnly and HumanApproved may be
enabled by explicit product policy, but they activate only the named authority
and deterministic-contract claims; they do not activate Definition 3.2 or
Paper III Theorems 3–5. perspt-policy remains part of the deterministic
trusted base and is invoked inside the contract evaluator;
perspt-sandbox enforces the process boundary for RunShell, RunTest,
RunBuild, and RunRepoScript. Confinement (Theorems 1–2) can activate
once authority/effect mediation is complete even when no probabilistic barrier
certificate is claimed; chance-safety Theorems 3–5 require the additional risk
evidence and their own statistical hypotheses.
The barrier allowance and the risk debit are the same number. Definition
3.2’s two numeric clauses are 𝔼[h(x’) ∣ x, p] ≤ h(x) + cc and
spent(x) + cc ≤ ρcap, and the cc in the
second is the cc in the first. For the event-specific deterministic
specialization above, BarrierWitness.certified_increment is ct and
the capability declares its ceiling cmaxc; the invocation uses
ct as Definition 3.2’s certified increment. An implementation with a separate
risk_cost field alongside a barrier increment has two numbers where the
definition has one, and can debit a budget for an increment it never certified —
which is precisely the shortcut this system removes. BarrierWitness
therefore supplies the invocation’s increment and the kernel debits exactly that.
ρcap is what keeps Theorem 3’s horizon-linear sum
∑tρt finite within a session: the per-capability budget bounds
accumulated certified increment, so a long session cannot buy unbounded risk one
admissible step at a time.
Allowance and budget consumption are one kernel transaction. Promoting a
candidate transition atomically decrements the capability call budget and risk
budget, records the witness, and advances the expected state hash. A read-only
check_admissibility that never consumes max_calls or risk_budget is
not sufficient. A failed append or stale expected head aborts the promotion and
does not leave a workspace effect without its budget record.
Three requirements make the confinement theorems mean something in practice:
Command IR, not strings. Shell-composed commands are canonicalized by
command::canonicalizeand classified bycommand::classify_tier. A command containing shell composition (|,&&,;, backticks, substitution) is aRunShelleffect regardless of which tool requested it.sh -cSHALL NOT remain an implicit path insiderun_testorrun_build.State witnesses.
edit_fileandapply_diffproposals carry the content hash of the target file read earlier in the turn. If the file changed between read and write, the witness fails, the effect is denied withRecoveryClass, and the model is told to re-read. This prevents the “model edits a file it remembers rather than the file that exists” class of state misreporting that Paper II names as failure mode 2, and it is what makes parallel nodes (system 15) safe.Attenuation on delegation.
spawn_agentmints a child capability viaCapability::delegate, which returnsNoneunless the child attenuates the parent. A subagent can never hold authority its parent lacked (Theorem 1) — including a subagent routed to a different provider — and no prompt rewrite, tool registration, or policy update by the agent can change that (Theorem 2), because all of those are themselves capability-mediated privileged effects.The current
Capability::attenuatesimplementation checks effect, path, call-budget, expiry, and delegability fields but omitscommand_scope,network_scope, risk-budget attenuation, and approval-policy strength. Those fields are part of Perspt’s effective Ec and MUST participate in the preorder before Gate L can pass. Empty child scope means unbounded only when the parent is also unbounded; it must never widen a bounded parent.
Subagents receive role templates intersected with parent authority, never a copy of the parent capability. The scheduler chooses one of three defaults:
Role |
Default effects |
Explicitly absent |
|---|---|---|
|
|
Every mutation, network, shell, approval, graph update, and delegation |
|
Explorer rights plus candidate-overlay writes to named paths and the exact verifier commands declared by the active language profile |
Durable delivery, arbitrary shell, network, dependency mutation,
|
|
Read-only candidate, diff, ledger evidence, and verifier results |
All mutation and delegation |
Every child grant is non-delegable, finite in calls/tokens/time, scoped to a
workspace id plus node revision/generation, and expires no later than the parent.
Its approval policy is at least as strict and its risk budget no larger. A
worker writes only to a disposable candidate overlay and returns a proposal;
the parent does not gain the ability to bypass the ordinary realization and
gate. A child needing more authority returns NeedsCapability. It cannot
approve its own request, and the model cannot select a more privileged role.
The route is chosen independently from authority. Explorer defaults to the
cheapest capable route, preferring a configured local model; Worker uses the
node’s implementation route; Reviewer prefers a separately measured review
route. Route failure may change the model but never the child capability. Only
the trusted scheduler/root actor receives SpawnAgent by default, which
prevents recursive fan-out while still supporting parallel exploration and
implementation.
Live capabilities are session-epoch leases and never survive serialization.
A ledger may record a capability id and its historical witness, but it never
stores a reusable capability or provider credential. Capability gains
session_id, workspace_id, authority_epoch, and optional
revision_id/generation bindings. The kernel checks all bindings and the
current durable epoch atomically with every effect promotion.
Replay still needs the authority facts used by the decision, so each witness
content-addresses a canonical non-authoritative capability descriptor
(effects, scopes, budgets, approval policy, lineage, bindings, and epoch). The
replay reducer may inspect that descriptor but the live kernel never accepts a
deserialized descriptor as authority; only a handle minted into the current
KernelState can authorize an effect.
Durable user intent is represented separately as a signed GrantPolicy:
effect/path/command/network ceilings, maximum risk and call budgets, expiry,
approval strength, repository identity, and revocation epoch. On resume Perspt
re-authenticates as required, loads current organization/user policy, and mints
new capability ids from the intersection of that policy, the saved grant,
and current workspace facts. Session approvals are not durable grants. If the
policy store or workspace identity cannot be verified, resume is read-only or
fails closed for durable effects.
Revocation increments the relevant durable authority_epoch and cancels
matching worker leases. In-flight preparation may finish, but promotion fails
when its stale epoch is compared transactionally at the ledger sequencer. This
gives resumed and parallel sessions one revocation boundary without relying on
best-effort process notification. Persistent grants are opt-in, visible, timed,
and revocable; the secure default is session-only authority.
Denials are evidence, not errors. A denied proposal produces a typed
residual — ResidualClass::CapabilityDenied or
ResidualClass::BudgetExhausted for admissibility outcomes,
ResidualClass::Policy for a perspt-policy rule — with a directed
correction telling the model what capability or scope it lacks. It is returned
to the model as the tool response so the loop can adapt, and it is recorded via
LedgerEvent::EffectDenied.
13. External Tool Providers Under the Kernel
Owner: perspt-sdk::toolset for registration and ToolOrigin;
perspt-agent for the client. New work — nothing of this exists today.
A platform must accept tools it did not write. Perspt has no external tool protocol today; this PSP specifies how one is admitted, because doing it after the kernel exists is the difference between an extension point and a hole.
An external tool server (an MCP-style server, a company-internal tool daemon)
registers ToolEntry records with origin: External(ServerId). Registration
requires, and does not infer:
a declared
EffectKindandRiskClass;a declarative
FootprintSpec, or else the tool is classified asRunShellwith an opaque footprint, which makes it serialize against everything and require an explicit capability;a capability that the session already holds — registering a tool never mints authority, so an external server can never exceed the user’s own grant (Theorem 1, and Theorem 2 for a server that rewrites its own manifest).
Three properties are stated because external tools break them by default in naive implementations:
Tool descriptions are untrusted text. A server’s tool descriptions and results are attacker-controllable in the same way repository content is. They enter the conversation as observations, never as instructions, and they cannot alter capabilities, policy, or the catalog’s effect mapping. Corollary 4.2 is what makes this survivable: injection changes what the model proposes, never what it may do.
External results are recorded observations. They go through
record_observationbefore use, so replay does not re-invoke a remote server (R2, Theorem 7).External calls are external effects. They are bracketed in
ExternalEffectLogwith intent, result, and compensation records (R5).
14. Event-Sourced Ledger and Replay
Owner: perspt-sdk::ledger for the event model and replay;
perspt-store for durability.
This closes PSP-8 Phase 4 / Gate F. perspt-sdk::ledger::LedgerEvent becomes
the live event model, persisted through perspt-store. The tool loop emits,
per turn: ProposalObserved, AdmissibilityChecked, EffectApplied or
EffectDenied, ObservationRecorded, VerifierCompleted,
ResidualEmitted, EnergyScored, GateDecisionRecorded, and
CandidateAccepted or CandidateRejected. The model plane adds
RouteResolved, ProviderDegraded, RouteFailover, and
VerdictRecorded.
Theorem 7’s hypothesis is a recording obligation on the kernel, adopted literally: the kernel refuses to commit any transition that depends on an unrecorded observation. Model outputs, tool results, timer reads, external tool responses, and user approvals are written before use. Recording only an event name and proposal id is insufficient. Each deterministic transition record must contain or content-address:
canonical proposal arguments and the complete admissibility witness;
the prior state/root hash and candidate overlay identity;
all nondeterministic observations consumed by the transition;
canonical effect result, including content-addressed changed artifact blobs, plus stdout/stderr/exit metadata where relevant;
post-state/root hash and the transition implementation version.
Replay has two distinct modes. audit replay is provider-free and does not
re-run tools; it folds recorded transition records and verifies the event chain,
state hashes, gate decisions, and accepted trajectory. verification replay
may materialize a disposable workspace and rerun deterministic verifiers, but
its result is a new observation and never substitutes for the original record.
The current replay_accepted_trajectory only projects accepted node/energy
events and is therefore a seed for audit replay, not yet a Theorem 7
implementation. perspt replay <session> SHALL distinguish chain validity,
deterministic fold equality, and optional verifier reproduction.
The six durable-execution obligations of Paper III Definition 9.1 map to concrete Perspt surfaces:
Obl. |
Requirement |
Perspt realization |
|---|---|---|
R1 |
Durable single-assignment outcomes |
|
R2 |
Recorded nondeterminism |
|
R3 |
Deterministic transition |
The replay reducer is a pure function of prior recorded state plus a versioned canonical transition record. Any ambient read used by live execution is first captured as an R2 observation. |
R4 |
Unforgeable capability transport |
Capabilities are kernel-minted records in |
R5 |
Write-ahead external effects |
|
R6 |
Ordered noncommuting durable turns |
Scheduler serializes conflicting footprints (system 15). |
Conversation compaction is a recorded context projection, never ledger
deletion. Conversation is rebuilt for each model turn from the immutable
ledger and artifact store. A deterministic ControlFrame is always inserted
verbatim and is never summarized: active goal and node generation, accepted
checkpoint/root, work-graph revision, capability ids and authority epoch,
remaining budgets, tool schemas, hard-gate policy, current residual vector, and
all unresolved tool calls. Closed tool-call/result pairs may be replaced in the
model context by content-addressed references; their complete arguments and
results remain in the ledger.
When packed context reaches a configurable fraction of a route’s context window
(default 70%, leaving output and emergency-verification reserve), a
provider-neutral ContextCheckpoint records:
pub struct ContextCheckpoint {
pub parent: Option<CheckpointId>,
pub covered_event_range: EventRange,
pub covered_event_root: ContentHash,
pub accepted_state_root: ContentHash,
pub graph_revision: RevisionId,
pub authority_epoch: u64,
pub active_model: ModelId,
pub remaining_fallback_models: Vec<ModelId>,
pub activated_tools: Vec<ToolName>,
pub artifact_refs: Vec<ContentHash>,
pub unresolved_call_ids: Vec<String>,
pub deterministic_digest: ContextDigest,
pub narrative_summary: Option<RecordedObservation>,
}
The deterministic digest carries decisions, residual changes, accepted/rejected candidate ids, file/symbol references, and outstanding obligations. An optional cheap-model narrative improves recall but is an untrusted recorded observation; it cannot supply a state witness, authority, tool result, or verifier verdict. Before use, a structural validator checks event-range coverage, hashes, open call/result pairing, artifact existence, and equality of the current accepted root, graph revision, and authority epoch. A stale checkpoint is rebuilt, not patched by a model.
Compacted context is provider-neutral, but it may cross providers only when the destination route’s confidentiality contract authorizes every projected item and the optional summary. The compactor itself is routed under the same content policy, with a local route preferred for confidential work. Audit replay consumes the exact recorded checkpoint and summary and performs no new model call. Hierarchical checkpoints allow old narrative detail to age out while preserving the control frame and exact evidence on demand. This gives long-running agents bounded prompt cost without weakening Theorem 7’s recording obligation.
15. Coordination and Bounded Parallelism
Owner: perspt-sdk::scheduler; the worker pool in perspt-agent.
This closes PSP-8 Phase 2 / Gate C, which the tool loop makes tractable because tool proposals declare footprints. Theorem 8 states the rule: serialize semantic commitments, not activity. Two durable turns whose footprints are read/write-disjoint may proceed concurrently and in either order.
scheduler::{Footprint, Resource, LeaseTable, Scheduler} becomes live. The
resource set is extended with WorkGraph, ProviderRateLimit, and an
OpaqueWorkspace fallback in addition to the existing file, interface,
manifest, capability, risk-budget, fresh-id, and ledger resources.
Theorem 8 carries a structural hypothesis on footprints that a declarative
FootprintSpec can violate silently: the theorem is stated for events with
writes(e) ⊆ reads(e). A tool that writes a resource
it did not read is outside the commutation lemma, so footprint validation SHALL
reject such a spec at catalog-assembly time rather than at execution. In
practice this is the declarative form of the state-witness rule — an effect that
mutates a file must also have that file among the components its admissibility
clauses evaluate.
A second distinction keeps Gate P honest. Theorem 8 is about the semantic
durable state X = ∏jXj; ProviderRateLimit is a throughput
resource, not a component of that product. Two turns contending on one
provider’s limit are still provably commuting turns, so the lease is a
scheduling delay and SHALL NOT be recorded as a required serialization. Gate P’s
falsifying predicate reads semantic footprints only.
A worker pool may explore, call models, run read-only tools, and prepare candidate overlays in parallel. It acquires leases before the first effect whose declared footprint can conflict; cancellation releases leases, and a lost lease invalidates the turn’s state witnesses.
The append-only ledger has a sequencer, but this does not make every turn’s
entire footprint conflict on LedgerRoot. Workers prepare immutable event
batches against an expected head; the sequencer assigns logical order and
appends them. If an event’s semantic preconditions conflict with intervening
commits, its state witness fails and the candidate is revalidated. Thus the
ledger append itself is ordered while non-conflicting preparation and effects
remain concurrent. Graph revisions, capability mutation, risk-budget spending,
dependency mutation, and overlapping workspace writes serialize on their
actual resources.
Parallelism interacts well with the portfolio: concurrent nodes can occupy
different providers, so wall-clock parallelism is not bounded by one vendor’s
rate limit, and a single vendor’s throttling degrades throughput instead of
stopping the run. Rate limits are portfolio state, so RateLimits is a
scheduler resource: two nodes on the same provider contend, two nodes on
different providers do not.
The default remains conservative: node-level parallelism is opt-in via
--max-parallel-nodes (default 1, preserving today’s sequential
behaviour); the pre-existing --max-parallel flag keeps its meaning of
concurrent compiler/test/lint sensors within one node. Multi-node dispatch
requires --yes because promotion approval cannot be prompted per node
while other nodes run.
The session is not a DAG. The current live orchestrator stores a mutable
petgraph::DiGraph<SRBNNode, Dependency> and walks it topologically, while
perspt-sdk::workgraph already models immutable node generations and durable
WorkGraphRevision values. This PSP makes the SDK revision the authoritative
scheduler input. Each individual revision must be acyclic over true dependency
edges so readiness is computable, but the session evolves through a sequence
where evidence ej may add, split, retire, requeue, or replace node
generations. ConflictsWith remains a lease relation and DerivedFrom an
audit relation; neither is forced into the dependency DAG. Running work is
bound to a revision id and node generation. A newly accepted revision cancels
or revalidates affected work, preserves unaffected work, and never mutates the
meaning of an already ledgered generation. This is how exploration and repair
change the plan without pretending that coding is known as one static DAG.
Parallelism exists at three levels under the same scheduler. Independent ready
nodes and read-only exploration agents may run concurrently. A single assistant
turn may also return several tool calls; the runtime validates all arguments,
derives footprints, and executes only a pairwise-commuting subset concurrently.
Conflicting calls from one nominally parallel provider response are not assigned
an invented order: they are returned as a ToolBatchConflict observation so
the model can sequence them explicitly. Verification and correction nodes wait
on the checkpoint and evidence revision they consume. Spawning more agents does
not bypass readiness, leases, provider limits, or capability attenuation.
16. Calibrated Risk Budgets
Owner: perspt-sdk::conformal; calibration sets persisted by
perspt-store.
This closes PSP-8 Phase 8 / Gate I. It is required when Perspt autonomously
commits a mutating effect whose declared unsafe event is not completely
discharged by a deterministic contract/barrier — normally yolo and
balanced medium-risk operation. Deterministic proof and calibrated
statistical evidence are distinct admissibility profiles, not two names for the
same claim.
The kernel holds a calibration set of (score, unsafe) pairs drawn from the
deployment’s own ledger. The score is the validator’s safety evidence for the
proposal; the delayed unsafe label comes from the undo/rollback boundary and
regression residuals already recorded. For target budget ρc,
conformal::conformal_threshold computes
and the kernel accepts autonomously only when s(p) > theta_hat — strictly,
with ties at the threshold rejected, because right-continuity of the strict loss
is what makes the infimum attained. This bounds the marginal accepted-unsafe
rate by ρc with a distribution-free, finite-sample certificate. It
is not the conditional per-step bound of Theorem 3; see the notation table.
Two properties of the theorem are implementation requirements rather than commentary:
A minimum sample count is implied by the target. The feasible set is empty exactly when ρc < 1 ⁄ (n + 1), in which case θ̂ = ∞ and everything is rejected. So a declared budget fixes a floor on calibration size: n ≥ 1 ⁄ ρc − 1, which for the common ρc = 0.05 means at least 19 labeled samples before any proposal can be autonomously accepted at all. Perspt SHALL compute this floor from the configured target, report
insufficient calibrationuntil it is met, and route mutating effects to approval in the meantime. Reporting a reject-all threshold as a satisfied budget is prohibited: it is technically true and operationally a lie.Dominance licenses the grid, not the drift response. Theorem 5 extends the bound to any θ̃ ≥ θ̂ almost surely, which is what makes a threshold selected from the finite grid of calibration scores certificate-preserving. That clause is conditioned on exchangeability like the rest of the theorem, so raising the threshold during a drift window is conservative behaviour under a broken hypothesis, not an inherited certificate — which is why the stale-window rule below reports uncertified rather than “certified at a stricter budget.”
Multi-provider makes exchangeability a first-class concern, and this PSP does not paper over it. Theorem 5’s guarantee rests on exchangeability between calibration and deployment. Different models fail differently, so a calibration set gathered under route A does not certify commitments made under route B. Therefore:
Calibration sets are keyed by a
CalibrationStratumcontaining at least domain package/version, effect kind and risk class, model route, verifier-suite fingerprint, tool-catalog fingerprint, policy version, and score definition.(capability, ModelId)alone is not enough to establish exchangeability.Changing any stratum field — including automatic model failover, verifier availability, or a score-definition change — marks the calibration stale via
CalibrationState::mark_stale.conformal::{ks_statistic, is_drifted}runs as a per-route drift monitor.On drift or staleness the kernel does not hard-halt the session. Read-only effects continue within capabilities; mutating effects covered by a separate deterministic hard contract may continue under that contract; all other autonomous mutating effects route to approval while recalibration runs. An inflated threshold without exchangeability is conservative behavior, not a conformal certificate. During the stale window
bound_is_asserted()is false and the UI SHALL report the window as uncertified.
Cold start is resolved as approval plus active local calibration, not a
shipped safety prior. CalibrationReadiness has four explicit states:
InsufficientSamples, Shadow, Active, and Stale. Before
Active, read-only work and effects proved safe by a separate deterministic
contract/barrier continue automatically; other mutations require approval. The
candidate score, counterfactual threshold decision, route, and later outcome are
still recorded in shadow mode, so normal work builds the local set instead of
blocking the agent.
Perspt reserves a configurable audit budget for a uniformly sampled subset of
all proposals in each stratum, selected before their outcome is known. Those
proposals receive a stronger delayed oracle (full tests, later regression
window, security scan, or human audit) whether the current policy would accept
or reject them. Uniform sampling preserves the proposal population needed by
Theorem 5. Risk-targeted extra audits are useful diagnostics but do not enter
the conformal certificate unless a separately proved weighted method is
implemented. Human approval alone is not an unsafe label.
Calibration operates in immutable epochs. One epoch’s labeled records fit the
next threshold; deployment records do not retroactively change the threshold
under which they were decided. At the theorem’s sample floor, Perspt may activate
the exact finite-sample certificate — no arbitrary larger n is presented as
mathematically necessary — but the UI also reports threshold granularity,
acceptance rate, audit coverage, label source, and drift state so an operationally
useless certificate is visible as such.
Bundled or organization-wide records are never certificates by default. They
may seed routing and shadow thresholds only. Cross-project data may enter a
certificate solely when the organization predeclares a calibration population
that includes those projects, gives it a signed CalibrationDomainId, and
the complete CalibrationStratum (including that id) remains unchanged.
Post-hoc pooling because one project lacks samples is prohibited. An unlabeled
validator pair is likewise excluded from conjunctive certification and treated
as fully dependent only for conservative route planning; it receives no numeric
ρeff claim.
This is a real cost of the multi-provider design and is stated as one: a portfolio that switches routes frequently will spend more time uncertified than a fixed single-route deployment. The mitigation is route stickiness (system 3), not a weaker claim.
17. Spectral Diagnostics and Platform Stability
Owner: perspt-sdk::{spectral, observability, stability}; surfaced by
perspt-tui / perspt-dashboard.
These close PSP-8 Gate G and Phase 9’s remaining items. Both are diagnostics computed off the critical path; neither may gate dispatch or acceptance.
Spectral gap. Paper II Lemma 2 requires a declared linear residual map r = Bx and A = BTWB. A graph whose vertices merely name sensors does not establish that map.
spectral::VerificationGraphmay always report a topology diagnostic, but it populatesStabilityClaim.muonly when the domain provides the coordinate map, restriction matrices, weights, and nullspace interpretation used to construct A. Otherwise the value is labeledtopology_gapand has no convergence-rate meaning.The lemma gives a verifier two ways to earn its cost, and reporting only the first would misdirect the very decision this diagnostic exists to inform: a new check helps insofar as it raises λ + min(A) or shrinks ker(A), since the safe set is exactly ker(A) = ker(W1 ⁄ 2B). For a coding workspace the second is the common case — adding a verifier for a property nothing previously constrained removes an unverified direction from the nominal safe set without moving the gap at all.
edge_mu_sensitivitySHALL therefore report a rank/nullspace delta beside the gap delta, and a verifier that changes neither is redundancy in the exact sense Corollary 5.2 prices probabilistically.Backlog stability.
observability::{phi, backlog_gauge}computes the per-workflow potential ϕi = 1 + Vi ⁄ ρgate + Bi and the platform potential Φ(W). Paper III Theorem 9 gives negative drift and positive recurrence under a work-conserving scheduler and sub-critical arrival load α < 1. That load bounds the expected arriving potential per step, 𝔼[∑a ∈ Atϕa ∣ ℱt] ≤ α, not the arrival count — a single arriving workflow with a large Va ⁄ ρgate can exceed the bound on its own, so the gauge SHALL be computed from arriving potential and labeled as such.perspt statusand the dashboard report Φ(W), its empirical drift, and the estimated α. Positive recurrence is reported only when gate discipline, work-conservation, the conditional arrival-load bound, finite initial potential, and reachable-class irreducibility are all evidenced; otherwise these remain capacity diagnostics.
Layer D — Product Surface
18. User Experience, Portfolio Control, and Local Operation
Owner: perspt-cli, perspt-tui, perspt-dashboard. The
confidential rule is a perspt-policy predicate evaluated inside the
kernel’s contract clause.
The platform is visible, interruptible, auditable, and controllable.
Streaming tool activity. The TUI and dashboard stream each proposal with its tool name, scope, risk class, serving route, and kernel decision as it happens — including denials, which are informative. Perspt shows the residual vector and energy per turn, not just a spinner.
Portfolio surfaces.
perspt providersprints the capability matrix and every recorded degradation.perspt portfolioprints resolved routes per phase with cost and latency accounting per vendor.perspt toolsprints the catalog and the capabilities granting each tool.perspt statusadds certification state and evidence metadata for ρeff, μ, and Φ(W); point estimates such as the κ matrix are visibly labeled diagnostic.Approval modes bound to the kernel.
--mode cautious|balanced|yolobecomeApprovalPolicypresets rather than ad-hoc branches:Mode
Approval policy
cautiousAuto-approve read-class effects only. Every mutating effect asks.
balancedAuto-approve read and workspace-scoped medium-risk effects under a calibrated budget or a complete deterministic safety contract; ask for high-risk, privileged, and cold-start uncertified effects.
yoloRemove prompts, not predicates: auto-commit effects that both the capability set permits and the configured certified/deterministic profile admits. An uncertified effect is denied or queued, never silently accepted. This bounds damage by Corollary 4.2 rather than by trust:
yolonever grants out-of-workspace, network, or privileged capabilities implicitly.Local and sovereign operation. A portfolio consisting only of local providers (
ollama, an OpenAI-compatible local server) is a supported, tested configuration, not an afterthought. In that configuration no code, diff, or repository content leaves the machine. The gate and authority contracts are unchanged, but success, descent frequency, and any calibrated risk claim may change with the proposal distribution and must be re-measured. Mixed portfolios support a per-pathconfidential = truemarker that restricts matching content to local routes; a proposal that would send marked content to a remote route is denied by the contract clause with aPolicyresidual.Undo/redo over the ledger. Because effects are recorded with idempotency keys and compensations,
perspt ledger rollbackoperates on accepted turns, and the rollback boundary doubles as the delayed unsafe-label source for systems 8 and 16.Operational controls. Status surfaces show the active verification cadence, mutations since the last evidence boundary, context-window reserve, checkpoint lineage, calibration readiness/audit coverage, child leases, and authority epoch. Persistent grants are explicit records with owner, scope, expiry, and revoke action; there is no generic “remember approval” checkbox.
New commands.
perspt replay <session>(deterministic, credential-free replay and head comparison),perspt providers,perspt portfolio,perspt tools,perspt grants list|create|revoke, andperspt context inspect.
One Authoritative Execution Path
PSP-9 makes ToolLoop the only live perspt agent path. There is no
--execution-mode switch and no provider-text convention that imitates tool
calls. A primary route without declared native tool calling fails before a
session is created; recovery may choose only another explicitly configured,
tool-capable actuator route.
The old bundle implementation remains useful solely as an offline benchmark arm for measuring cost, accepted-state correctness, and greenfield behavior. It is not a recovery level, an authority path, or a compatibility promise. If future evidence justifies a whole-file proposal tool, that operation shall be added to the typed catalog and return through the same kernel rather than reviving a parallel orchestrator.
Internal Quality Targets
This PSP is evaluated against Perspt’s current bundle path and against its own ablations. External coding agents may inform usability testing, but they are not normative references and do not appear in the conformance claim.
Property |
Before this PSP |
Required after this PSP |
|---|---|---|
Redundancy value |
Validator provenance exists but labeled joint misses are not consumed |
Certified ρeff only for matched, labeled,
conjunctive validator populations; otherwise |
Reliability claim |
SDK energy is telemetry beside the legacy convergence decision |
Measured gate is authoritative; optional analytic and probabilistic fields carry explicit certification state (Gates M, R, V) |
Effect safety |
Several orchestrator paths execute tools directly |
Complete capability, contract, effect, barrier, and risk witness before durable effects (Gates K, L) |
Auditability |
Session tables and a representative in-memory SDK ledger |
Versioned transition records, hash-chain audit fold, and optional verifier reproduction (Gate O) |
Vendor risk |
One bound provider handle per process |
Portfolio failover is recovery level 1 and preserves gate semantics while changing the calibration stratum (Gate S) |
Confidential code |
One process-wide provider policy |
Local-only portfolio and kernel-enforced path-to-route policy |
Cost control |
Model names vary by tier on one provider handle |
Per-phase routing: cheap or local exploration, expensive adjudication only where it changes a decision |
Progress reporting |
Bundle and verification records are only partly joined |
Gate reads the re-measured candidate overlay; edit projection mismatch
is telemetry and ‖rk‖ is |
Stuck loops |
Bounded revisions with largely prompt-driven re-planning |
Measured plateau triggers graph revision; Corollary 12.5 is used only by domains with certified proxy geometry |
Termination |
Several overlapping budget and convergence classifications |
Every node exits |
What this PSP does not claim. It does not claim that another model, another vendor, or another validator necessarily improves correctness. It claims that the harness exposes where evidence came from, applies fixed acceptance rules, and refuses certificates whose assumptions are absent. Portfolio features that do not improve the internal ablation remain optional.
Conformance Gates
Each gate names the theorem it discharges and the predicate whose failure falsifies it. Gates continue PSP-8’s lettering.
Gate |
Requirement |
Falsifying predicate |
|---|---|---|
J |
Model-driven tool use |
A run in |
K |
No unmediated effects |
Any durable effect in the ledger without a preceding
complete |
L |
Authority confinement (Thm 1, 2) |
A committed effect outside the initial effect closure Eff*, or a delegated capability that does not attenuate its parent, or a capability minted from proposal payload data, or an external tool registration that widens authority; a child that can self-approve/delegate or write outside its candidate overlay; a live capability serialized for resume; or an effect promoted under a stale authority epoch. |
M |
Bounded harness (Paper II Lemma 1, Thm 3) |
Gate decisions exceeding ⌊V0 ⁄ ρgate⌋ + B + 1, or a
configuration accepted at startup that permits unbounded unverified
turns, a mutation count exceeding |
N |
Terminating recovery (Thm 6) |
A cascade exceeding |
O |
Exact replay (Thm 7) |
A committed transition depending on an unrecorded observation, a
replayed head hash differing from the recorded head, or a replay that
requires provider credentials; a compacted turn whose |
P |
Coordination minimality (Thm 8) |
Two concurrently executed turns with conflicting semantic footprints; a serialization of two provably commuting turns reported as required (a rate-limit delay is not such a serialization); or a registered footprint whose writes are not contained in its reads. |
Q |
Calibrated autonomy (Thm 5) |
Autonomous commitment of a mutating effect while
|
R |
Honest diagnostics (Lemma 2, Cor. 5.2) |
A displayed validator, model, or provider count presented as a safety signal; a topology gap reported as Paper II μ; a point ρeff reported as certified; or a diagnostic value changing the fixed acceptance energy during a run. |
S |
Provider portability |
Any harness invariant — decision bound, gate rule, terminal classification, catalog contents for a fixed capability set, or replay determinism — whose behaviour differs by provider; or an admissibility decision that reads the proposing model’s identity. |
T |
Measured ensemble credit |
Corollary 5.2 claimed for proposers or an advisory reviewer; pairwise statistics computed from unmatched populations; degenerate pairs treated as independent; dynamic correlation-based energy weighting; or a risk bound lacking labeled outcomes and conservative uncertainty bounds. |
U |
Honest degradation |
A provider capability emulated rather than degraded-and-recorded; a
degradation not surfaced in |
V |
Realized-state gating (Paper I Def. 12.2) |
A gate decision computed from a model-claimed diff rather than from the re-measured candidate overlay; a floor-stopped node reported as verified success; projection telemetry labeled ‖rk‖; or a Theorem 12.4/Corollary 12.5 claim emitted without certified proxy geometry and analytic constants, after an observed residual exceeds δr, or outside the claim’s analysis domain. |
Practical Decisions
The trilogy specifies contracts; an SDK has to ship. Where the two pull against each other, this PSP records the decision and its price rather than leaving it to be rediscovered in review.
Decision |
Reasoning and price |
|---|---|
Port in the SDK, driver in
|
Keeps |
Do not fork |
Paper I’s mechanisms have one implementation, upstream, and Perspt is a consumer. Price: Perspt is blocked on upstream releases for kernel changes, and the 0.1.1 → 0.3.0 upgrade is a prerequisite of this PSP rather than optional work. |
Required agent methods on |
The breaking trait change forces every agent-capable domain to declare tools, verifier suite, and hard-gate policy. Price: all domain crates update in the same release; no silent empty-tool implementation remains. |
Kernel is in-process and synchronous |
Admissibility must be deterministic and on the path of every effect; a network hop would add a failure mode to the trusted base. Price: the kernel cannot be shared across machines, so multi-machine operation is out of scope here. |
Fixed energy, separately certified risk |
Domain energy weights are frozen for the run. Conservative certified risk bounds may select an approval or validator policy for a later candidate, but point diagnostics never rewrite V. Price: routing and acceptance remain two explicit decisions. |
Conservative defaults everywhere |
|
Unmeasured coding realizability |
Coding uses |
Pre-1.0 breaking changes taken now |
|
Technical Specification
Architecture. No new shipped crates. The work lands in existing
boundaries. (The repository additionally carries xtask, a
publish = false dev-only workspace member that enforces the project’s
coding-rule limits; it is not part of the crate set specified here.)
Crate |
Change |
|---|---|
|
Upgraded from 0.1.1 to 0.3.0 and extended with the two new companion
crates; not forked. Supplies |
|
New |
|
|
|
New |
|
|
|
Implements the new required tool, verifier-suite, and hard-gate methods.
It is the second-domain conformance check: if this requires
research-specific branches in |
|
Invoked from the kernel’s contract clause; owns the |
|
Real process-boundary enforcement for command effects: workspace-bound cwd, environment scrubbing, timeout, output capture. |
|
Ledger event tables, idempotency log, external-effect log, verdict records, context checkpoints, calibration/audit epochs, signed grant policies, and durable authority epochs. Live capabilities and provider credentials are never stored. |
|
Live proposal stream with serving route, per-turn residual vector and energy, capability audit, provider matrix, ρeff and Φ(W) gauges, calibration readiness/audit coverage, persistent-grant/revocation controls, context-checkpoint inspection, and replay view. |
Crate graph |
Three dependency edges are added and stated here because nothing else
in this PSP implies them: |
Performance. The tool loop trades one large generation for several small
ones: more requests and lower total tokens per node on edit work, higher latency
per node on trivial work. The benchmark measures whether a future typed
whole-file proposal tool is justified; it does not select another orchestrator.
Prompt caching across turns is essential and SHALL be used where the
provider supports it, which is why routing is sticky within a node. Ensembles
and adjudication are opt-in and triggered, not always-on; their cost is bounded
by EnsemblePolicy::budget. Kernel admissibility is in-process and
deterministic; its cost is negligible against a tool call. Spectral,
independence, and calibration computation runs off the critical path. Long-lived
incremental LSP sessions, bounded adaptive verifier flushes, and hierarchical
context checkpoints are the primary latency/token controls; none changes a
gate, authority decision, or recorded observation.
Dependencies. The kernel version bump and companion additions remain
first-party:
srbn and srbn-serde move 0.1.1 → 0.3.0, and srbn-ledger 0.3.0 joins
(srbn-regex is optional, for pattern sensors). ed25519-dalek is added
for signed persistent grant intent, and perspt-agent uses rand_core only
to generate a fallback installation key. shell-words is reused in the SDK
for shell-free argv parsing. genai 0.6.5 already exposes tool request/response types, streaming
capture, and the adapters listed in str_to_adapter_kind. Actual tool support
is capability-probed per route; it is not inferred from adapter existence.
nalgebra (spectral) is already in tree.
Multiple concurrent genai::Client instances are already possible; only
Perspt’s single-handle assumption prevents it.
Configuration. The replacement schema contains [providers],
per-tier ModelId, adjudicator_model, ensemble policy block (default
off), execution_mode (default bundle at first release, auto after
the parity gate), max_turns_per_node, descent_tolerance,
cascade_budget, max_parallel (verifier fan-out) and
max_parallel_nodes (node dispatch, both default 1), an
unlabeled-validator policy
(default uncertified), risk_budget per capability,
calibration_target_rho, per-stratum audit_rate, context-checkpoint
threshold/reserve, persistent_grants (default false), and confidential
path patterns. Per-language VerificationCadence defaults come from the
domain/plugin join and may be tightened by configuration, never loosened beyond
the registered maximum.
Data structures. Additions are the perspt-core model-plane and provider
types, perspt-sdk::toolset::{ToolEntry, ToolCatalog, ToolOrigin},
RouteObjective, EnsemblePolicy, new ResidualClass variants, and
ExecutionMode, NodeTerminalOutcome, CalibrationStratum,
CalibrationReadiness, VerificationCadence, ContextCheckpoint,
ControlFrame, ContractEvaluator, OperationalSafetyBarrier,
BarrierEvaluator, ChildRole, CapabilityLease, GrantPolicy, and
optional ProxyGeometry.
ModelRoute and ModelTierConfig change their model fields from String
to ModelId. PSP-8 ledger, graph, capability, and independence types are
revised where the code audit above found their current contracts insufficient.
Rationale
Why the tool loop, the model plane, and the platform contract in one PSP. They are one change viewed from three ends. The kernel, replay ledger, scheduler, and conformal budgets have been unwired since PSP-8 precisely because Perspt has no effect proposals. Model-issued tool calls supply them. A portfolio may also supply validator diversity, but only delayed labels can establish that. Splitting the work would risk shipping a tool loop whose configuration permits arbitrarily long unchecked intervals, which is the precise harness class Paper II Theorem 3 cannot certify.
Why multi-model is a practical plane with an optional mathematical use. Several providers enable cost routing, local execution, and failover. When model routes are used as conjunctive validators, Corollary 5.2 may additionally bound their joint miss risk from matched labeled statistics. The certificate comes from those statistics and conservative uncertainty bounds, not from the fact that the routes have different vendor names.
Why not majority voting across models. Voting is the intuitive multi-model design, but Corollary 5.2 governs conjunctive validator misses, not proposer votes. Correlated proposers can agree for correlated reasons, so Perspt selects candidate checkpoints by fixed measured energy and treats proposal diversity as an empirical search strategy. Validator diversity earns a risk bound only through system 8’s labeled conjunctive-gate path.
Why capabilities rather than an allow-list. A coding agent reads repository
content, issue text, dependency documentation, and now third-party tool
descriptions, all attacker-controllable in realistic settings. An allow-list
checked against model output is a check on what was proposed. Corollary 4.2
gives the stronger property: authority lives in kernel tables that proposals
cannot write, so injection changes what is proposed and never what is permitted.
This is also what makes yolo mode defensible — it removes the approval
prompt, not the capability bound.
Why residual-scored turns rather than a tool loop with retries. Contemporary
agent loops retry on failure. Paper II Lemma 1 is what a retry loop lacks: with a
nonnegative energy, a descent tolerance, and a finite budget, the loop provably
makes finitely many decisions and always lands in a classified terminal state.
It also converts “the agent kept trying” into named residuals a maintainer can
act on. The measured gate composes with the analytic bounds, and Paper II states
that composition as its own result — the Remark on gate composition following
Corollary 2.1: the accepted trajectory satisfies the better of the two
certificates, the analytic decay where the modelled assumptions hold and the
measured monotonicity of the acceptance gate even where they fail. This is why
this PSP can leave so many analytic claims not_claimed without leaving the
harness uncertified: assumption failure weakens semantic interpretation and
slows progress, but it does not break the gate invariant on accepted states,
because that invariant is a measurement rather than an assumption.
Why retain bundle generation as a benchmark. Whole-file generation may be cheaper for greenfield scaffolding. The ablation therefore keeps it as a measured baseline, but production authority stays in the typed tool loop. A provider without tools is eligible for chat or no-tool exploration and adjudication, not for an emulated coding loop.
Why removing sed_replace and awk_filter from the model
catalog. Their current contracts lack exact-match cardinality, expected-content
witnesses, and a structured transformation result. The path footprint is
computable, but safe effect preconditions are not. edit_file and
apply_diff cover the same use with checkable preconditions.
Alternatives considered.
Single-provider only. A valid deployment, and often the cheapest. Rejected as the only architecture because it cannot express local/remote policy, provider failover, or phase-specific credentials. No reliability penalty is asserted merely from having one provider.
A provider gateway (proxy) instead of an in-process portfolio. Would give multi-provider access with less code, but the harness needs the capability matrix, per-route calibration, family attribution, and failover attribution in the ledger; a gateway hides exactly those and would put an unaudited component inside the path that Theorem 7 requires be recorded.
Text-protocol tool emulation (model emits
<tool>blocks Perspt parses). Works on any provider and needs no transport change, but reintroduces the fragile parsing PSP 000007 removed and cannot produce the recorded, structured observations Theorem 7 requires. Rejected; providers without tool support are ineligible as actuators and may use an explicitly configured tool-capable fallback (Gate U).Adopt an external agent framework. Would supply a tool loop quickly but not the admissibility kernel, the residual/energy contract, the measured independence path, or the replay ledger — the parts that make Perspt’s claims falsifiable — and would put a third party inside the trusted base that Theorems 1–2 require Perspt to control.
Gate on the barrier only, skip conformal calibration. Acceptable for an effect only when a deterministic barrier/contract completely discharges the same declared unsafe event. Otherwise Gate Q routes autonomous mutation to approval or denial. Asserting a probabilistic risk budget without calibration would make
yolomode’s safety claim an assumption rather than a measurement, which the trilogy explicitly refuses.Ship parallelism first. Rejected: without footprints from tool proposals, the commutativity rule has nothing to compute over, and parallel unmediated effects are strictly worse than sequential ones.
Compatibility and Cutover
This PSP has no backward-compatibility requirement. Perspt and the SDK are pre-1.0, and maintaining two authority, ledger, configuration, or graph models would undermine the invariants being introduced. Bundle execution remains only an offline benchmark baseline; it is not a live compatibility path.
Breaking changes. The initial list is:
perspt-agent::tools::get_tool_definitionsis removed; the SDK catalog replaces it. It currently has no callers, so the break is nominal.sed_replaceandawk_filterleave the model-facing catalog.Direct tool execution paths inside the orchestrator are routed through the kernel. Any code path that performed an effect without a witness is changed, by design — that is Gate K.
perspt-sdkmoves fromsrbn0.1.1 to 0.3.0 and exposes the resulting status/realizer changes directly where that yields a clearer contract.routing::ModelRoute::model,ModelRoute::fallback_model, andModelTierConfig’s tier fields change fromStringtoModelId(andfallback_modelto afallbackchain).Flat provider keys are replaced by
[providers.<id>]and fully qualifiedModelIdroutes. A one-entry table remains simple, but the old flat schema need not deserialize.The live
petgraphplan and PSP-8WorkGraphRevisioncease to be parallel sources of truth; persisted work uses revision and generation ids.SDK ledger projections and store tables move to the versioned PSP-9 event envelope. Pre-PSP-9 sessions remain readable through an offline legacy viewer but are neither resumable nor replay-certified.
The legacy --mode, complexity, deferred-test, free-form energy-weight,
single-file, and unimplemented cost flags are removed rather than accepted and
ignored. The PSP-9 CLI exposes the actual finite controls: --rho-gate,
--max-turns, --max-calls-per-turn, --rejection-budget,
--max-parallel (verifier fan-out), and --max-parallel-nodes (node
dispatch, default 1). Model roles are explicit: --actuator-model,
--explorer-model, --adjudicator-model, and repeatable
--fallback-model. Architect or verifier routes are never silently treated
as actuator failovers. --yes removes the final promotion prompt within
granted authority; it does not grant network, privileged, or out-of-workspace
effects.
The cutover ships with a configuration converter and ledger exporter as one-way tools. Runtime dual-write, dual-read, and old-session resume are out of scope. This keeps one authoritative effect path from the first PSP-9 release.
Reference Implementation
Implementation is phased so that each phase is independently testable and each gate lands with the code it constrains.
Phase |
Work |
Gates |
Exit criterion |
|---|---|---|---|
P |
Kernel prerequisite: |
— |
Workspace builds against 0.3.0; existing SDK tests and serialization fixtures pass; no numbered phase begins on 0.1.1. |
0 |
|
U |
Three providers live in one process; every degradation is recorded and
printed by |
1 |
Provider tool transport; |
S, U |
A model completes a two-tool round trip on at least three provider families from one binary; the same conversation replays across providers without harness changes. |
2 |
SDK |
J |
Every catalog entry has a schema, footprint, effect, and round-trip
test; the catalog for a fixed capability set is provider-invariant; a
fixture language registers without editing |
3 |
|
M, V |
Decision count never exceeds the finite bound on fixtures; every
synthetic node exits with a |
4 |
Live |
J, K, L, M |
No durable effect without a complete record of all five clauses and an
explicit |
5 |
Recovery lattice; total classification; provider failover at level 1;
measured plateau driving graph revision at level 2; optional
|
N, V |
All failure classes, including transport failures, terminate within
|
6 |
Event-sourced ledger; |
L, O |
Audit replay folds full canonical transition records to the same state and head with credentials removed; a tampered observation, proposal, or state hash is detected; compaction preserves unresolved calls and the control frame; a revoked epoch rejects an in-flight and resumed effect. |
7 |
Portfolio routing with objectives; sticky routes; exploration phase;
|
S |
Explorer holds only read capabilities; a mutation attempt during exploration is denied and recorded; route switches are ledger events. |
8 |
Contemporaneous verdicts plus delayed labels; fix
|
R, T |
No dynamic energy attenuation exists; point estimates remain diagnostic; certified ρeff appears only with sufficient labeled matched samples and conservative pairwise bounds. |
9 |
Heterogeneous ensembles behind |
M, T |
Each candidate consumes a gate decision; distinct-family requirement enforced; ensemble arm measured against the single-model arm. |
10 |
SDK |
P |
Conflicting footprints never run concurrently; commuting ones do; per-provider limits contend only within a provider. |
11 |
Per- |
Q |
Realized accepted-unsafe rate is within the reported confidence interval
of the declared ρc on held-out fixtures — Theorem 5 bounds a
marginal expectation, so a single run’s realized rate is an estimate, not
the guarantee; the sub-feasible target ρc < 1 ⁄ (n + 1) rejects
everything; stale, shadow, imported, and cross-route windows are reported
uncertified; only a predeclared |
12 |
External tool registration under the kernel. |
K, L, U |
An external server cannot register a tool exceeding session authority;
undeclared footprints classify as |
13 |
Spectral topology diagnostic and certified μ distinction; conditional Φ(W) gauge; TUI/dashboard surfaces; undo/redo. |
R |
No topology gap is reported as Paper II μ; no platform stability is claimed without Theorem 9 assumption evidence. |
14 |
Parity and internal ablation benchmarks; possible typed whole-file tool; ensemble defaults, cadence bounds within registered maxima, compaction threshold, and audit rate decided by measurement. |
— |
Parity gate passes with failures preserved and reported. |
Mechanism checks. Following the trilogy’s discipline, each gate ships with a
deterministic check that falsifies a named theorem rather than “the
framework”. Placement follows the crate graph: checks provable from SDK types
alone (MC-K/L, MC-M, MC-P, MC-Q, MC-R, MC-T) extend the
perspt-sdk/tests/ mechanism-check suite, while checks that need a
transport, a live loop, or replay (MC-J, MC-N, MC-O, MC-S, MC-U, MC-V) live in
perspt-agent/tests/ against a synthetic in-process ModelTransport —
the SDK may not depend on I/O, so it cannot host them:
MC-J: a recorded tool-loop session in which every executed effect traces to a model-issued call and every returned call, including calls above
M, has a recorded proposal and result.MC-K/L: adversarial suite — unauthorized invocation, amplified delegation, payload-minted capability, exhausted call budget, out-of-workspace path, hidden shell composition inside
run_test, external tool registration claiming an effect the session lacks, missing barrier evaluator, false cc = 0, and a deterministic transition with h(x’) > h(x) + cc. Child fixtures attempt durable delivery, self-approval, delegation, and revision escape; resume fixtures serialize a live capability and race promotion against epoch revocation. All are denied; committed scopes remain inside Eff*.MC-M: synthetic energy trace confirming the decision bound, including an ensemble round; cadence fixtures verify per-mutation realization/parse, immediate high-risk and semantic-boundary diagnostics, and no more than
Hadmitted mutations between evidence boundaries.MC-N: all failure classes under an always-failing adversary, with a provider that always errors, terminate within
b + kin one of the four Theorem 6 classes. A companion fixture drives repeated fallback and refinement to prove they draw on the same pool: b horizontal steps distributed across levels must exhaust the budget exactly as b retries at level 0 do.MC-O: replay equality plus tamper detection, executed with all provider credentials removed. Compaction fixtures cross provider context sizes, preserve exact unresolved tool calls/control frames, rebuild stale checkpoints, and detect a changed covered-event root.
MC-P: footprint conflict matrix, including per-provider rate-limit resources, which must delay but never be reported as a required serialization; a registered footprint whose writes exceed its reads is rejected at assembly.
MC-Q: conformal calibration on synthetic and ledger-derived samples; realized risk against declared budget; drift injection routes uncertified mutation to approval; a calibration set is refused for any different stratum fingerprint; a target below 1 ⁄ (n + 1) yields reject-all and is reported as insufficient calibration rather than as a satisfied budget; a score exactly at the threshold is rejected. Cold-start fixtures remain
Shadow, collect a reproducible uniform audit sample, reject post-hoc cross-project pooling, and activate only the next immutable epoch after the local sample floor is met.MC-R: a sensor-name graph cannot populate
StabilityClaim.mu; a supplied linear B, W fixture reproduces 2λ + min(BTWB).MC-S: a fixture session executed under three portfolios produces identical decision bounds, terminal classifications, and catalog contents; only cost, latency, and success rate differ.
MC-T: the Paper III MC3 scenario reproduced on Perspt’s own path — a correlated validator pair with ground truth q = 0.1, κ = 0.5 must yield a measured joint miss near 0.055, not the independence product 0.01. Additional fixtures use unmatched candidate populations and zero-variance validators; both must use matched direct joint misses, and the displayed certificate must be a conservative upper bound rather than the point estimate. A three-validator fixture must report a bound no tighter than its best pair, since Corollary 5.2 is exact only at n = 2.
MC-U: a provider with each capability disabled in turn degrades along the declared ladder and records every degradation.
MC-V: an adversarial model that reports successful edits while every effect is denied must never reach a hard pass; the gate re-reads the unchanged overlay, projection mismatch is nonzero, and ‖rk‖ remains
not_claimed. A synthetic domain with validProxyGeometryseparately exercises Theorem 12.4 and Corollary 12.5.
Benchmarks. Fixture tasks per first-party language adapter, run in four internal ablation arms:
Legacy
Bundlemode, one-entry portfolio — offline baseline only.ToolLoop, single provider — isolates the tool loop.ToolLoop, portfolio routing without model validation — isolates cost, exploration, and failover policy.ToolLoop, portfolio routing with conjunctive adjudication and proposal ensembles — isolates optional review and search mechanisms.
Reported per arm: task success, accepted-state correctness, escaped-defect rate measured by a held-out verifier the harness never sees, correction rounds, energy trace and final energy, denied-proposal counts, escalation frequency, ρeff and the κ matrix where applicable, verifier latency by boundary, mutations per interleaved check, context tokens/checkpoint rebuilds, audit coverage, approval rate, cost, and latency. Per Paper II’s threshold list, failures are preserved and reported rather than filtered.
Arms 3 and 4 are justified only by measured cost, latency, availability, and escaped-defect outcomes against arm 2. Proposal diversity and adjudication may default on only where they improve the declared objective. Mechanism checks are labelled as mechanism checks and never reported as evidence about model capability.
Implementation Status
Note
This table tracks what is actually wired into the live execution path, in
the same discipline PSP-8 used: SDK contract implemented (a module
exists and is unit-tested) is distinct from wired (invoked during a
real run). It is updated as each phase lands on the psp9 branch.
Phase |
Gates |
Status |
Notes |
|---|---|---|---|
P — Kernel 0.3.0 upgrade |
— |
Done |
|
0 — Portfolio and capability matrix |
U |
Done |
|
1 — Tool transport |
S, U |
Partial |
SDK |
2 — Typed tool catalog |
J |
Done |
|
3 — Realizability, gate, certificates |
M, V |
Done |
|
4 — Live tool loop and kernel |
J, K, L, M |
Done |
|
5 — Recovery lattice |
N, V |
Done |
One shared non-replenishing pool is live for gate rejection and provider
transport failure; sticky failover and restore-best containment are
ledgered (MC-N). The runtime now holds the higher rungs: level 2
revises the work graph with the exhausted attempt’s evidence and
re-runs at a new generation, level 3 hands the node to the configured
architect route, and level 4 durably revokes the session’s authority
epoch — also wired to |
6 — Ledger and replay |
L, O |
Done |
Every live loop observation is durably appended before use;
|
7 — Routing and exploration |
S |
Done |
The live runtime builds a deterministic, content-witnessed repository
map before mutation and may send it to the configured Speculator route
with no tools or authority; the Actuator receives it as advisory
context, and configured tier/fallback routes form the sticky recovery
chain. |
8 — Verdicts and independence |
R, T |
Done |
Matched strata, degenerate-pair direct joint misses, Hoeffding upper
bounds, certification gating, |
9 — Proposal ensembles |
M, T |
Done |
|
10 — Scheduler and parallelism |
P |
Done |
|
11 — Conformal calibration |
Q |
Done |
SDK mechanism complete: feasibility floor |
12 — External tools |
K, L, U |
Done |
SDK |
13 — Diagnostics and surfaces |
R |
Done |
Both Lemma 2 levers in |
14 — Parity and ablation |
— |
Done |
|
Resolved Design Decisions
The six operational questions that previously blocked implementation are resolved normatively:
Verification cadence: use the bounded adaptive three-boundary policy of system 6. Realization/postconditions and incremental parse run after every mutation; touched-scope diagnostics run no later than
Hand immediately at risk/semantic boundaries; the complete suite runs before every gate. Measurement tunes cost only inside those bounds.Coding barrier: use the versioned operational safety barrier of system 12, with h = maxjhj over declared unsafe policy channels and exact deterministic increment ct = max(0, h(x’) − h(x)). Correctness remains in V. Missing or stochastic-uncertified channels downgrade the profile or require approval; determinism never makes cc = 0 automatically.
Conversation compaction: treat model context as a reconstructable ledger projection. Preserve a verbatim
ControlFrame, exact unresolved tool calls, and content-addressed evidence; record and structurally validate hierarchicalContextCheckpointvalues. Optional summaries are untrusted observations. Provider crossing is allowed because the projection is provider-neutral.Calibration cold start: ship no safety prior. Operate in shadow mode, route uncertified mutations to approval unless a separate deterministic contract applies, and fund uniform per-stratum delayed audits. Activate the exact theorem at its computed sample floor, reporting its practical granularity. Imported data is non-certifying unless it belongs to a predeclared signed calibration population; post-hoc pooling is forbidden. Unlabeled validator pairs receive no ρeff claim.
Subagent defaults: delegate role templates intersected with parent authority. Explorers and reviewers are read-only; workers may mutate only a named candidate overlay and run declared verifiers. Children are bounded, revision-scoped, non-delegable, unable to self-approve, and routed by the scheduler independently of authority.
Cross-session authority: persist signed
GrantPolicyintent, never a live capability. Resume re-mints new session capability ids from the intersection of current policy, grant ceilings, and workspace facts. Durable authority epochs are checked atomically on promotion, so revocation invalidates resumed sessions and in-flight workers. Session-only remains the default.
These choices favor useful autonomy without weakening a named theorem: cheap work continues, deterministic safety contracts avoid unnecessary prompts, and probabilistic claims remain unavailable until their evidence exists.
Remaining Open Issues
Where the adjudicator earns its cost. Adjudication on every turn is affordable only with a cheap route, and a cheap route has a high q. Gate failure, risk class, and energy plateau remain benchmark arms rather than assumed defaults.
Whether coding can define a useful proxy geometry. AST edit distance or verifier-vector distance can be useful metrics, but neither becomes Paper I’s ‖rk‖ unless the proposed and realized states inhabit the same declared analysis space and the remaining Theorem 12.4 assumptions are validated. Until then the field is
not_claimedand Corollary 12.5 is disabled.External tool wire completion. The implementation choice is a native deferred catalog and bounded Starlark composition for first-party work, with MCP stdio and Streamable HTTP retained only as optional edge adapters. External schemas are never eagerly injected, and an MCP server never becomes an authority, scheduler, ledger, or policy source. Both wire adapters are registered by the authoritative runtime and by the interactive chat (with a read-only admission ceiling);
[[external_tools]]in configuration is the single opt-in.
References
Vikrant R. and Ronak R., Stability is All You Need: Lyapunov-Guided Hierarchies for Long-Horizon LLM Reliability (Paper I). Sheaf consistency, Lyapunov energy, flow barriers, Merkle-ized state (Def. 7.1, Thm C.1), Theorems 5.1/5.2/12.1, and §12’s realizability interface: Definition 12.2 (hybrid state, Regimes A and B), Assumption 6 and Remark 12.3 (bounded realizability residual δr, and its caveats), Theorem 12.4 (practical stability, floor of order δ2r), Corollary 12.5 (commit feasibility, retry budget, and Topological Escalation).
srbn0.3.0,srbn-serde0.3.0,srbn-ledger0.3.0,srbn-regex0.3.0 — the published Rust kernel implementing Paper I, and the source ofstabilize_realized,Realizer,Policy,Status, and the Merkle chain this PSP consumes.Vikrant R. and Ronak R., Stability is All You Need II: The SRBN Harness Contract (Paper II). Harness contract, acceptance gate, Lemma 1 (finite acceptance and guaranteed termination), Theorem 1 (ISS energy tube), Theorem 2 and Corollary 2.1 (discrete descent), Theorem 3 (sparse feedback admits no horizon-independent certificate), Lemma 2 (spectral energy-slope).
Vikrant R. and Ronak R., Stability is All You Need III: The SRBN Platform Contract (Paper III). Admissibility kernel (Def. 3.2), Theorems 1–2 (confinement, self-modification), Corollary 4.2 (blast radius), Theorem 3 (workflow chance safety), Lemma 5.1 and Corollary 5.2 (correlated validators, certified ensemble risk), Theorem 4 (supermartingale barrier), Theorem 5 (conformal risk budgets), Theorem 6 (recovery termination), Theorem 7 (replay determinism), Theorem 8 (commuting commits), Definition 9.1 (six durable-execution obligations), Theorem 9 (Foster–Lyapunov platform stability), MC3 (measured correlated redundancy).
PSP 000005 — SRBN implementation continuation; multi-file coding UX and repo-native verification.
PSP 000007 — typed correction loops and plugin-aware prompt contracts; the fail-closed parse-validate discipline this PSP applies to tool arguments.
PSP 000008 — SRBN agent SDK, coding domain package, and mutable work graph; supplies every SDK contract this PSP wires to the live path.
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.