Skip to content

docs: concurrency, read consistency, Long/BigInt, and resource status codes#534

Open
kriszyp wants to merge 1 commit into
mainfrom
kris/qa-doc-clarifications
Open

docs: concurrency, read consistency, Long/BigInt, and resource status codes#534
kriszyp wants to merge 1 commit into
mainfrom
kris/qa-doc-clarifications

Conversation

@kriszyp

@kriszyp kriszyp commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary

Four documentation clarifications surfaced by the QA-explorer exploratory campaign. Each is a defensible-but-surprising behavior where the gap was documentation, not correctness — these write down the contract so developers don't have to discover it the hard way.

Section Where What it documents
Concurrency and Safe Concurrent Writes reference/resources/resource-api.md Atomic deltas (addTo/subtractFrom) are the only concurrency-safe write primitive; compare-and-set / read-then-write patterns (ifVersion, create-only, If-Match, read-decide-write) are not re-validated at commit, so concurrent writers can both pass. Covers the addTo no-return / no-floor limitations and the cluster replication-window caveat.
Read Consistency reference/database/api.md Per-request snapshot scope: a single request is self-consistent, a scan holds its start snapshot, but a cross-request search-then-fetch runs at two snapshots and can disagree (a hit whose later fetch 404s) — expected, not a bug. Points at single-method / transaction() for read-your-own-write.
Long vs BigInt reference/database/schema.md Long is bounded by 2^53 despite the name (not true 64-bit); use BigInt (sent as an actual bigint via CBOR/MessagePack, not a JSON number) for larger integers, including @indexed range queries.
Returning Errors and Status Codes reference/resources/resource-api.md Which throw/return shapes set the HTTP status (error.statusCode, return new Response(...), context.response.status) and the footguns that silently don't (throw {status}, a thrown Response, return {status} without headers).

No behavior changes — documentation only. Diff is +61 lines across three files.

🤖 Generated with Claude Code

…e status codes

Four clarifications surfaced by the QA-explorer campaign:

- Resource API: a 'Concurrency and Safe Concurrent Writes' section — atomic
  deltas are the only concurrency-safe write primitive; compare-and-set/
  read-then-write patterns are not re-validated at commit.
- Database API: a 'Read Consistency' section — per-request snapshot scope, and
  why a cross-request search-then-fetch can disagree (two snapshots, not a bug).
- Schema: clarify that Long is bounded by 2^53 (not true 64-bit); use BigInt
  (sent as an actual bigint) for larger integers.
- Resource API: a 'Returning Errors and Status Codes' section — which throw/
  return shapes set the HTTP status and the common footguns that do not.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kriszyp kriszyp requested a review from a team as a code owner June 20, 2026 17:46

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds documentation sections regarding read consistency, large integer types (Long vs BigInt), concurrency/safe concurrent writes, and returning errors/status codes. The review feedback points out two technical inaccuracies in the documentation: first, the term 'read-your-own-write consistency' is incorrectly used to describe a read-only sequence and should be changed to 'repeatable read consistency'; second, the JavaScript safe integer limit is incorrectly stated as 2^53 instead of 2^53 - 1.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread reference/database/api.md

Across separate requests there is no shared snapshot. A common pattern — querying for matching rows in one request, then fetching each by id in a later request — runs the two reads at two different points in time. If the data changes in between (a row is deleted or expires, say), the second read can disagree with the first; a query may return an id whose subsequent fetch returns a 404. This is expected: it is two independent snapshots, not a consistency bug.

For read-your-own-write consistency across a query and a fetch, perform both reads within a single resource method or `transaction()` callback.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The term read-your-own-write consistency refers to a client being able to immediately see writes they have just made. Since the scenario described here is a read-only sequence (a query followed by a fetch) where we want to avoid non-repeatable or phantom reads, repeatable read consistency or consistent reads is the correct terminology.\n\nSuggested change:\nmarkdown\nFor repeatable read consistency across a query and a fetch, perform both reads within a single resource method or `transaction()` callback.\n


### Large integers: `Long` vs `BigInt`

Despite the name, `Long` is bounded by the JavaScript safe-integer range — values must satisfy `|value| <= 2^53` (9,007,199,254,740,992). A `Long` attribute rejects integers beyond that range, so it is not a full 64-bit type.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In JavaScript, the safe integer range is defined by Number.MIN_SAFE_INTEGER and Number.MAX_SAFE_INTEGER, which is -(2^53 - 1) to 2^53 - 1 inclusive. Therefore, the maximum safe integer is 9,007,199,254,740,991 (not 9,007,199,254,740,992, which is 2^53 and is unsafe). The condition should be strictly less than 2^53 or less than or equal to 2^53 - 1.\n\nSuggested change:\nmarkdown\nDespite the name, `Long` is bounded by the JavaScript safe-integer range — values must satisfy `|value| < 2^53` (9,007,199,254,740,991). A `Long` attribute rejects integers beyond that range, so it is not a full 64-bit type.\n

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kriszyp wdyt about this? Should you adjust the line to be < instead of <= ?

@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-534

This preview will update automatically when you push new commits.

Comment on lines +824 to +835
```javascript
// throw an error with an explicit statusCode
const err = new Error('Not found');
err.statusCode = 404;
throw err;

// return a Response
return new Response(body, { status: 201 });

// set it on the context
this.getContext().response.status = 202;
```

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I prefer that all code blocks are actually "valid" javascript, even if incomplete. I think this can sometimes be confusing when you have what is three separate implementations all in what seems as a single block. Especially with throw/return where you really shouldn't have anything after it (since its unreachable). Also, this is somewhat vague on how it applies with promises. Like "returning a Response" is actually only valid if the user is implementing an async function. Otherwise, I think the more correct terminology is "resolve a Response".

Anyways, its honestly fine I'm being a little pedantic here I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants