Reputation Clearing
Combine what several partners report about one subject into one admission class, weighed under your policy and capped per issuer.
On this page
An operator can admit a subject on what several partners report about it, without letting any one partner decide. The receiver weighs every report under its own policy, caps what each issuer contributes, and needs two independent issuers before a negative event blocks.
A federated reputation clearing (chio.federation-reputation-clearing.v1, FederatedReputationClearingArtifact) records that decision for one subject. The published reference clearing, frc-1, weighs four inputs from three issuers and yields reviewable.
λlocal weighting requiredmat most 2 inputs per issuerwno weight above 4000 bpssone accepted summary per issuernat least 2 independent issuersνblocking events corroborated
Four inputs from three issuers clear as reviewable
Origin and mirror each contribute one summary, at 3000 and 2500 bps. The indexer's blocking negative event, at 2000 bps, is corroborated by origin's at 1500 bps. No input exceeds the 4000 bps oracle cap, and the clearing yields reviewable under admission policy foap-1. Reference clearing.
Every input names its issuer, and the receiver sets its weight
An input is a reputation summary or a negative event about the clearing's subject. It references a portable summary or a portable negative event by digest, names the issuing operator, and carries the receiver's weight for it in basis points, from 1 to 10000.
The clearing lists the operators party to it, and every input's issuer must be one of them. It names the receiver's local weighting policy and the open-admission policy its class is drawn from, and it sorts every input into exactly one of accepted or rejected. Only accepted inputs count toward the sybil control.
The sybil control caps what any one issuer can contribute
Five settings bound the clearing, and the validator refuses any clearing that breaks one. The reference clearing's values are in parentheses.
- Local weighting.
localWeightingRequiredistrueon every valid clearing, so the receiver's own weights always apply. - Inputs per issuer. One issuer contributes at most
maximumInputsPerIssuerinputs (2), and at most one accepted reputation summary. - Oracle cap. No input's weight exceeds
oracleCapBps(4000), so no single issuer becomes the oracle. - Independent issuers. Accepted inputs come from at least
minimumIndependentIssuersindependence groups (2). - Corroboration. With
negativeEventCorroborationRequired, a blocking negative event needs a second, independent issuer.
An input's independence group is its issuerIndependenceGroupId when it names one, and its issuer otherwise, so two issuers in one group count once. A clearing that accepts no input skips the minimum, and its class is then public_untrusted.
A blocking negative event stands only with a second issuer behind it
A negative event marked blocking can keep a subject out. The validator groups accepted blocking events by independence group and refuses the clearing when they all come from one group.
In frc-1, indexer-operator-a and origin-operator each report a blocking event, so the pair stands. Only negative events block: a reputation summary marked blocking is refused. Corroboration is requirement TRUSTMAX-04 in the qualification matrix on Federation Assurance.
The federation guide clears frc-1 and refuses three variants of it
The guide project validates the published reference clearing, then hands the same validator a clearing with two accepted summaries from one issuer, one without local weighting, and one under an unsupported schema.
Clear shared reputation under local weighting
Validate the reference clearing, then refuse a clearing with two accepted summaries from one issuer and a clearing that drops local weighting.
Complete the project setup, then run the program from federation-guide/. The download includes every constructor and input.
cargo run --locked --bin reputationreference clearing frc-1: valid; 4 inputs from 4 operators; effective class Reviewable sybil control: at least 2 independent issuers, at most 2 inputs per issuer, oracle cap 4000 bps two accepted summaries from one issuer: refused (invalid clearing: accepted reputation summaries must come from distinct issuers) clearing without local weighting: refused (invalid clearing: federated reputation clearing must require local weighting) unsupported schema: refused (unsupported schema: chio.federation-reputation-clearing.v0)
Clearing checks the contract over declared inputs; it does not fetch or verify the referenced summaries and negative events. Receiver-side scoring is a separate local policy, documented under Economy.
Read the complete program 49 lines · complete file
//! Validate a shared reputation clearing and refuse the shapes that would turn
//! it into an oracle: two accepted summaries from one issuer, and clearing
//! without local weighting.
use chio_federation::error::FederationContractError;
use chio_federation::reputation::{
validate_federated_reputation_clearing, FederatedReputationClearingArtifact,
};
use serde_json::Value;
fn receive(value: Value) -> Result<FederatedReputationClearingArtifact, FederationContractError> {
let clearing: FederatedReputationClearingArtifact = serde_json::from_value(value)
.map_err(|e| FederationContractError::InvalidClearing(e.to_string()))?;
validate_federated_reputation_clearing(&clearing)?;
Ok(clearing)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let reference: Value = serde_json::from_slice(&std::fs::read("reputation-clearing.json")?)?;
let clearing = receive(reference.clone())?;
println!(
"reference clearing {}: valid; {} inputs from {} operators; effective class {:?}",
clearing.clearing_id,
clearing.inputs.len(),
clearing.participating_operator_ids.len(),
clearing.effective_admission_class
);
println!(
"sybil control: at least {} independent issuers, at most {} inputs per issuer, oracle cap {} bps",
clearing.sybil_control.minimum_independent_issuers,
clearing.sybil_control.maximum_inputs_per_issuer,
clearing.sybil_control.oracle_cap_bps
);
let mut duplicate = reference.clone();
duplicate["inputs"][1]["issuerOperatorId"] = "origin-operator".into();
duplicate["inputs"][1]["artifactRef"]["operatorId"] = "origin-operator".into();
let err = receive(duplicate).unwrap_err();
println!("two accepted summaries from one issuer: refused ({err})");
let mut unweighted = reference.clone();
unweighted["sybilControl"]["localWeightingRequired"] = false.into();
let err = receive(unweighted).unwrap_err();
assert!(matches!(err, FederationContractError::InvalidClearing(_)));
println!("clearing without local weighting: refused ({err})");
let mut wrong_schema = reference;
wrong_schema["schema"] = "chio.federation-reputation-clearing.v0".into();
let err = receive(wrong_schema).unwrap_err();
assert!(matches!(err, FederationContractError::UnsupportedSchema(_)));
println!("unsupported schema: refused ({err})");
Ok(())
}Open the source file. Each program asserts its expected refusals; keys, timestamps, and digests change between runs.
You should see frc-1 valid with effective class Reviewable and the sybil control read back, then three refusals, each naming the rule or schema that failed.
Reputation from outside a clearing arrives as evidence you weigh
When your operator imports a partner's evidence package, the local comparison view reports native reputation and imported trust side by side. It shows explicit provenance and echoes the imported-trust policy at report time; the share's import-time requireProofs flag rides in its provenance. By default, proofless shares are rejected, stale signals expire, and the composite score is attenuated.
An Agent Passport carries issuer-signed credentials with identity and reputation information, including references to receipt evidence. Your operator checks the credential signatures and applies its own issuer, status, and evidence policy. A referenced receipt root identifies evidence, and each receipt beneath it is verified on its own. Compare a presented passport with your own receipts for the same subject, and the CLI prints both scores and the attenuation between them:
chio reputation compare --subject-public-key 5a2d…e7c4 --passport passport-halden-bounty-417.jsonsubject 5a2d…e7c4 (fixer-2) passport passport-halden-bounty-417, issuer did:chio:z6MkpA7…c2T, signatures verify native 0.71 composite over 38 receipts on your kernel imported 0.84 claimed, 0.42 after 0.50 attenuation, proofs required policy verifier policy satisfied; the passport authorizes no call
- Issuance. A passport feeds the verifier policy that decides whether the trust service issues a capability for its subject (
chio trust federated-issue). A presented passport authorizes no tool call itself, and the federated grant it leads to requires a DPoP proof at your door. - Several issuers. The bounded
CrossIssuerPortfolioprofile composes credentials from several issuers as an evidence container, and adds no trust root of its own. - Lifecycle. Status is issuer-signed, pulled from the status resolve URL, and kept for its TTL; a stale status fails closed. When verifier policy requires an active lifecycle,
stale,superseded,revoked, andnot-foundrefuse the presentation.
Read more in Portable reputation and Reputation and passports.
Clearing fields and refusals
Search for oracleCapBps, issuerIndependenceGroupId, or blocking.
FederatedReputationClearingArtifact
Field names are as they serialize. The types are defined in crates/trust/chio-federation/src/reputation.rs and validated there and in crates/trust/chio-federation/src/validation.rs.
| Field | Holds | Rule |
|---|---|---|
schema | schema id | chio. |
clearingId | id | non-empty |
generatedAt | Unix seconds | when the clearing was computed |
subjectKey | subject | every input targets it |
namespace | registry namespace | non-empty |
participating | list | non-empty, unique; holds every issuer |
local | policy reference | the receiver's weighting policy |
admission | policy reference | the open-admission policy the class is drawn from |
inputs[] | list | non-empty; ids unique |
sybilControl | object | the control below |
accepted, rejected | lists | every input in exactly one |
effective | enum | public_, reviewable, bond_backed, role_gated |
continuity | object, optional | continuityId, optional previous unequal to clearingId |
note | text, optional | free text |
FederatedReputationInputReference
| Field | Holds | Rule |
|---|---|---|
kind | enum | reputation_ or negative_event |
artifactRef | artifact reference | a portable summary or negative event to match kind; its operatorId is the issuer |
subjectKey | subject | equals the clearing's |
issuer | operator id | who issued the input |
issuer | id, optional | issuers in one group count once |
weightBps | basis points | 1 to 10000, at most oracleCapBps |
blocking | boolean | negative events only; blocking events group for corroboration |
publishedAt, expiresAt | Unix seconds | published by generatedAt; expires after it |
note | text, optional | free text |
FederatedSybilControl
| Field | Holds | Rule |
|---|---|---|
minimum | integer | non-zero; independence groups among accepted inputs |
maximum | integer | non-zero; inputs from one issuer |
oracleCapBps | basis points | 1 to 10000; the largest single weight |
local | boolean | must be true |
negative | boolean | blocking events need two independence groups |
Validation refusals
A clearing that breaks a sybil, issuer, or classification rule returns FederationContractError::InvalidClearing with one of these messages. Weight ranges and input windows return their own messages in the same variant, and a structural fault returns UnsupportedSchema, MissingField, or DuplicateValue.
federated reputation clearing must require local weightingissuer exceeds maximum_inputs_per_issuerinput weight_bps exceeds oracle_cap_bpsaccepted reputation summaries must come from distinct issuersaccepted inputs must meet the minimum_independent_issuers thresholdblocking negative events require corroboration from independent issuersreputation summaries cannot be marked blockinginput issuer_operator_id must appear in participating_operator_idsinput artifact_ref operator_id must match issuer_operator_ideach input must be classified as accepted or rejectednon-public admission classes require accepted inputs
Every federation contract error is indexed on Federation Refusal Codes.
Reference clearing
The published standards example, read from the Chio source and shipped with the federation guide project. The run above validates this file.
{
"schema": "chio.federation-reputation-clearing.v1",
"clearingId": "frc-1",
"generatedAt": 1743552180,
"subjectKey": "subject-1",
"namespace": "registry.chio.example/liability",
"participatingOperatorIds": [
"origin-operator",
"mirror-operator-a",
"indexer-operator-a",
"consumer-operator"
],
"localWeightingPolicyRef": "policy/reputation/federated-default",
"admissionPolicyRef": "foap-1",
"inputs": [
{
"kind": "reputation_summary",
"artifactRef": {
"kind": "portable_reputation_summary",
"schema": "chio.portable-reputation-summary.v1",
"artifactId": "summary-origin-1",
"operatorId": "origin-operator",
"sha256": "4444444444444444444444444444444444444444444444444444444444444444",
"uri": "https://origin-operator.chio.example/artifacts/summary-origin-1"
},
"subjectKey": "subject-1",
"issuerOperatorId": "origin-operator",
"weightBps": 3000,
"blocking": false,
"publishedAt": 1743552000,
"expiresAt": 1743638400,
"note": "Origin-issued portable reputation summary."
},
{
"kind": "reputation_summary",
"artifactRef": {
"kind": "portable_reputation_summary",
"schema": "chio.portable-reputation-summary.v1",
"artifactId": "summary-mirror-a-1",
"operatorId": "mirror-operator-a",
"sha256": "5555555555555555555555555555555555555555555555555555555555555555",
"uri": "https://mirror-operator-a.chio.example/artifacts/summary-mirror-a-1"
},
"subjectKey": "subject-1",
"issuerOperatorId": "mirror-operator-a",
"weightBps": 2500,
"blocking": false,
"publishedAt": 1743552010,
"expiresAt": 1743638400,
"note": "Mirror-issued portable reputation summary."
},
{
"kind": "negative_event",
"artifactRef": {
"kind": "portable_negative_event",
"schema": "chio.portable-negative-event.v1",
"artifactId": "negative-indexer-a-1",
"operatorId": "indexer-operator-a",
"sha256": "6666666666666666666666666666666666666666666666666666666666666666",
"uri": "https://indexer-operator-a.chio.example/artifacts/negative-indexer-a-1"
},
"subjectKey": "subject-1",
"issuerOperatorId": "indexer-operator-a",
"weightBps": 2000,
"blocking": true,
"publishedAt": 1743552020,
"expiresAt": 1743595200,
"note": "Indexers contribute corroborated negative-event evidence."
},
{
"kind": "negative_event",
"artifactRef": {
"kind": "portable_negative_event",
"schema": "chio.portable-negative-event.v1",
"artifactId": "negative-origin-1",
"operatorId": "origin-operator",
"sha256": "7777777777777777777777777777777777777777777777777777777777777777",
"uri": "https://origin-operator.chio.example/artifacts/negative-origin-1"
},
"subjectKey": "subject-1",
"issuerOperatorId": "origin-operator",
"weightBps": 1500,
"blocking": true,
"publishedAt": 1743552025,
"expiresAt": 1743595200,
"note": "Independent corroboration keeps a single issuer from becoming a universal oracle."
}
],
"sybilControl": {
"minimumIndependentIssuers": 2,
"maximumInputsPerIssuer": 2,
"oracleCapBps": 4000,
"localWeightingRequired": true,
"negativeEventCorroborationRequired": true
},
"acceptedInputIds": [
"summary-origin-1",
"summary-mirror-a-1",
"negative-indexer-a-1",
"negative-origin-1"
],
"rejectedInputIds": [],
"effectiveAdmissionClass": "reviewable",
"note": "Shared reputation clearing preserves local weighting and requires corroborated negative-event inputs."
}