Commit Graph
14 Commits
Author SHA1 Message Date
Robert Allan JamesandClaude Opus 5 1f44f47e69 FABRIC.md §23.3: fix header arithmetic, and stop asserting an unsized cell
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>
2026-08-03 11:00:37 -04:00
Robert Allan JamesandClaude Opus 5 a654e907e5 FABRIC.md §12: heading no longer overstates closure
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>
2026-08-03 10:59:07 -04:00
Robert Allan JamesandClaude Opus 5 3a9dfae280 FABRIC.md §17.1: heading no longer undercounts patrons
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>
2026-08-03 10:58:43 -04:00
Robert Allan JamesandClaude Opus 5 e44dc7830c FABRIC.md §16.3: correct the DictEntry wire count against the struct
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>
2026-08-03 10:58:21 -04:00
Robert Allan JamesandClaude Opus 5 fd820fc9eb FABRIC.md §3: declare the closed two-valued cell union
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>
2026-08-03 10:57:42 -04:00
Robert Allan JamesandClaude Opus 5 518334abef FABRIC.md §22.3: free lists are per-VM, not shared
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>
2026-08-03 10:56:34 -04:00
Robert Allan JamesandClaude Opus 5 055e944a73 FABRIC.md: correct §2 and §20.2 — fleet K is a real conservation law
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>
2026-08-03 10:56:03 -04:00
Robert Allan JamesandClaude Opus 5 7fe0133d07 FABRIC.md — reconcile §1-24, add §25 punch list
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>
2026-08-03 10:27:49 -04:00
Robert Allan JamesandClaude Opus 5 7c436351a0 FABRIC.md §23 — Q1 dissolved, Q2 sized
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>
2026-08-03 10:12:44 -04:00
Robert Allan JamesandClaude Opus 5 d74872c222 FABRIC.md §22 — elasticity resolved: elastic, via quota over one cell pool
§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>
2026-08-03 10:09:43 -04:00
Robert Allan JamesandClaude Opus 5 421c1d7602 FABRIC.md §21 — Q6 resolved: nested
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>
2026-08-03 10:06:17 -04:00
Robert Allan JamesandClaude Opus 5 1a5cd3fc74 FABRIC.md §20 — VMs are patrons
§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>
2026-08-03 10:02:52 -04:00
Robert Allan JamesandClaude Opus 5 85f59fca2e FABRIC.md §19 — mass, density, and what K actually is
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>
2026-08-03 09:57:59 -04:00
Robert Allan JamesandClaude Opus 5 8af19a545b Add FABRIC.md — Stadium design, sections 1-18
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>
2026-08-03 09:45:05 -04:00