Governed commits¶
The governed API on port 7001 records an authorized RDF change together with
its decision evidence and side-effect intents. Use it when a mutation needs a
signed policy decision, object version checks, and a receipt for recovery.
Ordinary /update authorization does not provide this contract.
This reference describes the implementation through source commit a3622025
of 16 October 2026. Confirm that every node runs a build containing these routes
before enabling clients. A source commit does not identify the image currently
deployed in your environment.
Write endpoints¶
| Method and path | Contract |
|---|---|
POST /governed/validate |
Validate a proposed commit without applying its changes. |
POST /governed/commit |
Apply facts, version changes, evidence, and outbox intents atomically. |
POST /governed/revert/prepare |
Prepare inverse facts. A caller must authorize and submit the resulting change separately. |
A version 1.0 commit includes mutation_id, tenant_id, ontology, intent,
policy, facts, and decision_trace. It can also include preconditions,
expected_object_versions, expected_snapshot_index, branch, and outbox.
mutation_id is a producer-stable UUID. Keep it when retrying the same mutation.
The server verifies the authenticated actor, tenant, signed policy proof, ontology binding, graph access, and applicable validation rules. The proof binds the canonical fact patch to the decision. An outbox entry records an intent; external delivery is a separate operation.
| Condition | Result |
|---|---|
Same mutation_id and request hash as a committed request |
Stored receipt, including after the original proof expires. |
Same mutation_id, different request hash |
409 MUTATION_ID_CONFLICT. |
| An expected object version differs | 409 STALE_OBJECT, with current_object_versions. |
| Too many touched objects | 413 ACTION_TOO_LARGE; IG_GOVERNED_MAX_OBJECTS defaults to 10,000 across the process. |
Every touched object receives a new igov:objectVersion, even when the request
does not supply expected versions. Every RID in expected_object_versions also
advances, including a RID whose facts remain unchanged. The version map is a
concurrency precondition; it is not part of the signed patch hash.
Prepare a versioned change¶
The following reads accept GET query parameters or POST JSON and return
Cache-Control: private, no-store. They establish a linearizable read point in
cluster mode. The caller needs Read permission and a matching verified tenant;
administrative and standalone development exceptions are separate from this
normal tenant-bound path.
| Path | Request | Response |
|---|---|---|
/governed/snapshot |
tenant_id |
tenant_id, snapshot_index. |
/governed/objects/versions |
tenant_id, objects: [{rid, graph}], 1 to 1,000 entries |
tenant_id, snapshot_index, object_versions. |
/governed/receipt |
tenant_id and mutation_id, request_hash, or both |
Stored receipt, patch_hash, and committed_at. |
For a versioned edit, read object versions before reading the facts, then submit
the change with expected_object_versions. A new object can use expected version
0. A hidden object and a nonexistent object are both absent from a version
lookup. Version 0 means a readable object has no governed version yet.
curl http://localhost:7001/governed/objects/versions \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"tenant_id": "acme",
"objects": [{
"rid": "https://id.indentia.ai/document/item/acme/example/42",
"graph": "https://id.indentia.ai/sources/acme/example"
}]
}'
snapshot_index is store-wide, so writes by another tenant can advance it.
Use object versions for independent edits that must not conflict with unrelated
ingestion. Adding expected_snapshot_index introduces that broader conflict.
Recover a lost response¶
Look up the original mutation_id at /governed/receipt. A receipt is visible
only to the committing actor or an Admin.
- On
200, comparepatch_hashwith the canonical patch hash you submitted. - On
404, retry with the samemutation_id. The original request may still complete after the lookup. - If a retry with a new proof returns
409 MUTATION_ID_CONFLICT, look up the receipt again and comparepatch_hash.
The lookup returns the stored object_versions, not later object versions.
Its snapshot_index is the current index, affected_triples is 0, and
idempotent_replay is true. It does not reproduce the original commit index.
If both lookup keys are supplied, a mismatched request hash returns 409.
RDF 1.2 triple terms¶
Fact objects and fact preconditions accept a recursive triple_term value:
{
"kind": "triple_term",
"subject": "https://id.indentia.ai/document/item/acme/example/42",
"predicate": "http://purl.org/dc/terms/title",
"object": {"kind": "literal", "value": "Quarterly report"}
}
A triple term describes a triple without asserting it. Subjects and predicates
must be IRIs; blank nodes are not accepted. Nesting is limited to eight levels.
The server includes the RDF 1.2 <<( s p o )>> form in canonical patch hashing.
Configure proof verification¶
Configure IG_ACTION_PROOF_JWKS_URL or IG_POLICY_PROOF_JWKS_FILE for proof
verification. URL-based JWKS is loaded at startup, so key rotation requires a
restart. Production requires HTTPS. With IG_GOVERNED_COMMIT_REQUIRED=true, a
production server refuses to start without a proof verifier.
Governed branch writes are confined to the selected tenant ontology branch. Release-manifest activation has a separate guarded path. A successful governed commit is not evidence that an ontology release has been activated.