EconomyCredit
Credit Scorecards
A CreditScorecardReport combines reputation, exposure, and settlement history into one of five bands.
Five bands
Every scorecard resolves to one of five bands. Bands are ordinal, from most permissive to most restrictive:
pub enum CreditScorecardBand {
Prime,
Standard,
Guarded,
Probationary,
Restricted,
}The band is a categorical output, not a numeric cut. The crate encodes no score threshold per band: the band follows from the reason codes, the anomalies, and the confidence the evidence supports. What each band then does to a credit facility is fixed, and per-band consequences below carries the exact factors.
| Band | What puts a subject here |
|---|---|
Prime | High score, clean settlement record, no loss pressure. |
Standard | Healthy default tier. |
Guarded | Mild signals of stress: slow settlement, a mixed-currency book, modest loss pressure. |
Probationary | Sparse receipt history, sparse day coverage, or low confidence. It yields no facility terms and sends the decision to manual review. |
Restricted | Persistent failed settlements, outstanding provisional losses, or low reputation. The facility disposition is always a denial. |
Four dimensions
A scorecard exposes the band's reasoning across four scored dimensions. Each dimension carries an optional 0.0 to 1.0 score, a weight, a description, and evidence references back to the receipts, decisions, or attestations that justify it:
pub enum CreditScorecardDimensionKind {
ReputationSupport,
SettlementDiscipline,
LossPressure,
ExposureStewardship,
}
pub struct CreditScorecardDimension {
pub kind: CreditScorecardDimensionKind,
pub score: Option<f64>,
pub weight: f64,
pub description: String,
pub evidence_refs: Vec<CreditScorecardEvidenceReference>,
}| Dimension | What it scores |
|---|---|
ReputationSupport | The composite reputation score for the subject, attenuated by imported-trust dependencies. |
SettlementDiscipline | Pending vs failed settlement counts on the subject's receipts. |
LossPressure | Provisional loss amounts still outstanding against the subject. |
ExposureStewardship | Concentration, currency mix, and reserve-aware utilization patterns. |
Confidence
pub enum CreditScorecardConfidence {
Low,
Medium,
High,
}Confidence indicates whether the scorecard has enough evidence to support its band. An agent with a strong reputation score but only 12 receipts cannot get the same band as an agent with the same score and 12000 receipts. Sample size determines confidence; confidence in turn caps the band.
The probation block on the report makes the receipt-count and time-span thresholds explicit:
pub struct CreditScorecardProbationStatus {
pub probationary: bool,
pub reasons: Vec<CreditScorecardReasonCode>,
pub receipt_count: u64,
pub span_days: u64,
pub target_receipt_count: u64,
pub target_span_days: u64,
}While receipt_count < target_receipt_count or span_days < target_span_days, the subject is probationary. The reason codes attached to the status say which threshold is missing:
pub enum CreditScorecardReasonCode {
SparseReceiptHistory,
SparseDayHistory,
LowConfidence,
PendingSettlementBacklog,
FailedSettlementBacklog,
ProvisionalLossPressure,
MixedCurrencyBook,
LowReputation,
ImportedTrustDependency,
MissingDecisionCoverage,
}Anomalies and severity
Anomalies are typed reasons the band would otherwise be too high for the underlying signal. They reuse the same reason-code enum and attach a severity:
pub enum CreditScorecardAnomalySeverity {
Info,
Warning,
Critical,
}
pub struct CreditScorecardAnomaly {
pub code: CreditScorecardReasonCode,
pub severity: CreditScorecardAnomalySeverity,
pub description: String,
pub evidence_refs: Vec<CreditScorecardEvidenceReference>,
}A scorecard with a strong composite score but a FailedSettlementBacklog anomaly at Critical severity will be band-shifted toward Restricted regardless of how clean the reputation looks.
Report shape
pub struct CreditScorecardReport {
pub schema: String,
pub generated_at: u64,
pub filters: ExposureLedgerQuery,
pub support_boundary: CreditScorecardSupportBoundary,
pub summary: CreditScorecardSummary,
pub reputation: CreditScorecardReputationContext,
pub positions: Vec<ExposureLedgerCurrencyPosition>,
pub probation: CreditScorecardProbationStatus,
pub dimensions: Vec<CreditScorecardDimension>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub anomalies: Vec<CreditScorecardAnomaly>,
}schema is CREDIT_SCORECARD_SCHEMA, chio.credit.scorecard.v1. The summary is where the whole book collapses into one row:
pub struct CreditScorecardSummary {
pub matching_receipts: u64,
pub returned_receipts: u64,
pub matching_decisions: u64,
pub returned_decisions: u64,
pub currencies: Vec<String>,
pub mixed_currency_book: bool,
pub confidence: CreditScorecardConfidence,
pub band: CreditScorecardBand,
pub overall_score: f64,
pub anomaly_count: u64,
pub probationary: bool,
}The CreditScorecardSupportBoundary on each report declares what the report authoritatively covers. The default boundary is subject_scoped_only = true with cross-currency netting, capital allocation, and facility policy support all turned off.
How a scorecard is produced
A scorecard is built from three local sources, all of which the operator already maintains:
- Reputation: a
LocalReputationScorecardfor the subject (see Reputation Scoring), with imported-signal acceptance counted. - Exposure: an
ExposureLedgerReport(schemachio.credit.exposure-ledger.v1) covering the subject's receipts and underwriting decisions in the window. - Settlement: per-receipt
SettlementStatus(Pending, Failed, Settled, etc.) drives both settlement discipline and loss pressure dimensions.
Export a scorecard with chio trust credit-scorecard export, or read the same signed report through trust-control at GET /v1/reports/credit-scorecard. Both emit the chio.credit.scorecard.v1 report documented above; the export resolves against a local receipt store (--receipt-db) or a remote trust-control service (--control-url). Optional flags narrow the window (--since, --until) and the row budget (--receipt-limit, default 100, and --decision-limit, default 50).
The scorecard does not mint capital. It is an evaluation report, and the capital decision is a separate artifact: a CreditFacilityReport (schema chio.credit.facility-report.v1) carries the scorecard summary in its scorecard field and adds a disposition, prerequisites, terms and findings on top of it. The CreditFacilityArtifact (schema chio.credit.facility.v1) then wraps that report with a facility id, an expiry, and a lifecycle state.
Worked example
A subject with three governed receipts against one tool server, each carrying a 2500 minor-unit USD ceiling, and one underwriting decision on the same subject.
Run it
The receipts the export scores, listed with the governed amount each one carried:
$ chio --receipt-db ./receipts.db receipt list --admin-all \
| jq -r '[.decision.verdict, .tool_server, .tool_name, .metadata.governed_transaction.max_amount.units] | @tsv'allow ledger settle_invoice 2500 allow ledger settle_invoice 2500 allow ledger settle_invoice 2500
Expected output
Without --json the command prints eleven aligned lines: the schema, the generation time, the key that signed the export, the subject, and the summary fields that decide the band.
$ SUBJECT=$(chio --receipt-db ./receipts.db receipt list --admin-all \
| jq -r '.metadata.attribution.subject_key' | head -1)
$ chio --receipt-db ./receipts.db trust credit-scorecard export \
--agent-subject "$SUBJECT" \
--authority-seed-file ./authority.seedschema: chio.credit.scorecard.v1 generated_at: 1788542733 signer_key: fb4d4902815fd5db1e628702eeb87c48271872ac2fde57298767c3f8c04f9402 subject_key: 3b9ed9e1a200eec3b3fcc461f54ca1cf8af94e7ab205751d0d330320afedcb41 overall_score: 0.6000 confidence: Low band: Probationary probationary: true matching_receipts: 3 matching_decisions: 1 anomaly_count: 1
Three receipts clear neither target_receipt_count nor target_span_days, so probationary is true, confidence resolves to Low, and the band lands on Probationary even though the settlement record is clean. The single anomaly is the one that low confidence itself raises.
With --json the same run emits a SignedExportEnvelope instead: a body holding the report, a signerKey, and a signature over the canonical JSON of the body, with deny_unknown_fields and camelCase keys. The block below pipes that envelope through jq '.body.summary', so the camelCase keys and the snake_case enum values are the wire form of the summary struct above:
$ SUBJECT=$(chio --receipt-db ./receipts.db receipt list --admin-all \
| jq -r '.metadata.attribution.subject_key' | head -1)
$ chio --receipt-db ./receipts.db --json trust credit-scorecard export \
--agent-subject "$SUBJECT" \
--authority-seed-file ./authority.seed \
| jq '.body.summary'{
"matchingReceipts": 3,
"returnedReceipts": 3,
"matchingDecisions": 1,
"returnedDecisions": 1,
"currencies": [
"USD"
],
"mixedCurrencyBook": false,
"confidence": "low",
"band": "probationary",
"overallScore": 0.6,
"anomalyCount": 1,
"probationary": true
}When it refuses
The export is signed and computed from receipts rather than defaulted, so it refuses on either gap before emitting anything. Without a signing key it exits 1 with an empty stdout:
$ SUBJECT=$(chio --receipt-db ./receipts.db receipt list --admin-all \
| jq -r '.metadata.attribution.subject_key' | head -1)
$ chio --receipt-db ./receipts.db trust credit-scorecard export \
--agent-subject "$SUBJECT"error [urn:chio:error:cli:other]: behavioral feed export requires --authority-seed-file or --authority-db so the export can be signed
context: {"domain":"cli","severity":"error","stability":"deprecated","string_code":"CHIO-CLI-OTHER"}
suggested fix: Preserve the original message and migrate the call site to a specific registry code when touched.With a key, against a store holding no receipt for that subject, it exits 1 the same way:
$ SUBJECT=$(chio --receipt-db ./receipts.db receipt list --admin-all \
| jq -r '.metadata.attribution.subject_key' | head -1)
$ chio --receipt-db ./empty.db trust credit-scorecard export \
--agent-subject "$SUBJECT" \
--authority-seed-file ./authority.seederror [urn:chio:error:cli:other]: credit scorecard requires at least one matching governed receipt
context: {"domain":"cli","severity":"error","stability":"deprecated","string_code":"CHIO-CLI-OTHER"}
suggested fix: Preserve the original message and migrate the call site to a specific registry code when touched.A third refusal sits between those two and catches the case the wording above does not describe. The first gate counts receipts; the second needs money on them. credit_scorecard_position_denominator returns a value only when governed exposure, or settled plus pending plus failed units, is above zero, and without one the export answers credit scorecard requires monetary exposure in the requested window. A subject whose receipts carry no governed_transaction.max_amount and no charged cost has receipts to count and nothing to score, so it stops here rather than reporting a zero.
There is no zero-evidence scorecard to read. The local reputation scorer returns Unknown metrics against an empty store; the credit export declines to sign anything at all.
Per-band consequences
The band does not translate into terms through operator judgement. The facility report derives the disposition first, and builds terms only when the disposition is Grant.
Denywhen the band isRestricted, or the subject misses the minimum runtime assurance tier, or certification is required for the tool server and no active certification is present.ManualReviewwhen the book is mixed-currency, or the scorecard carriesFailedSettlementBacklogorPendingSettlementBacklog, or the subject is probationary, or the runtime-assurance evidence came from more than one verifier family.Grantotherwise.
The credit limit is the subject's own exposure scaled twice, by the band and then by confidence, and floored: floor(base_units × band_factor × confidence_factor). The confidence factors are 1.0 for High, 0.9 for Medium and 0.75 for Low. The band factors and the rest of the terms:
| Band | Limit factor | Utilization ceiling | Reserve ratio | Concentration cap | Term |
|---|---|---|---|---|---|
Prime | 1.0 | 9000 bps | 1000 bps | 3500 bps | 30 days |
Standard | 0.85 | 8000 bps | 1500 bps | 3000 bps | 14 days |
Guarded | 0.65 | 6500 bps | 2500 bps | 2000 bps | 7 days |
Probationary | 0.40 | No terms. The builder returns None for this band, and the disposition is ManualReview anyway. | |||
Restricted | 0.0 | No terms and no facility. The disposition is Deny. | |||
The two weakest bands demand the strongest attestation
credit_facility_minimum_runtime_assurance_tier asks RuntimeAssuranceTier::Attested of Prime, Standard and Guarded, and Verified, the strictest tier, of Probationary and Restricted. A subject with a thin history that cannot produce verified runtime attestation is denied on the prerequisite before the band is weighed.Terms carry their own ttl_seconds, which is what expires a granted facility. A report without terms falls back to seven days for Grant and ManualReview, and one day for Deny. Every granted facility is stamped CreditFacilityCapitalSource::OperatorInternal, so the capital behind it is the operator's own.
See also
- Reputation Scoring for the composite that feeds
ReputationSupportand for the weights behind it. - Credit and Underwriting for how facilities, bonds, and bonded execution sit on top of the scorecard.
- Agent Passports for carrying scorecard-grade evidence across an organizational boundary.
- The Economic Stack for where
chio-creditsits among the other economy crates.