Repository navigation
A caller can make a write conditional on the state of the block it read - #124
Merged
Merged
Conversation
… when the block has changed An agent that reads a block, decides and writes minutes later could write over an edit made in Logseq in between. Now the caller passes what it read and the command refuses, writing nothing, when the block is another. - Block JSON from get-block, find-block, get-page, get-journal-range and get-todos carries a `hash` (12 hex characters over the normalised content; folding a block and CLOCK lines do not change it). get-block also carries `tree_hash` over the block and everything under it. - --expect-hash on update-block, set-todo-status, set-block-property, remove-property --id, move-block, copy-block --remove and add-journal-block --upsert-heading (checked on the block the upsert would replace; with no match there is nothing to check). --expect-tree-hash on remove-block and its alias, because a child added after the read would otherwise be deleted with the block. --expect-marker on set-todo-status. - The check reads past the cache and runs before --dry-run, before the no-change answer and before the first write. A mismatch ends with `reason: precondition_failed` and names the current marker and first line of the block, never the current hash. - `[safety] require_preconditions` (also --require-preconditions and LOGSEQ_CLI_REQUIRE_PRECONDITIONS) makes those commands refuse without a precondition (`reason: precondition_required`). It can only tighten, a broken config refuses writes, and `doctor` shows it like read_only. The gate sits once, behind the write gate, driven by `owes=` on WriteCommand. - update-block and the upsert hold the write to the text the check saw (`block_changed` between the check and the write). - The [safety] machinery works per key, add-journal-block --upsert-heading chooses its block before it creates anything, and examples/safe-update-block.sh shows the read, check and re-read habit. Limits, stated in the docs: no compare-and-swap, the hash sees content and not position, write outputs carry no new hash yet, and copy-block --remove does not cover the window in which it copies.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #123
Summary
[safety] read_only = false +require_preconditions = true # also --require-preconditions, LOGSEQ_CLI_REQUIRE_PRECONDITIONSEvidence
After: the same call refuses with
reason: precondition_failed(shown from the test double), nothing written:collapsed::andCLOCKlines, so folding a block or a running clock does not fire it.ruff check .clean; the wheel check passes.owesmark, thealwaystext, the order againstread_only, the Upsert exception).--jsonreads.Merge Danger
Door: two-way. The switch is off by default and the new options are optional; reverting the commit removes them.
Blast Radius: JSON output
hash(andtree_hashonget-block) are new fields in the JSON of five read commands, and--max-charscounts them. Scripts that compare whole JSON blocks will see the new key. Four calls that cannot use a precondition now say so (--expect-hashwithout--upsert-heading, with several--content, onremove-property --page, oncopy-blockwithout--remove) with a usage error instead of ignoring the option.Known limits, stated in
docs/safety.md: no compare-and-swap, the hash sees content and not position, write outputs carry no new hash yet, andcopy-block --removedoes not cover the window in which it copies.