Review item REVIEW-D4.
Item 1.1 (exclusive access, the "sitting in a car" primitive from §8) sits in
Phase 1 alongside questions with no structural effect, and it is not in that
class. A per-patron exclusivity primitive plausibly needs a held flag or holder
index -- a ninth wire in §3's table, in the header item 3.1 builds. Resolving
1.1 after 3.1 means rebuilding the cell header.
§25.4 already blocks Phase 3 on items 1.1-1.7, so the ordering was right; what
was missing was why 1.1 specifically, which is what gets an item quietly
reordered later by someone who does not know what it was holding up.
Item 3.1 now names both of its blockers explicitly: item 1.1, and §23.4 #4, the
continuation-cell encoding surfaced by REVIEW-C3. It also now requires defining
both members of §3's closed two-valued union rather than just the header.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-D3.
Item 1.3 decides what triggers a capacity transfer and said it should read the
density gradient rather than a schedule -- correct about what, silent about
when. Hera's arbitration mutates patron mass, so §18.5 binds it directly:
anything influencing patron state advances on tick count, and wall-clock time
must never be an input to a decision.
Without that stated in the item, a reasonable implementation could pace
arbitration off a wall-clock interval and reintroduce, in a new place, exactly
the defect item 2.1 exists to remove. Whatever 1.3 decides must be expressible
in ticks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-D2, following from REVIEW-A1/B1.
Item 2.2 claimed the unbounded registry "makes fleet K an identity that cannot
fail" and accepted on VM-CONSERVED? becoming able to fail. Both were wrong.
Heat is transferred rather than renormalised (§20.2), so conservation is already
a real invariant and already falsifiable -- via the dropped-remainder path at
capsule_vm_physics.c:240-244 and integer truncation at :304-305. Bounding the
population changes neither, so the item promised something it could not deliver.
The bound is still needed and now rests on the two grounds §2 states: finite
state for §13's induction and model checking, and density requiring a capacity
to be dense within, without which §19.3's admission rule has nothing to compare
against. Acceptance is now the bound existing, birth-at-bound behaving as 1.5
specifies, and the three-architecture boot unaffected.
Fixing the truncation leak is a separate and larger piece of work and stays in
§25.7 rather than being folded in here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-D1.
Item 2.1 restates vm_physics_touch on tick count and accepted on the
dictionary-hash double-boot check from item 0.10. That check cannot detect the
work: §18.5 establishes that vm_physics_touch writes node->physics, not
DictEntry.execution_heat, and so never reaches the parity hash. The dict hash
would be identical whether 2.1 succeeded, failed, or was skipped entirely.
Acceptance is now an identical fleet heat sum across two boots of the same
capsule -- fleet heat being the quantity the item actually changes. The
dict-hash check still runs, as a regression guard rather than as evidence.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-C4.
The header claimed §1-15 retained "arena" to stay quotable, but the rule was
not applied consistently -- §15 had been swept, §13 had not. A document with two
names for its central object costs every reader something on every section.
Swept all body text. "arena" now survives in four places only, each deliberate:
the src/starkernel/vm/arena.c file path; the two naming notes, which discuss the
word itself; §12's preserved question list, which the section explicitly retains
as the source several later sections quote; and the block quotes of §12 in §21
and §23.
One deviation from the review's stated rule, which said quoted text keeps the
original word. §17.3 quotes §4 and §17.6 quotes §13 -- both self-quotes within
this document, whose sources were just swept. Left unswept they would cite text
that no longer exists, so a reader following the reference finds different
words. Those two were updated to track their sources. §12's quotes were not,
because §12 itself is deliberately preserved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-C3.
The stated fields sum to 28, not the ~32 claimed, and 28 + 32 inline payload is
60, not the 64-byte cell. Now stated as 28 used plus 4 reserved. The reserve is
deliberate: it keeps the header a clean half-cell, leaves room for the
header/continuation discriminator §3 now requires, and gives §8's exclusivity
primitive somewhere to live if item 1.1 resolves to a holder index.
The larger problem was the "17 cells: 1 header + 16 payload" figure for a
1024-byte block. That silently assumed continuation cells are contiguous and
carry nothing but bytes. §22.3 allocates from a per-VM free list with no
adjacency guarantee, so continuation cells would need a next-index -- 4 bytes
off each one's payload, making the same block 18 continuation cells rather than
16. The alternative, guaranteeing contiguous runs, reintroduces the
fragmentation §3 avoids.
Those are different designs with different costs, and the choice sets the mass
of every large patron. Rather than pick one, the row is marked undetermined and
recorded as §23.4 #4, which gates punch item 3.1: the cell structure cannot be
built until it is settled.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-C2. The heading claimed all six questions closed while the
table below marked Q5 partial and a note explained why. Five closed, one
partial.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-C1. The heading read "Four patrons die four different ways"
above a table listing five. §17's preamble carries the caveat that its counts
predate §20, but a heading is where a reader anchors.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-B2, settled by reading include/vm.h:335-351.
The subsection's table and prose disagreed: the table listed the code field as
present, the prose named it as one of two missing wires, and neither accounted
for payload.
Actual mapping against §3's eight wires: identity, heat, TTL and pin are present
in correct form; link is a pointer rather than an index; the code field is a raw
function pointer rather than an enumerated tag; mass and payload are absent.
Four correct, two wrong-form, two absent -- not "six of eight."
The wrong-form pair matters more than the count. §13 names pointer-free index
links as the single biggest difference between a tractable proof effort and a
research project, and §18.3 requires the function pointer to become a closed
tag. Those are exactly the two.
The claim that the dictionary "is" a Stadium entry is therefore overstated and
has been weakened to what the struct supports: the dictionary already has the
concepts, and two of the eight wires need to change form. That still carries §1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-A3.
§23.1 dissolved the payload threshold by making large patrons heavy -- a
1024-byte block is 17 cells, one header and sixteen of payload. Those sixteen
carry no identity, heat, TTL or code field, so they are a second cell shape,
which §3's opening line ("One structure. No variants") forbade without saying
so. An implementer reading §3 literally would have built the wrong structure.
Declared: a cell is either a patron header or a continuation cell owned by
exactly one patron. The union is closed, two-valued, and fixed at build time.
This introduces no new principle -- it is the same discipline §18.3 applies to
behaviours, and a two-valued union is the smallest instance of a closed
enumeration. It is not a type field: the distinction is structural, tells the
engine only whether a cell begins or continues a patron, and is exhausted by
that. Continuation cells are never ranked, reaped or dispatched; they are floor
space accounted for in their owner's mass.
§13's "one datatype" bullet amended -- the datatype is a two-constructor sum
rather than a bare record, costing one case split.
§23.4 #3 (identity elision) expanded: it is downstream of the
header/continuation encoding, since a scheme reusing the identity field as
discriminator would couple the two decisions.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-A2.
§22.3 specified that cells are drawn from a shared free list. That undercut the
row that decided §21: its SMP discriminator claims messages are the only
boundary-crossers, so no shared memory and no locks, permanently. A shared free
list is shared mutable state touched by every VM on every admission and reap,
and would need a lock or atomics under SMP. §22.3's defence -- that VMs never
touch each other's cells -- does not cover it, because the free list is nobody's
cell and allocation touches it.
Each VM now holds its own free-list head index into the global array. Hera hands
over cells when she grants quota; a VM allocates and frees only within what it
holds. One index space, one datatype and §13 are all unaffected, and
disjointness becomes total rather than nearly total.
Capacity transfer remains arithmetic plus a list splice, arbitrated at a known
point per §22.5 #2.
The layout choice itself is unchanged -- one global array, one index space
remains correct for §13.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review item REVIEW-A1, settled by reading (REVIEW-B1).
§20.2 claimed fleet K was "bookkeeping" that could not fail, on the premise
that heat is renormalised after population changes. That premise is false. Read
end to end in capsule_vm_physics.c:
- vm_physics_transfer (:147-154) subtracts from one and adds to another,
clamped at zero: "Nothing is created or destroyed."
- Birth (:156-185) seeds Hera with Q48_ONE; every other VM starts at zero --
"cold mass added to a closed system." Population growth rescales nothing.
- Death (:225-247) transfers the dying VM's heat to its root before zeroing.
- Touch (:250-311) pulls proportionally, clamped so it "can never manufacture
heat."
There is no renormalisation. VM-CONSERVED? tests a genuine invariant and is
falsifiable today, by two paths: the documented dropped-remainder case at
:240-244, and integer truncation in the proportional fan-out at :304-305, which
loses heat on every multi-VM touch and drifts the sum downward monotonically.
Consequently §2's justification was also wrong -- capacity does not give a
normalised heat share its denominator, and §19.2 says mass never enters K. §2
now claims the bound on the two grounds it can honestly claim: finite state for
§13, and density needing a capacity to be dense within.
This also reframes the Artemis campaign's K-invariance arm. It was not
measuring an identity; it measured a quantity that could drift and did not trip
a 5% epsilon over that run.
The truncation leak is recorded in §25.7 as reported-not-scheduled. It is small
per touch but monotonic, and its rate has never been measured.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reconciliation. §1-15 were written before any code was read and had drifted
from §16-24 in twenty places. Each superseded claim is now marked in place
rather than rewritten -- §19.4 and §19.5 quote the original §4 wording
directly, and the retracing trail matters more than a tidy read.
Two real gaps surfaced during the reread, neither previously recorded:
- §3's wire table was missing `mass`. Density is heat / mass, so mass has to
live in the entry, and §3 is the table an implementer would work from. It is
now an eighth wire.
- §8 asserts a per-patron exclusivity primitive -- "one sits in a car, the only
exclusive thing in the room, no global lock" -- that nothing in §16-24
defines. §21 covers ISR-vs-mainline concurrency, which is a different
question. Marked OPEN at the source and carried as punch list item 1.1.
Also corrected: §9's admission table is complete for all five patron kinds with
both `?` marks closed; §12's six questions are all resolved; §5's third
category is supplied; §15's five-line summary had two wrong lines; §4, §6, §7,
§17.4 and §17.6 status markers now match reality.
§25 is the punch list, with its operating instructions first: one item at a
time, no jumping ahead, no scope increase, no fabricating anything unverified,
stop when blocked. Every checked item gets its own commit carrying both the
change and this file with that box ticked, so the document is never a claim
about work not in the branch.
Phase 0 is the substrate -- Hera alone plus real timers and IRQ return paths on
all three ISAs. Nothing else can start until it is done.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Q1 (payload threshold) does not need answering, it needs removing. §3 wanted
inline-if-small/by-reference-if-large so a cell need not be sized for a block.
§19 gives a better answer: a large patron occupies more cells, chained by
index, which is exactly what mass already means. A block is not by reference,
a block is heavy.
If the payload is in the Stadium, it counts toward mass. If it is not in the
Stadium, the patron is not resident -- it is a handle to the warehouse.
That closes the §19.6 loophole without a rule: a 1 MB block cannot occupy one
cell and read as dense. It also preserves the hysteresis in §19.3, which
depends on blocks being genuinely expensive to keep resident. Nothing in §3 is
violated -- cells stay fixed-size, links stay indices, the Stadium stays an
array. By-reference is reserved for things outside the Stadium, which are not
patrons.
Q2's premise is stale: §17.5 removed the screen grid, so the screen is no
longer the worst case. Underneath it sits a question §17.5 left half-settled --
it decided the dirty event is the patron but not what one event covers. Per
cell, an 80x25 redraw is 2,000 patrons and floods the Stadium; per region it is
about 25. Leaning region-based, to be confirmed with the console work. The
worst case then becomes messages, giving the rule: size the cell so a typical
message is exactly one cell.
Proposes 64-byte cells (one cache line), ~32-byte header, ~4096 cells per VM
at 256 KB. Structure decided, constants leaning -- heat at 8 bytes is fixed by
the existing Q48.16 convention, the rest need validating against a real build.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
§7, §12 Q4 and §17.6(c) are one question at three scales. Resolved elastic.
Under §19's density definition elasticity stops being a feature and becomes a
negative feedback loop: a busy VM's heat share rises, density rises, capacity
flows toward it, mass rises, density falls back. Capacity flows down the
density gradient -- diffusion, no threshold, no damping constant. §4's "read,
not decided" applied one level up. §7's own argument also holds: birth sizes
the resting volume rather than a cap, which is far easier to guess right and
self-corrects when wrong.
The larger finding is that hard-versus-elastic was the wrong framing. Elastic
is cheap or expensive entirely according to layout, which §21 did not settle.
Chosen: one global array of cells, one global index space, per-VM quota as a
count rather than a contiguous range. Cells come from a shared free list, so
transfer is arithmetic on two integers -- no fragmentation, no adjacency
requirement, index links keep working.
This makes §13 simpler rather than harder: one array, one datatype, one total
function over one finite index set, with nesting as a partition. §21's
reasoning survives -- K per level and messages as the only boundary-crossers
are both preserved, and SMP-safety holds so long as quota changes are
arbitrated by Hera. What is given up is physical fault containment, recorded
rather than glossed.
Adds a required ordering: capacity must move slower than heat, or two conserved
quantities chase each other and the ratio never settles. That is §12 Q5's
separation of timescales arriving as a concrete instance.
Opens: the resting floor (proposed derivation -- floor a quota at the mass of
its pinned patrons, which is derived rather than tuned), what signal triggers a
transfer, and the exact timescale ratio.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Q6 leaned toward nested for the right conclusion and the wrong reason.
Its premise -- that a single region "reintroduces locking, the one mechanism
this architecture has otherwise never wanted" -- is false. Every mutex in the
kernel build is a no-op (shim.c:415); the kernel compiles STARFORTH_MINIMAL and
the shim stubs dict_lock and tuning_lock out entirely. The architecture has not
avoided locking, it has locking, inert. The cost Q6 weighs is currently zero, so
Q6 cannot be decided on it.
Decided nested on six other grounds, the strongest being SMP-readiness: nested
keeps messages the only boundary-crossers, so no shared memory and no locks
ever, whereas a single region would need real locks and the present no-op stubs
would silently become a correctness hole. The most practical is that the outer
level already exists and works (§20.1) -- single-region means discarding a
working two-level structure.
Also records a step-one finding that lands before any Stadium work: enabling
timer interrupts introduces genuine ISR-vs-mainline concurrency where none
exists today. Making the mutexes real would deadlock a single hart outright,
since an ISR spinning on a lock the mainline holds can never be released. The
top-half/bottom-half split of §18.4 is the answer, stated as a rule:
Nothing in interrupt context may mutate Stadium structure. Ever.
That constraint should be written at the stub site so the no-op is not later
"fixed" into a spinlock.
Opens: two capacities to size rather than one, and elasticity (§12 Q4 / §7 /
§17.6c) becomes the live fork now that nesting makes capacity transfer real.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
§17 named four patrons and omitted the only kind already implemented. §9's
admission table has always included VM, and §6 says Hera becomes the first
entry; neither reconciles with a four-patron taxonomy.
This is a finding rather than a proposal. vm_physics_fleet_heat_sum() already
sums execution_heat_q48 across live VMs against Q48_ONE -- that is a Stadium's
K over VM patrons, and §19.1's definition was derived from it.
Two consequences:
- The outer level is unbounded. The VM physics registry is a kmalloc-backed
linked list, self-described as "unbounded, not a fixed array", so heat is
renormalised to 1.0 however many VMs exist. By §2's own test, fleet K is
currently bookkeeping -- VM-CONSERVED? cannot fail. This also explains why
the Artemis campaign's K-invariance arm found nothing: the quantity cannot
vary. Bounding the population is what would make it measurable.
- Nesting is half-built. Outer Stadium holds VM patrons; each VM's inner
Stadium holds words, blocks, ACLs and messages. That is §12 Q6's nested
option with the outer level already present. LEANING nested.
Proposes VM mass = the capacity share Hera allocated, making §7 concrete and
giving Hera a lifecycle signal that distinguishes starved from small. Marked
proposal: VMPhysics has no share field today.
Resolves §20.5 #3: Hera is pinned, and any attempt to evict her is a kernel
panic asserted at the eviction site, not filtered out of the candidate set.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Supplies the concrete definition §4 was missing. §4's claim that ranking is
read rather than decided is empty until the thing being read is a number.
Three quantities, not one:
Heat conserved share moved by traffic, sum = 1.0 always (already built)
Mass cells a patron occupies -- its footprint (new)
Density heat / mass -- heat per cell (new, derived)
K is left untouched. vm_physics_conserved() already defines it as a normalised
heat share summing to Q48_ONE, not an occupancy ratio; defining it as
mass/capacity would have contradicted implemented, tested code.
Ranking, admission-when-full, and migration hysteresis all read off density
with no policy and no damping constant.
Two corrections to §4:
- The self-limiting claim keeps its conclusion but loses its mechanism. A hot
entry is easier to reach, not harder; the real governor is conservation,
since heat is zero-sum and capped at 1.0.
- "Density generates heat" reverses the causality. Traffic confers heat;
density is heat per cell, derived downstream.
Open: mass depends on payload threshold and header size (§12 Q1, Q2), which are
now prerequisites rather than sizing details; and vm_physics_touch scales heat
transfer by wall-clock time, which §18.5 forbids and which must be restated on
tick count before L0 can use it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Captures the 2026-08-03 design session: collapsing the four independent
heat/TTL/pin implementations (blocks, messages, console cells, ACLs) into
one bounded Stadium of fixed-size entries, driven by an engine below every VM.
Sections 1-15 are the original design argument. Sections 16-18 add:
- 16 Substrate findings. No IRQ return path exists on aarch64 or riscv64;
riscv64's time base is a hardcoded 1 GHz guess; the dictionary already
carries six of the seven entry wires; the engine must stay deterministic.
- 17 Patrons. TTL, heat decay and pin are three distinct mechanisms on one
tick, not a type field. Reap means leaves the floor, not destroyed. The
framebuffer is a utility, not a patron. Dynamic in capacity, static in
structure.
- 18 The engine (L0). L0 and L8 bookend the gated loops L1-L7, both ungated.
Jacquard stays 7-bit/128 states, accounting for L0 by its absence.
Dispatch enumerates behaviours, never patron kinds.
Determinism traced end to end and confirmed intact: TIME-TRUST is measured
and never fed back, inference inputs are wholly execution-derived, decay is
tick-based, and the parity hash covers only word name and execution_heat.
One pre-existing exception recorded — vm_physics_touch scales fleet heat by
wall-clock elapsed time, outside the parity path.
Draft. Sections marked DECIDED / LEANING / OPEN throughout.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>