Chio/Docs
LOGIN · JOIN

Credit & Underwriting

Turn the metered service’s signed receipts into an underwriting decision, then see how a stricter policy changes the outcome.

Guide chio@5f63e6e

On this page

Underwriting turns an agent's signed operating record into a credit decision with reasons attached. The kernel's receipts are the evidence, and a policy you can edit decides what that evidence earns.

The example reviews the agent that ran the 15-unit discount service in Tool Pricing: three admitted calls and three settled local charges. You run the review, read why it stops short of approval, then tighten the policy and watch the outcome change.

Start

1. Review the agent that ran your service

Download the credit-review project and extract it beside pricing-metered. It carries its lockfile and pinned Rust toolchain. Replace YOUR_RUN with the evidence directory your service printed.

Review your service’s operating evidencebash
cd credit-review
cargo run --release --locked -- ../pricing-metered/runs/YOUR_RUN
Captured review of the three-call service
Default policy: StepUp (Elevated)
receipts: 3 matching; 3 selected
reputation: 0.7070; probationary: true
- ReduceCeiling: local reputation is still probationary for the requested window
- StepUp: no active certification evidence is available for tool server `text`
complete report: credit-review.json
editable policy: underwriting-policy.json
facility: Deny; terms available: false
facility report: credit-facility-review.json

You should see StepUp (Elevated) from three matching receipts, a reputation of 0.7070, and a probationary history. The application selects the subject and operation from your capability, reads the host's public key, and writes credit-review.json, credit-facility-review.json, and an editable underwriting-policy.json that later runs preserve.

2. Read how two findings became StepUp

Each policy check that fires adds a finding. The report's outcome is the most restrictive finding, and its risk class is the highest class among them.

Underwriting decisionChoose an outcome.
ρreceipt historysreputationvruntime assurancehighestTierπevaluationκApproveApproved · PreserveκReduceCeilingApproved · Reduce × 0.5τStepUpManualReviewRequired · HoldDenyDenied · DenyρreceiptssreputationvassurancehighestTierπevaluationκApproveApproved · PreserveκReduceCeilingApproved · Reduce × 0.5τStepUpManualReviewRequiredDenyDenied · Deny

Missing evidence waits for review

MissingRuntimeAssurance, or a missing certification when policy requires one, routes to StepUp: review state ManualReviewRequired and budget action Hold until stronger evidence arrives. Underwriting.

Evidence evaluated under the default UnderwritingDecisionPolicy, rolling up to one UnderwritingDecisionOutcome; the reputation score and premium follow the worked example and are illustrative. The signed decision record issues no capability and moves no funds.Underwriting

Your agent earns two findings. Its reputation is still probationary, a ReduceCeiling finding at Guarded. Tool server text has no active certification while the default policy requires one, a StepUp finding at Elevated with remediation active_certification. StepUp outranks ReduceCeiling, so the report reads StepUp (Elevated), with review state ManualReviewRequired and budget action Hold until stronger evidence arrives.

A passing threshold cancels no other finding. The default policy approves at a reputation of 0.6 and denies below 0.25, so 0.7070 clears both, and the decision still waits on certification.

Read more in Underwriting.

3. Read why the facility returned no terms

A separate facility evaluator decides whether the agent qualifies for a credit line. Open its report.

credit-facility-review.json · decision and prerequisitesjson
{
  "disposition": "deny",
  "prerequisites": {
    "minimumRuntimeAssuranceTier": "verified",
    "runtimeAssuranceMet": false,
    "certificationRequired": true,
    "certificationMet": false,
    "manualReviewRequired": false
  },
  "supportBoundary": {
    "providerNeutralPolicy": true,
    "crossCurrencyAllocationSupported": false,
    "bondExecutionSupported": false
  }
}

You should see deny with runtimeAssuranceMet and certificationMet both false. A probationary score band requires runtime assurance at the verified tier and an active certification, and this agent has neither, so the evaluator allocates nothing and computes no terms. A review evaluates evidence: it issues no facility, moves no funds, and leaves the agent's grant unchanged.

4. Compare a stricter policy against the same evidence

In underwriting-policy.json, raise minimumApproveReputationScore to 0.85 and denyReputationScoreBelow to 0.75, and set version to document-service.strict.v1. Leave the other fields as they are.

underwriting-policy.jsonjson
{
  "schema": "chio.underwriting.decision-policy.v1",
  "version": "document-service.strict.v1",
  "minimumReceiptHistory": 1,
  "maximumReceiptAgeSeconds": 2592000,
  "minimumApproveReputationScore": 0.85,
  "denyReputationScoreBelow": 0.75,
  "minimumStepUpRuntimeAssuranceTier": "attested",
  "minimumApproveRuntimeAssuranceTier": "verified",
  "requireActiveToolCertification": true,
  "requireComplianceScoreReference": false,
  "reduceCeilingFactor": 0.5
}
Compare your policybash
cargo run --release --locked -- ../pricing-metered/runs/YOUR_RUN underwriting-policy.json
Captured policy comparison
Default policy: StepUp (Elevated)
receipts: 3 matching; 3 selected
reputation: 0.7070; probationary: true
- ReduceCeiling: local reputation is still probationary for the requested window
- StepUp: no active certification evidence is available for tool server `text`
Your policy: Deny (Critical)
receipts: 3 matching; 3 selected
reputation: 0.7070; probationary: true
- Deny: effective reputation score 0.7070 is below the deny threshold 0.7500
- ReduceCeiling: local reputation is still probationary for the requested window
- StepUp: no active certification evidence is available for tool server `text`
outcome changed: true
complete report: credit-comparison.json

You should see Deny (Critical) under your policy and outcome changed: true. A score of 0.7070 now falls below the 0.75 deny threshold, and that Deny finding outranks the StepUp and ReduceCeiling findings it joins. The comparison writes credit-comparison.json; it installs no policy and persists no decision. Your own history can produce a different score.

5. Trace the decision to the receipts it rests on

Every report names the evidence it read. Open credit-review.json and find the receipt selection.

credit-review.json · input.receiptsjson
{
  "matchingReceipts": 3,
  "returnedReceipts": 3,
  "allowCount": 3,
  "receiptRefs": [
    {
      "kind": "receipt",
      "referenceId": "9d745a1a4a543a8b400fcf52e1f085f791db8309fd43366a0b0278b5d9408134",
      "observedAt": 1788928934,
      "locator": "receipt:9d745a1a4a543a8b400fcf52e1f085f791db8309fd43366a0b0278b5d9408134"
    },
    {
      "kind": "receipt",
      "referenceId": "cf108cd7ce5449c00be44617a0a5e3ab41d88adbe5eb8b0bb3a66e1de4bebd73",
      "observedAt": 1788928933,
      "locator": "receipt:cf108cd7ce5449c00be44617a0a5e3ab41d88adbe5eb8b0bb3a66e1de4bebd73"
    },
    {
      "kind": "receipt",
      "referenceId": "a3257f67251cfe33873b51eb082c25f2da07a2360040af56007832509394af5d",
      "observedAt": 1788928933,
      "locator": "receipt:a3257f67251cfe33873b51eb082c25f2da07a2360040af56007832509394af5d"
    }
  ]
}

You should see three matching receipts, three returned, all three allowed, each named by its receipt ID. The reference a3257f67…af5d is the receipt you verified in Tool Pricing. The query selects up to 100 receipt references, so compare matchingReceipts with returnedReceipts before you treat a larger review as complete.

Credit, bond, capital, and market records

The review application

The application calls the control-plane evaluation APIs with the run's subject, tool, and trusted public key. It reads the run's receipt store and its recorded financial metadata. Its README lists the local-store assumptions.

Complete credit-review applicationrust
use anyhow::{bail, ensure, Context, Result};
use chio_core::capability::token::CapabilityToken;
use chio_core::crypto::PublicKey;
use chio_kernel::{UnderwritingDecisionReport, UnderwritingPolicyInputQuery, UnderwritingSimulationRequest};
use std::path::Path;

fn print_report(label: &str, report: &UnderwritingDecisionReport) {
    println!("{label}: {:?} ({:?})", report.outcome, report.risk_class);
    println!("receipts: {} matching; {} selected", report.input.receipts.matching_receipts, report.input.receipts.returned_receipts);
    if let Some(reputation) = &report.input.reputation {
        println!("reputation: {:.4}; probationary: {}", reputation.effective_score, reputation.probationary);
    }
    for finding in &report.findings {
        println!("- {:?}: {}", finding.outcome, finding.description);
    }
}

fn main() -> Result<()> {
    let args: Vec<String> = std::env::args().skip(1).collect();
    if !(1..=2).contains(&args.len()) {
        bail!("Usage: cargo run --release --locked -- RUN_DIRECTORY [POLICY_JSON]");
    }
    let run = Path::new(&args[0]);
    let receipts = run.join("receipts.db");
    ensure!(receipts.is_file(), "Run directory must contain an existing receipts.db");
    let capability: CapabilityToken = serde_json::from_slice(
        &std::fs::read(run.join("capability.json")).context("Read the application's capability")?
    )?;
    // The host selected and saved this public key before receiving receipts.
    // In another deployment obtain the expected key through your trusted channel.
    let expected = std::fs::read_to_string(run.join("kernel-public-key.txt"))?;
    let trusted = PublicKey::from_hex(expected.trim())?;
    let grant = capability.scope.grants.first().context("Capability has no grant")?;
    let query = UnderwritingPolicyInputQuery {
        capability_id: None,
        agent_subject: Some(capability.subject.to_hex()),
        tool_server: Some(grant.server_id.clone()),
        tool_name: Some(grant.tool_name.clone()),
        since: None,
        until: None,
        receipt_limit: Some(100),
    };
    let trusted_keys = vec![trusted.to_hex()];
    // This review uses the application's local receipt store. No budget store
    // or certification registry is supplied; the report exposes missing evidence.
    // It evaluates policy without issuing a facility or moving funds.
    if let Some(policy_path) = args.get(1) {
        let policy = serde_json::from_slice(&std::fs::read(policy_path)?)?;
        let report = chio_control_plane::trust_control::build_underwriting_simulation_report(
            &receipts, None, None,
            &UnderwritingSimulationRequest { query, policy }, &trusted_keys,
        )?;
        print_report("Default policy", &report.default_evaluation);
        print_report("Your policy", &report.simulated_evaluation);
        println!("outcome changed: {}", report.delta.outcome_changed);
        std::fs::write("credit-comparison.json", serde_json::to_vec_pretty(&report)?)?;
        println!("complete report: credit-comparison.json");
    } else {
        let report = chio_control_plane::trust_control::build_underwriting_decision_report(
            &receipts, None, None, &query, &trusted_keys,
        )?;
        print_report("Default policy", &report);
        std::fs::write("credit-review.json", serde_json::to_vec_pretty(&report)?)?;
        // Do not overwrite a policy the reader has already edited.
        if !Path::new("underwriting-policy.json").exists() {
            std::fs::write("underwriting-policy.json", serde_json::to_vec_pretty(&report.policy)?)?;
        }
        println!("complete report: credit-review.json");
        println!("editable policy: underwriting-policy.json");
        let facility_query = chio_kernel::ExposureLedgerQuery {
            agent_subject: query.agent_subject.clone(),
            tool_server: query.tool_server.clone(),
            tool_name: query.tool_name.clone(),
            ..Default::default()
        };
        let facility = chio_control_plane::trust_control::build_credit_facility_report(
            &receipts, None, None, None, &facility_query, &trusted_keys,
        )?;
        println!("facility: {:?}; terms available: {}", facility.disposition, facility.terms.is_some());
        std::fs::write("credit-facility-review.json", serde_json::to_vec_pretty(&facility)?)?;
        println!("facility report: credit-facility-review.json");
    }
    Ok(())
}

Facility terms and dispositions

A facility records the credit terms an agent qualifies for. The evaluator weighs its scorecard band, runtime assurance, certification, and existing exposure. Missing required assurance or certification denies allocation; probationary history, unresolved exposure, mixed currencies, or mixed runtime provenance can require manual review. Only a qualifying Grant report carries computed terms. evaluate persists nothing; issue signs and stores the facility.

CreditFacilityTermsrust
pub struct CreditFacilityTerms {
    pub credit_limit: MonetaryAmount,
    pub utilization_ceiling_bps: u16,                // max % of limit drawable at once
    pub reserve_ratio_bps: u16,                      // reserve, as a share of outstanding exposure
    pub concentration_cap_bps: u16,                  // max size of any single allocation
    pub ttl_seconds: u64,                            // facility lifetime
    pub capital_source: CreditFacilityCapitalSource, // where backing capital comes from
}

CreditFacilityDisposition has three variants, and the same values are the --disposition filter on chio trust facility list:

  • Grant (grant): the evaluation permits a facility; inspect its computed terms before issuing.
  • ManualReview (manual_review): the evidence calls for provider review before allocation, and the report sets manualReviewRequired.
  • Deny (deny): the application misses the minimum underwriting criteria.

Every MonetaryAmount counts the currency's smallest unit: 100 units is one US dollar, so a USD 10,000 facility is units: 1000000. credit_limit is the facility size and utilization_ceiling_bps bounds how much of it may be drawn at once: a USD 10,000 limit at 8,000 bps allows USD 8,000 of concurrent draws.

Credit bonds

A credit bond records the reserve behind a facility: collateral, exposure, coverage, and the source of capital. The bond record is reserve accounting; locking or seizing funds at an external custodian takes that custodian's execution and reconciliation.

CreditBondTermsrust
pub struct CreditBondTerms {
    pub facility_id: String,
    pub credit_limit: MonetaryAmount,
    pub collateral_amount: MonetaryAmount,
    pub reserve_requirement_amount: MonetaryAmount,
    pub outstanding_exposure_amount: MonetaryAmount,
    pub reserve_ratio_bps: u16,
    pub coverage_ratio_bps: u16,
    pub capital_source: CreditFacilityCapitalSource,
}

Bond states:

  • Active: live and backing the facility.
  • Superseded: replaced by a new bond, for example after a facility amendment.
  • Released: reserve release recorded; the custodian's execution evidence shows any external return.
  • Impaired: reserve impairment recorded after default or a policy violation; external seizure carries its own execution evidence.
  • Expired: the bond's TTL elapsed without renewal.

Disposition actions move a bond between states: Lock locks additional collateral into the bond, Hold holds collateral pending investigation, Release returns collateral to the holder, and Impair records impairment after default or violation.

Risk classes

Risk class summarizes the findings; the outcome is the permission result. The report takes the highest class among its findings and defaults to Baseline when none fired. Facility terms use a separate scorecard band: prime, standard, guarded, probationary, or restricted.

  • Baseline: no finding fired.
  • Guarded: something fired, nothing severe.
  • Elevated: high risk, the highest class short of Critical.
  • Critical: at least one severe finding; every Deny finding lands here.

Underwriting outcomes

Facility disposition and remediation are separate fields: a recommendation to gather evidence or seek review issues no facility.

  • Approve: the selected evidence passes the policy.
  • ReduceCeiling: recommends the configured reduction factor for spending authority.
  • StepUp: requires the additional evidence the findings name.
  • Deny: refuses under the policy, with reason codes.

The default decision policy

Every review records the exact policy it evaluated. The editable file starts from these defaults:

credit-review.json · policyjson
{
  "schema": "chio.underwriting.decision-policy.v1",
  "version": "chio.underwriting.decision-policy.default.v1",
  "minimumReceiptHistory": 1,
  "maximumReceiptAgeSeconds": 2592000,
  "minimumApproveReputationScore": 0.6,
  "denyReputationScoreBelow": 0.25,
  "minimumStepUpRuntimeAssuranceTier": "attested",
  "minimumApproveRuntimeAssuranceTier": "verified",
  "requireActiveToolCertification": true,
  "requireComplianceScoreReference": false,
  "reduceCeilingFactor": 0.5
}

minimumReceiptHistory is a count: at least one matching receipt. maximumReceiptAgeSeconds is a freshness ceiling on the newest receipt, so one receipt from five minutes ago passes the history checks while two years of history whose newest receipt is 31 days old fails with StaleReceiptHistory.

The deny comparison is strict, effective_score < deny_reputation_score_below, so exactly 0.25 does not deny. A score from 0.25 up to 0.6 produces ReduceCeiling with reason ReputationBelowApproveThreshold and no remediation. reduceCeilingFactor is the factor a ReduceCeiling report suggests; applying it to a grant is a separate issuance action.

Reason codes

Every UnderwritingDecisionFinding carries a primary UnderwritingDecisionReasonCode in its reason field. There are eight:

UnderwritingDecisionReasonCoderust
pub enum UnderwritingDecisionReasonCode {
    PolicySignal,                     // an underlying policy signal fired
    ComplianceScoreRequired,          // a compliance score is missing
    InsufficientReceiptHistory,       // fewer receipts than the minimum
    StaleReceiptHistory,              // receipt history older than the window
    ReputationBelowApproveThreshold,  // reputation under the 0.6 approve floor
    ReputationBelowDenyThreshold,     // reputation under the 0.25 deny floor
    RuntimeAssuranceBelowApproveTier, // assurance tier below approve
    RuntimeAssuranceBelowStepUpTier,  // assurance tier below step-up
}

A finding may also carry a secondary signal_reason of type UnderwritingReasonCode, the signal behind the primary reason. There are 13:

UnderwritingReasonCoderust
pub enum UnderwritingReasonCode {
    ProbationaryHistory,           // insufficient operational history
    LowReputation,                 // composite reputation below threshold
    ImportedTrustDependency,       // reliance on external trust source
    MissingCertification,          // required cert not present
    FailedCertification,           // certification check failed
    RevokedCertification,          // certification was revoked
    MissingRuntimeAssurance,       // no runtime assurance attestation
    WeakRuntimeAssurance,          // assurance tier below minimum
    PendingSettlementExposure,     // unsettled financial exposure
    FailedSettlementExposure,      // prior settlement failure
    MeteredBillingMismatch,        // billing discrepancy detected
    DelegatedCallChain,            // delegation chain risk factor
    SharedEvidenceProofRequired,   // additional proof needed
}

Bonded execution

Bonded-execution evaluation weighs an autonomy request against the bond's state, reserve, assurance, and unresolved losses. The CLI runs it as a simulation over a persisted bond and returns an Allow or Deny report with a support boundary. The report is a policy result; enforcement happens at the execution boundary that consumes it.

Autonomy categories

  • Direct: a direct action in the governed autonomy model; the category installs no approval workflow.
  • Delegated: delegated authority, with chain and assurance requirements checked by the configured evaluator.
  • Autonomous: an autonomous request, subject to the bond and policy checks.

Operator control policy

CreditBondedExecutionControlPolicyrust
pub struct CreditBondedExecutionControlPolicy {
    pub version: String,
    pub kill_switch: bool,                                    // produce a Deny finding
    pub maximum_autonomy_tier: Option<GovernedAutonomyTier>,  // highest tier allowed
    pub minimum_runtime_assurance_tier: Option<RuntimeAssuranceTier>, // assurance floor
    pub require_delegated_call_chain: bool,                   // require a delegated chain
    pub require_locked_reserve: bool,                         // require the Lock disposition
    pub deny_if_bond_not_active: bool,                        // deny when the bond is inactive
    pub deny_if_outstanding_delinquency: bool,                // deny on outstanding delinquency
}

Setting kill_switch adds KillSwitchEnabled and makes the simulation deny. It does not terminate a process or cancel an in-flight call. require_locked_reserve requires the bond's Lock disposition, and the active-bond and outstanding-delinquency checks are on by default. The report also refuses when the bond does not claim autonomy-gating support. Wire the resulting decision into the execution boundary you control.

Execution evaluation

The simulation combines the persisted bond, loss history, requested autonomy and assurance, and the proposed control policy. Any finding yields Deny with codes that name the gate, such as KillSwitchEnabled, BondNotActive, RuntimeAssuranceBelowAutonomyMinimum, and MissingDelegatedCallChain; no findings yields Allow. The response includes sandboxIntegrationReady and a support boundary, read separately from execution.

An agent without the collateral to proceed is denied. Issuing a bond record (chio trust bond issue) is a separate action taken before the next attempt.

Capital book

The capital book projects facility commitments, reserve records, and loss events into one source-of-funds view. Its default support boundary leaves custody execution and capital execution to the configured custodian.

Capital-book events

  • Commit: capital committed to a facility or bond.
  • Hold: capital held pending a specific invocation.
  • Draw: capital drawn from a facility to fund an invocation.
  • Disburse: capital paid to a provider after settlement.
  • Release: held or committed capital returned to its source.
  • Repay: an outstanding draw repaid to the facility.
  • Impair: capital written off after default.

Capital roles

  • OperatorTreasury: the operator's own capital pool, for self-funded facilities.
  • ExternalCapitalProvider: a third party that funds facilities for a return.
  • AgentCounterparty: the agent or entity on the other side of the movement.

A capital instruction binds an authority chain, an execution window, a rail, and an intended state. Validation requires the source owner's approval and the configured custodian's signed authority step, and those steps cover the window and the named roles. A reconciled observation is a separate record from an instruction awaiting execution.

Liability market

The liability-market model connects provider records, coverage quotes, placement, and bound-coverage evidence, so a market can state which execution risks a provider covers and tie a claim to its receipts. Coverage takes effect through the bound terms and the provider's integration.

Provider categories

  • AdmittedCarrier: a licensed carrier in regulated markets.
  • SurplusLine: a non-admitted carrier for risks standard markets decline.
  • Captive: a self-insurance entity owned by the insured organization.
  • RiskPool: a pool that shares covered risk.

Coverage classes

  • ToolExecution: losses from failed or incorrect tool invocations.
  • DataBreach: costs of unauthorized data exposure during tool use.
  • FinancialLoss: direct financial losses from agent actions.
  • ProfessionalLiability: claims from errors in professional agent outputs.
  • RegulatoryResponse: costs of regulatory investigations or compliance actions.

Coverage lifecycle

Each stage requires its record and the configured provider action:

  1. Quote. The provider prices coverage from the agent's risk profile and requested class.
  2. Bind. The quote is accepted under the provider's terms; premium collection and effective coverage run through that integration.
  3. Active coverage period. The bound terms cover the named risks.
  4. Claim. The agent or operator files a claim after a covered event.
  5. Adjudication. The provider evaluates the claim against receipts and policy terms.
  6. Payout. An approved payment executes and reconciles through the configured provider and rail.

Market bonds and penalties

Market rules can require publication, listing, or dispute bonds and define penalties for violations. A penalty record binds the action to its evidence and authority; collateral moves through the market's execution and dispute process.

Bond classes

  • Publication: posted when publishing a tool or service listing; can back penalties for fraudulent descriptions.
  • Listing: posted when listing availability; can back service-availability obligations.
  • Dispute: posted when filing a dispute; can back penalties for unsupported disputes.

Penalty actions

  • HoldBond: freezes the bond pending investigation; capital stays put and is not seized.
  • SlashBond: seizes part or all of the bond; the governing decision and rail decide any distribution to the affected counterparty.
  • ReverseSlash: reverses a slash when the original decision is overturned on appeal.

Operator commands

Underwriting, credit, and liability-market modules are optional and off in default builds of the kernel, control plane, and CLI. With them enabled, evaluation and simulation return reports, issuance persists signed records, and execution and reconciliation are separate operations.

  • chio trust underwriting-input: builds a signed UnderwritingPolicyInput.
  • chio trust underwriting-decision: evaluates or simulates a report; issue persists an UnderwritingDecisionArtifact with its decision and premium state.
  • chio trust underwriting-appeal: runs the appeal lifecycle against a persisted decision.
  • chio trust facility: evaluates, issues, and lists credit facility records.
  • chio trust bond: evaluates, issues, lists, and simulates reserve-lock bond records.
  • chio trust loss: records delinquency, recovery, reserve-release, reserve-slash, and write-off events.
  • chio trust exposure-ledger: produces a signed ExposureLedgerReport, the per-currency settlement position.
  • chio trust credit-scorecard: produces a signed CreditScorecardReport from the exposure ledger and reputation inspection.
  • chio trust capital-book: exports a signed capital book tying facilities, bonds, and losses to one source-of-funds view.
  • chio trust capital-instruction: emits custody-neutral capital instructions.
  • chio trust capital-allocation: emits capital-allocation decisions, simulated first.
  • chio trust liability-provider: manages the curated liability-provider registry.
  • chio trust liability-market: drives the quote, placement, and bound-coverage flow.
  • chio trust provider-risk-package: assembles the signed insurer-facing evidence bundle.
  • chio trust credit-backtest: runs deterministic backtests over past subject-scoped evidence.

Next: settle what the agent spends

Credit & Underwriting · Chio Docs