Add capsules/sdk.4th: SDK v1.9.0 vocabulary + FENCE over the cookbook capsules

Loads turtle.4th and doe.4th, defines SDK-VERSION/SDK-HELP into an SDK
vocabulary, then calls FENCE once everything is loaded -- protecting the
base wordset and both cookbook capsules from FORGET. Kernel-only (EXEC
doesn't exist hosted), REPL-invoked via S" sdk.4th" EXEC, not part of
init.4th's boot sequence.

Verified before writing the capsule, not assumed: VOCABULARY/DEFINITIONS
does not actually scope word visibility in this interpreter -- vm_find_word
is a flat dictionary scan that never consults CONTEXT/CURRENT. Documented
plainly in the HOWTO so this isn't mistaken for namespace isolation later.

Block range 5109-5115 -- discovered along the way that user-block space is
capped at [2048, 5120) by mkcapsule, tighter than expected.

Verified: mkcapsule --lint clean, hosted-build trace runs SDK-HELP with
zero attributable VM errors, zero build warnings and identical 1012/0/0
POST results with matching dict_hash on all three kernel architectures.

HOWTO: docs/working/architecture/SDK-HOWTO-20260819.md

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-19 06:10:51 -04:00
co-authored by Claude Sonnet 5
parent 4e7dcdf889
commit d1547ecdae
10 changed files with 114512 additions and 21020 deletions
@@ -0,0 +1,95 @@
<!-- Living draft (docs/working/ tier). Source for a future docs/formal/cookbook
scrap once reviewed -- see docs/formal/CLAUDE.md's Scraps System. Not yet
promoted; do not cite. -->
# SDK HOWTO — `capsules/sdk.4th`
**Status:** WORKING. Part of the v1.9.0 scoping work (FABRIC-2.md section K).
Loads the two cookbook capsules (turtle graphics, DoE library) and adds an
`SDK` vocabulary entry point plus `FENCE` protection on top of them.
## Loading it
Kernel-only (it loads other capsules via `EXEC`, which does not exist in
the hosted build), REPL-invoked — not part of `init.4th`'s boot sequence,
matching `turtle.4th`'s own choice:
```forth
S" sdk.4th" EXEC
```
This loads `turtle.4th` and `doe.4th`, defines an `SDK` vocabulary with two
introspection words (`SDK-VERSION`, `SDK-HELP`), then calls `FENCE` to
protect everything loaded so far — the base wordset, both cookbook
capsules, and `sdk.4th`'s own words — from `FORGET`. Prints a one-line
confirmation and hint on load; run `SDK-HELP` for the full word list.
## What `VOCABULARY` actually does here — read before assuming isolation
`sdk.4th` defines its own words (`SDK-VERSION`, `SDK-HELP`) into a named
`SDK` vocabulary via `SDK DEFINITIONS`. This is **organizational, not
isolating**: this VM's primary word lookup (`vm_find_word`, used by the
ordinary interpreter loop) is a flat, first-character-bucketed scan of the
whole dictionary — it does not consult `CONTEXT`/`CURRENT` at all. Verified
directly before writing this file: a word defined while `CURRENT` targeted
a custom vocabulary remained globally callable immediately after switching
back to `FORTH DEFINITIONS`, exactly as if no vocabulary had been involved.
The `VOCABULARY`/`DEFINITIONS`/`CONTEXT`/`ORDER`/`(FIND)` machinery is real,
standard FORTH-79, and useful for anything that explicitly walks vocabulary
chains (`(FIND)`, `ORDER`) — it just isn't what makes SDK words reachable
day to day. Don't build anything on the assumption that loading a second
vocabulary hides or scopes its words from the rest of the system.
## FENCE — and the bug it surfaced
`FENCE ( -- )` is new (this scoping pass) — it raises the dictionary's
`FORGET` boundary to whatever is currently the newest word, so anything
defined afterward can be safely `FORGET`ten without reaching back into
protected territory. `sdk.4th` calls it once, at the very end of loading.
Building a direct test for `FENCE` surfaced a real, severe, pre-existing
bug in `FORGET` itself — completely independent of `FENCE`, reproducible
with the *original* boot-time fence alone. Forgetting the single newest
word wrongly destroyed every other word back to the fence too; forgetting
an older word (which correctly cascades to remove newer words, per
FORTH-79 semantics) crashed with a SIGSEGV — a use-after-free in the
dictionary relink logic. Found and fixed as part of this work; full
root-cause writeup in FABRIC-2.md section K. Three POST cases were added to
`dictionary_manipulation_words_test.c` (Module 14) alongside `FORGET`'s
own, including the exact regression scenario, so it can't silently return.
## Vocabulary
| Word | Effect |
|------|--------|
| `SDK-VERSION` | Prints the release tag (`SDK v1.9.0 (scoping)`). |
| `SDK-HELP` | Prints the full word list for both cookbook capsules, with HOWTO pointers. |
| `FENCE` | (Not SDK-specific — a base word, used by this capsule.) Raises the `FORGET` boundary to the current dictionary top. |
Everything from `turtle.4th` and `doe.4th` is also available after loading
— see their own HOWTOs (`TURTLE-GRAPHICS-HOWTO-20260819.md`,
`DOE-LIBRARY-HOWTO-20260819.md`) for their vocabularies.
## Verification performed
- `mkcapsule --lint capsules/` clean (block range `5109``5115`, clear of
`turtle.4th`'s `5100``5108`).
- Hosted-build logic trace: `fabric.4th`'s core blocks + `turtle.4th` +
`doe.4th` + `sdk.4th`'s own blocks (with its two `EXEC` lines stripped,
since `EXEC` doesn't exist hosted — the capsules they'd load were
concatenated directly instead) piped into the hosted binary. `SDK-HELP`
runs and prints correctly; zero VM errors from any of this content
(all errors present in the log are the built-in POST suite's own
deliberate error-injection cases, confirmed by cross-checking against
the same baseline used for the cookbook capsules' own verification).
- Built cleanly (zero warnings) and baked into the capsule set on all
three kernel architectures (amd64/aarch64/riscv64); boot verified clean
through POST on all three, `1012 passed / 0 failed / 0 errors`
identically, `dict_hash` unchanged from the pre-`sdk.4th` baseline on
all three (expected — `sdk.4th` isn't autoloaded, so it cannot affect
boot-time dictionary content).
- Not yet driven interactively through a live REPL — same practical
limitation as `turtle.4th`'s own HOWTO documents (the DoE campaign that
auto-runs on every kernel boot blocks the REPL for ~2530 minutes before
serial commands can reach it). The FORTH logic is verified; the
interactive load-and-run experience is not.