6a. Minimal, targeted writes
Source 06a-minimal-writes.md
Goal: each write changes as little as possible, so a wrong command does little harm and is easy to review.
- One target per command is strongly encouraged. It is not strict. A write names its target by exact ID. No wildcards, no “all”, no implicit “current” target. Bulk work is best done as many small commands, each confirmed on its own.
- A CLI that does take several targets says so in
describe(a repeatable-id). Thechangesoutput lists every target, and-change-limitcaps how many one command may touch. It is atomic over the targets where it can be, and reports exactly what was applied where it cannot (see Atomic).
- A CLI that does take several targets says so in
- Narrow verbs over general ones. Prefer
tracker task set-status -id T-12 -status donetotracker task update -file whole-task.yaml. A write takes only the fields it changes. - Patch, not replace.
updatemerges the named fields and leaves the rest alone. Whole-object replace is a separate, clearly named verb (replace). - Unset is explicit. Clearing a field needs its own flag (
-unset <field>). An empty or missing value never clears anything. - No upsert by default.
createfails if the thing exists.updatefails if it does not. Combine them only in a namedupsertverb. - Preconditions. A write can state what it expects to be true (
-if-version). An etag or revision is carried as the version token, so there is one parameter and one spelling (3a). Preconditions are optional. If the data changed since the agent last read it, the write fails with a conflict code and changes nothing.getoutput includes the version so it can be passed back. - Idempotent. Running the same write twice gives the same result and reports
unchangedthe second time. No duplicate side effects. This is a principle for every command, see section 1. - Atomic. A write either applies fully or not at all. Multi-step writes inside one command roll back, or report exactly what was applied.
- Show the exact diff.
changesin the confirm and dry-run output (section 6) lists each field asbefore -> after. If nothing would change, say so and exit 0 without writing. - Report what changed. The result lists only the fields actually changed, plus the new version.
- Guard the dangerous ones.
deleteandreplaceneed-confirmlike every mutation (it is always a bare parameter). Thechangesoutput shows exactly what will be removed or replaced. Prefer soft delete (mark deleted, keep recoverable) and print how to undo. - Limits. Caps per command (items touched, bytes written). Going over the cap needs an explicit
-change-limit N. The default is a number an adopter fixes. - Backups. For file-backed data, a write keeps the previous version (or an undo record) before it replaces anything. Backups are kept for a default time (for example 7 days, an adopter fixes the value): a write prunes backups older than that. They live in the CLI’s data folder,
~/.local/share/<cli>/backup/(section 9). - Remote systems. Same rules: one resource, one field set, version check against the remote revision, no cascading changes the caller did not name.