Skip to content
C.W.K.
Stream
Lesson 05 of 05 · published

Delete Only Before History

~12 min · delete, safety, references, mutations

Level 0Cold Vessel
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete

Delete Only Before History

Deletion still has one legitimate place: correcting a row that has never participated in work. An operator may create a misspelled or mistaken pipeline and want it gone. If no delegation references the row, deleting it removes unused configuration rather than history.

The safety condition must be checked by the canonical writer in the same transaction as deletion. A UI that first counts references and then sends delete opens a race: another session can queue work between the count and the mutation. The database-side decision must see one consistent state.

The protected oneoff row is stricter. Even with zero references it cannot be deleted because its existence is a product invariant, not a consequence of history. This shows why foreign keys alone are insufficient: referential integrity cannot express every domain rule.

A good refusal tells the operator what to do. If referenced, archive the row. If protected, edit its allowed fields or leave it alone. If unused, delete succeeds and the record should still emit a mutation event so operational history can explain the disappearance.

Resolve the Exact Target First

Show the row name, version, archival state, and reference count before offering deletion. Confirmation should repeat the stable key, not only a mutable title. Destructive operations become safer when the target is boringly explicit.

After deletion, verify that compose and get no longer return the row while existing event history still shows who deleted unused configuration. Recoverability is limited, so precision and a retained mutation receipt matter.

Deletion is valid only while nothing can cite the row. A never-used configuration mistake may disappear cleanly; once a delegation references it, removal would orphan evidence. At that point archive is not bureaucratic caution but referential integrity expressed as product behavior.

Code

Delete unused rows atomically·python
import sqlite3

con = sqlite3.connect(":memory:")
con.executescript("""
CREATE TABLE pipeline(name TEXT PRIMARY KEY);
CREATE TABLE delegation(id INTEGER PRIMARY KEY, pipeline TEXT REFERENCES pipeline(name));
INSERT INTO pipeline VALUES ('typo-row');
""")
with con:
    refs = con.execute("SELECT count(*) FROM delegation WHERE pipeline=?", ("typo-row",)).fetchone()[0]
    if refs:
        raise RuntimeError("archive referenced pipeline")
    con.execute("DELETE FROM pipeline WHERE name=?", ("typo-row",))
assert con.execute("SELECT count(*) FROM pipeline").fetchone()[0] == 0

External links

Exercise

Write a deletion decision table for protected, referenced, archived, and unused rows. Include the allowed action and user-facing guidance for each.
Hint
Protected and referenced are separate reasons even when both result in refusal.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.