Files
LithosAnanake/docs/v4.0.0/plans/2026-10-06-step6-storage.md
T
rajamesandClaude Opus 5.5 a7991f2757 docs(v4.0.0): storage -- the plan for step 6, and three details ruled into the spec
blk_subsys_init loses its unused VM argument (ruled).  Block done has a
fourth answer, no such block.  MESH.md 8.4 says which chain a number
means, that storage has a number like a node, and that a block number is
not signed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 19:12:23 -04:00

26 KiB

Step 6: Storage Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: A v4 node reads and writes blocks by sending messages; v3's block subsystem answers them; one node can have a private drive and one can have no storage (MESH.md acceptance 3).

Architecture: BLOCK and its family keep their two buffers; the one word under them sends a Block read or Block write message to "storage", which has a number like a node and is reached by the node's ordinary routes. On the storage port is a device (v4/system/storage.c) that speaks those messages and holds a view of one or two v3 block chains. A small glue file (v4/system/store_v3.c) is the only v4 file that includes v3 headers.

Tech Stack: C99 (engine, strict flags), v3's block_subsystem.c and blkio_*.c (gnu99, v3's flags), the v4 nucleus dialect (v4/capsule/*.v4), make -C v4, make -f kernel/Makefile.

Spec: docs/v4.0.0/MESH.md section 8 (rulings 8.1, design 8.2 to 8.4, exclusions 8.5) and step 6 in section 10. docs/v4.0.0/V3-PARITY.md section 1d.

Global Constraints

  • Work on branch StarForth-v4.0.0 in the main checkout. No new branch, no stash, no worktree.
  • Commit and push after every task. End commit messages with Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>.
  • No stubs, no stand-ins, no simulated devices. If something cannot be built as intended, stop and report.
  • Do not fix anything in v3 that this plan does not name. If the sanitizers or a test show a fault in v3's code, report it and stop.
  • A block is 1024 characters, 256 cells, four characters to a cell, the first lowest.
  • Message types: 4 Block read, 5 Block write, 6 Block data, 7 Block done. Block done's word: 0 worked, 1 no storage, 2 refused, 3 no such block.
  • Private block k is logical number 2^32 - 1 - k and is the private chain's block 2048 + k.
  • Node error codes: 13 "Block out of range" (existing), 17 "No storage", 18 "Storage refused".
  • Before any QEMU run read .claude/CLAUDE.md "Running / Acceptance" and the memory note acceptance-test-rules.md. One QEMU at a time, in the foreground, clean before qemu, all three ISAs, logs kept under logs/.
  • Access (claim, ACL, Stadium touch) is not checked in this step; do not add it.

Review Focus

  1. An answer lost on the way back. A passing node keeps waiting messages in 400 cells and a Block data message is 264; a third arriving while two wait is let go, and the node that asked waits for ever. Expected: no block answer is lost when two nodes use storage at once. Test in Task 5, step 4.
  2. Block numbers from the top down on 32-bit cells. They are negative there, and (FIND-BUF) refuses negatives today. Expected: -1 BLOCK reaches private block 0 at 32 bits. Test in Task 3, step 1.
  3. Block data that nobody announced. A Block data message with no Block write before it from that sender. Expected: Block done 2, nothing written. Test in Task 2, step 1.
  4. A write that is refused. UPDATE then SAVE-BUFFERS on a block storage will not take. Expected: the error message, the prompt, and the buffer empty so the next BLOCK asks again. Test in Task 3, step 1.
  5. A number no 32 bits hold, on 64-bit cells. 4294967296 BLOCK. Expected: "Block out of range", not block 0. Test in Task 3, step 1.

Unruled, to report and not to decide: a node waiting for an answer from storage that never comes (the node holding the device is asleep or killed) waits for ever, as Hera does for a birth that hangs.


Task 1: v3's block subsystem — two chains, no VM

Files:

  • Modify: v3/include/block_subsystem.h:330 and add the chain declarations beside it
  • Modify: v3/src/block_subsystem.c:169-201 (the global state), :647-652 (blk_subsys_init)
  • Modify: v3/src/main.c:319-321, kernel/src/capsule/capsule_loader.c:96-98, kernel/src/vm/bootstrap/sk_vm_bootstrap.c:306

Interfaces:

  • Produces:

    typedef struct blk_chain blk_chain_t;
    blk_chain_t *blk_chain_default(void);          /* the one chain v3 has always had */
    blk_chain_t *blk_chain_new(void);              /* another; 0 if there is no memory */
    blk_chain_t *blk_chain_select(blk_chain_t *c); /* every blk_* call acts on c from now on; returns the one before */
    int blk_subsys_init(uint8_t *ram_base, size_t ram_size);   /* the VM argument is gone */
    
  • Step 1: Record the baseline. Run make clean && make 2>&1 | tail -3 at the repo root (v3's hosted build) and note that it links. If it does not link before any change, stop and report.

  • Step 2: Make the state a struct with a current pointer. In block_subsystem.c, name the anonymous global struct and select it through a pointer, so that none of the 86 uses of g. change:

    struct blk_chain {
        uint8_t  *ram_base;
        size_t    ram_size;
        /* ... every other member exactly as it is today, except `VM *vm`, which is removed ... */
    };
    static struct blk_chain  g_default;
    static struct blk_chain *g_current = &g_default;
    #define g (*g_current)
    
    blk_chain_t *blk_chain_default(void) { return &g_default; }
    blk_chain_t *blk_chain_new(void) { return (blk_chain_t *)calloc(1, sizeof(struct blk_chain)); }
    blk_chain_t *blk_chain_select(blk_chain_t *c)
    {
        blk_chain_t *was = g_current;
        if (c) g_current = c;
        return was;
    }
    

    memset(&g, 0, sizeof(g)) in blk_subsys_init keeps working through the macro. Check every other file-scope static variable in the file (grep -n '^static [^(]*;' v3/src/block_subsystem.c): any that holds chain state moves into the struct; any that is a constant table stays.

  • Step 3: Remove the VM argument. blk_subsys_init(uint8_t *ram_base, size_t ram_size); drop the !vm test and g.vm = vm. Update the declaration and the three callers and the extern in v3/src/main.c:319. capsule_blk_init keeps its own void *vm parameter (its callers are not in this plan) and stops passing it on.

  • Step 4: Verify. make clean && make 2>&1 | tail -3 at the root links. grep -rn 'blk_subsys_init' v3 kernel --include=*.c --include=*.h shows no call with three arguments.

  • Step 5: Kernel acceptance. This changes code that only the kernel's v3 configuration runs (the kernel built without STARFORTH_V4). Boot all three ISAs in that configuration, per the Global Constraints, and keep the logs. First look at the newest logs under logs/ made in that configuration: if there are none from this branch, or the newest did not reach its prompt, the configuration may not have booted here before this change. In that case report it to Captain Bob and ask how he wants this change accepted. Do not improvise an acceptance test, and do not stash or branch to find out.

  • Step 6: Commit. git add v3/include/block_subsystem.h v3/src/block_subsystem.c v3/src/main.c kernel/src/capsule/capsule_loader.c kernel/src/vm/bootstrap/sk_vm_bootstrap.c logs/ then commit refactor(v3): the block subsystem's state is a chain there can be two of; blk_subsys_init takes no VM and push.


Task 2: The storage device and the messages

Files:

  • Modify: v4/include/v4/message.h (four types, four status values)
  • Create: v4/include/v4/storage.h, v4/system/storage.c, v4/system/store_v3.c
  • Modify: v4/Makefile (build v3's block_subsystem.c, blkio_ram.c, blkio_file.c and what they need with v3's flags; link them and v4/system/storage.c, store_v3.c into tests named test_store*.c and test_host_*.c)
  • Test: v4/tests/test_store.c

Interfaces:

  • Consumes: Task 1's blk_chain_* and blk_subsys_init; v3's blk_get_buffer, blk_update, blk_flush, blk_get_total_blocks, blk_is_valid, blk_subsys_add_raw_device, blk_subsys_attach_device.

  • Produces:

    /* message.h */
    #define V4_MSG_BLOCK_READ  4
    #define V4_MSG_BLOCK_WRITE 5
    #define V4_MSG_BLOCK_DATA  6
    #define V4_MSG_BLOCK_DONE  7
    #define V4_STORE_OK      0
    #define V4_STORE_NONE    1
    #define V4_STORE_REFUSED 2
    #define V4_STORE_RANGE   3
    
    /* storage.h */
    #define V4_STORE_TOP     0xffffffffUL       /* private block k is V4_STORE_TOP - k */
    #define V4_STORE_FIRST   2048UL             /* a chain's first block on a device */
    #define V4_STORE_PENDING 64u
    typedef struct {
        int           (*read)(void *chain, unsigned long block, unsigned char *bytes);        /* V4_STORE_* */
        int           (*write)(void *chain, unsigned long block, const unsigned char *bytes); /* V4_STORE_* */
        unsigned long (*blocks)(void *chain);   /* how many block numbers the chain answers to, fast RAM included */
    } v4_store_ops;
    typedef struct v4_store v4_store;           /* defined in storage.h; its owner supplies one */
    void v4_store_init(v4_store *s, const v4_store_ops *ops, void *common, void *private_chain, v4_cell number);
    int  v4_store_take(void *self, v4_cell value);    /* a v4_device's take */
    int  v4_store_give(void *self, v4_cell *value);   /* a v4_device's give */
    
    /* store_v3.c */
    extern const v4_store_ops v4_store_v3;      /* chain is a blk_chain_t * */
    
  • Step 1: Write the failing test v4/tests/test_store.c. It speaks to the device with v4_message_text and v4_store_take/v4_store_give directly; no node. It makes a common chain and a private chain, each blk_subsys_init with 2080 KiB of RAM and one blk_subsys_add_raw_device of 64 blocks. Checks, each one CHECK(cond, "words") in the style of v4/tests/test_host_unit.c:

    • a Block write of block 2050 then its Block data is answered by Block done 0, addressed to the sender, from the storage's number;
    • a Block read of 2050 is answered by Block data of 1024 characters equal to what was written;
    • a Block read of V4_STORE_TOP on a view with a private chain returns private block 0, and what is written there is not seen at any common number;
    • the same read on a view with only a common chain is Block done 3;
    • a read of 2050 on a view with only a private chain is Block done 1;
    • a read of block 0 is Block done 3;
    • a Block data message with no Block write before it from that sender is Block done 2 and block 2050 is unchanged (Review Focus 3);
    • two senders' writes interleaved (A's write, B's write, B's data, A's data) each land in their own block;
    • the device takes a second request while its answer to the first has not been read;
    • a chain is written through v3's own blk_get_buffer/blk_update/blk_flush, and the device reads the same bytes back: what v3 wrote reads through the port.
  • Step 2: Run it and see it fail. make -C v4 run-64-test_store.c fails to build: v4/storage.h does not exist.

  • Step 3: Find what v3's block code needs to link. block_subsystem.c, blkio_ram.c and blkio_file.c compile alone with -std=gnu99 -Iv3/include and need two symbols besides libc: log_message and sf_time_backend. Find the v3 files that define them (grep -rn '^.*log_message(\|sf_time_backend' v3/src --include=*.c), add those files, and repeat nm -u until only libc is undefined. If the chain of files reaches v3's VM (vm.c), stop and report with the list: that is a ruling for Captain Bob, not something to work around with definitions of your own.

  • Step 4: Write storage.c. It includes only v4/storage.h and v4/message.h and uses nothing from the C library, as image.c.

    • take collects words into a v4_message with v4_message_word. On a whole message:
      • Block read: queue {to = from, kind = read, block}.
      • Block write: remember {from, block} in a table of V4_STORE_PENDING.
      • Block data: find the sender in that table. If it is there, do the write now and queue {to, kind = done, status}; if not, queue done with V4_STORE_REFUSED.
      • Anything else addressed to storage is let go.
    • take returns 0 only when the queue of answers is full.
    • give builds the answer at the head of the queue when asked for its first word (for a read, the read is done then) and hands it over a word at a time.
    • Which chain a number means, as MESH.md 8.4:
      static void *chain_for(const v4_store *s, unsigned long n, unsigned long *block)
      {
          if (n == 0 || n > V4_STORE_TOP) return 0;                       /* V4_STORE_RANGE */
          if (s->private_chain) {
              unsigned long k = V4_STORE_TOP - n, have = s->ops->blocks(s->private_chain);
              if (have > V4_STORE_FIRST && k < have - V4_STORE_FIRST) { *block = V4_STORE_FIRST + k; return s->private_chain; }
          }
          *block = n;
          if (s->common) return s->common;
          if (n < V4_STORE_FIRST) return s->private_chain;                /* its fast RAM */
          return 0;                                                       /* V4_STORE_NONE */
      }
      
      The caller tells V4_STORE_RANGE from V4_STORE_NONE by the first line.
  • Step 5: Write store_v3.c. Each function selects the chain, calls v3, and selects back:

    static int v3_read(void *chain, unsigned long block, unsigned char *bytes)
    {
        blk_chain_t *was = blk_chain_select((blk_chain_t *)chain);
        uint8_t *b = blk_is_valid((uint32_t)block) ? blk_get_buffer((uint32_t)block, 0) : 0;
        int st = b ? V4_STORE_OK : (blk_is_valid((uint32_t)block) ? V4_STORE_REFUSED : V4_STORE_RANGE);
        if (b) memcpy(bytes, b, 1024);
        blk_chain_select(was);
        return st;
    }
    

    v3_write is the same with blk_get_buffer(block, 1), memcpy into it, blk_update(block) and blk_flush(block); any of those failing is V4_STORE_REFUSED. v3_blocks is blk_get_total_blocks(). Read blk_is_valid and blk_get_total_blocks in block_subsystem.c first and confirm they count block numbers as v3's BLOCK does; if they count something else, use what v3/src/word_source/block_words.c uses to bound a block number.

  • Step 6: Makefile. Compile the v3 files and store_v3.c to objects with $(CSTD:c99=gnu99) -Wall -Wextra $(OPT) -I$(ROOT)/v3/include; storage.c with the engine's strict $(CFLAGS). Add them to the link of every test whose name begins test_store or test_host_, in both the plain and the sanitizer rule.

  • Step 7: Run. make -C v4 run-32-test_store.c run-64-test_store.c and the sanitizer targets for the same file: all checks pass, 0 failures. A sanitizer report inside v3's code is reported, not fixed.

  • Step 8: Commit feat(v4.0.0): storage speaks messages -- a device over v3's block chains, common and private and push.


Task 3: The node asks by message

Files:

  • Modify: v4/capsule/blocks.v4:7-9,18,33-42,49-66 (the device comment, (DEVICE), (FIND-BUF))
  • Modify: v4/capsule/core.v4:21-22 (the error list), v4/capsule/quit.v4 (the messages for codes 17 and 18, beside the one for 16 in (RAISED); STORAGE)
  • Modify: v4/tests/host_map.h:61,66,212-215, v4/tools/mkimage.c:91,118, v4/include/v4/image.h:45, v4/src/image.c (v4_image_born loses disk, blocks), v4/include/v4/node.h:119-122,336-362, v4/src/node.c:21-57,140-141
  • Modify: v4/tests/test_node.c (remove the storage-register tests), v4/tests/test_host_quit.c:65-72,230-231,610-629,1136-
  • Regenerate: capsules/v4/nucleus-64.f18 (the build writes it)

Interfaces:

  • Consumes: Task 2's device and message types.

  • Produces: nucleus cells (STORE) (storage's number, 0: none) at BVARS + 10 and (B-TO) at BVARS + 11; the word STORAGE ( node -- ); v4_image_born(n, es, h, im).

  • Step 1: Write the failing tests in test_host_quit.c. Its node is driven by hand; put a v4_store on port 2 of it, served in the same loop that serves the console port, and tell the node 2 2 ROUTE 2 STORAGE after the nucleus is in. put_block writes through v4_store_v3.write. The existing block checks (lines 610 to 629 and 1136 on) must pass unchanged. Add:

    • before STORAGE is told: 20 BLOCK prints No storage and the prompt returns;
    • 0 BLOCK prints Block out of range;
    • on 64-bit cells 4294967296 BLOCK prints Block out of range (Review Focus 5);
    • -1 BLOCK at 32 bits, and 4294967295 BLOCK at 64, reach private block 0 of a view that has a private chain: write a character, SAVE-BUFFERS, EMPTY-BUFFERS, read it back (Review Focus 2);
    • on a view with a private chain whose device is still provisional (attach a blank blkio_ram device and do not confirm its format): -1 BLOCK DROP UPDATE SAVE-BUFFERS prints Storage refused, and a following -1 BLOCK sends a new Block read (count the messages the device took) (Review Focus 4).
  • Step 2: Run and see them fail. make -C v4 run-64-test_host_quit.c: the new checks fail and the build may fail on the removed attach call.

  • Step 3: Replace (DEVICE) in blocks.v4. The words, to be proven by Step 1's tests:

    \ ( n type -- flag )   send storage a message of one word, n.  0: there is
    \ no storage, or no way to it.
    : (B-ASK)
      push  (STORE) a! @  if NONE                \ n store            R: type
      dup (PORT-FOR)  if NOWAY                   \ n store port
      (GATE)  !b                                 \ n                  to: storage
      pop (HDR)  4 !b  !b  -1 ;                  \ from, type; four characters; n
      NOWAY: drop
      NONE: drop drop  pop drop  0 ;
    
    \ ( addr -- )   send storage the 256 cells at addr as Block data
    : (B-DATA)
      (STORE) a! @  dup (PORT-FOR)  (GATE)  !b   \ addr
      6 (HDR)  1024 !b
      a!  255 FOR @+ !b UNEXT ;
    
    \ ( addr -- status )   wait for storage's answer.  Block data goes into the
    \ 256 cells at addr and the status is 0; Block done gives its word.  Every
    \ other message that comes is kept with the messages waiting.
    : (B-AWAIT)
      (B-TO) a! !
      L: (PORT)+8 b! @b  (PORT)+9 b! @b  (PORT) +  dup b!  SWAP  (TAKE-HDR)
      (MQ-HDR) a! @  (ME) a! @  xor if W1  drop jump KEEP
      W1: drop  (MQ-HDR)+1 a! @  (STORE) a! @  xor if W2  drop jump KEEP
      W2: drop  (MQ-HDR)+2 a! @  -6 + if DATA  -1 + if DONE  drop jump KEEP
      DONE: drop  @b ;
      DATA: drop  (B-TO) a! @ a!  255 FOR @b !+ UNEXT  0 ;
      KEEP: (TAKE-KEEP)  jump L
    
    \ ( i status -- )   0: done.  Otherwise nothing is in buffer i, and the
    \ error is 17 no storage, 18 refused, 13 no such block.
    : (B-END)
      if FINE
      push  (B) + a!  0 !+  0 !  pop
      -1 + if E17  -1 + if E18  drop  NODE-ERROR b! 13 !b ;
      E17: drop  NODE-ERROR b! 17 !b ;
      E18: drop  NODE-ERROR b! 18 !b ;
      FINE: drop drop ;
    
    \ ( command i -- )   command 1: read buffer i's block; 2: write it
    : (DEVICE)
      SWAP  -1 + if RD
      drop  dup push  (B) + a! @  5 (B-ASK)  if NOWAY
      drop  pop dup push (BUF) (B-DATA)  0 (B-AWAIT)  pop SWAP  jump (B-END)
      RD: drop  dup push  (B) + a! @  4 (B-ASK)  if NOWAY
      drop  pop dup push (BUF) (B-AWAIT)  pop SWAP  jump (B-END)
      NOWAY: drop  pop  1 jump (B-END)
    

    In (FIND-BUF) remove the sign test and keep the test for 0 (if BAD). Replace the header comment's "four registers" paragraph with one sentence saying storage is asked by message (MESH.md 8.2). In quit.v4, beside ROUTE:

    \ ( node -- )   the number of what is on a storage port, that this node asks
    \ for its blocks; 0: it has no storage.  Whoever wires the node tells it.
    header STORAGE
    : STORAGE   (STORE) a! ! ;
    
  • Step 4: Take the registers out. Remove storage_reg, storage, storage_blocks, storage_command, v4_node_storage_attach and the BLOCK-COMMAND test in node.c; the four BLOCK-* constants and STORAGE_REG in host_map.h and mkimage.c (add (STORE) and (B-TO); mkimage.c:91 zeroes those two cells instead); storage_reg in image.h; the disk, blocks parameters of v4_image_born. Remove test_node.c's tests of the registers.

  • Step 5: Run. make -C v4 run-32-test_host_quit.c run-64-test_host_quit.c run-64-test_node.c: 0 failures. Then the whole suite will not build yet (boot.c, test_host_unit.c, hosted.c still pass a disk): that is Tasks 4 and 5. Do not commit a tree that does not build: go straight on to Task 4 and commit the two together.


Task 4: The lone node's storage port

Files:

  • Modify: v4/include/v4/boot.h (a storage member; v4_boot_run(const v4_boot *b)), v4/system/boot.c:115-166,338-351
  • Modify: v4/tools/hosted.c:18,58, v4/Makefile (the hosted binaries link Task 2's objects)

Interfaces:

  • Consumes: v4_device, v4_store_take, v4_store_give, STORAGE, ROUTE.

  • Produces: const v4_device *storage; in v4_boot (0: the node has no storage); #define STORAGE_PORT 2u and #define STORAGE_ID 2 in boot.c.

  • Step 1: boot.c. In the loop that serves the node's ports (lines 132 to 166):

    • a write on STORAGE_PORT is offered to b->storage->take, and the node is served when it is taken;
    • a read of STORAGE_PORT, or of any port when the console has nothing for it, is offered b->storage->give.

    Add 1u << STORAGE_PORT to the readers mask at line 351 when b->storage is set. When the nucleus is in and before the capsules, hand the node the line 2 2 ROUTE 2 STORAGE if b->storage is set; it must complete like any boot line. Confirm 2 is not CONSOLE_ID; if it is, use the next number free.

  • Step 2: hosted.c. Replace the disk array. Make the chain as v3's hosted program does (v3/src/main.c:319-340): blk_subsys_init on 2080 KiB of static RAM, then whatever device v3's hosted program attaches by default. Read those lines first and do the same; add no new command-line option. v4_store_init(&store, &v4_store_v3, blk_chain_default(), 0, 2).

  • Step 3: Run. make -C v4 hosted-check: POST: PASSED, pass=538 fail=0 on the three ISAs, and the existing COLD and FORGET lines. If the cross-compilers cannot link v3's files for aarch64 or riscv64, report the error and stop.

  • Step 4: Leave the commit to the end of Task 5, when the whole suite builds.


Task 5: Acceptance 3 in the unit of five

Files:

  • Modify: v4/tests/test_host_unit.c:20-21,39,45,96-113 and its checks
  • Modify: capsules/v4/hera.4th only if a node must be told STORAGE and its ROUTE at birth by Hera; keep every block to 16 lines of 64 characters and run build/tools/mkcapsule --lint capsules/

Interfaces:

  • Consumes: everything above.

The wiring, which is the test's and nobody's ruling (MESH.md ruling 4): storage is number 90. The common chain's device is on a free port of outer node 11. Node 13 has its own device on a free port, with a view of a private chain and the common chain, and is told 90 by that port. Nodes 10 (Hera) and 12 reach 90 through 11. Node 14 is told nothing.

  • Step 1: Write the failing checks.

    • node 12: 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS completes; node 10: 2100 BLOCK C@ . prints 65 (a block written by one node is read by another, through a node in between);
    • node 13 reads 65 at 2100 too;
    • node 13: 4294967295 BLOCK 1024 BLANK 66 4294967295 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 4294967295 BLOCK C@ . prints 66; node 12, asked for the same number, prints Block out of range;
    • node 14: 20 BLOCK prints No storage and the node answers the next line;
    • POST is still 538 of 538 on every node and the four outer nodes' dictionary hashes are still identical.
  • Step 2: Run and see them fail, then remove disks[] and the attach in host_born, add the two devices and the wiring, and tell each node its storage (90 <port> ROUTE 90 STORAGE by tell, or in hera.4th if the test's nodes are wired by Hera before the test can speak to them).

  • Step 3: Run. make -C v4 run-64-test_host_unit.c: 0 failures.

  • Step 4: Two at once (Review Focus 1). Have nodes 10 and 12 each be told, without waiting for the first to end, to write and read back ten blocks (: W 10 0 DO I 2200 + BLOCK DROP UPDATE SAVE-BUFFERS LOOP ; W), then check both ended completed and node 11's (LOST) is 0. If an answer is lost, do not enlarge the queue or change the passing rule: report it to Captain Bob with the numbers.

  • Step 5: The whole suite. make -C v4 -k test at both widths and the sanitizer run: all v4 tests passed and all v4 tests passed under ASan+UBSan. Then make -C v4 hosted-check.

  • Step 6: Commit Tasks 3, 4 and 5 together: feat(v4.0.0): a node asks for its blocks by message -- shared, private, and none and push.


Task 6: Bare metal

Files:

  • Modify: kernel/src/kernel_main.c:518-523,620-668 (the chain is set up before the v4 node starts)

  • Modify: kernel/src/v4/sk_v4.c:24,30,83-89, kernel/Makefile:616-624 (link v4/system/storage.c and store_v3.c)

  • Step 1: Read kernel_main.c:600-700 and list what the chain's setup needs that has not happened by line 523 (the heap, PCI, virtio). Move the v4 start below the setup, or lift the setup into a function called before it; whichever leaves the v3 path's order of events exactly as it is. If something the setup needs cannot be had before the v4 node starts, report it and stop.

  • Step 2: sk_v4.c. Remove sk_v4_disk. v4_store_init(&sk_v4_store, &v4_store_v3, blk_chain_default(), 0, 2); boot.storage = &sk_v4_storage_device.

  • Step 3: Acceptance. The three bare-metal boots, per the Global Constraints. Each log must show PARITY:V4_POST tests=538 pass=538 fail=0, POST: PASSED, and the typed session of the previous step's logs; add to the typed session 2100 BLOCK 1024 BLANK 65 2100 BLOCK C! UPDATE SAVE-BUFFERS EMPTY-BUFFERS 2100 BLOCK C@ . printing 65.

  • Step 4: Commit with the three logs: feat(v4.0.0): bare metal -- the node's storage port is the kernel's block chain and push.


Task 7: Write it up

Files:

  • Modify: docs/v4.0.0/MESH.md (step 6: done, what was built, what is not as intended), v4/README.md, docs/v4.0.0/V3-PARITY.md section 1d (what now goes through v3's subsystem and what is still skipped: claim, ACL, Stadium)

  • Step 1: Write step 6 up in the manner of step 5: the date, the files, the test counts, the log directories, and under "not as intended yet" at least: access not checked; anything reported under Review Focus; the unruled case of an answer that never comes.

  • Step 2: Commit docs(v4.0.0): storage -- step 6 done and push.