Decision records
Non-trivial changes to DocStack are recorded as architecture decision records in specs/adr/. Some are decisions; some are findings dispatched from applications built on DocStack, kept because the fix they led to is only legible next to the failure. The numbering is sparse on purpose: 0001 and 0002 are DocStack's own first records, and 0003 through 0017 were never in this repository.
| # | Title | Status | Date | In one line |
|---|---|---|---|---|
| 0001 | Sync belongs to DocStack, transports do not | accepted | 2026-08-24 | remote is any PouchDB database; DocStack owns the lifecycle, filters and the schema gate, and never takes a transport dependency. |
| 0002 | stack.db is a guarded handle | accepted | 2026-08-24 | Writes that skip the authoring path throw StackWriteGuardError; replication uses an internal handle. |
| 0018 | The document key lifecycle | finding, accepted | 2026-08-24 | DocStack never invents document keys; a keyless stack opens locked; the canary is the admission test. |
| 0019 | StackPlugin pristine capture | finding, fixed | 2026-08 | PouchDB installs core methods per instance; the plugin receives the originals as an argument. |
| 0020 | Change events carry ciphertext | finding, fixed | 2026-08 | Live subscriptions decrypt before delivery; ciphertext belongs to replication, never to a read. |
| 0021 | One changes feed per stack | accepted | 2026-08-25 | Subscribers demultiplex one feed; building a class does not subscribe it. |
| 0022 | Findings: @docstack/react 0.0.9 | findings, addressed | 2026-08-26 | The provider raced itself under double effects; hooks reported "loaded" during startup. |
| 0023 | Findings: @docstack/client 0.1.6 | findings, fixed | 2026-08-26 | Sequential ids lost writes under replication; log records and internal documents leaked to the remote. |
| 0024 | Random document ids, and replicating only what binds two instances | accepted | 2026-08-26 | Ids are Type-<24 hex>; what replicates is what the peer cannot already derive. |
| 0025 | Proposal: make useQuerySQL live | proposal, implemented | 2026-08-26 | Subscriptions derived from the query's AST. |
| 0026 | Live SQL views, and the subquery paths that never ran | accepted | 2026-08-26 | useQuerySQL is live by default; IN, NOT IN and EXISTS subqueries fixed and pinned. |
| 0027 | Log records recognised by shape | accepted | 2026-08-26 | Pre-existing bare log records stay local; the default sink level drops to warn. |
| 0028 | Ephemeral and simple classes | accepted | 2026-08-26 | Two class flags: purged on open and never replicated; stored as given with no pipeline. |
| 0029 | Proposal: hub architecture support | proposal, dispatched | 2026-08-28 | Cross-origin convergence and tenancy declared on the model. |
| 0030 | The channel is an adapter, a tenant is a stack | accepted | 2026-08-28 | Topology is configuration; a tenant is its own database; keys move with grants or the grant is fiction. |
| 0031 | Scheduling jobs on a client | accepted | 2026-08-28 | An allow-listed scheduler the application starts; missed occurrences collapse; cron refused. |
| 0032 | Reads decrypt again, and a policy arms on active: true | accepted | 2026-09-01 | The decrypting get override restored; the legacy rule engine's active contract confirmed. |
| 0033 | DocStack.sync() binds to the stacks that existed when it was called | finding, fixed | 2026-09-01 | A workspace mounted after sync() replicated nothing while every status read healthy. |
| 0034 | Late stacks join a running sync | accepted | 2026-09-01 | An un-scoped sync() is a standing instruction; getSyncCoverage() tells idle from unbound. |
| 0035 | useFind never applies an empty result | finding, fixed in react 0.1.1 | 2026-09-01 | A list could never lose its last row; staleness is now owned by a run counter. |
| 0036 | applySchemaDelta applies one attribute | finding, fixed | 2026-09-03 | Propagation returned from inside its loop and skipped in-place edits. |
| 0037 | A class patch should say what changed | proposal, accepted in property | 2026-09-03 | Restating a class dropped whatever the restatement forgot. |
| 0038 | A class patch merges its schema, and null drops an attribute | accepted | 2026-09-03 | Every delta entry applies; schemas merge attribute by attribute. |
| 0039 | Transactions stage above the plugin and commit through it | accepted | 2026-09-03 | Named write transactions with overlay reads and reported atomicity. |
| 0040 | Sync on a locked stack: three junctions | finding, resolved | 2026-09-03 | The consumer schema gate; locked deferral of class patches; revision-addressed reads serve the stored form. |
| 0041 | The patch ledger arms on active | accepted | 2026-09-03 | A ledger entry records success, deferral or a legacy application; failures retry. |
| 0042 | A patch chain applies through one internal transaction | accepted, implemented | 2026-09-03 | Chains compose in memory and land as one batch; all-or-nothing. |
| 0043 | bulkDocs class resolution ignores the batch | finding, fixed | 2026-09-04 | A patch can introduce a class and seed its first document in one batch. |
| 0044 | A patch carries one-shot jobs | accepted, implemented | 2026-09-04 | preApply and postApply migration jobs, staged with the model. |
| 0045 | Access control is cryptographic: CP-ABE scopes beside the engine | accepted, implemented 2026-09-06 | 2026-09-04 | One access-control language, enforced by decryption; the rule engine is removed, @docstack/abe carries the primitive. |
Specs
specs/01-sync.md: the replication lifecycle, filters and their identity, the schema gate, the adapter contract.specs/02-crypto-access.md: the cryptographic access architecture in full and the integration checklist for the cycle that builds it.specs/pouchdb-adapter-tauri-sqlite.md: the brief for an in-repo storage adapter that is not yet published.
Reading them
An ADR states a decision, the reasoning, and the consequences, and names the tests that pin it. When a page on this site makes a claim about behaviour, the ADR it links is where the claim is argued. If you change code that an ADR describes, update or supersede the ADR in the same change.