Expand description
The policy machinery: what a policy declares, the tree that indexes it, and deny-only evaluation over the ordered list the tree produces.
This is the core plan/policy.md describes — not a policy language, not
an evaluator, not I/O. Two sibling crates use it: didbot-policy-regex
is a deterministic in-process Evaluator, and didbot-pds’s write
path drives evaluate() per write, outside its store lock, and turns a
Verdict::Freeze into the queue-draining behaviour plan/policy.md
describes under “Outcomes” — this crate produces the verdict and stops
there.
§What is here, and why
Subject,WriteAction,Diff,Change,SubjectAttributes,AccountKind,DeploymentAttributes,UniversalandClientId— what a policy is asked about. Three subject shapes, one set of mechanics; a write’s diff carries before/after values, not just paths, so a rule reads a changed value rather than only knowing that a path changed; and a subject is not always an agent — seeAccountKind.Applicability,Scope,ActionSet,KindSet,Predicate,RevisionandPolicyDeclaration— what a policy declares statically. This is what goes in the tree; a policy’s actual judgement stays behind theEvaluatortrait, opaque to this crate.Predicateis what lets a policy’s applicability be known and scoped even when its predicate is not — see its doc comment for why that split matters once policies are independent records rather than a set.PolicyTreeandPolicyTreeBuilder— the applicability index. Turns a subject into an ordered candidate list in time bounded by the subject’s own diff, not by how many policies are registered.Outcome,Staleness,Observed,Lifecycle,EvalErrorand theEvaluatortrait — the contract every evaluator implements.LanguageandKnownLanguage— the open union of policy languages this build can turn into a workingEvaluator. A wrapper’s loader resolvesLanguage::UnknowntoPredicate::Unusablerather than failing to parse the record; seeLanguage’s doc comment.Verdict,combineandevaluate()— ordered evaluation with deny-only semantics.combineis where monotonicity is structural rather than conventional: see its doc comment.
§What is deliberately not here
No I/O, no async, anywhere in this crate. Evaluators do the work — some
of them out of process, some of them with a model or a network
resolution in the loop — and this crate stays the thing that is testable
without a runtime and cheap to reason about under a deadline. See
Evaluator’s doc comment for what that implies for anyone implementing
one.
No storage of policies, no polling, no wrapper metadata (source, format
version, which PDS a record applies to). plan/policy.md calls that “a
policy is not its wrapper” and leaves the wrapper’s shape and the
lexicon that carries it unsettled; this crate only consumes the
PolicyDeclaration a wrapper resolves to, never the wrapper itself.
No position on what a delete means. Diff makes exact every path
whose value differs between before and after, absence included as a
value, and WriteAction says which kind of write it was. A policy can
declare it applies only to deletes; an evaluator decides what a delete
means for its own rules.
Modules§
- client_
id 🔒 - An OAuth client’s identifier, in the one spelling a policy matches.
- evaluate 🔒
- Ordered evaluation with deny-only semantics, made structural rather than conventional.
- index 🔒
- The applicability index: the tree that turns a subject into an ordered list of candidate policies.
- json 🔒
- JSON text that does not depend on the order a client wrote its keys in.
- language 🔒
- The language a policy’s predicate is written in — an open union, the same
shape
bot.did.registration’sactorunion already uses and the same shape this crate gaveSubjectKind:KnownplusUnknown. - outcome 🔒
- The evaluator contract: what a policy decides, how stale its view may be, and the three channels an evaluator is asked to answer on.
- policy 🔒
- What a policy declares about itself, statically — the data the applicability index is built from.
- subject 🔒
- What a policy is asked about.
Structs§
- Action
Set - Which
WriteActions a write-shaped applicability declaration covers. - Change
- One field’s value before and after a write, at a dotted path such as
"displayName"or"profile.bio". - Client
Id - An OAuth
client_id, known to be in canonical form. - Compiled
Id - A compiled predicate, as an evaluator itself names it.
- Deployment
Attributes - Facts about this deployment a policy may reference, independent of the
account or the write — a different kind of fact from
SubjectAttributes, which is why it is its own type rather than a field folded into that one. An evaluator asking for the PDS’s own DID or hostname is asking a different question than one asking about the account, and naming them separately keeps that visible at the call site — for a rule like “deny a handle that is not under this deployment’s zone”. - Diff
- What changed in a write, as the applicability index’s key.
- Evaluator
Id - An evaluator, registered once and referenced by any number of policies.
- KindSet
- Which account kinds a write-shaped applicability declaration covers.
- Lookup
- What a policy’s declared lookup found in somebody else’s repository.
- Observed
- One evaluator’s account of a single policy’s attempt and outcome, on its declared observation surface.
- Policy
Declaration - One policy: its applicability, its observation surface, its staleness mode, its predicate, and its own revision.
- Policy
Id - A policy, identified by its position in a
PolicyTree. - Policy
Tree - The built applicability index: every registered policy’s predicate, and the decision and observation trees to route a subject through.
- Policy
Tree Builder - Builds a
PolicyTreefrom a set of evaluators and the policies that use them. - Revision
- A policy record’s own revision, for detecting a stale observation.
- Subject
Attributes - Attributes about the writing account a policy may need beyond its DID, explicit and extensible rather than a bag.
- Universal
- Facts that do not belong to the account or the write, but that a
stateless predicate is still allowed to reference — grouped into one
field per
Subjectvariant rather than left flat, since the field list otherwise grows by one every time a new universal fact is added.
Enums§
- Account
Kind - One of the four account kinds this build recognizes.
- Applicability
- What a policy statically applies to — the data the tree indexes on.
- Asked
- How a create asked for its account’s name.
- Client
IdError - Why a string is not a
ClientId. - Compile
Outcome - What
Evaluator::compiledecided about one predicate document. - Eval
Error - Why an evaluator could not produce an
Outcome. - Found
- What reading one declared lookup established.
- Known
Language - The evaluator languages this workspace names. Naming a member here is
naming a sibling crate that implements
Evaluatorfor it — a decision for whoever maintains this workspace, not something a policy record can request into existence — but naming one ahead of the crate that implements it is exactly what an open union is for: it makes that crate’s later arrival an addition to this list, not a change to its shape. - Language
- A policy language, known to this build or not.
- Lifecycle
- An account-lifecycle event, so an evaluator’s per-account state does not
outlive the account it belongs to. Not agent-only — any
AccountKindcan be frozen, unfrozen or deleted. - Outcome
- What one policy decides about one subject.
- Policy
Lifecycle - A policy-lifecycle event, parallel to
Lifecyclebut scoped to a compiled artifact rather than an account. Without it, an evaluator that accumulates state per compiled policy (a cache, a counter) has no way to learn that one of its artifacts no longer corresponds to anything the tree will ever route to again, and keeps it forever. - Predicate
- What decides this policy’s outcome, once its applicability is already established.
- Scope
- Whether a declarative dimension is unconstrained, or limited to a specific set of values.
- Staleness
- How stale an evaluator’s view of the world may be before it is unhealthy.
- Subject
- What one policy is asked to decide about.
- Subject
Kind - What kind of account a subject is, including a kind this build has never heard of.
- Verdict
- The result of evaluating a subject against every candidate policy.
- Write
Action - What kind of write this is, carried alongside the diff rather than inferred from it.
Traits§
- Evaluator
- What judges one or more policies.
Functions§
- combine
- Fold a set of
(policy, outcome)pairs into oneVerdict, taking the most severe outcome regardless of the order the pairs arrive in — the structural half of “order is presentational, not semantic”. - evaluate
- Evaluate a subject against a
PolicyTree, in the tree’s presentational order. - is_
local_ origin - Whether
originis the origin of the profile’s local form,http://localhost. A client the server shows with this origin built its own metadata from itsclient_id, so any process on its machine can send the same one. A client fetched fromhttp://localhost/…on a development deployment has this origin too. - sorted_
json - The compact JSON text of
value, with every object’s keys sorted. - worst
- Fold outcomes into the most severe one, taking
Allow < Reject < Freeze— the same total ordercombinefolds by, exposed for callers that hold outcomes without aPolicyIdto attribute each one to.