Context
0252 made offline a property of every client and listed the queue’s mechanics, but stayed Proposed until the owner agreed the rows. On 2026-10-24 the owner confirmed deeper offline for the retail edition: a till keeps selling, returns a sale from any branch, redeems a gift card within a cap, and comes back in order. A shared till is also a device that can be lost, so what it holds must be sealed and wipeable. The rows of 0252 are therefore accepted, and the five rules below complete them.Decision
- Per-device order. Every queued mutation carries the device’s id (0235) and a per-device sequence number. The server applies one device’s mutations in sequence order and never applies a later one before an earlier one has been applied or rejected. Order across devices is not promised; a cross-device conflict is the version precondition of 0252 decision 2.
-
Payloads are sealed at rest. The
outboxandcachestores (0256) hold their payloads encrypted with a key that lives in thesecretsstore and is bound to the device’s session. A payload is readable only while the device is signed in and not revoked. -
Bounded replicas with an “as of” time. A client holds read models that an action needs offline, such as recent
sales across the tenant’s branches, customers and the rule data of 0337,
as replicas declared by the module (
replica: { of, window, limit, scope? }). Each replica is bounded by age and size, is refreshed in the background, and carries the “as of” time of its last refresh, which every screen that reads it shows. A refresh is incremental: the server hands each replica an opaque, monotonic change cursor, the client sends it back and receives only the changes since it, on start, on reconnect and on the refresh signal of the live query it mirrors (0315); the first fill is the only full download. A query that is not declared a replica is not available offline. A replica may be scoped by a dimension of the tenant (scope: "legalEntityId"), so a device holds only the records of its own legal entity and personal data never crosses a border inside a multi-country tenant (the legal entity is the transfer boundary, as 0343 decision 4 defines it); an action that touches a record outside the device’s scope is online-only. -
Revoke means wipe and lock. When identity revokes the device principal, or when the tenant’s offline limit
(default 24 hours, a tenant setting) passes without a sync, the client wipes
outbox,cacheandsecrets, keeps nothing readable, and locks until it is signed in again. A revoked device’s unsynced mutations are lost by design, and the server lists the device’s last acknowledged sequence so the loss is known. -
Caps per action. An action’s
offline:option gains a cap:offline: { cap: { count, amount, window } }. The client refuses the action offline once the cap is reached within the window, with the refusal of the action pipeline (0137), and the server reconciles the capped actions on sync. A gift-card redemption or a store-credit spend is the kind of action that carries one; a sale does not. -
The mechanics of 0252 stand. Client-minted ids, version preconditions on writes, retention, a queue leader across
tabs, action-version survival across an upgrade and the
offline:option are accepted as 0252 decision 2 lists them. Whether a sale is refused on stock is a product rule, not a queue rule (0334 rule 22).
Consequences
- A till that was offline replays in the order it sold, and a shop can see what a lost device had not yet sent.
- A stolen tablet holds nothing readable once its session is revoked or its offline limit passes.
- Every offline screen says how old its data is, and an action that could cost real money offline has a ceiling.
Enforcement
-
planned — a conformance test in
@stackra/storage: a refresh with a stale change cursor receives every change since it and nothing older, and a scoped replica never receives a record outside its scope. - planned — the queue conformance test of 0252 gains cases for per-device order, a rejected earlier mutation blocking later ones, wipe on revoke and on the offline limit, and a cap reached within its window.
-
planned — gen (STA-340): a replica without
windowandlimitfails; anofflineaction whose output is money without a cap is a warning the review reads. -
planned — a
@stackra/storagetest that a payload at rest is unreadable without thesecretskey.