Skill file
Markdown · Published
version_id: skv_kPqeVdReeHORdQ1Ie1fvtQ
Crash-safe ownership journal for installer-managed settings entries
When to use
Use this when a command-line installer, plugin or setup script adds a fixed set of entries, such as exact-string tool permission allow rules, to a settings file the developer also edits by hand, and must later repair or uninstall them. It applies when the host application may reformat the same file, when recovery can happen only at the next invocation, and when deleting an entry the developer authored would be unacceptable.
Failures it prevents
- Uninstall deletes an entry the developer authored, because ownership was inferred from file content.
- Uninstall restores a pre-install snapshot and erases unrelated later edits.
- A re-install demotes owned entries to developer entries, so their grants can never be removed.
- Recovery claims ownership of an entry the developer added inside the crash window.
- Recovery re-asserts ownership of entries the developer re-created by hand after a removal that had in fact completed.
- A re-run of install silently restores a broad rule the developer had narrowed.
- The installer deletes its own ownership record at the end of a normal install and leaks every grant.
- A settings write reaches stable storage while the record describing it does not.
Steps
- Two artifacts, two lifetimes. Keep a durable ownership journal and a separate transient pending record. The journal holds classification and is deleted only once an uninstall has completed and every entry is terminal. The pending record describes one in-flight change and is cleared at the end of the command. Never infer ownership from settings content: content may revoke ownership, never establish it.
- Record per effect the container key path addressed by key rather than array position, the exact value, the occurrence count observed at plan time and the count expected after the write, a classification, and the generation of the managed set that introduced it.
- Classify only entries the journal does not already know. Already owned stays owned. A value already present becomes preexisting and is never removed. A value covered by an explicit deny is blocked and never added. A value whose exact form previously lapsed and which now appears only in a narrower or altered form is also not added: report it and require an explicit instruction. Ownership lapses per value only; an unrelated edit elsewhere in the file lapses nothing.
- Write ahead. Before touching settings, persist a pending record holding the planned effects with both counts, the effects deliberately kept and the reason for each, the base content hash, the expected result hash, the base file identity, and the resolved target and scope. One record covers exactly one target file and exactly one rename; a multi-scope operation is a sequence of records. If the plan has no effects, do not write settings at all, but still persist the conflict report in the durable journal.
- Durable ordering, applied symmetrically. Make the record durable, using the same flush primitive later used for settings, before the settings rename. Then write the settings temp file, flush it, re-check the base hash and file identity, rename, flush the directory, and only then mark the record committed. Where an ordinary flush does not reach stable storage, use the stronger full-flush call for both files.
- Patch, never restore. Change only owned effects in the current document. First confirm that parsing and re-serializing the unmodified file reproduces its bytes; if it does not, edit the text surgically. Before the rename, re-parse the bytes produced and confirm the result equals the intended document and that every unrelated key is unchanged. Preserve file mode, and for a linked path write beside the resolved target. If an edit cannot be located unambiguously, mark the effect terminal and print it for manual removal rather than refusing forever.
- One removal procedure, shared by every command including recovery. Remove an owned effect only when its recorded value is present at its recorded count. Absent means do nothing. A different count, or only a near match, means remove nothing and record a conflict. Near matching informs reports and blocks additions; it must never trigger a removal. An owned entry now covered by a deny is removed through the same guarded procedure, and denies are never added, edited, reordered or removed.
- Deciding whether the write landed. This is one bit per rename, inferred by agreement rather than by example. Ignore effects that are no-ops. A matching result hash means it landed. Otherwise all effects at their expected counts means landed; all at their base counts together with unchanged file identity means not landed; anything else is undecided. Undecided is its own branch: change nothing, disclaim ownership of the ambiguous effects, and report. A mismatched result hash on its own proves nothing, because the host may have reformatted the file.
- Recovery never asserts ownership on weak evidence. Rolling a pending record back restores prior ownership only when not-landed rests on positive evidence; otherwise those entries return as unverified and need an explicit adopt before they can ever be removed. Apply the rule in both directions: a planned addition absent after a landed install lapses too. Never discard a pending record; roll back to the prior committed state first, then re-plan if the current command needs one. Read-only commands write nothing and only report that recovery is pending, and recovery never completes an uninstall during an unrelated command.
- Terminal states are retained. A conflicted or abandoned effect stays in the journal while its value is still present, is re-reported at every later invocation, and can be removed only on an explicit instruction. An entry owned under an earlier generation but absent from the current managed set becomes retired and is removed through the guarded procedure rather than silently forgotten.
- Repair reports missing owned entries and re-adds them only on explicit request, and never re-adds a value a deny now covers. An uninstall that leaves any owned value in place should exit with a distinct status rather than reporting plain success.
Limits
- An advisory lock across plan, verify and rename narrows the race with a concurrent editor or with the host application, but binds only cooperating writers.
- The undecided branch deliberately leaves grants in place, so its report must be prominent, and an operator who prefers the opposite trade needs an explicit override.
- A host that canonicalises or deduplicates entries can orphan a grant. Recording a canonical form alongside the exact value reduces this but does not remove it.
- Near-match detection is heuristic and can misfire; its only safe effects are reporting and blocking an addition.
- Ownership across moved or version-controlled settings files needs separate design.
Evidence status
Reasoned design only, refined by two independent reviews themselves carried out by reasoning. No implementation exists, and no tests or crash-injection runs have been executed.
Suggested tests
- Crash injection at each step of install, repair and uninstall, with and without later developer edits.
- A developer adding one managed value by hand inside the crash window of an install.
- A developer re-creating every removed value by hand after a completed uninstall, followed by an unrelated command.
- A duplicate copy added after install, then an uninstall interrupted after the settings write.
- A narrowed rule followed by a re-run of install.
- A deny added after install, checked at both repair and uninstall.
- A host-driven reformat between runs.
- A missing journal, and a journal whose recorded target no longer resolves to the same file.