Unreleased documentation. These pages follow the main branch and can change before the next release. For supported guidance, use v0.44.0.
Decide how long Registry Casework keeps a review, what survives erasure, and what the audit journal records, so a producer collects its result in time and a caller recovers safely when an audit write fails.
Retention windows
Section titled “Retention windows”A retention window is how long Casework keeps a part of a review after the request settles. The
policy author sets two of them per ReviewPolicy, in casework.yaml:
retention: terminalRetentionDays: 90 accountabilityRetentionDays: 365terminalRetentionDayskeeps the review itself: submitted context, tasks, notes, decisions and the result. It is from 1 to 3,650 days.accountabilityRetentionDayskeeps the accountability record: who decided and the private reason. It is at least as long as the terminal window and at most 3,650 days.
Both run from the request’s terminal settlement; a request still under review has no expiry. Each trusted producer also sets how long its admission receipt can be recovered:
retention: {receiptRetentionDays: 30}Keep erasure running
Section titled “Keep erasure running”Erasure runs inside casework serve; there is no separate
job or command. The maintenance worker runs a retention pass about once a minute, and each pass
erases at most 100 eligible requests and skips rows another transaction holds, so a backlog drains
over several passes. Erasure starts only while the audit writer is ready, and each erasure is
recorded in the audit journal.
What remains after the review is erased
Section titled “What remains after the review is erased”When the terminal window closes, Casework deletes the ReviewResult, the decisions, private drafts, history and notes, the ReviewTasks, clock occurrences, and pending completion calls, and drops every stored response it would have replayed. It also scrubs the ReviewRequest: the submitted context, the subject and source fields, the requester reference, the result constraints, and the completion destination are removed, and the subject is replaced by the submission digest.
If accountabilityRetentionDays is longer, these remain until it closes:
- the accountability record: who decided, the private reason, and the public reason flag;
- the scrubbed ReviewRequest: its producer, policy binding, lifecycle state, submission digest, and timestamps;
- pseudonymous stand-ins for the producer and the initiating caller, so the initiator can still learn that its result expired;
- each idempotency record: the caller’s issuer and subject, access profile, operation, resource,
Idempotency-Key, and request hash, without the stored response, so a resend is refused withidempotency.expiredinstead of admitted again; - the submission reservation, keyed by the digest: the same submission is answered
review.result-expired, and different content for the same producer, subject, version, and policy isreview.submission-conflict.
Then all of it is deleted.
Recover before the result window closes
Section titled “Recover before the result window closes”The result carries its own deadline, availableUntil: its settlement time plus
terminalRetentionDays. Until then the producer reads it, and a request that is still under
review answers 202. After it, the result read answers 410 with no body.
A producer that lost the admission response retries the same body under the same
Idempotency-Key within its receipt window; Casework answers 200 with the request it already
accepted, rather than 201. A changed body under that key is idempotency.key-reused, and a
resend after the response was erased is idempotency.expired.
Completion destinations
Section titled “Completion destinations”A completion destination is the producer’s URL Casework calls when a result is ready. The call
carries no decision; the producer then reads the result. Each destination is declared under
reviewCompletionDestinations in the runtime configuration,
keyed by the destination id the producer names in casework.yaml.
A failed call returns to the queue and is tried again after retryDelaySeconds (default 30), up to
maximumAttempts (default 12), each attempt bounded by attemptTimeoutMilliseconds (default
5000). Delivery stops when the attempts run out or the result window closes; the result stays
readable until availableUntil.
An attempt interrupted by a crash or restart counts as a failed attempt, so an interrupted final
attempt is not tried again. The producer still learns the result from the result feed,
GET /v1/review-results, which the Base Registry Engine polls. With maximumAttempts: 1, any
interrupted attempt ends the delivery as dead-lettered.
Keep the audit file
Section titled “Keep the audit file”The audit journal is the file Casework appends one line
to before each admitted operation and one after it commits. On a deployment it is the file
audit.path names; a development session keeps its own under .casework/dev/audit/ in the
project until the session is removed. Search it for the decisions reviewers made:
rg '"casework.review-decided"' /var/lib/registry-casework/audit/casework.ndjsonThe first matching line is the request entry; the next has "phase":"response" and adds the
pseudonymous ReviewRequest and ReviewTask, the accountability event id, and whether a public
reason was given. This is the request entry of the decision in
Decide your first ReviewRequest:
{"schema":"registry-casework-audit/v1","eventId":"<id>","time":"<time>","phase":"request","correlation":"<id>","record":{"event":"casework.review-decided","principalPseudonym":"<pseudonym>","profileId":"staff"}}The journal names people and records only by keyed pseudonym and carries no context, reason or
result. Its location, key, rotation and local retention are audit.path, audit.hashKeyRef,
audit.rotateBytes and audit.retentionDays in the
runtime configuration. Entries are neither chained
nor signed, so ship sealed files to an archive you control, and keep the key as long as you need
to recompute pseudonyms; audit key handover
covers rotation.
Recover from a refused audit write
Section titled “Recover from a refused audit write”A refused audit write answers 503 with service.unavailable, and /ready answers 503 until
you repair the destination and restart. The caller cannot tell from the response which entry
failed, and the two cases differ:
- The request entry is written before the database transaction opens. If it is refused, nothing changed.
- The response entry is written after PostgreSQL commits. If it is refused, the change stands: the decision is recorded, the claim is held, or the ReviewRequest is admitted, and the journal lacks its response line.
So a caller that receives 503 on a mutation must not assume it failed. Once Casework is ready,
resend the same Idempotency-Key with the same body and If-Match: Casework returns the stored
response if the change committed and runs it if it did not. For a route without an idempotency
key, such as grant revocation or a caseload apply, read the resource instead. Only then choose
another operation; a fresh key on a stale picture can apply a second change.
A database restore can bring back data that was already erased; Back up and restore Casework gives the order of recovery.
Cookies on Registry Stack
We use optional cookies to understand how you use the main Registry Stack website and this documentation. If you contact us, we may link this activity to your enquiry. You can change your choice at any time. Read the privacy policy.
Your browser asks sites not to track you, so optional tracking stays off.
We could not use or save that choice. Optional tracking remains off.