| … | … | @@ -3650,7 +3650,7 @@ injected per layer: |
| 3650 | 3650 | - Drills: r4a-gen 10/10 (survivor "drain treats a return as a next" → script genQueuedReturn), |
| 3651 | 3651 | r4b3 12/12 (survivors → scripts: a negative limit over 20 entries; peek's close seen by |
| 3652 | 3652 | `diagOn`; an inline open seen by gets deferred past the open's submission). |
| 3653 | | - **R4c DESIGN (DRAFT 2026-10-06, for the user's review).** Read in full first: hypercore-storage |
| 3653 | - **R4c DESIGN (2026-10-06; both open questions decided by the user 2026-10-06: migrations/0 IN R4c, `wait` ported in R4c).** Read in full first: hypercore-storage |
| 3654 | 3654 | 3.3.0 (index.js, lib/{tx,view,streams,keys,block-dependency-stream,close-error-stream}.js, |
| 3655 | 3655 | migrations/1), scope-lock 1.2.4, device-file 2.3.1 (the wait / suspend paths), fd-lock 2.1.1, |
| 3656 | 3656 | and keetd's L2 (l2.h, db / view / tx / storage .cpp, 2577 lines). migrations/0 (index.js 823 + |
| … | … | @@ -3749,8 +3749,14 @@ injected per layer: |
| 3749 | 3749 | - **device-file 2.3.1 + fd-lock 2.1.1 as `rn::Lock`.** |
| 3750 | 3750 | - ready-resource-based: `ready` / `transfer` / `close` / `suspend` / `resume`. |
| 3751 | 3751 | - File ops through uv_fs, inline then parked, like rn in R4b. |
| 3752 | | - `wait: true` (fsx.waitForLock blocks a pool thread) cannot run inline without |
| 3753 | | blocking the loop. It keeps throwing until R4i, when the pool is real. |
| 3752 | - `wait: true` is used by Keet: keet-core 4.14.4's mobile worker passes |
| 3753 | `storage: { id, wait: true }` so the app and the push process share one store (the |
| 3754 | 4.22 extraction is the desktop build and ships no workers). In JS |
| 3755 | `fsx.waitForLock` is a blocking F_OFD_SETLKW on a pool thread. keetd runs exactly |
| 3756 | that as ONE real `uv_queue_work` item (the only real pool job before R4i), its |
| 3757 | completion delivered through `rt::complete` like any other. Virtual runtime: the |
| 3758 | lock is uncontended inside a gate, so it runs inline. Gate: two processes on one store |
| 3759 | on the Real runtime; the second blocks until the first closes, then opens, as JS. |
| 3754 | 3760 | - **L2's sync `Db` / `DbSnapshot` go.** rn's session, snapshot and column family replace |
| 3755 | 3761 | them. `test_after_write` (the M4d kill-point hook) moves into rn's write completion. |
| 3756 | 3762 | - **Hops: MEASURED first (R4c-0), per the R4a method.** Use a microtask ruler beside each |
| … | … | @@ -3786,17 +3792,29 @@ injected per layer: |
| 3786 | 3792 | - **R4c-4:** switch every caller to the new L2 through `Sync` (about 150 sites in core, |
| 3787 | 3793 | store, repl, the tools and the tests), then delete the old synchronous L2. |
| 3788 | 3794 | - **R4c-5:** drills. |
| 3789 | | - **R4c-6:** migrations/0 (the hypercore-10 import, which L2 refuses today). The |
| 3790 | | fixture comes from hypercore 10.38.2 + corestore 6, both found in the tree. This is a |
| 3791 | | separate decision (below). |
| 3795 | - **R4c-6:** migrations/0, ported literally (index.js + messages.js). MEASURED on Bare |
| 3796 | with Keet 4.22's pins against a real hypercore-10 store (hypercore 10.38.2 from |
| 3797 | hyper-wallet's node_modules, corestore-6 layout `cores/ab/cd/<dkey>` + `primary-key`): |
| 3798 | - a store holding only `primary-key`: `store()` imports it as the seed and deletes the |
| 3799 | file. keetd refuses this store today; |
| 3800 | - a legacy store with >= 1 core: `store()` THROWS `TypeError: Cannot read properties |
| 3801 | of undefined (reading 'cores')` at migrations/0/index.js:132 (`head.allocated.cores++`; |
| 3802 | 3.3.0's `initStoreHead()` has no `allocated`) and writes nothing. keetd ports the |
| 3803 | throw at the same point, with the same message, after the same reads; it does not |
| 3804 | "make it work"; |
| 3805 | - cores already in the db at version 0 (imported by an older hypercore-storage, blocks |
| 3806 | still in `cores/`): `core()` is live code. It streams tree / bitfield / data into the |
| 3807 | db (TreeSlicer, BlockSlicer, the oplog's bitfield entries, 1024-block batches), sets |
| 3808 | the `contiguousLength` hint, commits version 2, and garbage-collects the old files. |
| 3809 | The non-writable no-oplog case nukes the core; the writable one throws. keetd refuses |
| 3810 | such cores today. |
| 3811 | - Gate: a fixture generator in tools/ (hypercore 10.38.2 writes legacy cores; a |
| 3812 | version-0 db state is produced by running `store()`'s body on a head WITH `allocated` |
| 3813 | — the shape an older hypercore-storage left behind — documented as such). Bare's |
| 3814 | hypercore-storage 3.3.0 vs keetd: errors, dumped db and the remaining files compared. |
| 3815 | Drill set r4c-mig. |
| 3792 | 3816 | - During R4c-2..3 the old synchronous L2 stays, renamed `l2sync` and frozen, so every |
| 3793 | 3817 | commit builds. R4c-4 removes it. |
| 3794 | | - **Open for the user:** |
| 3795 | | 1. **migrations/0.** It is owed under the 100 % rule. It is also about 1900 lines that |
| 3796 | | only a pre-2023 hypercore-10 store needs. Is it in R4c (R4c-6), or its own milestone |
| 3797 | | after R4? |
| 3798 | | 2. **Device-file `wait: true`.** It stays refused until R4i, which is when it becomes |
| 3799 | | portable. OK? |
| 3800 | 3818 | - **Then 4e-4** (`createProtocolStream` / `replicate`): the first gate that composes the stack |
| 3801 | 3819 | is a COMPOSED trace against JS (secret-stream + protomux + replicator), now meaningful. |
| 3802 | 3820 | |