Module references
Module reference / Govern it
Warrant
- Atlas
Govern concepts, relations, and ontology changes.
- Lens
Constrain what retrieval may reveal and what answers may state.
- Ports
Suspend consequential agent tools for human approval.
Warrant is the module that answers who vouches for this, and who is allowed to change it. Adopt it alone if you already have concepts or documents somewhere and you need a review queue, an authority tier, an owner, and a trail you can defend.
What it does
Warrant tracks four things about a concept: its authority tier (machine_extracted → asserted → curated → certified), its lifecycle (draft, pending_review, published, deprecated, superseded), its owner and stewards, and its review clock. Destructive or schema-level edits do not happen in place: they are proposed as change requests that a reviewer approves, rejects, or that the proposer withdraws. Every accepted change appends an immutable revision carrying a full snapshot and a field-level diff. Documents get a parallel, simpler treatment — a verification stamp with a re-verify due date.
Nothing in this module calls a model. All of it is transactional database work inside a workspace transaction.
Use it standalone
Issue a key with the scopes Warrant actually checks
Reads (the change-request queue, the revision trail) require
kb:read. Every mutation — propose, approve, reject, withdraw, certify, review, set authority, set owner, deprecate, verify a document — requireskb:write. There is nogovernance:*scope; the scope taxonomy isagents:run,runs:read,kb:read,kb:write,data:read,data:run,reports:read,reports:write.Delegated user keys (
eli_uk_…) are additionally narrowed by the owner's live workspace role: these routes name the capabilitygovernance:readorgovernance:write, and a 403insufficient_capabilitycomes back if the owner has lost it. Workspace keys (eli_sk_…) carry no role, so the capability check does not apply to them.Install two packages and import one entry
Headless:
@eli-ai/client/governance. React:@eli-ai/react/governance. Neither pulls in query, agents, data, reports, connectors or evals code.Call it
The client is a thin typed wrapper over
/api/v1. The transport takes an origin, a credential resolver and an optional workspace id; it makes no authorization decision of its own.
What Warrant does NOT require
update, deprecate, supersede or delete must name an entity that is live in the workspace (404 otherwise), and POST /documents/{id}/verify needs a live document. Kind create is the one path that needs no pre-existing row — it proposes the concept and creates it on approval.React components
The React package exports exactly one component for this module, plus its two types. EliGovernance is a client component ("use client") that renders the open change-request queue and, optionally, a proposal form. It uses scoped eli-* class names and ships no styling of its own — import @eli-ai/react/styles.css or provide your own rules for those classes.
EliGovernance
What it renders, top to bottom:
- a titled surface with a Propose change / Cancel toggle button (only when
canPropose); - when toggled open, a form with a kind select (
create,update,deprecate,supersede,delete), an Entity ID input (required for every kind exceptcreate), a Review note textarea, and a Proposed fields (JSON) textarea that must parse to a JSON object — an array, a scalar or invalid JSON is rejected inline before any request is sent; - one card per open request: a kind badge (critical tone for
delete, warning otherwise), the entity name — falling back to the entity id, then to "New concept" — the created date, the request note, the names of the keys inpayload, and the proposer; - when
canReview, a per-request note input plus Approve and Reject buttons; a non-empty note is sent as the request body, an empty one is omitted; - loading, error (with a retry button) and empty states.
It calls four operations only: listChangeRequests({ status: "open" }) on mount and after every successful mutation, proposeChangeRequest, approveChangeRequest and rejectChangeRequest. The status filter is fixed to open and is not a prop.
EliGovernance props
emptyLabel is deliberately absent
EliGovernanceProps is Omit<CommonSurfaceProps, "emptyLabel"> — the empty state is driven by labels.empty instead. Passing emptyLabel is a type error.EliGovernanceLabels — every key, with its default
Never ship a workspace key to the browser
eli_sk_ keys are workspace-wide. EliProvider takes a transport, not a credential, precisely so the key stays server-side — see the SDK page for the proxy pattern.What the React surface does not cover yet
EliGovernance has no UI for withdraw, for certify / review / set authority / set owner / deprecate, for the revision trail, or for document verification, and it cannot list anything other than open requests. All of those are available on the headless client (createGovernanceClient) and over HTTP — build your own markup with useEliQuery / useEliMutation from @eli-ai/react/hooks if you need them in React.HTTP API
Twelve operations. Every one authenticates with a Bearer key; the scope column below is what the route enforces, and delegated user keys additionally need the named capability. All examples use https://eli.ai with -L on non-GET calls, because the apex issues a 308 redirect that curl will not follow for a POST without it.
Warrant — change request flow
The change-request state machine. Approve is claim-then-apply across transactions: the row flips to approved first, the edit runs second, and applied_at is stamped only after that commits. A failed apply reverts the row to open; a crash between the two leaves approved with a null applied_at, which a later approve resumes idempotently.
Downloads
Concepts
- Change request flow
- Modules
- Warrant
Keywords
- applied_at still NULL
- stamp applied_at
- revision activity change_request:id
- audit change_request.approve
- POST /change-requests
- status: open
- owner / steward gate
- status → approved
- apply the edit
- apply throws
- status: rejected
- status: withdrawn
- POST /change-requests/:id/approve
- POST /change-requests/:id/reject
- POST /change-requests/:id/withdraw
- reviewer
- claim
- commit
Source and generation provenance
Status: current
Generated at: 2026-08-17T18:41:49.318Z
Source hash: 83bc93c5a053b8d8852d08f551771b1f9ca93f0a71a3776a31052956966b4211
Metadata payload hash: 80b54e3ec8335d60685212c14f5f219f57b4ef1925459dbd05f64589c100703f
Canonical appearance
src/app/(docs)/docs/modules/warrant/page.tsx:49 route /docs/modules/warrant
All appearances
canonical—src/app/(docs)/docs/modules/warrant/page.tsx:49route/docs/modules/warrant
No mirrored appearances.
Generation versions
App: eli-ai 0.1.0
Mermaid: 11.16.0 · Mermaid CLI: 11.16.0
Node: v26.3.1 · Yarn: 4.17.1
Renderer config hash: 68c10966fe84406ee626034d58bfabd555df9f65f691204b7c46db24038da101
Renderer theme hash: c80287a78d80ad63d27bd5ca348b2ef9a7e2f44da289e436be6484ea28a1b033
Adapter versions: diagramGenerator=2, drawioFlowchart=1, drawioGantt=1, drawioSequence=1, drawioState=1
Full sidecar JSON: warrant-change-request-flow-83bc93c5.json
Change requests
/api/v1/change-requestsBearer · kb:read · governance:readThe change-request queue, newest first (created_at desc, then id desc). Rows are joined to the target entity so entityName comes back with them.
Query parameters
/api/v1/change-requestsBearer · kb:write · governance:writePropose a change. Returns 201 with the created request. The payload is validated strictly per kind, so an unknown field is a 400 rather than a silent drop.
Request body
/api/v1/change-requests/{id}/approveBearer · kb:write · governance:writeApprove and apply. The response carries both the closed request and the entity the change landed on — for kind create that id did not exist before the call.
Request body
The review-note field is `note`
{ note?: string }. Body validation strips unknown keys, so sending reviewNote is accepted with a 200 and the note is silently discarded. Send note; read it back as reviewNote on the request object.Who may approve, and what a 409 means here
If the target entity has an ownerId or a non-empty stewardIds, only those identities may approve — anyone else gets 409 conflict with "Not a reviewer". With neither set, any caller who passes the scope check may approve.
The acting identity is the user id for a delegated eli_uk_ key, and the API key id for a shared eli_sk_ workspace key. A workspace key therefore can never match an owner or steward: owned concepts must be approved with a user key belonging to a reviewer, or through the workspace UI.
A 409 also comes back when the request is no longer open — first reviewer wins, and a double apply is impossible.
/api/v1/change-requests/{id}/rejectBearer · kb:write · governance:writeClose an open request as rejected without applying it. 409 when the request is not open, 404 when it does not exist.
Request body
/api/v1/change-requests/{id}/withdrawBearer · kb:write · governance:writeClose an open request as withdrawn. Takes no request body. 409 when the request is not open.
What approval actually applies
create inserts the concept at authority curated and lifecycle published (or draft when the payload asks for it); a name collision with a live concept is a 409. update writes the fields and promotes authority to at least curated in one transaction — a promotion only, never a demotion of a certified concept. deprecate and supersede route through the same code as the deprecate endpoint below, and delete soft-deletes. Every one of them records the revision with activity change_request:<id>, which is how you trace an edit back to its proposal.Concept authority & lifecycle
These five mutations all return the same CurationMeta object and all append a revision. They are the direct path — use them for the states a change request does not cover (authority, owner, review stamps), and use change requests for edits you want reviewed.
/api/v1/entities/{id}/certifyBearer · kb:write · governance:writeOwner/admin sign-off. Sets authority to 'certified', refreshes lastReviewedAt and nextReviewAt (now + the workspace reviewIntervalDays, default 180), bumps version, and writes a revision with changeKind 'certify'. Lifecycle is untouched.
Request body
/api/v1/entities/{id}/reviewBearer · kb:write · governance:writeStamp a review without certifying. Refreshes lastReviewedAt and nextReviewAt; a machine_extracted concept is promoted to 'curated', higher tiers are left alone. Takes no request body.
/api/v1/entities/{id}/authorityBearer · kb:write · governance:writeSet the authority tier explicitly, including a demotion. Setting the tier it already has is an idempotent no-op: no version bump, no revision, no audit row.
Request body
/api/v1/entities/{id}/ownerBearer · kb:write · governance:writeAssign or clear the owner and optionally replace the whole steward list. This is what arms the reviewer gate on change requests for this concept.
Request body
/api/v1/entities/{id}/deprecateBearer · kb:write · governance:writeRetire a concept. Without supersededBy the lifecycle becomes 'deprecated'; with it the lifecycle becomes 'superseded' and supersededBy points at the successor.
Request body
Only a published concept can be retired
published. A draft or pending-review concept gets a 400 telling you to publish or delete it instead; a concept that is already deprecated or superseded gets a 409. There is no draft → deprecated edge in the state machine.Revision trail
/api/v1/entities/{id}/revisionsBearer · kb:read · governance:readThe append-only history for one concept, newest first. Returns 404 for an unknown or deleted entity, so revisions of purged ids stay private.
Query parameters
changeKind is one of create, update, review, certify, set_authority, set_owner, deprecate, supersede, delete, change_request, verify. activity records where the change came from — api for the authority and deprecate endpoints, and change_request:<id> for anything applied by an approval.
Document verification
/api/v1/documents/{id}/verifyBearer · kb:write · governance:writeStamp a document. verified and certified record who verified it, when, and a re-verify due date (now + the workspace reviewIntervalDays); unverified and deprecated clear all three stamps. Audited as document.verify.
Request body
Error envelope
{ error, message } — plus issues on a body-validation 400. Across this module: 401 unauthorized (missing, invalid or revoked key), 403 insufficient_scope or insufficient_capability, 400 invalid_body / invalid_json / invalid-params / invalid, 404 not_found, and 409 conflict. One exception worth coding around: the document-verify route's own not-found reply is { "error": "Document not found" } with no message key. That branch also applies the caller's content ACL, so a document restricted away from the key looks identical to one that does not exist. There is no pagination envelope, idempotency key or rate limiter on these routes.Data elements
Warrant owns two tables outright, owns a column group on two more, and appends to the audit log. Every one of the five carries a workspace_id and a <table>_tenant_isolation row-level-security policy whose USING and WITH CHECK clauses both require workspace_id to equal the workspace of the current transaction. There is no cross-workspace read path: a wrong-workspace id is simply invisible, which is why several routes return 404 where you might expect 403.
Two details worth knowing before you build on these rows. First, editorial_note is steward-only: it is stored on the entity but deliberately excluded from the revision snapshot and diff, so it never travels into a history view. Second, entity_revisions.version is bumped with an atomic UPDATE … RETURNING that takes the entity row lock, so two concurrent mutations can never mint the same version number.
Feature map
Five feature areas make up the module. Each names the concrete modules and tables that deliver it, and the same names reappear in the code map and internals below, so every behavioural claim on this page is traceable to the code that enforces it.
System architecture
The module is three route groups over four services and five stores — and no model anywhere. Rectangles are API routes and services, cylinders are tables; the two append-only cylinders (entity_revisions, audit_log) are what make the trail defensible.
Warrant — system architecture
Change requests claim in concept_change_requests and apply through the same manual.ts and curation.ts writers the direct endpoints use, so every accepted change lands in entity_revisions and audit_log regardless of which track it took. Document verification is the parallel, simpler lane on the right.
Downloads
Concepts
- Warrant architecture
- Governance services
- REST surface — src/app/api/v1
- Modules
- Warrant
Keywords
- change-requests routes (API)
- documents/:id/verify route (API)
- change-requests.ts — propose, claim, apply (service)
- curation.ts — authority, lifecycle, recordRevision (service)
- store: table
- document stamps (service)
- store: append-only table
- workspace-settings — reviewIntervalDays (service)
- vault/verification.ts
- manual.ts — the create, update, delete apply path (service)
Source and generation provenance
Status: current
Generated at: 2026-08-17T18:41:55.969Z
Source hash: 45a113726a4cbf5440690b372fec5c435b498e2596d7735a829f59d47641a2fc
Metadata payload hash: dbea75e50953c0942da6849fb9f84cd07b68b2946c5ba7a9235ff4f0c7b27fd7
Canonical appearance
src/app/(docs)/docs/modules/warrant/page.tsx:58 route /docs/modules/warrant
All appearances
canonical—src/app/(docs)/docs/modules/warrant/page.tsx:58route/docs/modules/warrant
No mirrored appearances.
Generation versions
App: eli-ai 0.1.0
Mermaid: 11.16.0 · Mermaid CLI: 11.16.0
Node: v26.3.1 · Yarn: 4.17.1
Renderer config hash: 68c10966fe84406ee626034d58bfabd555df9f65f691204b7c46db24038da101
Renderer theme hash: c80287a78d80ad63d27bd5ca348b2ef9a7e2f44da289e436be6484ea28a1b033
Adapter versions: diagramGenerator=2, drawioFlowchart=1, drawioGantt=1, drawioSequence=1, drawioState=1
Full sidecar JSON: warrant-system-architecture-45a11372.json
How to read the Warrant system architecture
- Two tracks, one writer set: Change-request approvals and the direct governance endpoints both mutate entities through manual.ts and curation.ts, so the revision and audit guarantees hold on both paths.
- Follow the settings dependency: Review and verification due dates derive from the workspace reviewIntervalDays, read before any transaction opens.
- Note the column-group ownership: The entities and documents rows belong to other modules; this module owns their governance and verification column groups and is their only writer.
- Check the append-only pair: entity_revisions and audit_log are written inside the same transaction as the mutation they record and are never updated or deleted.
- Trust boundary
- Every route guards on kb:read or kb:write plus the governance:read or governance:write capability for delegated keys; owned concepts additionally gate approval on the owner and steward identities.
- Durable state
- concept_change_requests with review metadata, append-only entity_revisions and audit_log, and the governance and verification column groups on entities and documents.
Failure paths
- An apply that throws reverts the claimed request to open
- A crash between claim and apply leaves approved with null appliedAt — resumable, not wedged
- A second concurrent approval loses the claim and returns 409
- Deprecating a non-published concept is rejected with a 400
Signals
- Open change-request queue depth and age
- approved rows with null appliedAt (crash wedges)
- Authority-tier distribution over time
- Documents past their next_verify_at date
Where the logic lives
The code map is the module boundary in file terms. Every path is real; table names are stated in the notes because tables are defined in the schema module, not in files of their own.
Primary runtime flow
The highest-value flow is an approval, because it exercises the reviewer gate, the claim, the apply, and the trail in one call. Message labels use the operation names from the HTTP API section above.
Warrant — primary runtime flow
approveChangeRequest claims the row before applying and stamps appliedAt only after the apply commits. The apply itself runs through manual.ts and curation.ts, so the revision and audit rows are identical to what a direct edit would have produced — plus the change_request activity link.
Downloads
Concepts
- Warrant runtime flow
- Modules
- Warrant
Keywords
- POST :id/approve (API)
- audit_log (store)
- change-requests.ts (service)
- concept_change_requests (store)
- manual.ts + curation.ts (service)
- entity_revisions (store)
- append change_request.approve
- Reviewer (SDK or curl)
- entities (store)
- append a revision with activity change_request:id
- approveChangeRequest with an optional note
- load the request, must be open
- claim the row, status open to approved
- apply the payload by kind
- stamp appliedAt only after the apply commits
- closed request plus appliedEntityId
- guard kb:write and the governance:write capability
- /api/v1/change-requests
- reviewer gate — owner or steward only, when either is set
- write the fields, promote authority to at least curated
Source and generation provenance
Status: current
Generated at: 2026-08-17T18:41:53.943Z
Source hash: eb6432fde77d55f982c084e22ea0fb29b05ef24382ab24d98c65b036bfaa6d0b
Metadata payload hash: ccaf6fc341f8c4abac579f2ac598923d3912bff32602a0ca2231a003b2e9e453
Canonical appearance
src/app/(docs)/docs/modules/warrant/page.tsx:97 route /docs/modules/warrant
All appearances
canonical—src/app/(docs)/docs/modules/warrant/page.tsx:97route/docs/modules/warrant
No mirrored appearances.
Generation versions
App: eli-ai 0.1.0
Mermaid: 11.16.0 · Mermaid CLI: 11.16.0
Node: v26.3.1 · Yarn: 4.17.1
Renderer config hash: 68c10966fe84406ee626034d58bfabd555df9f65f691204b7c46db24038da101
Renderer theme hash: c80287a78d80ad63d27bd5ca348b2ef9a7e2f44da289e436be6484ea28a1b033
Adapter versions: diagramGenerator=2, drawioFlowchart=1, drawioGantt=1, drawioSequence=1, drawioState=1
Full sidecar JSON: warrant-primary-runtime-flow-eb6432fd.json
How to read the Warrant primary runtime flow
- The gate comes before the claim: When the target concept has an owner or stewards, only those identities may approve; a workspace key can never match one, so owned concepts need a user key.
- The claim is the concurrency control: Flipping open to approved before applying means a concurrent second approval loses the claim and gets a 409 — a double apply is impossible.
- The apply is ordinary graph code: Kind create inserts at curated authority, update writes fields with a promote-only floor, deprecate and supersede route through the same code as the direct endpoint, delete soft-deletes.
- appliedAt is the commit marker: It is stamped in a separate step after the apply transaction commits; approved with null appliedAt is a detectable crash wedge a later approve resumes.
- Trust boundary
- Scope kb:write plus the governance:write capability gate the route; the owner and steward identity check gates the decision itself.
- Durable state
- The closed request row with reviewer and notes, the applied entity state, one entity_revisions row with activity change_request:id, and the audit event.
Failure paths
- Reviewer mismatch returns 409 with no state change
- Payload that no longer applies (for example a name collision) reverts the claim to open
- A crash after claim leaves approved plus null appliedAt for idempotent resume
- Reject and withdraw close the row without touching the entity
Signals
- Time from proposal to review decision
- Approve versus reject ratio by kind
- Revisions with change_request activity per week
- 409 rate on approve (contention or gate misses)
Internals and invariants
Gated change through change requests
A proposal validates its payload against a strict per-kind schema — unknown fields are a 400, not a silent drop — and lands as an open row. Approval is claim-then-apply across transactions: the claim serializes reviewers, the apply runs through the ordinary graph writers, and the appliedAt stamp is deliberately last.
- Invariant — A change request is applied at most once: the open-to-approved claim is the lock, a failed apply reverts to open, and appliedAt is stamped only after the apply commits, enforced in
src/server/graph/change-requests.ts. - Invariant — When a concept has an owner or stewards, only those identities may approve or reject its requests (409 otherwise), enforced by the reviewer gate in
src/server/graph/change-requests.ts.
Direct curation mutations
The five direct endpoints are one workspace transaction each: load the live entity, mutate the governance columns, record the revision, append the audit row. Review stamps derive their due date from the workspace review interval, which is read before the transaction opens.
- Invariant — Applied updates promote authority to at least curated and never demote a certified concept; explicit demotion exists only on the authority endpoint, enforced in
src/server/graph/change-requests.tsandsrc/server/graph/curation.ts. - Invariant — Only a published concept can be deprecated or superseded, and a supersession target must be live, unmerged, and published, enforced in
src/server/graph/curation.ts.
Append-only revision trail
Every accepted change appends one revision carrying a full snapshot and a field-level diff against the previous one. The version number is minted with an atomic bump that takes the entity row lock, and the table deliberately has no foreign key to entities.
- Invariant — Revision rows are never updated or deleted, and two concurrent mutations can never mint the same version number, enforced by
recordRevisioninsrc/server/graph/curation.ts. - Invariant — The steward-only editorial note is excluded from revision snapshots and diffs, so it never travels into a history view, enforced in
src/server/graph/curation.ts.
Document verification
Verification is a single-row state machine on the document: verified and certified stamp who, when, and a re-verify due date; unverified and deprecated clear all three. The route applies the caller's content ACL first, so a restricted document is indistinguishable from a missing one.
- Invariant — Setting verified or certified always stamps verified_by, verified_at, and next_verify_at together, and the other two states always clear them, enforced by
verifyDocumentinsrc/server/vault/verification.ts.
Reviewer gating, audit, and access
Every route resolves the bearer key to a workspace, checks scope by exact membership, and re-checks the live capability for delegated user keys. Every mutation appends an audit event named for what happened, and all reads and writes run under row-level security.
- Invariant — Every governance mutation appends an audit_log event in the same transaction as the change it records, enforced across
src/server/graph/curation.ts,src/server/graph/change-requests.ts, andsrc/server/vault/verification.ts. - Invariant — A cross-workspace id is invisible rather than forbidden: tenant RLS policies on every table turn it into a 404, enforced through
src/server/db/tenant.ts.
For a self-hosting team the safe extension points are observation and policy, not the state machine: attach read-only policy observers, read stale-concept and curation summaries through the plugin facade, and drive markReviewed / setAuthority / deprecateEntity through it so every change still appends the same revisions. Adjusting the review cadence is a workspace setting. The claim-then-apply protocol, the promote-only floor, and the append-only trail are load-bearing and not configurable.
How it composes
Warrant is usable on its own — the state it records is meaningful whether or not anything reads it. What follows is what each neighbour adds, and what genuinely breaks without it.
With Atlas — the concepts being governed
Atlas owns the entities row; Warrant owns its governance columns. This is the one real dependency: a change request of kind update, deprecate, supersede or delete, and every one of the five authority/lifecycle endpoints, needs a live entity to point at. Approving a create request is how you get one without touching Atlas's write API at all — the entity is created by the approval, at authority curated.
With Lens — where the state changes answers
This is where governance stops being paperwork. Retrieval's graph-fusion stage excludes entities whose lifecycle_status is draft or pending_review, so drafting a concept keeps it out of answer context. On the document side, documents.verification is a direct input to the answer policy's confidence features — ranked unverified 0, verified 1, certified 2, and deprecated −1, so a deprecated source counts against the answer — and when no cited document is verified or certified the policy raises a no_verified_source caveat. Entity authority participates too: the feature set tracks whether any detected concept is certified. Without Lens, all of this is recorded and simply not consumed.
With Lineage — the trail, assembled
entity_revisions and the audit rows are Warrant's, and GET /api/v1/entities/{id}/revisions reads them without any Lineage code. Lineage is what stitches them together with document revisions, extraction runs and citations into a single provenance view. Note that createGovernanceClient also exposes documentLineage(id), which calls GET /api/v1/documents/{id}/lineage— that endpoint is Lineage's, not Warrant's, and is documented there.
With Intake — verification on ingested content
Connector-ingested documents arrive at the default verification of unverified. Warrant's verify endpoint is the human stamp on top of that. No connector is required to use it — any document row will do.
With Crucible — the policy decision log
GET /api/v1/policy/decisions and GET /api/v1/policy/stats are guarded by the same governance:read capability as this module's reads (accepting either kb:read or runs:read), and their wire types PolicyDecision / PolicyStats live in @eli-ai/contracts/governance. Their client methods, however, are on the quality entry — createQualityClient(transport).listPolicyDecisions() — so they are documented with Crucible. Adopt Warrant alone and you still get the write-side governance state; you do not get the decision log unless you also take that entry.
With Ports — two approvals that are not the same thing
Agent runs have their own human-in-the-loop approval at POST /api/v1/runs/{id}/approve, gated on agents:run. It has no relationship to the change-request queue: different table, different scope, different lifecycle. Do not wire one to the other expecting shared state. Separately, the SKOS/PROV-O export at GET /api/v1/export/skos is reachable from createGovernanceClient(transport).exportSkos() but guards on graph:read — it is a graph export whose contents are lifecycle-shaped (published, deprecated and superseded concepts only; drafts never export).
With Conduit
No coupling. Live-data connectors and governed queries neither read nor write any Warrant table, and Warrant needs nothing from them.
Going deeper
Extending Warrant
policyObservers runs post-hoc on a recorded decision and can never change a verdict — and can read and write governance through the facade: staleConcepts, getCurationMeta and curationSummary under governance:read, and markReviewed, setAuthority and deprecateEntity under governance:write, each appending the same revision rows a human action would. Warrant emits entity.certified, entity.authority_changed, change_request.* and policy.decision.recorded. See the extension model for the contract and the trust boundary, and Build a plugin for a worked example.