HarperFast / HarperFast/harper

Document lock()'s exclusion-only limitations in the public API documentation

Open Beginner friendly
#2,547 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
89
Forks
10
Avg merge
2d 6h
Merged PRs (30d)
200

Description

The Phase 1 `lock()` guarantee was settled as **exclusion-only**
([harper#483 comment](https://github.com/HarperFast/harper/issues/483#issuecomment-5603461590),
`docs/record-lock-ownership.md` §10). That decision was taken *on the condition* that the two things
`lock()` does not promise are documented rather than implied — §10 says so in terms:

> Nothing above may be softened into "rare" or "best-effort" in the API docs, and neither limitation
> may be described as crash-only or as unreachable on a clean handoff.

The design note is the normative source and `DESIGN.md` routes writers to it, but the §14 work
decomposition assigns issues to every *implementation* slice and none to the documentation change.
This issue is that owner.

## What the public `lock()` documentation must say

Lifted from §10, which is normative and must not be paraphrased into something weaker:

1. **`lock()` guarantees exclusive admission** of a critical section for a key, and successor
freshness after a clean handoff — the latter only while the key's home still holds that handoff's
dependency set.
2. **A predecessor's write can outrank its successor's.** `lock()` changes nothing about how two
conflicting writes resolve, so whatever the pair would do to the record without a lock is what
they do with one, silently and with no error raised. Reachable on a *completely clean* handoff
when a caller stamps a future `context.timestamp`.
3. **Successor freshness is not promised on the recovery path** — the predecessor crashed, is
unreachable, or its native commit settled after the recovery barrier was measured. Both the
predecessor's transaction and the successor's derived write end up wrong, which is exactly the
read-then-conditionally-write case `lock()` exists for.
4. **There is no caller-side mitigation.** The obvious candidate (`X-Replicate-To` / `confirm=`) is
super-user-gated and entangled with residency, and closes none of limitation 3's routes anyway.
5. **Neither limitation is crash-only, and both are reachable on a clean handoff.** Three separate
pre-push review rounds on #2498 produced text that got this wrong in three different directions,
so it is worth stating plainly rather than in a caveat.

## Why this is worth its own issue

The honesty argument is load-bearing for the *decision*: exclusion-only was chosen over fenced and
quorum-confirmed (#2540) partly because the limitations would be written down. If Phase 1 ships
behind its gate and the public `lock()` page still describes exclusion without (2) and (3), an app
author reaches for `lock()` for read-modify-write and hits the failure the design note predicts, with
no warning anywhere they read — and the tradeoff that justified the decision was never actually paid.

Blocked on nothing, but it should land with or before the Phase 1 enablement, not after.

Refs #483, #2540

🤖 Filed by Claude Opus 5 on behalf of Kris.

Contributor guide

Open the contributing guide

Research direction

Read docs/record-lock-ownership.md §10 and DESIGN.md first, then locate the public lock() API documentation they govern. Update that page to state the five listed exclusion-only guarantees and limitations without weakening them, including clean-handoff reachability and the lack of caller-side mitigation. Done means the public documentation matches the normative wording and covers both failure paths.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
documentation
Issue type
Documentation
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.