feat(v4): word accounts at call -- the word ID in the header, the kernel's records, the Stadium charged per tick (#189)

ENGINE step 4 Phase 2 (plan docs/v4.0.0/plans/2026-11-13-engine-step4-phase2-word-accounts.md). Rulings,
Captain Bob 2026-11-13: "ID field in the header"; "Per heartbeat tick"; the ACL "All of it in Phase 4".

- The word ID, at xt-4 before the flags (ENGINE.md 3b). The system's words are numbered as they are
  assembled, by a new directive, #id, (and #ids, the count), in the C assembler (text.c) and in the
  machine ROM's (capsules/v4/rom), which counts in the system's own (NEXT-ID). (HEADER) numbers later
  words; FORGET gives back the IDs it frees, always the newest; COLD resets to (BOOT-ID); (SEAL) records
  it. All 313 system headers carry the cell.
- The kernel's records (v4/mesh.h): (TELL-DEFINED) and (TELL-FORGOTTEN), requests -19/-20 on port 0,
  which the kernel puts in (WORD-DEFINED)/(WORD-FORGOTTEN) when it seals a node, and reads the system's
  own words once. A bit per address marks a word's xt (calls into the ROM or headerless code are not
  words); at call, the bit test and a count. v4_mesh_charge hands the owner the calls since.
- The Stadium: stadium_words_charge -- N calls as N of stadium_word_dispatch's dispatches, shared by calls
  when the reservoir is short; sk_v4.c charges every node's words at the tick beside its opcodes, and
  stadium_word_forget before an ID is used again.
- Tests first: test_text.c, test_host_dict.c, test_host_quit.c (numbering, FORGET, COLD),
  test_mesh_boot.c (44 checks), kernel/tests/test_stadium_words.c; qemu_session.py: Hera's words
  admitted after POST.
- amd64: Stadium words: promotions=141 after POST, CONSERVED; POST 539/539; word_count=377;
  dict_hash 0xa854ba15b437d288 (the new cell); the boot 142 s against Phase 1's 153 s.
- v4 test, test-32: all pass; v4-checks: 80 programs under the sanitizers, 0 failures; the hosted
  builds alike. docs/reference/v4-dictionary.tsv: the two new words; FABRIC-3 XLVIII.24.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
This commit is contained in:
Claude
2026-11-13 19:12:44 +00:00
parent d64ad4a1c3
commit e8e7ec8b9f
44 changed files with 1060 additions and 349 deletions
+8
View File
@@ -63,6 +63,14 @@ typedef struct {
* (v4_image_seal). */
v4_cell boot_cells, fence;
/* the word IDs (#189, Phase 2): (NEXT-ID), the ID the next entry is given, and (BOOT-ID), what
* it was when the system was complete, which COLD comes back to (v4_image_seal sets it) */
v4_cell next_id, boot_id;
/* (WORD-DEFINED) and (WORD-FORGOTTEN): the xts of the words a node runs when an entry is made
* and when entries go, or 0 (dict.f18); a kernel that keeps records puts its own there */
v4_cell word_defined, word_forgotten;
/* the block window: the word address of the slots the kernel copies
* blocks into (v4/blocks.h) */
v4_cell block_window;
+28
View File
@@ -43,6 +43,21 @@
#define V4_MESH_CONSOLE 1 /* the console's number as a sender, and her port to it */
#define V4_MESH_NUCLEUS_CELLS (2u * V4_NODE_WORDS + 64u)
/* A WORD'S ACCOUNTS (#189, Phase 2; ENGINE.md 3b): the kernel's record of a word on a node, joined to
* it by the word ID in its header. The node tells the kernel of each entry made and of entries gone
* (dict.f18, (TELL-DEFINED) and (TELL-FORGOTTEN): requests V4_REQ_WORD_DEFINED and _FORGOTTEN on port
* 0); the kernel reads the system's own once, when the node is sealed. At every `call` to a word
* its record counts one: `calls` (v3's execution_heat) and `since`, which the owner takes and clears
* when it charges the Stadium (v4_mesh_charge; Captain Bob, 2026-11-13: "Per heartbeat tick"). */
#define V4_MESH_WORD_IDS 1024u /* word IDs a record is kept for: v3's DICTIONARY_SIZE, the Stadium's bound */
#define V4_REQ_WORD_DEFINED (-19)
#define V4_REQ_WORD_FORGOTTEN (-20)
typedef struct {
v4_uheat_t calls; /* every call since the word was defined */
v4_uheat_t since; /* calls since the owner last charged them */
v4_cell xt; /* the word's xt; 0: no word has this ID */
} v4_mesh_account;
typedef struct v4_mesh v4_mesh;
struct v4_mesh {
/* ---- the owner's: set before v4_mesh_boot ---- */
@@ -72,6 +87,12 @@ struct v4_mesh {
const char *const *capsules;
unsigned capsule_count;
v4_image *im; /* the map's description (v4_map_image), which the boot completes */
/* the words' accounts: `capacity` x V4_MESH_WORD_IDS records, and `capacity` x V4_NODE_WORDS / 8
* bytes, a bit for each address of a node: set for a word's xt (0: none kept) */
v4_mesh_account *accounts;
unsigned char *is_word;
/* a word has gone, its ID free for the next: the owner forgets what it keeps by it (may be 0) */
void (*forgot)(void *self, unsigned place, v4_cell id);
void *self;
/* ---- the mesh's own ---- */
@@ -106,6 +127,13 @@ int v4_mesh_tell(v4_mesh *ms, v4_cell node, const char *text, unsigned len);
unsigned v4_mesh_step(v4_mesh *ms);
int v4_mesh_busy(const v4_mesh *ms);
/* A word's record on the node in `place`, by its xt: 0 if that is not a word's xt. */
const v4_mesh_account *v4_mesh_account_at(const v4_mesh *ms, unsigned place, v4_cell xt);
/* For each word on the node in `place` called since the last charge: `each(ctx, id, calls)`, and its
* count since is cleared. */
void v4_mesh_charge(v4_mesh *ms, unsigned place, void (*each)(void *ctx, v4_cell id, v4_uheat_t calls), void *ctx);
/* The node numbered `number`, or 0. */
v4_fabric_node *v4_mesh_node(const v4_mesh *ms, v4_cell number);
+1
View File
@@ -142,6 +142,7 @@ typedef struct {
v4_cell latest; /* xt of the newest header, 0 if none */
v4_cell start; /* the word `start` named, -1 if none yet */
int header_pending; /* a header waits for its `:` */
v4_cell next_id; /* the next word ID a header is given (#189, Phase 2) */
unsigned line;
int failed;