ADR-045: Preflight and contain FlexForm deletion
Status
Accepted; implement through the dependent deletion repair.
Date
2026-10-10
Context
ADR-018 requires a refused vault deletion to cancel the owning record deletion.
The FlexForm hook instead caught a failed secret deletion and left Core's
cancellation flag unchanged. A real Core DataHandler test with the actual vault
ACL denied the secret deletion, wrote an access_ audit and then
removed the owning record while its secret survived.
ADR-036 L1 separately states the preflight and best-effort boundary for multi-field records. It does not promise that a later independent secret deletion can restore earlier deletions.
Decision
For a hard-deleting record, collect unique, existing, non-shared references
from all its FlexForm columns and preflight every selected identifier through
Vault before the first secret deletion.
Use the same service for the actual deletions.
A reference is a value at a position the column's data structure configures
with renderType vault, as a flat element or inside a section
container. Candidate selection walks the data structure with the same matcher
the write path uses. A UUID in any other element is ordinary content and never
a candidate, whether or not a secret with that identifier exists. A column
value without any identifier-shaped string needs no data structure. When such
a string exists but the data structure cannot be resolved, or the stored value
cannot be parsed, the vault positions cannot be located. That is a discovery
failure: it cancels the record deletion like any other, and never reads as a
column without vault positions.
On discovery, authorization or deletion failure, stop the cascade and set Core's existing cancellation flag before invoking diagnostics. Report the existing correlation reference to the editor without including the raw cause. On success, leave Core to remove its record normally. A duplicate reference is processed once.
Sharing is an exclusion for the complete identity: if any discovered column is shared, another occurrence in an unshared column cannot select that secret for deletion. This holds regardless of the order of the FlexForm columns.
Storage presence and consumer availability are distinct. Complete sharing
exclusions before resolving the remaining identities' presence. A false
exists result does not establish absence: administrative get
also sees disabled custody. Only its Secret excludes an
absent or already-deleted identity. Permission and lookup failures cancel the
record deletion before any secret preflight or mutation. Resolve presence for
all selected identities before the first assert call. Shared
identities need no metadata authorization because this record will not delete
them. Retain the service's existing metadata and deletion authorization; do
not retrieve plaintext or widen consumer availability.
Keep FlexForm soft-delete/recycle behavior: its secrets remain available for record restoration. Translation-shared secrets remain outside this record's cascade. No public interface is extended and no second ACL path is introduced.
Consequences
A denied preflight leaves all selected secrets and the owning record intact.
A deletion failure retains the record and stops the remaining cascade,
but already-applied secret deletions cannot be undone automatically. The
failing current operation may itself have persisted its deletion before a
Secret observer throws. The editor diagnostic must say that
secrets may already have been deleted; it must not imply rollback or promise
that the failing target is intact. Cancellation is set before reporting so a
diagnostic failure cannot defer that protection.
A record whose FlexForm value holds an identifier-shaped string and whose data structure cannot be resolved cannot be hard-deleted until its data structure resolves again. Deleting it anyway would either miss its secrets or delete secrets this record merely mentions.
This is a preflight within the FlexForm hook. A record mixing plain TCA vault fields and FlexForm fields still needs a separate cross-hook coordination repair; this decision does not claim that guarantee. Copy compensation is also outside this deletion repair.