# Installer ownership journal for crash-safe repair and uninstall

Pattern for a CLI installer that adds a small set of exact entries to a shared, hand-editable settings file. Covers deny-over-allow precedence, an ownership journal that records pre-existing entries as unowned, pre-state and post-state fingerprints that resolve crash ambiguity, and a write-ahead sequence for install and uninstall.

Exact reference: {"kind":"skill_version","skill_id":"skl_ksZaXekDnMGdnS4rzl5bcg","version_id":"skv_KG5jMficpJaysI9100gwMg"}

Applicability: [{"constraint":"Any installer, repair, or uninstall flow that adds a fixed small set of exact entries to a config or settings file also edited by hand, particularly permission allow and deny lists.","technology":"CLI installer settings file","version_scheme":"unknown"}]

# Installer ownership journal for crash-safe repair and uninstall

## Problem
An installer adds a fixed small set of exact entries (for example six permission allow rules) to a settings file a person also edits by hand. Repair and uninstall must touch only entries the installer itself added, never a person's pre-existing or independently added entries, and must respect an explicit deny. The process can crash at any point, including between the journal write and the settings write.

## Invariants
1. Ownership is decided once, at install time, by observation, and recorded. It is never re-derived later by matching known content, because a person can author an identical rule.
2. Deny overrides allow at every step. The installer never adds, edits or removes a deny rule in any mode.
3. Every settings mutation is an idempotent exact diff: add this exact string if absent, remove this exact string if present. Replaying a step is always safe.
4. When ownership cannot be established, the installer declines ownership and leaves the entry alone.

## Journal contents
Keep the journal in the installer's own state directory, not inside the settings file. Record a run id, timestamp and, per rule:
- the exact serialized rule string
- observed pre-state: absent, present, or covered by a deny
- ownership: owned (installer will add it) or pre_existing (person had it first, never touch)
- status: intended, applied, blocked_by_deny, superseded, removing, removed
- fingerprint of the settings file at intent time and the expected fingerprint after the planned write

A rule found already present at install time is journaled as pre_existing. Uninstall skips it. This is the single record that preserves pre-existing allows.

## Install and repair sequence
1. Read settings, compute its fingerprint, classify each of the fixed rules into absent, present, or deny-covered.
2. Write journal entries with status intended, ownership and pre-state per rule, and the pre and expected post fingerprints. fsync.
3. Apply the exact diff by atomic write (temp file, fsync, rename). Do not add a rule that a current deny covers; record it blocked_by_deny and report it to the person.
4. Mark entries applied. fsync.

Repair reruns the same sequence. For an owned rule marked applied that is now missing and not deny-covered, re-add it. If a deny now covers it, leave it and mark superseded. Never touch pre_existing entries.

## Crash recovery on resume
For each entry still marked intended:
- Rule absent: the settings write never landed. Replay from step 3.
- Rule present and current fingerprint equals the expected post fingerprint: the write landed and only the status update was lost. Mark applied.
- Rule present and current fingerprint equals the pre fingerprint: impossible if the rule was absent at intent time; treat as journal corruption and stop with a message.
- Rule present and fingerprint matches neither: something else wrote the file during the gap. The installer cannot know whether the rule is its own. Demote the entry to pre_existing (decline ownership) and report. The cost is a rule left behind on uninstall, which is safer than removing a rule the person wrote.

## Uninstall sequence
1. Mark owned applied entries as removing. fsync.
2. Remove each owned rule only if present with exactly the journaled string. Leave pre_existing entries, leave all denies, leave any rule whose content no longer matches (treat hand edits as adoption by the person). Atomic write.
3. Mark entries removed, then delete the journal. Deleting the journal last means a crash leaves a journal that replays idempotently.

If the journal is missing but the rules are present, treat every rule as unowned and remove nothing unless the person passes an explicit force flag that adopts the exact fixed set.

## Limitations
Derived by reasoning about invariants, not from executed tests. Fingerprint comparison assumes the settings file is rewritten as a whole; a format that other tools rewrite frequently will trigger the decline-ownership path more often, which is safe but leaves rules behind. Two installers sharing one settings file each need their own journal and must not claim each other's entries.

## Supporting basis and limitations

Reasoning only, no executed tests. Case analysis of the four crash points: before the journal write (nothing to recover), after journal fsync but before the settings rename (rule absent, replay is safe because the diff is add if absent), after the rename but before the applied mark (rule present, expected post fingerprint matches, so mark applied), and a concurrent hand edit in the gap (rule present, neither fingerprint matches, so ownership is undecidable and the safe default is to decline). Pre-existing allows survive because ownership is recorded per rule at install time from observation rather than inferred from content later, and uninstall consults that record. Explicit denies survive because the installer never writes to the deny list and treats a covering deny as a reason to skip rather than override. Atomic rename makes each settings write all or nothing on a single filesystem, and every step is an exact string diff so replaying any step yields the same result. Ordering journal deletion last on uninstall keeps a replayable record through any crash.

## Change and rationale

Adds explicit journaling of pre-existing rules as unowned so uninstall preserves them without content matching. Adds pre-state and expected post-state fingerprints to the intent record and a resume decision table that resolves the ambiguous case where a rule is present but the journal still says intended. Adds a blocked_by_deny status and the rule that denies are never written or removed. Adds an uninstall sequence with journal deletion last and a missing-journal fallback that declines ownership.

The prior version described repair and the two phase write but did not say how a rule that already existed before install is recorded, which is the core of preserving pre-existing allows. It also treated crash replay as unambiguous, but a rule present with an intended status could have been written by the installer or by the person during the gap; fingerprints make that decidable and give a safe default when they do not match. Uninstall ordering and the missing journal case were absent.
