ADR 0029: Record recycle bin and restoration
- Status: Accepted; recycle/restore implemented in the local prototype
- Date: 2026-11-04
- Complements: ADR 0019, ADR 0027 and ADR 0028
Decision
Section titled “Decision”Store nullable recycled_at and recycled_by together on the existing composite record registry identity. Do not add business columns, copy contents or move records into another table. The original row, UUID, fields, security policy, edges and immutable journal remain intact. There is no automatic expiration or purge.
recycle_record requires current Delete access; restore_record requires current Full access. Both require an active object type and the opened record version. They increment that record’s version once, update last-change metadata and write one lifecycle event in the same transaction. Linked records are neither recycled nor versioned. Concurrent/stale writes cannot silently succeed, and journal failure rolls back the complete action.
Normal policy predicates exclude recycled identities before search, counts, sorting and pagination, including Administrator queries. Normal record opening, modification, security changes, duplication, linked creation and relationship selection reject recycled records. Workspace recycle-bin reads use the same current object/record/field permissions and workspace isolation. They include inactive object types so retained records cannot become stranded by deactivation; restoring requires reactivating the object first.
list_recycled_records provides a paginated, searchable, sortable standard-column view. get_recycled_record inspects retained values without permitting edits. Explicit list_record_journal.includeRecycled allows authorized retained-history inspection; it does not bypass current field or endpoint rights. The web bin has its own workspace route, search shortcut, object filter, shared table/selection/pagination and read-only Details/Journal dialog. The bin is also available in Command-K navigation. Its read-only preview reuses the standard form group surfaces, translated headings, configured order/widths and Unassigned section. Current applicability and field visibility apply; inactive retained fields are disclosed separately. The dialog uses the shared action footer and blocks navigation while restoration is pending. Normal record forms offer confirmed recycling only while clean; the bin offers confirmed restoration only with Full access and an active type.
Relationships and validation
Section titled “Relationships and validation”Retained edges continue reserving their cardinality slots. They count in definition activation/preflight and lifecycle dependency checks; disappearing from UI must not make the slot available for a conflicting new connection. Normal Dossier/tree projections omit unavailable endpoints. Primary fields retain their restricted marker and show a generic unavailable association without exposing the recycled/restricted parent’s identity. Children remain active and retain the same version.
Restoration validates current active fields, requiredness, classification and applicability without changing their stored values, then validates the record’s retained relationship pairs, conditions, cardinalities and Primary rules. Invalid restoration fails atomically; no edges or values are silently removed or remapped. Other recycled endpoints remain unavailable until independently restored. Whole-workspace unrelated relationship scans are not required for this operation; existing write/definition validation continues enforcing the retained graph.
Permanent deletion — local implementation, 2026-11-05
Section titled “Permanent deletion — local implementation, 2026-11-05”R-039/R-040 retain complete immutable record/relationship history for installation Administrators after confirmed permanent deletion. This replaces the earlier plan to erase historical contents as part of ordinary permanent deletion. Non-Administrators, including Designers and object-level Full users, receive only a content-free deletion notice in otherwise authorized, previously visible contexts; no deleted values or endpoint snapshots may leak through surviving linked-record journals or alternate API/MCP/query/detail projections. Other records retain their independent history. PRD section 8 owns the complete behavior and acceptance criteria.
The live record and operational edges are removed without cascading deletion to other records. Required-context/dependency conflicts must be resolved before committing. Retained journal identity/authorization references are separate from live contents and must not reserve operational cardinality slots. The transaction preserves the Administrator-only history boundary atomically with deletion. Confirmation explicitly states that history remains available to Administrators; normal journal entries are not rewritten. A separate history-erasure feature is later evaluation, not this operation. The registry retains deletion timestamp/actor, policy and frozen reader field/event/context eligibility, while the live row and operational edges are removed. The current rights resolver combines that policy with live memberships, foreign rules and administrative ceilings. Snapshot eligibility additionally prevents later grants from opening previously hidden events. Journal projection replaces otherwise eligible historical content with the one real deletion event before counting/paging; raw events stay unchanged. Administrators inspect retained history from the recycle-bin history area or the shared API/MCP journal.
The retained identity also stores the last display Keyword solely for Administrator history lookup, captured through the installation Administrator’s read projection before live contents/edges are removed. This private caption includes derived Contact names and is never part of ordinary users’ deletion notices. list_deleted_records searches captions/IDs and filters object types before counts/pagination, with localized object labels and standard sorting. The web view reuses record-table selection/columns and the shared Journal, including its filters and value formatting.
Boundaries and verification
Section titled “Boundaries and verification”R-038 is implemented locally; the restore portion of R-039 is implemented. Confirmed permanent deletion and R-040 retained-history projections are implemented locally. permanently_delete_record requires a recycled record, current Full access, source version and confirm: true; it preflights surviving dependencies and rolls back all contents/edges/versions/history together on failure. No journal rewriting or background cleanup is introduced. Ordinary journal immutability and the runtime database role remain unchanged.
Isolated PostgreSQL tests cover normal-query exclusion, API/MCP parity, retained contents/edges/history, Primary children, reserved one-to-one slots, field redaction, current Delete/Full access, revocation, workspace isolation, inactive definitions, invalid restoration, optimistic races and journal-failure rollback. Reproducible validation and public CI evidence are in the development guide. This is local prototype acceptance, not release or physical-device acceptance.