# Pathrule Pattern: Browser Storage and IndexedDB (1.0.0)
# ::pathrule:package:browser-storage-indexeddb

### [RULE] Keep IndexedDB transactions synchronous in ownership  (path: /src/storage)
<!-- scope: folder | priority: high | strict -->

IndexedDB transactions can become inactive when control returns without a pending request. Awaiting network calls, timers, or unrelated promises inside a transaction can make later writes fail after partial application logic.

- Load remote data and perform expensive computation before opening the transaction, then revalidate local assumptions once the transaction begins.
- Create all reads and writes that form one invariant from the same transaction and wait for its completion event before reporting durable local success.
- Abort on validation or write failure and treat transaction abort as a first-class result, not an exception to suppress.
- Keep transaction scope to the required object stores and duration so one tab does not block upgrades or unrelated local work longer than necessary.

See /src/offline for the adjacent decision or procedure that completes this constraint.

---

### [RULE] Do not persist reusable secrets in script-readable storage  (path: /src/storage)
<!-- scope: folder | priority: high | strict -->

All script-readable origin storage is available to code executing in that origin, including compromised dependencies and injected scripts. Obfuscation or a key stored beside ciphertext does not create a meaningful boundary.

- Use protected cookie or platform credential mechanisms for reusable session secrets when the architecture supports them.
- Persist only the minimum offline data the product contract permits, and classify personal or sensitive fields before writing them.
- Delete user-scoped databases, caches, queues, and cross-tab state on sign-out or account removal according to the privacy contract.
- Do not log stored records during migration or corruption recovery; diagnostics should use schema versions, keys, counts, and non-sensitive error codes.

See /tests/storage for the adjacent decision or procedure that completes this constraint.

---

### [RULE] Give cross-tab work a lease and idempotent identity  (path: /src/offline)
<!-- scope: folder | priority: high | strict -->

Each tab has its own JavaScript runtime but shares origin storage. Storage events or broadcast messages notify peers; they do not provide durable mutual exclusion or exactly-once execution.

- Give every queued operation a stable idempotency key that the server also understands.
- Acquire a time-bounded lease or use a single worker owner for replay, and renew only while the owner is alive and making progress.
- Recheck operation state before external submission and before final local commit because another tab may have completed it after the first read.
- Broadcast state changes for responsiveness but recover truth from storage after missed messages, suspended tabs, or browser restart.

See /src/storage for the adjacent decision or procedure that completes this constraint.

---

### [MEMORY] Schema upgrades are short structural transitions  (path: /src/storage)

An IndexedDB upgrade blocks other connections and can be blocked by old tabs that keep the prior version open. Long record-by-record work inside the version-change transaction creates startup stalls and fragile recovery.

- Use the version-change transaction for creating, deleting, or renaming stores and indexes and for only the bounded data changes required for structural validity.
- Prompt or coordinate old tabs to close when an upgrade is blocked, and provide a usable recovery path rather than waiting forever.
- Record a separate data-migration cursor and process large transformations in resumable batches after the database opens.
- Test upgrade from every supported stored version and preserve a reset or export path when corrupted legacy data cannot be migrated safely.

See /tests/storage for the rule or workflow that puts this decision into practice.

---

### [MEMORY] Browser persistence is a rebuildable cache unless the product says otherwise  (path: /src/storage)

Browsers can evict data, users can clear it, and storage availability differs across contexts. If local data is the only copy, that is a product-level durability promise requiring backup and user communication, not an implementation shortcut.

- Classify each store as cache, draft, queued command, downloaded content, or local-only user data and assign recovery behavior.
- Estimate usage and handle quota errors without deleting unrelated stores or looping on the same failed write.
- For rebuildable caches, version the cache key and allow a full reset from authoritative data.
- For local-only user content, provide export, backup, and explicit deletion semantics and test them before claiming offline durability.

See /src/offline for the rule or workflow that puts this decision into practice.
