Skip to content

Adopt CIRISPersist v28.2.0: the node-state surface lands (10 of 10 signals now reach Python), and consent-revocation proxy authority shrinks #450

Description

@emooreatx

CIRISPersist v28.2.0 is tagged (6ac441c). Certified by exit code on an uncontended host: sqlite 1773, test-anchor 1778, sqlite+postgres 2119 on a virgin database, postgres server pyo3 sqlite 2179, and 42 pytest against a built wheel.

No migration. This is mostly a gain for consumers — the observability surface you have been unable to read is now readable.


1. The mesh is observable — 7 new bindings, and an aggregate

Only 3 of 10 node-state signals reached Python before this. Persist computed the rest and discarded them. Now:

binding answers
trust_root_verdict_json is the trust root live, and the drill band (Green/Yellow/Red)
resolve_key_statement_standing_json do this key's past statements still stand
resolve_quarantine_json is this key withheld from serving
resolve_reverse_quorum_json is a brake active, and did the duty-holders answer
peer_quota_observation_json throttling state + its denominator
list_consent_revocation_promotion_overdue_readonly_json overdue deletions, writing nothing
node_state_json the node-scoped aggregate

Start with node_state_json. It folds the node-scoped signals into one call so you do not make ten round-trips per refresh and reimplement the composition — a second definition of "how is this node" is the drift class we spend most of our time closing.

Three properties it holds deliberately, and which a consumer surface should preserve:

  • Bands, never floats, and the band never replaces the typed token. Four ways of having no valid root are four tokens across two bands.
  • The zeroes stay distinct. not_quarantinedreleased. overdue: 0overdue: null. silentoverruledno_duty_holders. Collapsing any pair re-introduces the defect the type exists to prevent.
  • unknown ranks between yellow and red and is enumerated in unknown[], so a roll-up cannot swallow it. A signal the node cannot compute renders unknown — never green, never absent.

clock_dependent[] names the signals that move on their own. DrillFreshness goes Green→Yellow→Red with no state change and no new row — a consumer diffing two reads sees a transition nothing caused. This is a gauge, not a ledger.

Four of the ten are not node facts and are deliberately not in the aggregate — transit eligibility needs a peer, load-bearing an object, both reverse-quorum standings a cohort and action. Inventing a target would yield an answer indistinguishable from a real one. targeted[] names each and the binding that answers it.

⚠️ If you poll, use the read-only reader

list_consent_revocation_promotion_overdue_json flags each overdue row as a hard_case idempotently — which means no duplicate rows, not no writes. A dashboard refreshing on a timer has been writing to the audit plane on every tick. Use ..._readonly_json; node_state_json already routes through it.

2. BREAKING — consent-revocation proxy authority shrinks

The consent-revocation proxy walk consulted no retraction at all: a delegates_to withdrawn by its own granter still conferred authority. Fourth and last occurrence of a class fixed in #578 (ownership, v25.1.0), #584 (stewardship, v27.0.0) and #593 (moderation, v28.0.0) — and the strongest, because the other three consult too narrow a set while this one built no set.

This is CEG 2.4.1.1 rule (3) — the proxy path for non-federation-enrolled subjects. So a revoked proxy could revoke consent on behalf of someone, and the affected party is by construction the one who cannot hold a key to object.

Read-time only, no migration. Proxy chains with a retracted hop stop resolving. If you hold proxy delegations for Discord user-ids, canonical-hash subjects, or any non-enrolled party, re-check that those chains are intact.

3. Worth a look even though it needs nothing from you

The crate has not compiled without a backend feature since v25.1.0validate_subject_key_ids was cfg-gated to postgres|sqlite while a later change added an ungated caller. CI's own default wire_format_fixtures leg was unbuildable. Fixed; recovers 1,146 previously unrunnable tests.

Mentioning it because if you carry a similar cfg-gated helper with a caller that drifted out of the gate, the same failure is invisible until someone builds the un-featured configuration — which nobody does by habit.


Questions welcome. If your reading of any behaviour above differs from what is described, that difference is worth an issue on its own.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions