feat(privacy): audited redaction that keeps history's shape and removes its content

Rows in append-only history are never deleted; their content can now be
made irrecoverable through one audited path. A redaction replaces the
content columns of an event, memory, message, model call, belief or
assertion with a fixed marker, keeps identifiers, links, timestamps,
scores and breakdowns, writes an append-only ledger row with a SHA-256 of
the removed content, appends a redaction event, optionally cascades to
derived rows and to the events that quote them, and scrubs stored snapshot
archives before re-signing them. noema_redact() is the only write the
append-only trigger admits, for UPDATE only, under a transaction-local flag
the application never sets; plain updates and all deletes stay refused.
Replay labels redacted stimuli instead of inventing them.

Cryptographic erasure was considered and deferred with reasons (ADR-0009);
docs/privacy.md defines retained, redacted, irrecoverable and deleted and
states what backups and earlier exports are not covered. Migration 0023.
This commit is contained in:
Andy Dixon
2026-08-23 23:52:07 +01:00
parent 9eed6e2a18
commit 7d608c2783
33 changed files with 1245 additions and 45 deletions
+117
View File
@@ -6345,6 +6345,123 @@
}
}
},
"/api/v1/minds/{mind}/redactions": {
"get": {
"tags": [
"minds"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"401": {
"$ref": "#/components/responses/Error"
},
"403": {
"$ref": "#/components/responses/Error"
},
"404": {
"$ref": "#/components/responses/Error"
},
"201": {
"description": "Redacted; irreversible"
}
},
"parameters": [
{
"name": "mind",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"operationId": "redactionsList",
"summary": "list the redaction ledger",
"x-required-role": "operator"
},
"post": {
"tags": [
"minds"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
},
"401": {
"$ref": "#/components/responses/Error"
},
"403": {
"$ref": "#/components/responses/Error"
},
"404": {
"$ref": "#/components/responses/Error"
},
"201": {
"description": "Redacted; irreversible"
}
},
"parameters": [
{
"name": "mind",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"operationId": "redactionCreate",
"summary": "redact a row's content irreversibly (event, memory, message, llm_call, belief, assertion), optionally cascading to derived rows",
"x-required-role": "administrator",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"kind": {
"type": "string"
},
"id": {
"type": "string"
},
"reason": {
"type": "string"
},
"policy": {
"type": "string"
},
"cascade": {
"type": "boolean"
}
},
"required": [
"kind",
"id",
"reason"
]
}
}
}
}
}
},
"/api/v1/minds/{mind}/reflections": {
"get": {
"operationId": "reflectionsList",