EconomyTools
Listing Disputes, Freezes, and Sanctions
Signed charters and cases for registry listings, evaluated into an effective state and admission decision.
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 that charter.
| Record type | Schema tag | Purpose |
|---|---|---|
GenericGovernanceCharterArtifact | chio.registry.governance-charter.v1 | Grants a governing operator authority over a namespace and the case kinds it may open. |
GenericGovernanceCaseArtifact | chio.registry.governance-case.v1 | Records one dispute, freeze, sanction, or appeal against a single listing under a charter. |
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. The crate is re-exported by chio-core and chio-open-market as governance.
The charters on this page govern registry listings: their dispute, freeze, sanction, and appeal lifecycle. The economic parameters an economy runs on, credit tiers, discount curves, premium schedules, fees, and bonds, are governed by a separate, specialized charter family whose amendments move through a propose, m-of-n approval, timelock, then activate lifecycle before they take effect. That fiscal system is documented in Fiscal Charters.
The charter
A charter names the governing operator, the namespace it covers, the case kinds it may open, and an optional set of escalation operators. Its authority_scope can pin the charter to specific listing publishers and actor kinds; an empty list on either field means the scope is unrestricted on that axis, because evaluation only tests a list it finds non-empty (crates/trust/chio-governance/src/evaluation.rs:169-196).
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), and the scope the charter carries is its own type:
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 non-empty, 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 identifier as a content hash over the issuing operator, the normalized namespace, the allowed case kinds, and the issue time, so the same inputs always yield the same charter id:
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())?
)
);The builder returns an unsigned body; the governing operator signs it 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)?;The case
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, and an optional sha256 is validated as a 64-character hex digest when it is 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 enforces the shape independently of any evaluation context: the schema must match, evidence_refs must be non-empty, an appeal must carry appeal_of_case_id (and no other kind may), and an escalated case must list at least one escalated_to_operator_ids.
build_generic_governance_case_artifact (crates/trust/chio-governance/src/generic.rs:445-509) verifies the signatures on the charter, listing, and (when present) trust activation before minting the body, and it refuses a case whose charter is governed by a different operator, or whose trust activation was issued by anyone other than the governing operator. 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())?
)
);Case kinds
Four kinds cover the adjudication lifecycle. A charter must list 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_of_case_id plus a matching non-appeal prior_case |
Effective state and admission
Evaluation resolves a case to a GenericGovernanceEffectiveState (one of clear, disputed, frozen, sanctioned, appealed) and a boolean blocks_admission. The mapping is driven by the case lifecycle state and kind together.
| Case state | Effective state | Blocks admission |
|---|---|---|
resolved, denied, superseded | clear | No, for every kind |
open, escalated | Mirrors the kind (disputed / frozen / sanctioned / appealed) | No, for every kind |
enforced | Mirrors the kind | Only freeze and sanction |
One rule blocks admission
blocks_admission = true: an enforced case whose kind is freeze or sanction. A dispute or appeal never blocks, and a resolved, denied, or superseded case resolves to clear regardless of kind. The relying party consumes blocks_admission as the gate; the effective state is the human-readable status.Case evaluation
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 returns a GenericGovernanceCaseEvaluation.
pub fn evaluate_generic_governance_case(
request: &GenericGovernanceCaseEvaluationRequest,
now: u64,
) -> Result<GenericGovernanceCaseEvaluation, String> {The request is GenericGovernanceCaseEvaluationRequest (crates/trust/chio-governance/src/generic.rs:291-303), whose evaluated_at falls back to the now argument when it is absent. Every path returns the same record, whether evaluation completes or stops at a finding:
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>,
}Evaluation is ordered. The first failure ends evaluation and returns a finding without an Err:
- Validate the listing body and the
current_publishershape. These are the only hardErrpaths, alongside an internal crypto or canonicalization error. - Verify the signature and body of the listing, charter, and case, and of the activation and prior case when present.
- If an activation is present, its
local_operator_idmust equal the charter'sgoverning_operator_id. - Charter, case, and listing must agree on governing operator, charter id, namespace, and listing id.
- Neither the charter nor the case may be expired as of
evaluated_at; expiry is exclusive at the boundary (expires_at <= evaluated_atis rejected). - The charter must allow the case's kind and, where its scope is set, admit the current publisher operator id and the listing subject actor kind.
- A
freezeorsanctioncase requires a trust activation whoseactivation_idmatches the case; a superseding case requires a matchingprior_case; an appeal requires a matching non-appealprior_case. - On success, the case state and kind map to an effective state and the
blocks_admissionflag, and the evaluation carries an emptyfindingslist.
Failure handling
Ok evaluation carrying a single finding, with effective_state = clear and blocks_admission = false. An unverifiable or malformed case does not block admission, and the finding explains why. Only an internal crypto or canonicalization error returns Err(String). A clear result on a failed case means "could not enforce".Finding codes
When evaluation short-circuits it emits one GenericGovernanceFinding with a typed code and a human-readable message. The codes:
| Code | Meaning |
|---|---|
ListingUnverifiable | Listing signature or body failed verification |
ActivationUnverifiable | Trust activation signature or body failed verification |
CharterUnverifiable | Charter signature or body failed verification |
CaseUnverifiable | Case signature or body failed verification |
PriorCaseUnverifiable | Referenced prior case signature or body failed verification |
CharterExpired | Charter expires_at reached as of evaluation |
CaseExpired | Case expires_at reached as of evaluation |
CharterScopeMismatch | Current publisher or listing actor kind falls outside the charter scope |
CharterKindUnsupported | Charter does not authorize this case kind |
CaseMismatch | Charter or case does not match the current listing identity or namespace |
MissingActivation | A freeze or sanction case was submitted without a trust activation |
ActivationMismatch | Activation was not issued by the governing operator, or its id does not match the case |
AppealTargetMissing | Appeal is missing appeal_of_case_id or its prior_case |
AppealTargetInvalid | Appeal target does not match a valid, non-appeal prior case |
SupersessionTargetMissing | Superseding case is missing its prior_case |
SupersessionTargetInvalid | Supersession target does not match the referenced prior case |
Worked example: an enforced freeze
Operator origin-a governs the namespace https://registry.chio.example under a charter that allows all four case kinds. It freezes listing listing-artifact-1 and signs the case, referencing a trust activation it also issued. On the wire the case envelope uses camelCase fields and snake_case enum values:
The field names below are the record's own. The values are made up for the example, and the two digests are shortened to their first bytes so the shape stays readable; a real envelope carries a full 64 characters of hex in each.
{
"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 relying party evaluates it against the live listing at now = 150:
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);Drop the activation from the request and the same case resolves to a single MissingActivation finding with blocks_admission = false: a freeze the crate cannot substantiate does not silently take effect. Move the case to resolved and the effective state becomes clear with no block, which is how a lifted freeze reads.
Leases and receipts in the same crate
chio-governance defines charter and case records plus two other record groups. The other groups govern action authority instead of listing status and use the same signature and schema checks:
- Capability leases (
chio.capability-lease.v1) carry a scope digest and an action class ofScopedObservation,DelegatedAction, orNarrowDestructive.verify_capability_leasechecks schema, signature, the validity window, and an exactscope_digestmatch. - Destructive-action governance receipts (
chio.governance-receipt.v1) authorize a single 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 any step marked destructive and none otherwise.
Those two families, their issuance path, and the checks the crate deliberately leaves to the caller are documented in Capability Leases. See Capabilities for the scoped, time-bounded authority these leases attenuate, and Mandates & Capabilities for how the kernel enforces a destructive-step boundary at runtime.
Related reading
- Capability Discovery · the
chio-listingmarketplace module whose listing identity a case references - Operating an Economy · how an operator wires governance authority into a running economy
- Assurance Model · the admission and trust-activation decisions a governance case gates
- Compliance Certificates · the session-scoped attestation that shares this crate's canonical-JSON signing substrate