Commit Graph
14 Commits
Author SHA1 Message Date
Claude e8e7ec8b9f 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
2026-11-13 19:12:44 +00:00
Claude 046ce0be65 feat(v4): the mesh boot to spec -- Hera born empty in the kernel's fabric; births, kills, every node stepping together (#189)
ENGINE step 4 Phase 1, Tasks 5b-5d, and the edge cases (Captain Bob, 2026-11-13: "Build it to proper
spec"; "Check for the edge cases"; "Yes, add it to v4-checks").

- v4/system/mesh.c, v4/include/v4/mesh.h: the nucleus assembled by the ROM and given to Hera as F18
  cells; Hera born empty at place 0, the kernel on port 0, the console on port 1; told she is 10, in the
  registry, the kernel's words, FORTH-79, sealed, POST, the kernel's capsules. NODE-BORN / NODE-KILL in
  the owner's room.
- No scheduler: v4_mesh_tell returns once the node told says how its text ended, and
  v4_mesh_step / v4_mesh_busy let the host step the fabric while it waits, so nodes run between
  lines as during them. A text left "waiting" is owed its end: the next line ends it "Interrupted"
  and is then run (MESH.md 7b.6).
- kernel: sk_v4.c boots through the mesh; its idle steps the fabric while a node can run, and halts
  only when none can (#151 kept). stadium_return_quota and stadium_ops_forget on a kill.
- Tests: v4/tests/test_mesh_boot.c (32 checks: the boot, births, kills, rebirth, a live number, a
  fault, no such node, Hera not killing herself, no room, a line too long, a node running for ever,
  a wait broken by the next line), run by `make -C v4 test` and under ASan+UBSan by `sanitize`
  (v4-checks); kernel/tests quota return; scripts/qemu_session.py births() and the edges on bare
  metal.
- Docs: ENGINE.md 6 "who runs next" struck (settled: no scheduler); the Phase 1 plan; FABRIC-3
  XLVIII.23; .claude/memory/rules.md: alpha.5 closed to new work.
- Evidence: v4-checks 80 programs under the sanitizers, 0 failures; the hosted builds alike; two
  stopped v4-checks runs labelled STOPPED; three development amd64 boots labelled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
2026-11-13 17:00:08 +00:00
Claude dd6c393a89 feat(v4): HEAT-OP[0..31] and ANTICLOCK, read by HEAT-OP@ and ANTICLOCK@
#189 -- Captain Bob, 2026-11-12: "Add HEAT-OP. If it's a huge performance
hit, we'll revert it. If not ... it stands"; a full 33-cell array, as
DECOMPOSITION.md section 7 draws it; the Stadium feed is Phase 1's.

- node.h/node.c: v4_node_heat_regs_attach; a data fetch from base+k gives
  opcode k's count, base+32 the anti-clock (the low cell at 32 bits); a
  store changes nothing. Reset detaches them.
- host_map.h: HEAT_REG at word 13824, in what was free between the
  dictionary space and SEND_TEXT; the compile-time check covers it.
  Nothing moved. map-*.f18: HEAT-OP 13824, ANTICLOCK 13856.
- image.h/image.c/mkmap.c: the image carries the address; v4_image_born
  attaches the node's own counts.
- system.f18: HEAT-OP@ ( op -- n ), op mod 32; ANTICLOCK@ ( -- n ).
  word_count 318 -> 320 (hosted 317 -> 319): dict_hash changes.
- v4-dictionary.tsv: both words; DECOMPOSITION.md 7 records the build.

Also in this batch:
- Makefile: make init installs qemu-user -- hosted-check needs it
  (Captain Bob: "Add to make init now").
- .claude/memory/rules.md, rule 5: stop and ask when something comes up
  (Captain Bob: "you are supposed to stop and ask").

Tests first (logs/20261113-005047/heat-op): test_node did not compile;
test_host_quit 3 of 1337 failed. Suite: 199 programs, 7448554 checks, 0
failures; hosted-check, the three alike. Timing: no measurable cost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
2026-11-13 00:50:56 +00:00
Claude 3bd81097e1 chore(license): an SPDX header on every source file that had none (LicenseRef-Starship-1.0) [skip ci]
The header scan (Captain Bob, 2026-11-10): 788 source files -- 351 with the
SL-1.0 header, 12 with the old name (docs/working/experiments, kept by
ruling), 31 under someone else's licence (tools/kconfig, Linux's, GPL-2.0:
kept), and 394 with none. Ruled: the SPDX form; capsules (.4th, .f18) and
proofs (.thy) left for a ruling of their own (mkcapsule's 64x16 block format,
content-addressed capsules).

253 files now begin
    SPDX-License-Identifier: LicenseRef-Starship-1.0
    Copyright (c) 2023-2026 Robert A. James
as a /* */ block (C, headers, assembly, linker scripts) or # lines (scripts,
Makefiles, Kconfig; below a shebang or a coding line); tools/mkcapsule.c,
which had the copyright line, gets the SPDX line only.

Not touched: docs/working/ (archive and old campaign material, as the
ruling kept the experiments); v4/system/post_cases.c (generated by
v4/tools/mkpost.py, "do not edit" -- the generator has the header).

Comments only: the kernel builds on amd64, aarch64, riscv64; make -C v4
test-32: 39 programs, 0 failures; every changed script parses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
2026-11-10 04:12:49 +00:00
rajamesandClaude Opus 5.5 afd9d46d29 feat(v4): the system's UM*, UM/MOD, D+, DNEGATE, Q.* and Q./ call the ROM
MACHINE.md 2.2.  Each is its entry's address, push and ;.  Every node the
tests make carries the host ROM (host_load, Hera's births, the depth and
mesh tests' own nodes), and a division by zero inside the ROM returns to
the prompt (hosted-check).  test_host_quit's fetch outside memory moves
past the ROM's range: 16384 is the ROM's first word now the tests' system
has its ROM, as the product's always had.  dict_hash 0xfec8c47cfc6f437f.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 20:16:50 -04:00
rajamesandClaude Opus 5.5 11b5d402b1 feat(v4): the shared math in both ROMs, and a mesh node's ROM
MACHINE.md 2.2.  UM*, UM/MOD, D+, DNEGATE, Q.* and Q./ are entries 0-5
of the host ROM and of a mesh node's ROM, from one source (rom/math.f18)
and one entry list (v4/rom_entries.h).  The host ROM starts at entry 18.
The mesh ROM is 277 words; the host ROM 2372.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 19:46:00 -04:00
rajamesandClaude Opus 5.5 a28b5f2230 fix(v4): the final review's six minors in the ROM boot
- Text after start is refused, as text.c refuses it: before it jumps, the
  ROM reads on to the end of the source; blanks, comments and the ends of
  blobs may follow, a token is ERR-AFTER (26), "text after start".
- A token too long where a name, a target or a value is wanted is "name
  too long", as text.c says: (MISSING) reports "missing" only when no error
  came first.  `", keeps "missing", which is text.c's word for both.
- text.c's "address out of range" names the address, not the value.
- The system's source files are one list, v4/sys_files.h: boot.c, the
  harness and the nucleus test are made from it.
- The ROM's error codes and words are one list, v4/rom_errors.h: boot.c's
  messages, host_map.h's ROM_ERR_* and mkmap's ERR-* are made from it.
- node.h says what v4_node_store does with a ROM address (nothing, as for
  any address outside RAM, D-14); test_host_rom_range pins it.

ROM: 2095 words, rom_hash 0x06d0dcb7a0cb41a1.  dict_hash unchanged,
0xe5a57f3eb72ff94a.  make -C v4 test test-32 hosted-check pass.  QEMU:
amd64, aarch64, riscv64 to ok>, POST 538/538, POST: PASSED.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 17:10:45 -04:00
rajamesandClaude Opus 5.5 ff75e69e91 fix(v4): the final review's four defects in the ROM boot
- The boot left the source's last new line in the console input, and the
  first KEY after the boot read it.  What the ROM has not read when it
  starts the system is taken back (boot.c, rom_harness.h).  hosted-check:
  KEY after the boot reads the key typed.
- A comment or macro left open at the end of a blob ran on into the next,
  and the ROM accepted source text.c refuses.  The loader ends each blob
  with FS (V4_ROM_BLOB_END) after its new line; the ROM ends a blob there
  as text.c ends a file: an open comment or macro is an error, and the word
  being assembled ends.  test_host_rom_asm: seven blob pairs against text.c.
- store to an address outside RAM faulted the ROM with no message.  It is
  now refused, as text.c refuses it: ERR-RANGE, "address out of range".
- The kernel build did not regenerate capsules/v4/sys/map-<w>.f18 before
  packing the capsule directory; it now does.

ROM: 2084 words, rom_hash 0x4c458c6e48b35456.  dict_hash unchanged,
0xe5a57f3eb72ff94a.  make -C v4 test test-32 hosted-check pass.  QEMU:
amd64, aarch64, riscv64 to ok>, POST 538/538, POST: PASSED.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 16:35:07 -04:00
rajamesandClaude Opus 5.5 a73580e949 feat(v4): the machine boots from its ROM; the prebuilt nucleus is gone
The host node starts in its ROM (entry 12), and the boot feeds it the
system's source through the console: capsules/v4/sys/map-64.f18, the
fourteen .f18 blobs and end.f18, each found, hash-checked and
signature-checked as any capsule, then EOT.  The ROM assembles the system
and starts it at (IDLE); the host reads the image record
(v4_image_from_node) for what only the assembled system knows.  A ROM
error is reported with its blob, line and meaning, then PARITY:FAIL.

Deleted: v4/tools/mkimage.c, capsules/v4/nucleus-64.f18, v4/capsule/*.v4,
v4/tools/v4tof18.py.  The .f18 files are the source now.

- text.c speaks the rest of the ROM's language (set, here, store, start;
  v4_text_value, v4_text_start), so the oracle reads the same source:
  test_host_rom_nucleus compares the ROM against text.c on the .f18 files,
  word for word, image record included.  Host tests load the .f18 files.
- mkmap image writes v4_map_image (the map's description of the system);
  hosted and the kernel link the ROM and the map instead of v4_image_64.c.
- Hera (Captain Bob's ruling, option 1): births stream the system the ROM
  assembled, as assembled code; hera.4th is unchanged.
  test_host_unit's host builds the system with the ROM.
- New parity lines: PARITY:V4_F18 per blob, PARITY:V4_ROM words=2049
  rom_hash=0xa6c792b5821010b7 instructions=60725216.

Acceptance: amd64, aarch64, riscv64 boot to ok> with PARITY:V4_POST
tests=538 pass=538 fail=0, POST: PASSED, and PARITY:V4_SYSTEM
word_count=317 dict_hash=0xe5a57f3eb72ff94a on all three -- the same hash
as the prebuilt nucleus gave.  make -C v4 test test-32 hosted-check: all
pass.  Logs: logs/20261015-141648, -141938, -142350.

Startup cost under QEMU TCG, the ROM's assembly (last V4_F18 line to
V4_ROM): amd64 26.7 s of 132 s to ok>; aarch64 41.0 s of 195 s; riscv64
20.5 s of 101 s.  Hosted native: +0.85 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 14:26:02 -04:00
rajamesandClaude Opus 5.5 1bf19d6224 feat(v4): the ROM assembles the system's .f18 to the nucleus, word for word
capsules/v4/sys: the nucleus's fourteen sources as .f18 blobs (made once by
v4/tools/v4tof18.py: header becomes the ROM's directives, every other token
and line kept), the memory map as map-<width>.f18 (mkmap sys, from one
table in host_map.h that host_load reads too), and end.f18, the switch-on
state mkimage.c set in C, the image record, and start (IDLE).

test_host_rom_nucleus.c: the ROM, fed those blobs through the console,
builds RAM identical word for word to mkimage.c's, outside its own state
and the image record, and starts at (IDLE), at both widths.  The cost:
60.7 million instructions, 1.5 s on the C model.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:27:50 -04:00
rajamesandClaude Opus 5.5 084c520a54 feat(v4): the ROM assembles text as text.c does -- words, labels, macros, FOR, directives, start
word.f18: (NEXT-TOKEN) reads the console or a macro being expanded; labels,
branches by name (a label of the word, or a word, now or later), the
table of branches waiting, end of word, FOR/NEXT/UNEXT, macros, &NAME,
CONST+N, and (ONE), which dispatches a token.  A forward branch to a name
not yet defined waits on a placeholder symbol, filled in by (DEFINE).
dir.f18: constant set here #, ", store, and start, which resolves, clears
the tables the ROM used and runs the word it names.  main.f18: the ROM
itself, entry 12; on an error it stops at (ROM-FAILED) with the code and
line in its state, for the loader to report.  sym.f18 generalized: any
counted string, placeholders, a hash of only a name's own cells.

test_host_rom_asm.c gives test_text.c's own texts (accepted and refused),
its four real definitions and the ROM's directives to text.c and to the
ROM: the same words, the same errors on the same lines, at both widths.
The ROM is 2036 words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:24:08 -04:00
rajamesandClaude Opus 5.5 c233cb6536 feat(v4): the ROM's slot packer, word for word with asm.c
(OP) (LIT) (BRANCH) (BRANCH>) (RESOLVE) (LABEL), entries 6-11: the code
generator of any language built on the machine (MACHINE.md 2.1).  asm.c's
layout rules with text.c's branch placement; 400 random sequences agree
word for word with asm.c at both widths, memory-full and out-of-reach are
refused on both sides, and a ref with no branch is refused, not looped on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 11:58:47 -04:00
rajamesandClaude Opus 5.5 07911dcf91 feat(v4): the ROM's symbol table
(FIND) ( -- rec | 0 ), (DEFINE) ( value kind -- ) and (OPCODE) ( -- op | -1 ),
entries 3-5.  Names are refused as text.c's define refuses them, compared
case by case with text.c; a set variable may be set again.  256 hash heads,
records growing up and names growing down in dictionary space, used only
while the ROM assembles.  text.c gains the data directives #, and ", (the
ROM's language; its mnemonic and reserved-word tables are data); the
nucleus image is byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 11:54:15 -04:00
rajamesandClaude Opus 5.5 0f82d8c22a feat(v4): mkrom -- the ROM built off the node; it reads tokens
The ROM's source is F18 code in capsules/v4/rom, assembled off the node by
v4/tools/mkrom.c with the memory map's constants from v4/tools/mkmap.c
(MACHINE.md 2).  main.f18 is the entry table payloads call through (2.1);
in.f18 reads the console and splits it into tokens exactly as text.c does,
the token held packed as a counted string.  The ROM's state is a reserved
area of the map (host_map.h ROM_*).  text.c gains the constant directive,
so the off-node assembler and the ROM speak one language.  The map also
names (NUMBER)'s state, for the next task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 11:49:05 -04:00