Chio/Docs
LOGIN · JOIN

Reputation Scoring

Size an agent’s next grant from its execution history, and look up the scoring inputs, metric weights, issuance ceilings, and marketplace tiers.

Concept chio@5f63e6e

On this page

The capability authority sizes an agent’s next grant from the agent’s signed history. The local scorecard folds eight metrics from receipts, capability lineage, and resource use into one composite, and the issuance policy maps that score to a tier whose ceiling bounds the scope and lifetime of the grant.

Each operator chooses the evidence and policy it trusts. The scorecard, the issuance ceiling, the feed-based marketplace tiers, and passport comparison take separate inputs and serve separate consumers; a composite reaches a capability only through the issuance policy.

Eight weighted metrics fold into one composite

Each metric asks one question of the subject’s history: how hard it presses policy boundaries, how it uses capped grants, how much of its authority it uses, how deep its history runs, how it spreads across tools, how it narrows what it delegates, how its non-denied work completes, and how often incidents name it.

Local scorecardChoose a subject’s history.
boundary_pressure0.20× 0.90resource_stewardship0.10unknownleast_privilege0.15unknownhistory_depth0.10unknowntool_diversity0.05unknowndelegation_hygiene0.15unknownreliability0.15× 0.80incident_correlation0.10unknownccomposite0.857weight 0.3500.400.650.851probationarystandardtrustedelevated0.60elevated · read, get, invoke, read_result, delegate, subscribeuncapped invocations · 3600 sboundary_pressure0.20resource_stewardship0.10least_privilege0.15history_depth0.10tool_diversity0.05delegation_hygiene0.15reliability0.15incident_correlation0.10ccomposite0.857 · weight 0.3500.400.650.851probationarystandardtrustedelevated0.60elevated · uncapped invocations · 3600 sread, get, invoke,read_result, delegate, subscribe

A partial composite still folds to one score

Boundary pressure contributes 0.90 at weight 0.20 and reliability 0.80 at weight 0.15. The six unknown metrics add neither value nor weight, so the composite is 0.30 / 0.35 ≈ 0.857 from 0.35 of the default weight. Past probation, that score selects elevated. Reputation and passports.

The eight local scorecard metrics at their default weights, the weighted mean over the known ones, and the score-to-tier lookup over the example policy hushspec-reputation.yaml. The metric values are illustrative; the example’s monetary ceilings and delegation depths are left out.

The default weights sum to 1.00. For known components with positive weights, the composite is sum(weight × value) / sum(weight); an unknown metric contributes neither a value nor a weight, and with no contributing weight the composite is MetricValue::Unknown. A denial counts toward boundary pressure and leaves reliability’s denominator, so the two metrics measure different things.

A partial composite reports how much evidence it used

Suppose the only known values are a boundary-pressure contribution of 0.90 and a reliability of 0.80, at their default weights of 0.20 and 0.15. The six other components are unknown.

Composite arithmetictext
effective_weight_sum = 0.20 + 0.15 = 0.35
weighted_sum         = 0.20 × 0.90 + 0.15 × 0.80 = 0.30
composite_score      = 0.30 / 0.35 ≈ 0.8571

The score is about 0.86, and only 0.35 of the default weight contributed. That figure is a share of weight, distinct from an observation count or a confidence of 35 percent.

The fold runs over supplied component values, so read effective_weight_sum, the observation counts, the effective score, and the probationary status of the report in hand before applying its ceiling. Under the example policy, a subject past probation with this composite lands in elevated; a probationary one is capped at 0.60 and lands in standard.

The capability authority turns the score into a ceiling

Before it issues authority, the configured capability authority computes the subject’s local scorecard and applies four rules in order:

  1. Probation. The subject is probationary while its receipt count is below probationary_receipt_count or its observed span is below probationary_min_days. Defaults: 1,000 receipts and 30 days.
  2. Effective score. An unknown composite becomes zero. While probationary, the effective score is capped at probationary_score_ceiling, default 0.60.
  3. Tier. The last matching score range in the sorted tier list wins. Both endpoints are inclusive, so a shared endpoint resolves to the later, higher tier; with no match, the first tier applies.
  4. Ceiling. Requested scope or lifetime beyond that tier’s max_scope is rejected.

Tier names and ceilings come from extensions.reputation.tiers. These values belong to the example policy examples/policies/hushspec-reputation.yaml:

TierScoreOperationsInvocationsLifetime
probationary0.00 to 0.40read, get5060 s
standard0.40 to 0.65read, get, invoke500300 s
trusted0.65 to 0.85read, get, invoke, read_result50001800 s
elevated0.85 to 1.00read, get, invoke, read_result, delegate, subscribeuncapped3600 s
The rest of the example policy

The example also sets monetary ceilings and requires constrained grants in the probationary tier. Materialization sorts tiers by the range’s lower bound, upper bound, then name, and an empty tier list matches nothing, so issuance is refused. The example declares delegation depths 0, 1, 3, and 5: the issuance check reads depth 0 as a prohibition on delegation and enforces no numeric depth ceiling from the positive values. The lookup is stateless, mapping the current score to a ceiling on each issuance, and the example’s promotion and demotion blocks are outside it.

An empty history reads as Unknown, distinct from a low score

This captured report has no history for its subject. The output is projected to the score, the observation status, and the import policy; the full report includes every component.

No history · captured local scorecardtranscript
$ chio --json --receipt-db ./receipts.db reputation local \
    --subject-public-key 80f2b577472e6662f46ac2e029f4b2d1300f889bc767b3de1f7b63a4c562fd8f \
  | jq '{subjectKey, scoringSource, weights: .scoring.weights,
$          probationary, probationaryStatus, effectiveScore,
$          composite: .scorecard.composite_score,
$          effectiveWeightSum: .scorecard.effective_weight_sum,
$          importedTrust}'
{
  "subjectKey": "80f2b577472e6662f46ac2e029f4b2d1300f889bc767b3de1f7b63a4c562fd8f",
  "scoringSource": "default",
  "weights": {
    "boundary_pressure": 0.2,
    "resource_stewardship": 0.1,
    "least_privilege": 0.15,
    "history_depth": 0.1,
    "tool_diversity": 0.05,
    "delegation_hygiene": 0.15,
    "reliability": 0.15,
    "incident_correlation": 0.1
  },
  "probationary": true,
  "probationaryStatus": {
    "belowReceiptTarget": true,
    "belowDayTarget": true
  },
  "effectiveScore": 0.0,
  "composite": {
    "state": "unknown"
  },
  "effectiveWeightSum": 0.0,
  "importedTrust": {
    "policy": {
      "attenuationFactor": 0.5,
      "requireProofs": true,
      "requireSignerIdentity": true,
      "maxSignalAgeDays": 30,
      "requiredTrustMode": "bilateral_evidence_share"
    },
    "signalCount": 0,
    "acceptedCount": 0
  }
}
exit 0

The composite is Unknown and effectiveWeightSum is zero. The caller-facing effectiveScore substitutes zero, while probationaryStatus identifies insufficient history, so a missing record and a measured low score stay distinguishable to whoever reads the report. Under the example policy, that zero effective score lands in probationary.

Another operator’s evidence enters by comparison or by import

Operators can reach different scores from different corpora, trust keys, and scoring policies. Chio brings another operator’s evidence into an assessment along two paths:

  • Passport comparison. The receiver verifies the credentials and their claimed metrics, compares them with its own independently computed inspection, and applies the verifier policy when one is supplied.
  • Bilateral evidence share. The receiver takes authorized stored shares holding receipt bodies and capability snapshots, recomputes a score from that corpus under its own configuration, then applies the import policy.

The default import policy uses 0.50 attenuation, a 30-day maximum signal age, required proofs, required signer identity, and the bilateral_evidence_share trust mode, all visible in the captured report. A signed passport and an evidence share disclose different things, and sharing receipts requires the corresponding authorized exchange.

Read more in Portable Reputation, which follows an import from one organization to another.

Commands, inputs, and scoring constants

Run a local report

Pass the subject’s public key in bare hexadecimal form. The CLI reads your configured local stores, so set the receipt database and policy for the tenant whose evidence you inspect.

Command synopsistext
# Local evidence for one subject
chio --json --receipt-db receipts.sqlite3 reputation local \
  --subject-public-key <64-hex> \
  [--since <unix>] [--until <unix>] [--policy policy.yaml]

# A presented passport compared with local evidence
chio --json --receipt-db receipts.sqlite3 reputation compare \
  --subject-public-key <64-hex> --passport passport.json \
  [--local-policy policy.yaml] [--verifier-policy verifier.yaml]

The trust control plane also serves /v1/reputation/local/{subject_key} and /v1/reputation/compare/{subject_key}. chio reputation local|compare lists every argument.

Scoring inputs

The local corpus

The caller supplies LocalReputationCorpus. The scorer performs no network lookup and owns no tenant store; the calling service decides which tenant’s records it loads.

InputUsed forBoundary
receipts
Outcomes, tools, policy pressure, history
Only attributed receipts that pass integrity validation contribute
capabilities
Granted authority, constraints, parent-child links
Subject capabilities and delegations it issued are selected separately
budget_usage
Per-grant invocation utilization
Counters describe usage of capped grants
incident_reports
A decay-weighted incident penalty
None means unavailable; an empty list means no supplied incidents

Receipt integrity checks require a trusted kernel key, a matching content-addressed receipt ID, a valid signature, and a valid action hash. The scoring function authenticates receipts only; the caller vouches for the capability, usage, and incident records it supplies and scopes incidents to the subject, because the scorer evaluates every supplied incident.

compute_local_scorecard

The Rust entry point takes a subject key, an explicit evaluation time, the corpus, and a configuration. Fixed inputs, including now, produce the same scorecard.

compute_local_scorecardrust
compute_local_scorecard(
    subject_key: &str,
    now: u64,
    corpus: &LocalReputationCorpus,
    config: &ReputationConfig,
) -> LocalReputationScorecard

Read effective_weight_sum and the observation counts beside the composite; they show how much evidence the result used.

Scoring model

Metric definitions and default weights

The eight default weights sum to 1.00. An unavailable metric is omitted from the weighted mean.

  • boundary_pressure · weight 0.20 · field deny_ratio from compute_boundary_pressure in score.rs. The unweighted mean of each policy hash’s decay-weighted deny ratio. The metric contributes 1.0 - deny_ratio, so less pressure scores higher.
  • resource_stewardship · weight 0.10 · field fit_score from compute_resource_stewardship in score.rs. 1.0 - |average_utilization - target_utilization| across grants with a positive max_invocations cap. Utilization is capped at one; missing usage counts as zero.
  • least_privilege · weight 0.15 · field score from compute_least_privilege in score.rs. Per capability, used_tools / grants counts distinct allowed tool uses, multiplied by a constraint factor 0.5 + 0.5 * constrained_ratio and an operation factor 0.5 + 0.5 * non_delegate_ratio, then decay-weighted across capabilities.
  • history_depth · weight 0.10 · field score from compute_history_depth in compare.rs. The mean of three ratios, each capped at one: receipts against history_receipt_target, span in days against history_day_target, and active days over span days.
  • tool_diversity · weight 0.05 · field specialization.score from compute_specialization in compare.rs. Normalized Shannon entropy over decayed per-tool weights. The scorecard field is specialization while the weight key is tool_diversity, and the contribution is capped at diversity_cap where it is folded in.
  • delegation_hygiene · weight 0.15 · field score from compute_delegation_hygiene in compare.rs. The mean of the scope-reduction, expiration-reduction, and budget-reduction rates across delegations the subject issued against their parents.
  • reliability · weight 0.15 · field score from compute_reliability in compare.rs. Decayed allow weight over allow plus canceled plus incomplete. Denials are excluded from the denominator, so a denied request counts against boundary pressure alone.
  • incident_correlation · weight 0.10 · field score from compute_incident_correlation in compare.rs. 1.0 - incident_penalty * weighted_incidents, clamped into [0, 1]. Unknown when incident_reports is None.

Default configuration

FieldDefaultMeaning
target_utilization
0.75
Preferred utilization of invocation-capped grants
diversity_cap
1.0
Upper bound on the diversity contribution
temporal_decay_half_life_days
30
Age at which an observation carries half its weight
history_receipt_target
1,000
Receipt-count target for history depth
history_day_target
30
Observed-span target for history depth
incident_penalty
0.20
Deduction per decay-weighted incident
trusted_kernel_keys
Empty set
Keys whose signed receipts may contribute

Trust and time configuration

Populate the Rust configuration through ReputationConfig::with_trusted_kernel_keys before using receipt history. The capability authority supplies its signing key and trusted peer keys when it evaluates issuance. With no trusted kernel keys, every receipt fails integrity validation, while other supplied records can still produce known metrics; inspect the component counts to tell missing receipt trust from missing history.

The 30-day history target and the 30-day half-life are separate parameters, and neither imposes a rolling 30-day cutoff. The caller chooses the corpus. The control-plane report’s since and until bounds filter receipts inclusively, while capability snapshots and budget usage stay the loaded current records.

Decay uses 2^(-age / half_life). The Rust scorer treats a zero half-life as no decay; HushSpec policy validation requires at least one day. History depth also weighs activity across the observed span, so reaching the count and day targets fixes two of its three terms.

Scorecard fields

Interpret the scorecard

  • subject_key and computed_at: the evaluated subject and the explicit scoring time.
  • Component metric records: values and counts such as receipts, policies, capped grants, distinct tools, and delegations observed.
  • composite_score: the known weighted mean, or Unknown.
  • effective_weight_sum: the sum of the weights that contributed.

The local report adds issuance-oriented fields such as effectiveScore and probationary status. Adequate history, permission, and a verified identity each come from their own record, never from a high composite alone.

Feed deltas and marketplace tiers

A ReputationFeed consumes caller-supplied observations and returns a ScoreDelta: a feed ID, a numeric value, and the count of observations consumed. The struct carries no signature or issuer proof, so authenticating the observation source is the caller’s responsibility.

ScoreDelta::from_value clamps the value to the supported nonnegative range; negative and non-finite inputs become zero. The supplied feeds are arena_survival and cross_provider_equality, and they run outside the kernel’s admission path. compose_deltas takes the maximum delta in place of a sum, and an empty slice returns None. tier_from_deltas applies these thresholds:

TierMaximum deltaOther conditions
tier_0
Fallback
Includes an empty delta slice
tier_1
≥ 0.50
None
tier_2
≥ 0.75
None
tier_3
≥ 0.90
Every delta ≥ 0.80; at least two distinct feed IDs

The highest satisfied tier wins. Two different feed ID strings count as two feeds whether or not independent organizations or verified issuers stand behind them. The CLI compares the tenant’s tier with each catalog entry’s reputation_floor for both listing visibility and installation eligibility.

Threshold constants from the source
crates/trust/chio-reputation/src/tier.rs33-46rust
/// Composed-score floor for `tier_1`.
pub const TIER_1_THRESHOLD: f64 = 0.50;

/// Composed-score floor for `tier_2`.
pub const TIER_2_THRESHOLD: f64 = 0.75;

/// Composed-score floor for `tier_3`.
pub const TIER_3_THRESHOLD: f64 = 0.90;

/// Per-feed minimum delta required for `tier_3`. Every shipped feed
/// MUST clear this value independently for the publisher to reach the
/// highest tier; this is the Sybil-resistance mitigation: a flood of
/// arena rounds alone cannot promote a publisher past `tier_2`.
pub const TIER_3_PER_FEED_THRESHOLD: f64 = 0.80;

Behavioral profile signals

The behavioral-profile guard is advisory: it tracks deviations from a workload’s baseline and always returns an allowed decision. Its runtime evaluate path observes call rate from a bounded receipt window, and other supported metrics arrive through observe_sample.

On a fresh time window, anomaly detection requires enough baseline samples and an absolute z-score above the configured threshold; same-window evaluation follows a separate path. The runtime guard discards the observation outcome. An explicit caller can inspect the observation result or the baseline; anomaly evidence reaches neither the decision nor the local scorecard on its own.

Behavioral metrics and defaults
crates/guards/chio-guards/src/behavioral_profile.rs45-67rust
/// Default EMA smoothing factor. Equivalent to a ~10-sample window.
pub const DEFAULT_EMA_ALPHA: f64 = 0.2;
/// Default sigma threshold above which a window is flagged.
pub const DEFAULT_SIGMA_THRESHOLD: f64 = 2.0;
/// Default rolling window length in seconds.
pub const DEFAULT_WINDOW_SECS: u64 = 60;
/// Default number of historical windows used to prime the baseline
/// before the guard starts emitting signals. Guarantees the z-score
/// has enough history to be meaningful.
pub const DEFAULT_BASELINE_MIN_WINDOWS: u64 = 3;

/// Metric captured per (agent, window).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BehavioralMetric {
    /// Total receipts per window.
    CallRate,
    /// Denies per window.
    DenyRate,
    /// Distinct tool names per window.
    UniqueTools,
    /// Approximate parameter entropy per window.
    AvgParameterEntropy,
}

Compliance score

The kernel’s compliance score evaluates supplied deny rate, revocation rate, velocity anomalies, policy-coverage gaps, and attestation age on a 0 to 1,000 scale, with default maximum deductions of 300, 300, 150, 150, and 100. With any revocation, the default score ceiling is 499. The calculation is separate from the eight-component reputation composite and from a signed compliance certificate; Compliance Certificates covers the signed session record.

Compliance factor constants
crates/kernel/chio-kernel/src/compliance_score.rs29-46rust
/// Maximum possible compliance score.
pub const COMPLIANCE_SCORE_MAX: u32 = 1000;

/// Weight (maximum-deducted points) for the deny-rate factor.
pub const WEIGHT_DENY_RATE: u32 = 300;
/// Weight for the revocation factor.
pub const WEIGHT_REVOCATION: u32 = 300;
/// Weight for the velocity-anomaly factor.
pub const WEIGHT_VELOCITY_ANOMALY: u32 = 150;
/// Weight for the policy-coverage factor.
pub const WEIGHT_POLICY_COVERAGE: u32 = 150;
/// Weight for the attestation-freshness factor.
pub const WEIGHT_ATTESTATION_FRESHNESS: u32 = 100;

/// Default staleness threshold (seconds) beyond which the attestation
/// freshness factor is fully deducted. Ninety days mirrors the default
/// receipt-retention window in [`crate::receipt_store::RetentionConfig`].
pub const DEFAULT_ATTESTATION_STALENESS_SECS: u64 = 7_776_000;

Implementation sources

  • crates/trust/chio-reputation/src/model.rs, score.rs, and compare.rs: corpus, configuration, metric formulas, and weighted mean.
  • crates/platform/chio-control-plane/src/issuance/reputation.rs and scope.rs: report loading, probation, score ranges, and issuance ceilings.
  • crates/trust/chio-reputation/src/feed.rs and tier.rs: unsigned feed deltas and tier predicates.
  • crates/products/chio-cli/src/market.rs: tenant-tier checks for catalog listing and installation.

Next: carry the score to another operator