# Ownership journal for installer-managed allow rules
## When to use
Use this when a CLI installer adds a small fixed set of exact permission allow rules to a settings file that the developer also edits by hand and that may contain explicit deny rules. The installer must offer repair and uninstall that never remove a rule the user wrote, never disturb unrelated settings, and never add, remove or bypass a deny. The settings write and the ownership journal cannot share one transaction.
This is a reasoned design, corrected after two independent adversarial reviews. No executed tests back it.
## Effects model
The installer owns effects, not the file. An effect is one of: an allow list entry identified by target file, exact rule string and the number of instances the installer inserted which is zero or one because the installer never inserts a string that is already present; the installer own namespaced witness entry in that file; optionally a container the installer created such as the file itself or an empty allow list recorded so uninstall can remove it only if it is still empty. Nothing else in the file is ever read for ownership or written. Every command is a structural edit: parse, change only owned effects, serialize. Never restore a pre-install snapshot; it would overwrite every unrelated edit made since.
## Invariant
The journal must always claim at least as much as the installer has placed in settings, and every command runs recovery first. The invariant bounds what the journal claims. It says nothing about who wrote a string that is present now, so it never justifies removing a rule whose provenance is uncertain.
Install: journal a pending intent first, settings second, journal confirmation to owned third. Uninstall: journal a releasing intent first, settings shrink second, journal released third, journal deletion last.
## Landing evidence
At intent time the installer already holds the parsed file and the plan, so it can serialize the exact bytes it will write. Record three things in the intent: the pre-write digest, the predicted post-write digest, and a fresh random marker that the write places in the witness entry. Recovery compares the current file digest: equal to the predicted digest means the write landed, equal to the pre-write digest means the write never happened, anything else means another writer touched the file. Use marker equality as a secondary hint, and resolve any remaining doubt toward touching nothing and reporting. Marker presence alone is never evidence. An older marker from a previous attempt is always present after the first install, and a host application or editor may strip an unknown entry. Only equality with the marker of this specific intent counts.
## Marker verification gate for uninstall
Before removal, verify cryptographic proof of ownership. For each owned record, check that the witness marker in the current settings file equals the recorded journal marker. If the marker is absent or mismatched, set removal count to zero and report an ownership conflict. This prevents four critical failures: removing a rule the developer manually re-added with identical text after removing the installer version, removing a rule when external tools stripped the witness marker, claiming ownership of a value the developer independently set to match the installer target, and proceeding with removal when provenance is uncertain. The marker verification gate closes the ownership gap between tracking ownership via journal and enforcing removal via string matching alone.
Removal count calculation becomes: IF marker in settings does not equal journal marker THEN removal count equals zero ELSE removal count equals minimum of current exact match count and recorded insert count.
## Journal records
One record per target file and exact rule string, plus one witness record per target file. States: pending, owned, preexisting, vetoed, releasing, released. Preexisting rules were present before install and are never removed or re-added. Vetoed rules had a matching deny at install and were not inserted. Released rules were removed by uninstall or were tombstoned after being observed absent, with a conflict note. Records also hold installer version, managed rule set, insert count, and the digests and marker of the current intent. Write the journal with a temporary file, flush, and atomic rename. An unparseable journal fails closed: refuse repair and uninstall, report, and require an explicit force flag whose only permitted action is removing exact managed strings with a loud report since preexisting status is unknown. Canonicalize target paths, resolving symlinks and case differences, so a second install cannot create duplicate ownership.
## Recovery, run first by every command
Pending records: landed by digest or witness marker equals this intent then promote to owned, not landed by digest then discard the intent, file changed by another writer and rule absent then tombstone as released with a conflict note, file changed by another writer and rule present and marker not equal then ambiguous stay pending report and require the developer to claim or disclaim explicitly. Releasing records: landed by digest then mark released, not landed by digest then rebuild the plan from the current file and retry, file changed and rule absent then mark released, file changed and rule present and witness marker equals the recorded one then the shrink did not happen rebuild the plan and retry, file changed and rule present and witness absent or different then the shrink may have landed and the developer may have re-added the rule do not remove it mark released with the note possibly re-added by developer. Owned record with rule absent: the developer removed or edited it by hand tombstone as released. Install that meets releasing records completes the release first then proceeds with a fresh intent. Recovery is per record and per target file.
## Deny handling
A deny that exactly matches a managed rule at install time vetoes insertion. Record vetoed and tell the user. A broader deny pattern does not veto; the allow is inserted and shadowed which is consistent with never touching denies. A deny added later for an owned rule blocks repair from re-adding; uninstall still removes the installer allow. The installer never adds removes or rewrites a deny under any command.
## Repair
Repair requires a journal; with none report not installed rather than behaving as install. Run recovery then per record: owned and present nothing, owned and absent already tombstoned re-grant only on explicit confirmation or reinstall, preexisting and absent nothing, vetoed with the deny now gone fresh intent insert promote to owned, rules newly managed in this version fresh intent insert, rules no longer managed but still owned remove as in uninstall but rewrite the witness with a fresh marker instead of removing it while any other rule stays owned.
## Uninstall: compare before remove with marker verification
One take a lock that spans the whole command from recovery through the final journal write parse the current file if it is empty or unparseable refuse to write. Two build the plan from the current parse. For each owned record verify that witness marker in settings equals journal marker. If marker absent or mismatched set removal count to zero and report ownership conflict. Otherwise remove the smaller of the recorded insert count and the current exact match count; zero matches means modified or removed by the developer so plan no change and report a conflict. Always plan removal of the witness entry if its value equals the recorded marker independent of rule records. Plan removal of a recorded container only if it is still empty. Three write the releasing intent with the plan pre-write digest predicted digest and marker in one atomic journal write. Four apply the plan to the parsed structure and touch nothing else. Five self-check: the semantic difference between the old and new parse must equal the plan exactly else abort. Re-read and abort if the digest changed since step one. Write with temporary file flush of file and directory atomic rename. Six mark records released. Delete the journal only when every record including the witness record is released preexisting or vetoed. Matching is exact string equality only. Fuzzy or prefix matching is rejected because any similarity rule can be satisfied by a user rule. An in-place edit of an owned rule is indistinguishable from delete plus user add and exact matching classifies it correctly.
## Conflict report
One line per record with a fixed category: removed, left modified or removed by developer, left possibly re-added by developer, left ambiguous ownership, left preexisting, left extra duplicates, left deny present, left witness changed, left found in a different scope file, left marker verification failed. Offer a dry-run flag that prints the plan and report without writing. Use a format-preserving editor when the format supports comments and warn once that re-serialization may normalize formatting.
## Known limits
A rule the developer removed and re-added by hand between commands is indistinguishable from untouched and will be removed by uninstall. Document it. If the host application deduplicates identical strings a developer duplicate of an owned rule collapses and uninstall removes the survivor. The window between the final re-read and the rename is inherent; the lock narrows it against the installer own commands only.
## Anti-patterns
Treating witness presence or absence as proof of what the installer did. Removing a present rule because the journal claims it when another writer has touched the file since the intent. Silently discarding an intent when the file changed so repair re-grants a removed rule. Tracking the witness only through rule records so it is orphaned when every rule is tombstoned. Locking per write instead of per command. Restoring a pre-install snapshot on uninstall. Removing a rule that merely resembles an owned rule. Guessing ownership when the journal is unparseable. Touching deny lists for any reason. Calculating removal count without verifying marker equality first.
## Supporting basis and limitations
Derived by reasoning about crash points on both sides of the settings write for install and uninstall during the journal write and between target files then checked by two independent adversarial reviews that produced concrete failing scenarios. The first review found that inferring landing from witness presence rather than from predicted digest and marker equality or resolving ambiguity in the direction that removes or claims a rule led to removing developer-written rules disclaiming installer allows and tombstoning rules the developer never saw. The second review found four failures from the missing marker verification gate at uninstall: developer manually re-adds identical rule after removing installer version uninstall removes it, external tool strips marker uninstall proceeds without proof, developer sets value to match installer target between planning and writing installer claims it, backup restore between verification and write resurrects rule but journal claims released. All scenarios are reasoning only not executed tests.