- Status: proposed 2026-09-29 — the text first, checkpointed before any code, the way ADR 0021, ADR 0023 and ADR 0034 were. Nothing in it is implemented. Most of what it states was settled before it was written, in discussion, and is recorded here as settled. The rest are decisions this record takes itself. They are marked decided here where they are made, so that acceptance can rule on them one by one
- Shipped: unreleased
- Date: 2026-09-29
- Opens: nothing on landing. No
SCHEMA_VERSION, noOUTPUT_VERSION, noREGISTER_VERSION, noJOURNAL_VERSION, no migration. The ledger is a new format with a version of its own (§4), and it is born at implementation, not here - Requires, at implementation: a new artifact outside the tenant's
directory, at a path the data owner configures (§2). Two configuration
keys that are set together or not at all: the path and the retention
(§2, §8). A writer, which is the process that performs a removal (§6).
Two notices, whose words are fixed here (§9). A refusal for two
tenants configured onto one path, classified in
host.REFUSALSortests/test_refusals.pywill not see it (§2). No new reader anywhere in digline (§10) - Assumes: ADR 0002 §1 (the tenant is the perimeter), §2 (the payload stays where it is born, and a flag is verified rather than believed) and §6 (retention is mandatory, not a setting with a default); ADR 0003 §4 (a digest is a verifier over a guessable space); ADR 0014 §3 (a ledger has its own reason to exist, its own retention question and its own boundary question, and a name is payload in a way a timestamp is not); ADR 0021 §1 (a disposition is a person's), §5 (nothing rewrites a committed line) and §6 (absence is stated, never read as zero); ADR 0034 §1 (the store lives in the end company's perimeter), §5 (a token and not a digest), §6 (the name table, rewritable row by row, and a restored backup re-identifies), §12 (who the digests protect against, and what reopens it) and §14 (a delete, a removed run absent from every reader, and a delete is not an erasure)
- Amends, at acceptance:
CLAUDE.md's fixed decision 2, by an exception to its sentence "Everything lives in.digline/<tenant>/" (§2). It is an exception to that sentence and not an entry in the list of what the end company's store holds, and §2 says why the two must not be merged - Names, and does not amend: ADR 0021 §6's journal paragraph, whose premise "a record of the journal's existence held somewhere that does not expire — which is a committed file" this record makes false for deletions (§1). The correction belongs to ADR 0021. Its wording must say nobody can rewrite and never does not expire, which §8 makes false of this ledger. It also has to say whether it reopens the expired-journal case or is confined to deletions, and this record does not decide that. The name table's own place in fixed decision 2, which is an addition to the list, a different amendment from this record's, and not made here (§2)
- Closes: ADR 0034 §14's unstated half. §14 requires that a removed run be absent from every reader. It does not say where the fact of the removal is kept, and a reader who owes an authority that fact had nowhere to find it. This is that place. ADR 0034 §Not decided here's "erasure as a procedure" is not closed: this record keeps the record of a removal, not the procedure that decides one (§Not decided here)
- Touches, in
CLAUDE.md's fixed section: decision 2 gets an exception (§2), and keeps its stated reason whole: nothing in a home directory, no global state, and the ledger's location is configured per tenant by the owner of the data. Decision 5 is upheld: the ledger is a path, never a service that digline calls (§2). Decision 8 is upheld by making the path per tenant and refusing a shared one (§2). Decision 9 is upheld: no field of an entry is a digest, and §5 is where that is measured rather than assumed - Number: 0035. Swept on 2026-09-29, before a line was written, across
origin/main(4a4fe17), every remote ref, every local branch and tag, every sibling worktree'sdocs/adr/, the one stash, the open pull requests (none), and the site repository's refs. The highest number taken anywhere is 0034
Context¶
ADR 0034 §14 gave the product a delete, and with it a question it did not
answer. Before §14, nothing in digline removed anything. The retention of a
run document was forever, by omission. §14 adds the verb and states its
contract: "A removed run must be absent from every reader — scan_runs and
read_run included." ADR 0034 §6 adds the other removal, a row of the name
table: "an erasure needs a writer that removes a row."
Neither says where the fact of a removal is kept. The one party that needs
it is the end company, when it owes an authority proof that it erased what it
was asked to erase. The gate's exit code does not depend on it: an absent run
is an absent run. Promotion's conditions begin with read_run and do not
depend on it. The register's reading does not depend on it. One consumer,
at administrative time, needing a record that a removal happened, and three
constraints that leave that record no home among the artifacts that exist:
- The store may not hold it. §14 forbids a marker a reader could meet: a
tombstone in the run store is an erasure left incomplete. A tombstone that
carried the run's key would carry
created_atandconfig_hash, which may be exactly what had to go. - A committed file is on the wrong side. Under ADR 0034 the repository that commits is the software house's, and the removal runs in the end company's perimeter. Giving the end company a committed side would put git there, and ADR 0034 §3's division between the side that produces and the side that commits holds "for as long as there is no git there".
- The register is not it (§3).
What ADR 0021 §6 said about the one similar case. Meeting an expired
journal, it declined to record the journal's existence because "solving it
would take a record of the journal's existence held somewhere that does not
expire — which is a committed file, which is the thing §1 says the journal is
not." The rule of §6 stays true: absence is stated, never read as zero;
rotation is allowed for ignored files only; a committed file's retention is
git. What this record makes false is the premise in that sentence: that only a
committed file can hold a record nobody rewrites. The property was never
git. Git was the only thing that had it, and git never had it from the writer
alone. A commit on a protected main cannot be rewritten because of the other
holders: the clones, the remote, the ruleset that blocks force pushes. §7 says
where the property comes from here.
Decision¶
1. A ledger of removals exists, at the data owner's side¶
A removal from the store, of a run or of a name-table row, is recorded in a ledger that lives at the data owner's side, is written only by appending, and sits apart from the data whose removal it records.
What it is for, and it is the whole of it: a controller showing an authority that it performed the erasures it owed. That use is rare, it is deliberate, and it is aimed at someone outside both the software house and digline. Every other decision below is measured against it.
What it protects, and against whom. Not against the end company. The end company is the controller, and the data is theirs. The ledger protects the end company towards an authority, by showing that the gesture was made. A ledger its keeper could alter is still its keeper's evidence, the way a book of accounts kept by the company it describes is falsifiable and is still the basis of those accounts. A dishonest keeper can alter it. A dishonest keeper can also simply not erase.
2. Where it lives: a path the data owner configures, one per tenant¶
The ledger lives at a path the data owner configures. The process that writes it does not choose the path.
Why a configurable path, and not a place digline picks. It is the only shape that lets the data owner point the ledger at a volume with a backup regime of its own, or at storage that refuses modification (§7). A path digline chose would sit wherever digline chose it, under whatever regime that place already had, and a constraint the data owner configures cannot be given to a place the data owner did not pick.
Two shapes refused:
- A sibling directory under .digline/, outside <tenant>/. It solves
nothing. It is on the same volume, under the same backups, and a data owner
cannot give a subdirectory a regime of its own. Apart from the data (§11)
would be met in wording and not in fact.
- A service digline calls. It removes the storage problem and adds a worse
one. Fixed decision 5 refuses any network call the user has not configured,
and a ledger that needed one would make every erasure depend on it.
This is an exception to fixed decision 2's sentence, not an entry in its
list. Decision 2, as ADR 0034 §1 widened it, says "Everything lives in
.digline/<tenant>/" and then enumerates what the end company's store holds.
A configurable path is outside .digline/<tenant>/ by construction, so it is
an exception to the sentence. The amendment, at acceptance, says so, and
keeps the decision's stated reason whole: nothing in a home directory, no
global state on a machine, and a location set by the owner of the data for
one tenant.
The name table is a different amendment. It lives inside the store's
layout, beside the data, and it is missing from decision 2's list, so its
amendment is an addition to the list. The two artifacts are met in the
same paragraph of decision 2, and they need two different changes. They
must not be merged into one amendment, and this record makes only its own.
Per tenant, and a shared path is refused. Decided here. Fixed decision 8
makes the tenant the perimeter, and it enforces addressing by putting the
tenant in the directory layout: filing one client's history as another's is a
refused mistake. A path outside .digline/<tenant>/ loses that addressing, so
the configuration carries it instead. The ledger's path is configured per
tenant, and the writer refuses to start when two tenants are configured
onto the same path. A ledger shared by tenants would hold several perimeters'
removals in one place, with nothing in its location to tell them apart.
Set at the data owner's side, and nowhere else. The path is configuration the data owner writes where the store is. Nothing the software house sends can set it or change it. If it could, the software house would decide where the controller's record of its own erasures lives, which is the opposite of this section's first sentence.
3. It is not the register¶
The register (ADR 0021) is append-only, typed, and already a ledger. It cannot be this one, for four reasons, and they accumulate rather than compete:
- It lives at the software house, in git. This ledger lives at the data owner's side (§1).
- It is already on a read path.
digline loghas a register section, and the wire carries it (wire/log.py,register_entry_json). A removal recorded there would land where a reader meets it, which §10 forbids. - Git's retention would decide §8 by placement. A committed file's retention is git (ADR 0021 §6), so a ledger in the register would never expire, and nobody would have chosen that.
- Its outcome counts include what was removed. A register entry counts the cases of the comparison it records. The record of a removal would sit in the file whose counts the removal made stale.
And three things the separate ledger has that the register lacks, which is why this is a choice and not only the last option standing. It is off every read path (§10). It sits apart from the data's backups (§11). It has storage of its own, which the data owner can make refuse modification (§7).
4. What an entry carries, and what it never carries¶
One line per removal, in a format of its own, LEDGER_VERSION = 1,
independent of every other version in the tree, never migrated. A line this
digline cannot read is refused by name and left where it is, as ADR 0021 §5
does for the register.
An entry carries:
- what was removed, named without its content:
- for a name-table row, the row's token. A token carries no text
(ADR 0034 §5), and the committed projections already hold it for as long
as git keeps them;
- for a run, the run's created_at and nothing else of its key
(§5);
- when the removal was made;
- who decided it: the identity digline records for the person who
decided, together with where that identity came from. Two identities of
the same shape are not of the same worth when one comes from a source the
end company can revoke and the other does not. A record that does not say
which lets its reader assume the stronger.
An entry never carries: - what the row said, or anything the run contained; - which request caused the removal. A request identifier names the person who asked to be erased. That is the reason it is excluded. ADR 0014 §3's "a name is payload" would exclude the decider's identity too, and at the data owner's side payload is where it belongs.
What it says, in its own words: "this row was removed from this store" and "this run was removed from this store". Never "this data no longer exists". ADR 0034 §14 already rules that a delete is not an erasure on a filesystem somebody backs up: the old blocks survive until reused, a copy-on-write filesystem keeps them, a snapshot holds the removed row. No entry can prove the data is gone. It can prove the gesture was made, and the gesture is what a controller has to show. A ledger that claimed more would announce a guarantee nothing provides, which ADR 0002 §2 calls worse than no flag.
A journal leg has no entry of its own. Decided here. A leg belongs to a
run, and a leg has no key of its own. The run's created_at is in the
journal's header, so an entry for a run names it whether the run was removed
as a document, as legs, or as both. One run, one entry.
created_at is not unique by construction, and this record does not
assume the practice. Decided here. utc_now_iso keeps microseconds because
two runs in the same second once collided. But that collision needed the same
suite as well, and created_at alone needs only the same microsecond, for any
two runs within the tenant's ledger. And created_at is a wall clock: a clock
stepped backwards, by NTP or by hand, repeats a microsecond with no coincidence
at all. So the ledger never treats created_at as a key. An entry is the
record of one gesture. Two removals that name the same created_at are
two entries, not a conflict. Each entry carries its position in the
segment it was appended to (§7), which is a sequence number, not a digest.
A reader matching a run key to the ledger (§5) is told how many entries
matched, and one match is never assumed.
5. No digest in an entry — measured, not assumed¶
The run's key would have been the obvious name, and it is refused.
key_of(created_at, config_hash) is created_at, slugged, then config_hash,
in clear. config_hash is not a digest of configuration in the sense of a
model and a temperature. It digests each assertion's identity: its type
and its parameters, meaning the needle, the pattern, the schema and the
rubric. It also digests their thresholds and tolerances, samples,
min_agreement and the declared price. A rubric is exactly the text ADR
0003 §4 keeps from travelling, and ADR 0034 §12 already calls config_hash
"the most widely travelling digest in the tree".
ADR 0034 §12 answered who that digest protects against: nobody in
particular. The reason is that the committed reference and the suite live
in one repository, so whoever reads the digest already holds its inputs.
Its status line says what would reopen that answer: "a backup taken apart
from the source, a handover to a third party, or a later design that ships a
reference on its own." This ledger has both properties. It sits apart,
with backups of its own (§2, §11), and its use is to be shown to an authority
that holds no suite (§1). A config_hash in an entry would be a digest
reaching a place its inputs do not.
Measured on 2026-09-29, at 4a4fe17, with ADR 0003 §4's loop pointed at
config_hash. The attacker is modelled as holding one string, a
config_hash, and nothing else. There are two controls, because without them
not recovered cannot be told from not searched well:
| Case | Space | Result |
|---|---|---|
Control, must recover. [IsJson()], default values, samples=1 |
four built-ins that take no argument, subsets of one to three, × samples 1–5 | recovered after 6 candidates |
ADR 0003 §4's own model. The software house wrote the template, the end company tuned the numbers: an LlmRubric "Escalate the ticket when the refund exceeds {X} EUR and the account is older than {Y} days." beside a PiiAbsent, with a declared list price |
X 100–5000 by 50, Y in six values, threshold 0.50–0.95 by 0.05, samples 1–5: 29,700 | recovered after 14,523 candidates, in 0.56 s, returning the rubric with 2500 and 90 in it, threshold 0.7 and samples 3 |
| Control, must not recover. The same template with X = 2537, off the grid | the same 29,700 | not recovered, space exhausted in 1.16 s |
What decides it is the template, not the hash. A template shared across a software house's clients makes the recovery a loop of seconds, and that is the ordinary case, not the rare one. And a recovery returns text, not more digests. Identities are 64-bit digests and nobody enumerates those. The loop enumerates candidate suites, and a hit confirms the whole guess. The loop was run from a working note and is not in this repository. The table gives its three cases and its grid so that it can be rebuilt. An unknown price multiplies the space, to about two billion candidates for ±20% to the cent on two rates. That figure is computed, not run. An unknown template is beyond this loop, and it is not shown to be safe.
So a removed run is named by created_at alone. It is a timestamp, and it
digests nothing. It is a weaker name, taken against a measured leak. It
also breaks the correspondence with the run key used everywhere else, but in
one direction only. Whoever holds a key can slug an entry's created_at and
match the key's prefix, so key → entry works, with the count §4 requires.
Entry → key does not. For this ledger's use that costs nothing: the authority
it is shown to holds no keys, and the holders of keys never read it (§10).
Every field of an entry, checked against the same question:
- a token is not derived from its text, by ADR 0034 §5;
- created_at and when are clocks;
- who decided is an identity and its source.
None of them is a digest, so ADR 0034 §12's condition has nothing to fire on here. That is the property this rests on, and it is written as a condition: any digest in an entry reopens §12 for this ledger. It would reopen it for a digest of a run, of a suite, of a row or of a request. It would also reopen it for a token, if the name table's design ever made tokens derivable from their text. A count or a delta in an entry is not a digest. It would raise a different question, what may be counted about a data owner's removals, and that question is not this record's either.
6. The removal first, the entry after¶
The removal is made, and then the entry is appended. Never the other way round. The two torn states are not equally bad:
- Removed, and the entry not written: a removal with no record. The ledger says less than happened, and none of what it says is false.
- Entry written, and the removal not made: the entry says "this row was removed from this store" and it was not. The ledger says more than happened, which is the failure ADR 0002 §2 calls worse than no flag.
With the removal first, the only torn state possible is the first. A crash can leave the ledger short. It cannot leave it lying.
The writer is the process that performs the removal, at the data owner's side, and it is the ledger's only writer. Written as the condition it rests on: the ledger needs no exclusion for as long as nothing else appends to its path. A second writer would need one. A lock file is not one, and ADR 0031 records why: a stale lock blocks everything behind it. This record provides no exclusion, and it does not claim the condition is enforced.
7. Where "nobody can rewrite" comes from, and what the ledger says about it¶
The property comes from the storage, not from a second holder. Storage that lets the writing process add and neither modify nor remove gives nobody can rewrite without anyone else holding anything. The data owner configures that storage. digline does not. Where the data owner configures nothing, the process appends to an ordinary file, and the property is a promise rather than a fact.
So the ledger declares what it knows about its storage, instead of asserting
immutability, and what it knows is what it was told:
- It is a source, not a flag. A redacted flag is verified by digline at
construction (ADR 0002 §2). A claim about storage that came from
configuration can be verified by nobody. So the ledger records where its
knowledge came from, and does not state a property.
- The default declaration is "I was not told", not "ordinary".
Ordinary would be a claim about the storage that the process has not
verified. I was not told is exactly what it knows.
How the process learns: from configuration, and only from configuration. Decided here. The data owner may declare, beside the path, that the storage refuses modification and removal, and the period for which it holds what it is given. The process records that it was told so, and by configuration. It does not probe. The only probe that could tell append-only storage from an ordinary file is an attempt to modify or remove an entry. That is the one act the ledger exists to refuse, and on storage that allows it the probe would damage the thing it tested. Nothing turns on the answer anyway, because the process writes in either case.
On ordinary storage the process writes, and declares. It does not refuse. A ledger on an ordinary disk does not prove immutability, but it proves something: that the gesture was recorded, with its date and who decided it. Altering it takes somebody reaching the disk with intent. Append-only storage is a strengthening that a data owner with tighter obligations chooses. It is not a requirement.
The ledger is written in segments, and the declaration belongs to the segment. Decided here. A segment is one file, covering one calendar day of removals in UTC. Its first line records what the process was told about the storage when the segment was opened. The storage under a ledger can change while the ledger lives: a data owner can move it to append-only storage, or back. A declaration made once for the whole ledger would say nothing true about entries written before the change. A declaration per entry would repeat itself on every line. A segment is also the unit that storage holding objects for a period can hold, and the unit §8 expires.
8. Retention: mandatory, configured by the data owner, and without a default¶
The ledger's retention is configured by the data owner. The ledger expires. §1's written only by appending is immutability. It is not permanence: a ledger can refuse rewriting and still have an end. The use (§1) has a window. Its length depends on the data owner's obligations, which vary by sector and jurisdiction. That is the same shape as the data's own retention: the data owner sets it, and digline cannot read it. So nothing about the ledger's retention is decided by where it is placed. Placing it in the register would have decided it, and §3's third reason is that refusal.
ADR 0002 §6's shape, taken. Decided here. §6 says of the production store: "A production store without a declared deletion policy is not compliant and digline must not allow creating one: the window is a mandatory constructor parameter, not a setting with a generous default." The ledger takes the same shape. Its retention is mandatory whenever a path is configured, and a path without a retention is refused at start. There is no default. - Why §6 applies here, when ADR 0034 §1 declined it for the reference. §1's reason was that "a reference that can expire is a reference that can vanish from under a gate." Nothing gates on this ledger (§10), so that reason has no ground here. - Why it costs nothing. A ledger exists only when the data owner configures its path (§9), and at that moment asking for the retention in the same place is one more line. A default would make not chosen the ordinary outcome, which is the gap §6 was written to close. - A default was considered and refused, and §Alternatives considered says why: a number nobody can source is worse than no number, and this record found no source that fixes one. It does not claim that none exists. Nothing here is legal advice.
What expires, and what happens to it. Decided here: whole segments are dropped. When a segment's last day is older than the retention, the segment is removed as a whole. It is not rolled up into a count and it is not moved. A count of removals per period would be a new derived record with a question of its own (§5's last paragraph). A move would put the entries in a second place with a retention of its own, and the question would start again there.
The ledger says from when it holds anything. Decided here. ADR 0021 §6's rule already covers this: absence is stated, never read as zero. So: - The first segment written to a new path opens with the ledger's own start. It records the moment the ledger began, and states that removals before it are not recorded here. A ledger configured late would otherwise look like the whole history. - Each expiry appends a line to the current segment, saying that segments before a date have expired and when. A ledger that has expired entries says so rather than looking young.
When the storage holds objects for a period of its own. Storage that refuses modification commonly does it by holding each object for a set period, and refusing to remove it until that period ends. Where the data owner has configured such storage, the storage's period decides when a segment can actually go, and the ledger's configured retention cannot shorten it. That is the same shape as git deciding retention by placement, one layer down, and it is a condition, not a caveat. What the process does about it is decided here: if the data owner has declared a storage period and it differs from the configured retention, the process says so at start, beside §9's start notice, naming both periods. It does not refuse, because both periods are the data owner's.
A token that has expired from the ledger is not reused, and no rule is needed for it. A token is not derived from anything, and minting a new one never consults the ledger. Once an entry has expired, nothing at the data owner's side records that its token existed, while the software house's git still carries it in old projections. A resolver meeting it reads what it reads for any token it cannot resolve. This holds for as long as tokens are not derived (§5's condition), and it is the name table's design that keeps it so.
9. No path configured: nothing is written, and it is said out loud¶
With no path configured, the process does not write the ledger, and it says so, at start and at every removal. The other two options are refused, and the reason is the same for both: they lie. - Writing beside the store is §2's refused sibling directory. It would claim a ledger apart from the data while having none. - Refusing to remove would mean not erasing, and not erasing is worse than an imperfect record of erasing.
Empty is a state the data owner can see and repair. Apart in name only is not.
Saying it out loud is part of the decision, not a courtesy. A controller
who finds out afterwards that there was no ledger has already lost the proof,
and the point of the ledger is to have it at the moment it is needed. The
notices never name what was removed: no token and no created_at.
Otherwise the process's own log becomes a record of removals, beside the
store, under whatever backups the logs share, chosen by nobody. That is the
apart in name only ledger this section refuses, arriving through logging.
Their words, decided here:
no deletion ledger is configured for this tenant: removals will be made and not recorded
at start, and
removed, and not recorded: no deletion ledger is configured for this tenant
at each removal, printed where the removal is performed. The second is an ordinary line, not refusal-shaped. The removal succeeded, and a refusal's shape would say that it had not. The two reach different readers. The first reaches whoever starts the process and can configure the path. The second reaches whoever is removing, at the moment of the gesture.
Nothing harder to ignore than the notice. Decided here. A confirmation, or a flag the operator must pass, is the next thing somebody will propose. It is refused for two reasons. A gesture repeated at every removal is learned and passed without reading. And a flag moves the decision to whoever writes the script that passes it, away from the person the second notice reaches. The start notice repeats at every start, for as long as the path stays unconfigured.
10. Off every read path, and nothing reads it to decide anything¶
The ledger is not consulted by any reader in digline. It is not read to resolve a token. It answers no reader's question about a run. No exit code, refusal or promotion condition depends on it. It is a record somebody goes to, deliberately, to answer did this removal happen. It is never a marker a reader meets while doing something else. That distinction is what ADR 0034 §14 is about: §14 requires a removed run to be absent from every reader of the store, not that no artifact anywhere may name what went.
This holds only for as long as nothing in digline reads it, and one repair
would break it. After a removal, two messages are wrong:
- latest says "… so there is no latest one. Run it first."
(host/resolve.py), and re-running restores nothing;
- view's runs page says "No run has been recorded yet."
(report/text.py, key view.no_runs), when a run was recorded and then
removed.
Repairing either by reading the ledger, and saying removed, puts the ledger on the read path. It would become the marker a reader meets, and the distinction above collapses. Whatever repair those messages get must not consult the ledger. Which repair they get is not decided here.
The ledger does not reach the software house. Nothing that serves the software house's reads returns it, and nothing the software house sends can set its path (§2). It is the controller's record, kept towards an authority. That is exactly why it has no business crossing.
11. What the ledger concentrates, and does not remove¶
A ledger of removals is, beside a restored backup, a list of the people who asked to be erased. This section says so in its own place, because it is the cost the design carries rather than a risk it removes.
The ledger does not create the risk. It concentrates it. Without a ledger, whoever restores a backup of the name table has everything anyway. The table comes back whole, removed rows included, and ADR 0034 §6 already says "a restored backup re-identifies every orphaned token in every committed file." The ledger adds no data. What it adds is an index: these are the rows, and these are the runs, whose removal somebody asked for. Those are the people with the strongest claim not to be re-identified.
And the index comes grouped by person, at no cost. An entry carries when and who decided (§4). A removal is one person naming what goes, at one sitting. So the entries that share a decider and a time band are the rows of one request, which means one subject's rows grouped together. Refusing the request's identifier stops the ledger from naming the subject. It does not stop it from grouping the subject's rows, and the grouping needs no field of its own: it falls out of two fields this record requires.
What this record does about it: the ledger sits apart (§2). It is outside the store's backup regime, at a path with a regime of its own. The concentrate is worth the proof it buys, but not beside the data. The use is rare, deliberate and aimed at an authority, and it has no need to sit where the data is restored.
What that does not do, stated plainly: it reduces the concentrate. It does not remove it. A ledger anywhere is still a grouped list of who asked to be erased. Somebody who holds both the ledger and a restored backup has what this section describes. Sitting apart makes the two harder to hold together. It does not make it impossible. And a ledger whose retention outlives the table's backups points into nothing, while one that does not points into them. The backups' retention is the data owner's, and digline cannot read it.
Consequences¶
- A removal can be shown. An end company that removed a row or a run can show an authority when, by whom, and in what words, without showing what was removed.
- A new artifact outside
.digline/<tenant>/, the first one. It is an exception to fixed decision 2's sentence, made at acceptance, with the decision's reason kept whole (§2). - Two configuration keys that exist together or not at all: the path and the retention. Two notices whose words are fixed (§9). One refusal: a shared path (§2).
- A weaker name for a removed run, taken against a measured leak (§5). A reader matching a key to the ledger gets a count, not an assumption.
- A permanent condition on digline's readers: none of them may read the ledger (§10), and the obvious repair of two wrong messages is the one that is forbidden.
- A concentrate that is reduced and not removed (§11). It is the cost of having a record at all, and it is stated rather than hidden.
- ADR 0021 §6's journal premise is false for deletions, and its correction is owed to ADR 0021 (Names).
Alternatives considered¶
- A tombstone in the run store. Refused by ADR 0034 §14: a marker every reader of the store would meet, and an erasure left incomplete.
- A committed file at the data owner's side. Refused because it puts git where ADR 0034 §3's division holds only while there is none.
- The register. Refused, for the four reasons in §3.
- The name table itself. Refused: the table is rewritable row by row, and the ledger is append-only. They have opposite properties, and the table is the very data whose removal the ledger records.
- A sixth item inside the store. Refused by §11: inside the store, the ledger shares the store's backups.
- A sibling directory under
.digline/, or a service digline calls. Refused in §2. - The full run key in an entry. Refused on a measurement (§5).
- A default retention. A figure of three years was considered: shorter than ordinary limitation periods, longer than the practical window of a complaint, and derived from neither. It was refused in favour of ADR 0002 §6's shape (§8). A default no source fixes is still a number the product chose for the data owner, and §6 exists because a convenient default is how a policy nobody chose becomes the policy. The three statements that placed the figure are not sourced in this record, and none of them is needed once there is no default.
- Probing the storage. Refused in §7: the only probe that could tell the storages apart is the act the ledger refuses.
- Refusing to write on ordinary storage, or refusing to remove when no path is configured. Refused in §7 and §9: each makes not erasing the price of an imperfect record.
- One declaration for the whole ledger, or one per entry. Refused in §7 for one per segment.
- Rolling expired entries up into a count, or moving them. Refused in §8.
- One path for several tenants. Refused in §2 by fixed decision 8.
- A confirmation or a flag when no path is configured. Refused in §9.
Not decided here¶
- The procedure that decides a removal: who may perform one, how a person is recognised in the rows, and what happens to cases whose shared label is removed. This record keeps the record of a removal. It does not design the act.
- Whether a record of the gesture is what a controller owes. That is counsel's question. This record's position is that it records the gesture honestly and claims nothing more (§4).
- The name table's own amendment to fixed decision 2, which is an addition to its list (§2).
- ADR 0021 §6's correction (Names), including whether it reopens the expired-journal case.
- The repair of
latest's andview's messages after a removal, beyond the one repair §10 forbids. - Who may read the ledger at the data owner's side, and how it is handed to an authority. Access is the operator's, as fixed decision 8 says of every perimeter, and the handing over is not digline's act.
What this record does not claim¶
- That a removal is an erasure. ADR 0034 §14, and §4's wording.
- That the ledger cannot be rewritten. It cannot be, where the data owner's storage refuses it. Where it does not, the ledger says it was not told (§7).
- That the ledger is safe. §11: it reduces a concentrate and does not remove it.
- That
config_hashis safe elsewhere. §5 measures it for a place its inputs do not reach. ADR 0034 §12's answer for the committed reference, where its inputs sit beside it, is untouched. - That an unknown template protects a
config_hash. Unmeasured (§5). - That
created_atis unique. §4 says what the ledger does because it is not. - That it is lawful, or sufficient. Nothing here is legal advice.