Skip to content

compute fabric design - #9467

Merged
briansrls merged 25 commits into
mainfrom
fabric/cell-realization
Aug 28, 2026
Merged

briansrls merged 25 commits into
mainfrom
fabric/cell-realization

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Auto-opened by session-dashboard for session silent-bear-842.
Pushing to fabric/cell-realization advances this PR.

Worker attestation

Before flipping this PR to ready for review, confirm each item:

  • Title describes the change (not the session id or branch).
  • PR body summarises what and why (replace the TODO below).
  • Tests run: name the command (e.g. npm test, cargo test) and the result.
  • If this closes a work item, the body contains a Closes #N directive.
  • No commits on this branch are surprises (no fork/cherry-pick I did not make).
  • No secrets / credentials / large binaries staged.

Summary

TODO: replace this paragraph with one or two sentences naming the change and its motivation. Reviewers read this first.

Test plan

  • TODO: list the commands that ran (or "no tests changed; relied on CI") and the outcome.

Brian Searls and others added 24 commits August 26, 2026 05:41
…ecome a real probe (#fabric)

gunbc.fabric_cell_observe has been the pure half of an observer whose other
half did not exist -- every production call site passed
fabric_cell_observation_unobserved, which says "nobody looked" and is honest
precisely because nobody did. This is the half that looks.

IT ADDS NO HOST VOCABULARY, AND THAT IS THE LOAD-BEARING FACT ABOUT IT.
Filesystem.List, shell.Test.IsDirectory/IsFile and Systemctl.ShowProperty/
ListUnits are already declared with cited upstream authorities, so the
acquisition composes five declared readonly reads. An acquisition layer that
needed a NEW operation would have been telling us the observation model wants a
fact the substrate cannot establish -- a modeling question wearing transport
clothes -- and it did not.

A DIRECTORY HAS FOUR HONEST STATES, NOT TWO, AND THE PAIR A Bool MERGES IS THE
PAIR WITH OPPOSITE CONSEQUENCES. Filesystem.List answers success: Bool, so a
listing that FAILED and a directory that IS NOT THERE arrive as the same false
-- and not-there licenses a provisioning ADD while could-not-read must stop the
line. They are separated by an independent declared read rather than by
matching the error text for "No such file", because parsing a message is a
heuristic standing where an operation was available. The fourth state is the
one no Bool can hold: a regular FILE where a cell root belongs is not an
absence and not a listing, and calling it absence would license an ADD whose
failure surfaces at apply time as a mkdir refusal instead of here as an
observation.

THE CONTRADICTION LAW IS OBEYED AT ACQUISITION TIME RATHER THAN REPAIRED
AFTERWARDS. A state read is performed only where the parent listing held the
entry, so this module cannot hand the observer an address that is absent from
its namespace and simultaneously read -- the impossible host the observer
refuses, and the exact shape three fixtures on the last PR had to be corrected
for. An absent directory contributes NO address probe at all rather than one
carrying a refusal, because absence is the namespace's answer and overruling it
would make a fresh host refuse instead of plan.

ONE SPELLING AUTHORITY, BECAUSE THE OBSERVED SIDE NOW HAS TO PRODUCE THE SAME
STRING. The boundary digest was spelled inline in the desired function; an
observer composing its own would fork, and a reordered key would make every
cell on every host read as drifted with the drift in the RENDERER rather than
on the host. fabric_cell_boundary_state_digest_of is now that one function with
two callers. It takes rendered strings and not typed magnitudes on purpose: the
observed side holds whatever systemctl printed, which is a decimal or the word
"infinity", and parsing it back to re-render it would invent a round trip the
comparison does not need.

NINE LAWS, ALL PURE, AND ONE MUTATION RECEIPT THAT CORRECTED ITS OWN ROW. The
digest-agreement law looked like it should red when the shared spelling changes.
Measured: it does NOT -- renaming a key in the shared function leaves it green,
because both sides route through it, which is what one authority MEANS. That is
not a hole, but the comment claiming otherwise would have been. The RED it
actually carries is on the acquisition side and is executed: transposing
memory_high and memory_swap_max where this module composes the reading fails it,
restored green after. The row now states the boundary it measured rather than
the one I assumed.

The host effects are unreachable from a hermetic fixture by construction, and
that is the boundary rather than a gap: a mocked listing would assert these laws
against authored data instead of against the projection.

WIRED AT THE PLAN AND APPLY CALL SITES, ONE OBSERVATION EACH. The apply path
binds the probe ONCE and compares it against both the member-set fingerprint and
the observed baseline -- two probes there could disagree with each other, and a
plan refused because the host changed between two reads of the same run would
name drift that never happened. Spark's planner stays unobserved, and correctly:
it is a pure fn that does not read a host and must not claim to.

4052 file(s) parse-clean; nine rows green by execution; the CLI closure resolves
through a witness that imports it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…dary was asking about nothing (#9304)

Two findings from the side chat, both real, and the first is a live
contradiction in the module whose header claims the opposite.

THE BOUNDARY WAS ASKED UNCONDITIONALLY. The header says a state read is
performed only where the parent said the entry is there. That was true of the
two directory addresses and FALSE of the slice: every expected slot issued
`systemctl show` regardless of what the slice enumeration said. And the failure
mode is worse than an inconsistency, because `systemctl show` on a unit that
does not exist EXITS ZERO AND PRINTS DEFAULTS -- so an unprovisioned slice came
back as a SUCCESSFUL read of values no host is carrying. The observer then saw
an address absent from its namespace with a state supplied, refused it as a
contradiction, and the cell could never be planned. That is the exact "first
real observation of an unprovisioned host blocked instead of planning" failure
gunbc.fabric_cell_observe records in its own header, reintroduced by the
producer. A success exit is not evidence that a unit exists.

The enumeration now decides, and the three answers are not two: HOLDS asks;
RAN-AND-DOES-NOT-HOLD establishes absence and asks nothing, because absence is
the namespace's answer; REFUSED establishes nothing and the address refuses
with it rather than inheriting an absence nobody observed.

"NOT A DIRECTORY" IS NOT "IS A REGULAR FILE". The first cut asked `test -f`
after `test -d` and called everything else absent -- so a socket, a FIFO, a
device node or a symlink reported a path that CANNOT BE CREATED as one that is
free to create. `shell.Test.Exists` and `shell.Test.IsSymlink` are added to
extdeps and cited: `-e` answers the question the two proxies were approximating
and closes every case but one, because it follows symlinks, so a link whose
target is gone answers false while the link still holds the name and still
defeats mkdir. `-L` sees the link rather than through it.

This module claimed as a virtue that it added no host vocabulary. It does now,
and the reason is the signal I said to watch for: the observation model wanted a
fact the declared vocabulary could not establish. That is a modeling question,
and it is answered in extdeps where it belongs rather than by composing two
tests that do not add up to the third.

AND A THIRD FINDING THE FIRST TWO TURNED UP, WHICH IS ABOUT MY EVIDENCE RATHER
THAN MY CODE. The first cut of the ask/do-not-ask law had to REACH the arm that
asks in order to establish the contrast -- and that arm performs a host effect.
It passed. It passed because claim_batch runs hermetically and systemd's
operation carries a declared mock_response, so the row was asserting a law about
acquisition against AUTHORED DATA. The same row under `gunbc run` errored:
"failed to execute 'systemctl'". Two runners disagreeing about one row is what
exposed it.

The decision is now its own named fact -- FabricCellBoundaryStanding -- and the
effect happens strictly downstream of it. Both rows are pure, no mock
participates, and the receipt is that they now PASS under the runner that
errored on them before.

Mutation receipt: making the does-not-hold branch ask anyway reds the law.
11/11 rows green after restoring; 4052 file(s) parse-clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… "not there" from "could not look" (#9304)

The last commit replaced `test -d` plus `test -f` with `test -e` plus `test -L`
and called the occupancy question closed. It is not, and the second spelling
fails for the same reason as the first: EVERY BOOLEAN TEST REPORTS ITS OWN
FAILURE TO OBSERVE AS A NEGATIVE ANSWER. `test -e` returns false for a path
that is not there AND for a path whose parent directory cannot be searched, so
absence and "I could not look" -- the pair whose remedies are furthest apart --
still arrive identically. A third boolean would not have helped either; the
shape of the answer is the problem.

THE KIND IS NOW OBSERVED AS A KIND. `stat.File.FileType` is declared in
extdeps.tools.stat beside the argv builder that already spelled those words,
following the pair shape extdeps.shell already carries for IsExecutable. It
reports the GNU type token on success and reports only that the read FAILED
otherwise. It never reports absence, because a metadata read that failed
establishes nothing. GNU stat uses lstat by default, so a symbolic link reads
as a link rather than as its target -- which is what an observer deciding
whether a name is OCCUPIED needs, since a link defeats mkdir whether or not its
target exists.

AND ABSENCE COMES FROM WHERE THIS FAMILY ALWAYS SAID IT COMES FROM: THE PARENT
ENUMERATION. That is the observe module's own parent-observation law, applied
here instead of approximated by a probe of the path itself. A failed metadata
read is routed by what the containing directory already established -- absent
if the parent listed and did not hold the entry, unreadable otherwise,
INCLUDING when the parent itself was never observed. Nothing turns a failed
read into an absence on its own authority any more.

THE CELLS ROOT WAS THE PATH WITH NO PARENT TO ASK, AND THAT IS WHY ITS SPELLING
SPLIT. Every other path in the family has a modeled containing namespace; the
top of the family had none, so its absence was exactly the case the old code
could not get right. `/opt` is now listed and asked whether it holds
`fabric-cells` -- the same law one level up rather than an exemption from it --
and `fabric_cell_base_dir` is DERIVED from the parent and the entry name so the
three do not fork. The recursion stops there deliberately: `/opt` is filesystem
hierarchy standard, not something this family provisions, so an unobservable
`/opt` is a refusal rather than another level.

THE TYPE WORDS DECODE INTO A CLOSED VOCABULARY with an UnknownKind arm carrying
the word verbatim. Folding an unseen type into a known arm would report a
device node as a regular file, and the refusal messages now name what is
actually sitting there.

Three new laws, all pure: a failed metadata read is an absence only when the
parent said so; the parent standing is derived from a successful enumeration
and from nothing else -- an unlistable parent must not read as "lacks the
entry", which is the arm that licenses an ADD; and the GNU words decode with no
silent default. 14/14 green, 4052 file(s) parse-clean.

Found by the side chat, which rejected the `test -e` fix I had just pushed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…er was dropping them (#9304)

Two things, and the first is the one the acquisition layer was CHANGED to make
possible before anything downstream could use it.

THE ENUMERATION PRODUCED THE EVIDENCE AND THE OBSERVER THREW IT AWAY. This lane
changed the boundary read from probing one expected unit by name to enumerating
`fabric-cell-*.slice`, for the stated reason that probing desired names can
never discover an undesired one. But gunbc.fabric_cell_observe read the slice
namespace ONLY to answer whether each EXPECTED boundary was present -- discovery
was driven by the filesystem cells-root alone -- so `fabric-cell-srv3-07.slice`
on a host that does not declare srv3-07 was enumerated, matched against nothing,
and dropped. No output position, no refusal, no baseline row. The old blindness
survived one layer downstream of the fix for it.

Discovery now spans every family-owned namespace through ONE classifier,
distinguished only by how a slot spells itself there -- `srv3-06` in the cells
root, `fabric-cell-srv3-06.slice` in the slice namespace. Every committed
identity is rendered FORWARD into the namespace's own spelling and compared; no
identity is parsed back out of an observed name, which would be a second naming
scheme that disagrees with the first the moment either spelling changes -- and
which would have reported a committed slot's own slice as foreign.

EITHER ENUMERATION FAILING REFUSES THE WHOLE DISCOVERY, because a population
that was only half enumerated is not a population: an out-of-band slice would
be invisible while the cells root read clean, and reporting the clean half as
the answer is the empty-observation narrow. Seven existing rows went red on
exactly this, all of them probes that supplied a cells-root listing and no
slice enumeration -- fixtures written when the slice namespace answered a
narrower question. They now supply both, which is what a fully-read host means.

AND TWO ORPHAN OPERATIONS DELETED, FOUND BY REVIEW 56184. `shell.Test.Exists`
and `shell.Test.IsSymlink` were added one commit and made unreachable the next,
when the boolean approach was replaced by `stat -c %F`. That leaves declared
surface with no consumer, standing beside a module header that argues why the
primitive does not work -- the unmarked-scaffold shape exactly. Deleted.

The header claiming this module "adds no new host vocabulary" is corrected
rather than quietly dropped: it reaches four declared readonly operations and
added ONE, `stat.File.FileType`, and the reason it added one is the finding --
no composition of boolean tests can express the fact the observer needs, so the
gap was answered where modeling lives instead of approximated in the producer.

60 rows green by execution across the two witness files; 4052 file(s)
parse-clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… from the namespace that owns it (#9304)

Review 56191 noted that `fabric_cell_slice_namespace_name() = "fabric-slices"`
is a wire label rather than a systemd pattern, so it does not fork the
`fabric-cell-*.slice` authority. That is correct, and checking it turned up a
DIFFERENT fork the note was not about: the label is spelled twice -- once in
`fabric_cell_namespace_wire`, which owns how a namespace spells itself, and
once in the location helper beside it. `fabric-cells-root` had the same pair,
pre-existing.

Two authorities for one concept, and a rename moves one of them. A discovered
subject's location IS the namespace it was found in, so it is now projected
through the function that already owns that spelling; both helpers become
one-line derivations and each label appears exactly once in the module.

Nothing about the discovery behaviour changes -- the strings are identical,
which is the point: this is the class where a fork stays invisible until
someone edits one side. 60 rows green, 4052 file(s) parse-clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ed nothing admitted as a value (#9304)

Two more producer defects, both found by the side chat, and both are the same
shape as ones this lane already repaired -- one level down.

THE CELL ROOT WAS ACQUIRED TWICE INSIDE ONE NOMINAL PROBE. `fabric_cell_probe_wet`
observed it once while building the child-namespace entry and the address fold
observed it AGAIN. That is not a duplicate cost, it is a consistency hole: if
the path changes between the two reads, the observer receives a namespace
derived from read A and address evidence derived from read B, and refuses a
contradiction ITS OWN ACQUISITION LAYER MANUFACTURED. It fails closed, which is
why it would have surfaced as host drift that never happened rather than as a
false ADD -- and that is the worse diagnostic outcome, because the search starts
on the host instead of in the producer.

One acquisition per slot now, projected into both views. This is the same law
the plan and apply paths already obey one level up, where the probe is bound
once and compared twice; it is stated at slot grain because that is where a
second read is cheapest to write and hardest to see.

A COMPLETED CALL THAT PRINTED NOTHING WAS ADMITTED AS A READING. `systemctl
show` can exit zero and print an empty line, and the reader took every
success=true as a value -- so an empty string entered the digest, the digest
differed from the desired one, the boundary reported MemberChanged, and a repair
would have been planned against a property nobody read. It is the
exit-zero-with-defaults defect again in its other half: there the unit did not
exist, here the question was not answered.

The three answers are now a pure projection: unsuccessful refuses, successful
and empty refuses, successful and non-empty reads. THE POSITIVE CONTROLS ARE
WHAT MAKE IT A LAW rather than a filter -- a reader that refused everything
would satisfy the empty-output row and break every real host, so "0" and
"infinity" are asserted READ. "0" because it is falsy-looking and a plausible
accidental filter; "infinity" because it is what systemd prints for an unset
cap and is therefore the most common real value.

Mutation receipts, both executed: admitting empty output again reds law 15;
projecting the namespace from a different observation than the addresses reds
law 16. 62 rows green after restoring, 4052 file(s) parse-clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`stat -c %F` can exit zero and print an empty line. The reader took every
success as a reading, so the empty string fell through the token decoder --
which is TOTAL, and that is exactly what made this reachable: an empty `%F`
is simply a word it has never met, so it decoded to `UnknownKind { word: "" }`
and left as `PathOccupiedByNonDirectory`. That is a POSITIVE assertion that
some object nobody can name occupies the path.

It fails closed for provisioning and is still wrong, because the two readings
send an operator to opposite remedies: "clear the obstruction, go look at it"
versus "the metadata read did not answer, the host read is broken". Success is
a fact about the CALL, never about whether the OUTPUT carrying the answer
arrived -- the same distinction the property reader already draws one operation
over for `systemctl show`.

So emptiness is decided BEFORE the decoder rather than inside it:

  fabric_cell_path_kind_observation(success, output)
    -> PathKindRead { kind } | PathKindReadRefused { cause }

`PathMetadataUnread` now carries that cause, threaded through the parent-routed
refusal, so the operator is told WHICH read failed. Without it the new cause
would have been a dead field, and the parent still decides absence-versus-
unreadable exactly as before.

LAW 17 asserts the whole `success x output` table. "0" and "weird new thing"
are asserted READ, so the rule is a presence test and not a value filter -- a
reader that dropped values it found uninteresting would pass an emptiness
assertion and still lose real answers. Receipt: mutating the wall away gives
FAIL, restoring gives PASS, file byte-identical after restore.

TWO STALE ANNOTATIONS RETIRED. The module header still credited `test -d` as
the mechanism separating absence from unreadability, while the same source four
paragraphs down explains why every boolean construction was retired for typed
`stat` evidence -- so a reader who stopped at the header left with the
predecessor mechanism. Review named one; checking found the claim spelled twice,
the second at the host-effects boundary. The surviving `test -d` mentions are
the historical narrative and are correct in the past tense.

63 rows green (17 acquire + 46 observe), 4052 file(s) parse-clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ide the all-families signature (#9369)

A fleet converge answers for a set of resource families, and the fabric
execution-cells cut needs to answer for exactly one of them. The tempting
spelling is a scope flag alongside the existing signature with the unselected
families passed empty -- and the existing signature made that the ONLY spelling
available: `fleet_converge_plan_subject` and `observed_baseline_text` both took
all five families positionally, so a fabric-only plan could only be expressed by
passing four empty lists.

That is the empty-observation narrow at the plan layer. An empty list says THIS
FAMILY HAS NO MEMBERS -- a positive claim about the host, and the one that
licenses removals -- while the truth is that nobody was asked. The two states
have opposite consequences and the signature could not tell them apart.

OUT OF SCOPE IS NOT A REFUSAL EITHER, and that is what decides the shape. A
refusal means a SELECTED obligation could not be satisfied; out of scope means
the obligation was never selected. Rendering the unselected families as refusals
would make every fabric-only plan operationally red for reasons no operator can
act on.

So neither state is represented:

  FleetConvergeRequest
    = FullHostConverge { host, timers, caps, spark, slots, fabric }
    | FabricExecutionCellsConverge { host, fabric }

The fabric-only arm carries no position for timers, caps, spark or slots. There
is no field to pass empty and none to pass refused, so the fabric-only CLI
branch cannot invoke those observers and discard them -- it cannot reach them.
Subject, member-set fingerprint, baseline text and apply-time admission are all
derived FROM the request.

SCOPE IS IN THE BASELINE TEXT, AND THE THIRD LAW IS WHY THAT IS NOT DEFENSIVE.
Give the full-host request empty families and it renders no timer, cap, spark or
slot rows -- exactly what the fabric-only arm renders, because it has no such
fields. Without a scope row the two baselines would be BYTE-IDENTICAL, the two
subjects would collide, and an apply could admit a fabric-only plan against a
full-host re-observation. `witness_scope_row_is_what_separates_the_two_baselines`
asserts the two line sets are the same size and differ only by which scope row
they carry.

APPLY-TIME ADMISSION WAS NOT PLANNED INTO THIS CHANGE; THE COMPILER FOUND IT.
Rewriting the fingerprint signature made `fleet_converge_apply_subject_admits`
refuse to compile, which surfaced that apply re-observes through the same
function. Had it kept taking loose families, an apply could have compared a
fabric-only plan against a full-host observation and read the mismatch as
ordinary drift rather than as a scope confusion.

Three of the four remaining call sites construct a `FullHostConverge` internally
rather than taking a request parameter -- they ARE the full-host builders, so
that is honest rather than a shim, and it leaves the CLI untouched until its
fabric-only branch exists. The one site that needed the parameter is apply-time
admission, where scope must survive from plan to apply or the two can be crossed.

4052 file(s) parse-clean. Three new scope laws green; full regression roster
across nine witness files in progress.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… that does not exist (#9369)

THE ANNOTATION WAS FALSE AND THAT IS THE MOST IMPORTANT LINE OF THIS COMMIT. It
said the fabric-only CLI branch "cannot invoke those observers ... it cannot
reach them at all". There is no fabric-only CLI branch: the wet plan path
observes timers, caps, slots and fabric unconditionally and builds a
FullHostConverge, and the wet apply path still routes through the loose-family
matchers. The sentence described the construction this type MAKES POSSIBLE in
the present tense, which is how a reader concludes coverage exists that does
not. Corrected in place, with the overclaim recorded rather than erased -- a
type that makes a wall possible is not the wall.

SCOPE IS NOW CARRIED ON THE SUBJECT, NOT ONLY INSIDE ITS FINGERPRINT. The
baseline text already includes the scope row, so two scopes hash differently and
a crossing was refusable. But that only DISTINGUISHES subjects; apply also has
to DECIDE which observers to run, and A HASH CANNOT BE INVERTED into FullHost
versus FabricExecutionCellsOnly. Distinguishing and routing are different jobs
and a digest does only the first.

It is a field rather than a parse of plan.txt for the same reason the bundle
digest exists: recovering a routing decision by reading back rendered human text
would make the reviewed artifact's PROSE load-bearing, and prose is the one part
of a plan nobody hashes for meaning.

fleet_converge_apply_subject_admits now compares scope explicitly through a
total fleet_converge_scope_matches, written as a nested match rather than == so
that adding a third scope arm FAILS TO COMPILE instead of quietly answering
false and routing nothing.

Two laws. witness_subject_carries_scope_as_a_readable_fact asserts the routing
fact is readable off the subject rather than implied by a digest.
witness_apply_refuses_a_scope_crossing_and_admits_its_own_scope refuses a
crossing in BOTH directions and admits the matching scope -- the positive
control is what makes it a scope wall rather than a blanket refusal.

WHAT IS STILL THE PREDECESSOR SEAM, named rather than left to be discovered: the
production wet apply does not call the request-based predicate at all. Its live
path runs fleet_converge_member_set_fingerprint_matches and
fleet_converge_observed_baseline_matches, both of which reconstruct a
FullHostConverge internally, so the canonical decision exists while production
consumes the older one. Porting that path, and then deleting or explicitly
naming the loose-family matchers, is the next commit in this lane.

Five scope laws green. 4052 file(s) parse-clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…cope

# Conflicts:
#	dag/extdeps/tools/stat.dag
…#9369)

witness_scope_row_is_what_separates_the_two_baselines asserted equal line
counts, one expected scope row in each, and the shared host row. None of that
establishes what its name claims. A mutation that CHANGED a non-scope row, or
reordered the rows, preserves every one of those assertions -- so the law was
green for reasons narrower than its name, which is the worst kind of green
because it gets cited as coverage.

It now compares the two line lists after normalising the scope rows away, so the
remainder must be IDENTICAL. "Only" is in the check rather than in the name.

RECEIPT, and the mutation is chosen to be one the OLD law passed: reordering the
fabric arm's rows preserves line count, preserves both scope-row counts and
preserves the host row, so every previous assertion still held. Mutated: FAIL.
Restored: PASS. Source byte-identical after restore. Row order is not a
cosmetic property here -- the baseline text feeds the fingerprint, so two
orderings are two subject identities.

line_is_a_scope_row routes through fleet_converge_scope_wire rather than
matching two literals at each site, so a third scope's row cannot be left in the
remainder and read as an ordinary difference.

Found by review, not by me. The defect class is the one this lane has been
finding all day in other people's instruments and has now found twice in its
own: an assertion that passes for reasons narrower than its name implies.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Named in an earlier commit on this branch so it could not go quiet, and this is
that commit: the canonical request-based decision existed while the LIVE apply
path did not call it.

fleet_converge_member_set_fingerprint_matches and
fleet_converge_observed_baseline_matches each took five loose family parameters
and rebuilt a FullHostConverge internally. So the request coproduct was the
authority everywhere EXCEPT where it matters -- one authority standing beside
the older one rather than replacing it. That is DESIGN section 3's
two-authorities case arriving as a leftover instead of as a fork, which is the
shape that survives review because nothing about it looks like a second model.

Both now take the request. The apply CLI binds observed_request ONCE and passes
it to both, rather than spelling the same five observations twice.

IT ALSO CARRIES SCOPE INTO APPLY BY CONSTRUCTION, which is the part that is not
just tidying. A caller now has to say WHICH REQUEST it observed, so a fabric-only
plan re-observed as a full host cannot reach these predicates at all -- where
before, the loose parameters would have been compared against whatever
fingerprint the plan carried and a scope crossing would have read as ordinary
member drift.

The CLI constructs FullHostConverge because that is what today's wet apply
observes -- there is still no fabric-only branch, and this commit does not
pretend otherwise.

4122 file(s) parse-clean, debt=42, zero citation refusals.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nch made about its own strength (#9369)

THE BREAKAGE: porting the two apply predicates to take a FleetConvergeRequest
left four witness call sites passing five loose family parameters. Every
fleet_converge_plan row failed on one resolve error. My local roster found it;
CI independently reproduced it at the same three source positions, so the
attribution was never in doubt.

Two things about that are worth keeping. Parse-clean held at 4122 with zero
citation refusals throughout, because call shape is RESOLVE and not PARSE -- a
sweep count is not a build. And a regex fixed three of the four sites and
silently skipped the fourth, because that one orders host: before
observed_baseline_hex:. Three of four is the shape that survives a spot check
and dies on a roster.

RETRACTION ONE -- the scope crossing is REFUSED, not PREVENTED. An annotation
said a fabric-only plan re-observed as a full host "cannot reach these at all".
False: the predicates take a request of either arm beside a fingerprint STRING
and nothing binds the two, so the crossing reaches them and FAILS a value
comparison, because scope is inside the baseline the fingerprint hashes. What is
actually unspellable is an observed request with no stated scope. Making the
crossing unwritable would need the plan artifact to hand over its scope as a
typed field rather than a hex string.

RETRACTION TWO -- production apply did NOT stop consuming the predecessor seam,
which is what the previous commit on this branch claimed. True of the two
comparison helpers; false of fleet_converge_apply_subject_admits, the composed
predicate that judges host AND scope AND fingerprint together and whose only
callers are witnesses. So the canonical decision still sits beside production
rather than being what production runs -- the same two-authorities shape the
helpers were just ported out of, one level up.

WHY IT CANNOT SIMPLY BE SWITCHED OVER, which is the useful residue: that
predicate takes a FleetConvergePlanSubject and the subject carries SCOPE. The
apply CLI has no subject -- it has an observed host plus a fingerprint string
and a baseline hex read back from FILES THE PLAN WROTE, and nothing in that
artifact records which scope was planned. So persisting the planned scope in the
artifact is a PRECONDITION rather than a follow-up, and it is inside piece 1 of
the brief, which requires scope to enter the plan text, the bundle digest and
apply-time admission -- not only the subject and the baseline.

All three overclaims on this branch have one shape: describing what a
construction makes POSSIBLE as though it were already wired. Each was caught by
review and none by a check. Recorded in the source rather than quietly edited,
because the rate is the finding.

62/62 fleet_converge_plan rows green -- the file the port broke, fully
re-measured. 4122 file(s) parse-clean, debt=42.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nstead of widening

Review 56581 found production apply composing separate admission checks while the
composed predicate had only witness callers -- two authorities for one decision,
read off an annotation that said so in as many words. It was right, and the reason
it could not simply be switched over was that the artifact recorded no scope: apply
had a host it observed plus a fingerprint string and a baseline hex read back from
files, so a subject could not be rebuilt without inventing the one field that
decides routing.

The subject is still not rebuilt, and that is deliberate. Turning the persisted
fingerprint text back into a ContentHash would mean minting a content hash from
untrusted file bytes -- the forgeable-mint shape DESIGN 4b records for
UriValidatedScalar, where a sole_constructor type's emitted mirror admitted a
representative from every refusal partition. So the direction is fixed one way:
serialize the subject down to the wire the artifact holds and judge there. Nothing
parses back. fleet_converge_apply_artifact_admits is the canonical predicate,
fleet_converge_apply_subject_admits is a projection of it, and the wet path calls it.

The planned scope is persisted as subject_scope.txt and decoded fail-closed.
Defaulting an empty or unrecognised wire to FullHost is the expensive mistake
available here: it would widen apply from one resource family to every family on
the host, and the widened run is indistinguishable from what the pre-scope
signature always did, so nothing would ever report the widening. That is the
absorbing fallback with its deficit frequency zeroed by construction. Empty and
unrecognised are separate causes because a write that did not complete and an
artifact minted by another vintage have different remedies.

The admission returns a coproduct rather than a Bool because the three failures
have different operator remedies -- wrong machine, would actuate an unselected
family, ordinary drift -- and only the third is routine.

Executed on this tree, five rows, each returning true:
  witness_an_undecodable_scope_wire_refuses_and_never_defaults_to_full_host
  witness_apply_admission_distinguishes_its_three_refusals
  witness_a_foreign_artifact_reports_its_host_before_its_scope
  witness_apply_refuses_a_scope_crossing_and_admits_its_own_scope
  witness_scope_row_is_what_separates_the_two_baselines
The fourth is the pre-existing law, passing after the delegation, so the refactor
preserved the behaviour rather than merely compiling. gunbc.fleet_converge_plan_cli
typechecks whole-module.

The annotations disclosing the two-authority gap are deleted with the gap, not
left standing over a construction that no longer has it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ource cannot inherit teardown

/opt/fabric-cells is one directory shared by every cell on a machine. It is
observed today and is not a converged member, and it could not become one:
FabricCellMember.slot is a required RunnerSlotIdentity and fabric_cell_member_key
joins on slot fields, so a host-scoped resource had no spelling except by naming an
arbitrary slot as its owner -- and every available slot is the wrong answer rather
than an imprecise one.

The prior ownership authority was worse than an over-broad claim:

  fn fabric_cell_member_ownership(member) -> Optional<Ownership> { Present { value: Owned } }

a constant function that never reads its parameter. There was no arm to add, so a
host-scoped subject would have inherited Owned with nothing going non-exhaustive and
nothing failing to compile. Total over its input by not inspecting it.

That matters because Owned is teardown eligibility. A host that stopped serving
fabric execution produces an empty desired set; an owned host root would reconcile
as an observed extra and select removal of the directory containing every cell on
the host. No step in that chain is a mistake, which is why a policy field saying
do-not-remove would have been the wrong repair.

So ownership is now a total match over a subject coproduct, in gunbc.fabric_cell_subject,
and BOTH cell families route through it. No classification moves -- every slot member
is still Owned. What moves is where the decision is made: a fourth subject kind now
fails to compile at one function instead of being inherited silently by both families.

The subject is upstream of both families rather than inside either, and that was
forced rather than chosen: either family owning it would make the other import it and
the first import back, which the acyclicity law forbids.

It is NOT a spelling of FabricCellNamespace, and the difference is decidable.
fabric_cell_address_namespace maps FabricCellRootAddress -- per-slot, created by this
family, teardown-eligible -- onto the SHARED FabricCellsRootNamespace, because listing
the shared parent is how one slot's cell root is proven absent. Deriving ownership from
the namespace would make every slot's cell root Ensured and permanently un-tearable.
Container and subject coincide for two of three addresses and diverge for the third,
and the third is the one this piece is about.

Ensured for the host root is measured, not assumed: nothing creates /opt/fabric-cells.
gunbc.fabric_cell_converge emits no effects surface at all, corroborated by
runner_lifecycle and by fleet_converge_plan's own apply line.

No EffectsOrRefusal surface is exposed here for the same reason -- it would be the
subsystem's first, with no consumer until the realization pieces land.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…olved last-wins

Review 56598 found two definitions of fleet_converge_apply_subject_admits in one
module. My edit replaced the annotation above the original and appended a new
definition below it, leaving both. The original is deleted; the artifact-level
projection is the sole authority its annotation describes.

THE REVIEW'S "WON'T COMPILE" IS REFUTED BY EXECUTION, AND THAT IS THE WORSE HALF.
The duplicate compiled, and five witnesses passed over it. Probed deliberately with a
two-line fixture -- one module, two definitions of one fn returning 1 and 2, and a
caller:

  probe_dup_caller() -> returned 2

No diagnostic. The compiler admits duplicate function definitions in a single module
and resolves the call to the LAST one. That is the same class DESIGN 4b already
records for a census-AMBIGUOUS type name resolving by silent last-import-wins instead
of refusing, one level over: definitions inside a module rather than imports across
them.

WHY MY OWN EVIDENCE WAS BLIND TO IT, stated because green-by-execution is the standard
I hold others to. The two definitions were semantically equivalent -- both computed
host AND scope AND fingerprint -- so no behavioural witness could discriminate them,
whichever one won. Execution proved the behaviour and could not see the duplication,
and no gate reported it either. I do not claim to know which definition CI was running.

Verified after the deletion: witness_apply_refuses_a_scope_crossing_and_admits_its_own_scope
returns true. compare_content_hash and ContentHashEqual became unused imports with the
deleted body and are removed with it; the two annotation blocks that had been left
stacked are merged into one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Review 56618. The block above witness_teardown_eligibility_is_projected_from_the_subject_both_ways
appeared twice: my edit anchored on the `test fn` line rather than on the annotation,
so the replacement was inserted and the predecessor was left standing.

THE STALE COPY WAS THE WEAKER ONE, which is why this is not purely cosmetic. It read
"a host-scoped subject is never teardown-eligible and a slot-scoped one always is",
describing the sampled-slot form the row had before it was strengthened; the current
row folds over the whole fabric execution slot population and says so. A reader taking
the first block at face value would have understood the assertion to be narrower than
it is.

SAME ROOT CAUSE AS THE DUPLICATE PREDICATE THIS STACK ALREADY CARRIES a fix for
(119e00c): an edit anchored on the wrong boundary, leaving the thing it replaced.
There the compiler admitted the duplicate silently; here nothing could refuse it at all,
since 4c makes annotations invisible to every semantic pass. Swept the four touched
files for repeated annotation openers -- clean.

witness_teardown_eligibility_is_projected_from_the_subject_both_ways returns true after
the deletion.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Piece 3 of the provisioning brief needs a create that REFUSES a missing parent.
extdeps.tools.mkdir modeled only the -p form, so there was no door -- the module
mis-described its cited upstream by omission rather than by error. The authority it
already cites (pubs.opengroup.org mkdir) specifies both forms.

WHY THE REFUSING FORM IS THE ONE A CELL ROOT WANTS. The module's own annotation makes
the argument without knowing it was doing so: "-p is the idempotent form: an existing
directory is not an error. That is what makes this an ENSURE rather than a CREATE."
A missing parent is a failure state, and -p answers it by FABRICATING the whole chain
instead of refusing -- an absorbing fallback in the DESIGN section 5 sense. Where the
parent belongs to another authority, that is not merely untidy: gunbc.fabric_cell_subject
classifies /opt/fabric-cells as Ensured, meaning required present and never created by
the cell family, so -p would have the cell family silently create the exact directory
its ownership model says is not its to make, and nothing would report it.

THE NON-IDEMPOTENCE IS NOT A DEFECT TO WORK AROUND, and the annotation says so rather
than leaving a reader to discover it. This form is reached from an ADDED hunk, where the
member was observed absent. A second run erroring means the observation and the host
disagree, which is a line-stop, not a nuisance. A caller wanting run-anyway semantics
wants -p and should say so by calling it.

ONE WALL FIRED AND IS RECORDED BECAUSE IT WORKED. extdeps.exec.command.argv_command
carries an admit_callers roster and refused mkdir_exact_command_at at resolve, naming
every permitted caller. That is the per-function admission wall DESIGN 4b describes as a
live capability, and it is live: the refusal could not be silenced from inside this
module. Added to the roster in extdeps/exec/command.dag, which is where the fact belongs.
Worth stating beside the duplicate-definition hole this stack already carries a fix for:
same substrate, same afternoon, one guarantee real and one absent.

Verified: mkdir_exact_args(path: /opt/fabric-cells/srv3-06) returns [/opt/fabric-cells/srv3-06]
-- exact args, no -p. No duplicate declarations in the module (8 fns, checked).

NOT PUSHED AS ITS OWN PR. Per the grouping ruling, piece 3 lands whole -- this surface,
the closed effect sum, and the cell-root create that consumes both -- because a create
surface with no consumer is section 6 residue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…act create

WIP for piece 3. Full message on the eventual PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The effect sum had only witness callers, which is the same two-authorities shape
piece 1 existed to close, one level over: a realization surface exists and the thing
that needs it does not consult it.

gunbc.fleet_converge_plan's FabricCellFamilyRealizationUnavailable arm rendered every
action as an undifferentiated REFUSED-REALIZATION. That was honest when the fabric
family had no realization surface at all -- fabric_cell_converge emits no effects and
two carriers say so in their own words. It has one now, so the family asks it, and an
operator reads WHICH address could not be realized and WHY rather than learning that
something somewhere is unrealizable.

THE PLAN STILL REFUSES AS A WHOLE and the lines say so rather than implying partial
progress. A cell root created without its resource boundary is an UNBOUNDED cgroup
slice, which is worse than an absent cell: absent is honest, unbounded looks
provisioned, and the fleet's dominant failure is eviction under resource pressure.

THE REFUSAL COUNT STAYS TOTAL WHEN THE PLAN REFUSES, and this is the part that would
have gone wrong quietly. With a realization surface in place it is tempting to count
only the TYPED refusals -- which today reports ONE deficit for a cell whose three
addresses all went unapplied, understating the owed work by exactly the amount the
all-or-nothing rule causes. The existing annotation ("the deficit is per unit of work
owed") survives unaltered, because its argument was never about the arm it sat on.

Verified on this tree, six rows returning true:
  witness_one_unrealizable_address_refuses_the_whole_cell_and_emits_no_effects
  witness_directory_addresses_alone_realize_both_creates
  witness_the_directory_create_carries_no_parents_flag
  witness_refusals_accumulate_across_addresses
  witness_the_refusal_causes_are_distinguished
  witness_apply_refuses_a_scope_crossing_and_admits_its_own_scope  (pre-existing, after the wiring)

No duplicate declarations in any touched file. Recording that my first two checks for
that were FALSE POSITIVES from my own regex truncating at digits and then matching a
prefix -- the check that decided it uses full identifiers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…verb no longer carries the distinction

The realization wiring moved WHICH address could not be realized and WHY
off the action verb and onto the refusal variant. These three rows were
still asserting the old rendering: one undifferentiated line per action,
with ADD and CHANGE spelled into the line text.

The distinction they exist to protect survives -- an absent boundary
refuses through BoundaryDirectiveVocabularyIncomplete and a drifted one
through CellChangeNotYetRealizable, each naming its address -- so the rows
are re-expressed against that structure rather than the code reverted.

The line count moves from one-per-action to per-address refusals plus
exactly one whole-plan line, which is the all-or-nothing rule made visible:
an operator reads which addresses are owed and that none was applied.

Verified by execution rather than by adjusting to output: refusal_is_
rendered read false before this change and true after, on the same row.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The realization call replaced the only use of fabric_cell_action_line, so
it stood defined with zero callers -- an artifact with no consumer,
introduced by this branch rather than inherited.

Found by merging main and re-reading what the wiring displaced, not by a
check. The five-arm match it carried is not lost: the refusal variants in
gunbc.fabric_cell_effect now carry the same distinction, and each names
its address rather than its action verb.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@briansrls
briansrls marked this pull request as ready for review August 28, 2026 05:51

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ac0862b18f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +778 to +781
CellPlanRealizable { effects: es } =>
map(es, e => match e {
FabricCellDirectoryCreate { path: pth, command: _ } =>
concat("REALIZE fabric-cell create-directory ", pth as String)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Execute directory effects before labeling them realized

When an admitted readback has the resource boundary converged but either directory absent, this branch emits REALIZE fabric-cell create-directory even though the fleet-converge apply path never executes the stored ArgvCommand: fabric_cell_apply_lines turns every returned line into a shell comment and explicitly states that no fabric-cell host effect is emitted. Applying such a plan therefore leaves the directory absent despite the plan presenting it as realizable; either wire these effects into the apply/host-effect path or continue rendering them as unavailable.

Useful? React with 👍 / 👎.

@briansrls
briansrls merged commit 02452b0 into main Aug 28, 2026
2 of 6 checks passed
@briansrls
briansrls deleted the fabric/cell-realization branch August 28, 2026 18:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant