Listing Disputes, Freezes, and Sanctions
Evaluate signed registry charters and cases into a listing's effective state, findings, and admission decision.
On this page
Any relying party can tell whether a provider's listing is frozen or sanctioned by evaluating the same signed charter and case. A case blocks admission only as an enforced freeze or sanction backed by the governing operator's trust activation; a dispute or an appeal is recorded beside the listing.
The governing operator signs a charter naming the case kinds it may open, then signs each case against one listing. In the example, operator origin-a freezes listing-artifact-1 in the namespace https://registry.chio.example.
An enforced freeze blocks admission; an unsubstantiated one is recorded
A relying party evaluates the signed case against the live listing and reads back one effective state and one flag.
An enforced freeze blocks admission
A charter that allows freeze, an enforced freeze case, and a trust activation from the governing operator whose activation_id matches the case resolve to frozen with blocks_admission = true. Listing disputes.
chio.registry.governance-case.v1 case evaluated against its charter and an optional trust activation, ending in an effective state and the blocks_admission flag. Listing and publisher checks, prior cases for appeals, and the finding codes are left out.With a valid charter, an enforced case, and a matching activation at the evaluation time, the listing reads frozen and admission is blocked. Without the activation, the same case returns one MissingActivation finding and blocks_admission = false, so a freeze the evaluator cannot substantiate has no effect on admission. Once the case is resolved, the listing reads clear and only its other admission checks apply.
Inspect the signed freeze case
The field names are the record's own, and each digest is shortened from its full 64 hex characters. The charter allows all four case kinds, and the case references a trust activation the same operator issued. The envelope uses camelCase fields and snake_case enum values.
{
"body": {
"schema": "chio.registry.governance-case.v1",
"caseId": "case-6f2a9c...",
"charterId": "charter-1d4b0e...",
"governingOperatorId": "origin-a",
"kind": "freeze",
"state": "enforced",
"namespace": "https://registry.chio.example",
"listingId": "listing-artifact-1",
"activationId": "activation-8c71...",
"subjectOperatorId": "origin-a",
"openedAt": 140,
"updatedAt": 140,
"expiresAt": 500,
"evidenceRefs": [
{ "kind": "trust_activation", "referenceId": "activation-8c71..." }
],
"issuedBy": "governance@chio.example",
"note": "freeze"
},
"signerKey": "9f2c1a...",
"signature": "b0e4d7..."
}A charter bounds which cases its operator may open
A charter names the governing operator, the namespace it covers, its allowed_case_kinds, and optional escalation operators. The builder returns an unsigned body, which the operator signs with a governance-authority keypair issued through chio-federation-authority.
let charter = build_generic_governance_charter_artifact(
"origin-a",
Some("Origin A".to_string()),
&request,
130,
)?;
let signed = SignedGenericGovernanceCharter::sign(charter, &authority_keypair)?;authority_scope can pin a charter to specific listing publishers and actor kinds. An empty list leaves that axis unrestricted, because evaluation tests only a list it finds nonempty. The charter id is a content hash over the issuing operator, the normalized namespace, the allowed kinds, and the issue time, so the same inputs always yield the same id.
Registry charters govern listing status. Credit tiers, discount curves, premium schedules, fees, and bonds belong to a separate charter family whose amendments move through propose, m-of-n approval, timelock, and activate before they take effect.
Read more in Fiscal charters.
Case state and kind together decide the effective state
Evaluation maps the case's lifecycle state and kind to a GenericGovernanceEffectiveState (clear, disputed, frozen, sanctioned, or appealed) and the boolean blocks_admission.
| Case state | Effective state | Blocks admission |
|---|---|---|
resolved, denied, superseded | clear | No, for every kind |
open, escalated | Mirrors the kind | No, for every kind |
enforced | Mirrors the kind | Only freeze and sanction |
The relying party gates on blocks_admission; the effective state is the readable status. A freeze or sanction needs a trust activation from the governing operator whose activation_id matches the case, and an appeal needs appeal_of_case_id plus a matching non-appeal prior_case.
Read every kind's requirement in Case kinds.
Evaluation stops at the first failed check and names it
evaluate_generic_governance_case takes the current listing, the current publisher, the charter, the case, and optionally a trust activation and a prior case. It checks, in order:
- Shape. The listing body and the
current_publishershape are valid. - Signatures. The listing, charter, and case verify, and so do the activation and prior case when present.
- Issuer. A present activation's
local_operator_idequals the charter'sgoverning_operator_id. - Identity. Charter, case, and listing agree on governing operator, charter id, namespace, and listing id.
- Expiry. Neither charter nor case has expired at
evaluated_at;expires_at <= evaluated_atis expired. - Charter scope. The charter allows the case's kind and, where its scope is set, admits the current publisher operator id and the listing subject actor kind.
- Supporting records. A freeze or sanction has an activation whose
activation_idmatches; a superseding case has a matchingprior_case; an appeal has a matching non-appealprior_case.
Success maps the state and kind to an effective state and blocks_admission, with an empty findings list. A failed check returns an Ok evaluation carrying one finding, effective_state = clear, and blocks_admission = false; only a malformed listing or publisher shape, or an internal crypto or canonicalization error, returns Err(String). A clear result with a finding means the case could not be enforced, so read findings beside the other two fields.
Inspect the Rust evaluation
The relying party evaluates the example freeze against the live listing at now = 150, with the activation supplied. evaluated_at falls back to the now argument when it is absent.
let evaluation = evaluate_generic_governance_case(
&GenericGovernanceCaseEvaluationRequest {
listing,
current_publisher,
activation: Some(activation),
charter,
case,
prior_case: None,
evaluated_at: Some(150),
},
150,
)?;
assert!(evaluation.findings.is_empty());
assert_eq!(evaluation.effective_state, GenericGovernanceEffectiveState::Frozen);
assert!(evaluation.blocks_admission);The same crate signs capability leases and destructive-step receipts
chio-governance also defines two record groups that govern action authority, with the same signature and schema checks as charters and cases.
- Capability leases (
chio.capability-lease.v1) carry a scope digest and an action class ofScopedObservation,DelegatedAction, orNarrowDestructive.verify_capability_leasechecks the schema, the signature, the validity window, and an exactscope_digestmatch. - Destructive-action governance receipts (
chio.governance-receipt.v1) authorize one destructive workflow step.verify_destructive_authorizationbinds a receipt to an expected lease id, workflow id, and step hash, andverify_step_governance_boundaryrequires a valid, unexpired receipt for every step marked destructive and none for any other step.
Their issuance path and the checks a caller runs are in Capability leases. Capabilities covers the scoped, time-bounded authority a lease attenuates, and Mandates and capabilities covers how the kernel enforces a destructive-step boundary at runtime.
Charter, case, and finding reference
Search for MissingActivation, allowed_case_kinds, or appeal_of_case_id.
Charter and case records
Both record types scope to a namespace and a governing operator, and both reference a listing identity from chio-listing. A charter is issued once and authorizes a set of case kinds; cases are issued against individual listings under it.
| Record type | Schema tag | Purpose |
|---|---|---|
Generic | chio. | Grants an operator authority over a namespace and its case kinds |
Generic | chio. | Records one dispute, freeze, sanction, or appeal against one listing |
Each record is wrapped in a SignedExportEnvelope<T> containing the body, an Ed25519 signer key, and a signature over the RFC 8785 canonical JSON body. The aliases are SignedGenericGovernanceCharter and SignedGenericGovernanceCase. chio-core and chio-open-market re-export the crate as governance.
Charter fields
pub struct GenericGovernanceCharterArtifact {
pub schema: String,
pub charter_id: String,
pub governing_operator_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub governing_operator_name: Option<String>,
pub authority_scope: GenericGovernanceAuthorityScope,
pub allowed_case_kinds: Vec<GenericGovernanceCaseKind>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub escalation_operator_ids: Vec<String>,
pub issued_at: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub expires_at: Option<u64>,
pub issued_by: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
}The schema is the constant GENERIC_GOVERNANCE_CHARTER_ARTIFACT_SCHEMA, chio.registry.governance-charter.v1 (crates/trust/chio-governance/src/generic.rs:12). The scope is its own type, and an empty list on either axis is unrestricted on that axis (crates/trust/chio-governance/src/evaluation.rs:169-196):
pub struct GenericGovernanceAuthorityScope {
pub namespace: String,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub allowed_listing_operator_ids: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub allowed_actor_kinds: Vec<GenericListingActorKind>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub policy_reference: Option<String>,
}allowed_case_kinds must be nonempty, and a validated charter with an expires_at requires it to be strictly greater than issued_at. build_generic_governance_charter_artifact (crates/trust/chio-governance/src/generic.rs:407-442) derives the id as a content hash over the issuing operator, the normalized namespace, the allowed case kinds, and the issue time:
let charter_id = format!(
"charter-{}",
sha256_hex(
&canonical_json_bytes(&(
local_operator_id,
normalize_namespace(&request.authority_scope.namespace),
&request.allowed_case_kinds,
issued_at,
))
.map_err(|error| error.to_string())?
)
);Case fields
A case binds a charter to one listing and carries the case kind, its lifecycle state, at least one evidence reference, and optional links to a prior case for appeals and supersession.
pub struct GenericGovernanceCaseArtifact {
pub schema: String,
pub case_id: String,
pub charter_id: String,
pub governing_operator_id: String,
pub kind: GenericGovernanceCaseKind,
pub state: GenericGovernanceCaseState,
pub namespace: String,
pub listing_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub activation_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub subject_operator_id: Option<String>,
pub opened_at: u64,
pub updated_at: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub expires_at: Option<u64>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub escalated_to_operator_ids: Vec<String>,
pub evidence_refs: Vec<GenericGovernanceEvidenceReference>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub appeal_of_case_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub supersedes_case_id: Option<String>,
pub issued_by: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
}Each entry in evidence_refs names what the case is built on. An optional sha256 is validated as a 64-character hex digest when present.
pub struct GenericGovernanceEvidenceReference {
pub kind: GenericGovernanceEvidenceKind,
pub reference_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub uri: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub sha256: Option<String>,
}Body validation holds independently of any evaluation context: the schema matches, evidence_refs is nonempty, an appeal carries appeal_of_case_id (and no other kind may), and an escalated case lists at least one escalated_to_operator_ids entry.
build_generic_governance_case_artifact (crates/trust/chio-governance/src/generic.rs:445-509) verifies the signatures on the charter, the listing, and a present trust activation before minting the body. It refuses a case whose charter another operator governs, or whose trust activation another operator issued. The case id is a content hash of the same shape as the charter id:
let case_id = format!(
"case-{}",
sha256_hex(
&canonical_json_bytes(&(
local_operator_id,
&request.charter.body.charter_id,
&request.listing.body.listing_id,
request.kind,
request.state,
opened_at,
&request.appeal_of_case_id,
&request.supersedes_case_id,
))
.map_err(|error| error.to_string())?
)
);The evaluation request is GenericGovernanceCaseEvaluationRequest (crates/trust/chio-governance/src/generic.rs:291-303), and every path returns the same record, whether evaluation completes or stops at a finding:
pub fn evaluate_generic_governance_case(
request: &GenericGovernanceCaseEvaluationRequest,
now: u64,
) -> Result<GenericGovernanceCaseEvaluation, String> {pub struct GenericGovernanceCaseEvaluation {
pub listing_id: String,
pub namespace: String,
pub charter_id: String,
pub case_id: String,
pub governing_operator_id: String,
pub kind: GenericGovernanceCaseKind,
pub state: GenericGovernanceCaseState,
pub effective_state: GenericGovernanceEffectiveState,
pub evaluated_at: u64,
pub blocks_admission: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub findings: Vec<GenericGovernanceFinding>,
}Case kinds
A charter lists a kind in allowed_case_kinds before a case of that kind evaluates.
| Kind | Active effective state | Can block admission | Extra requirement |
|---|---|---|---|
dispute | disputed | No | None |
freeze | frozen | Yes, when enforced | Matching trust activation from the governing operator |
sanction | sanctioned | Yes, when enforced | Matching trust activation from the governing operator |
appeal | appealed | No | appeal_ plus a matching non-appeal prior_case |
Finding codes
When evaluation stops, it emits one GenericGovernanceFinding with a typed code and a readable message.
ListingUnverifiable: the listing signature or body failed verification.ActivationUnverifiable: the trust activation signature or body failed verification.CharterUnverifiable: the charter signature or body failed verification.CaseUnverifiable: the case signature or body failed verification.PriorCaseUnverifiable: the referenced prior case signature or body failed verification.CharterExpired: the charter'sexpires_atwas reached as of evaluation.CaseExpired: the case'sexpires_atwas reached as of evaluation.CharterScopeMismatch: the current publisher or the listing actor kind falls outside the charter scope.CharterKindUnsupported: the charter does not authorize the case kind.CaseMismatch: the charter or case differs from the current listing identity or namespace.MissingActivation: a freeze or sanction case arrived without a trust activation.ActivationMismatch: the activation was issued by another operator, or its id differs from the case.AppealTargetMissing: an appeal lacksappeal_of_case_idor itsprior_case.AppealTargetInvalid: the appeal target fails to match a valid, non-appeal prior case.SupersessionTargetMissing: a superseding case lacks itsprior_case.SupersessionTargetInvalid: the supersession target fails to match the referenced prior case.