Nishi Debt Program

Eating the ecosystem’s technical debt from the first byte up — compiler first, because everything above it inherits its defects. Every number below is measured from the live hub, not asserted.

Measured 2026-07-25 · hub epoch 1785027879 · warden beat 1785026401 · workstream debt-eater · services 14/14 OK

The ledger, as measured

900debt rows total
660open
240eaten
251gating (sev ≥ 6)
0sev 9 (was 1)
Open rows by severity
Severity987654321
Open rows036801352381015992
Honest counter-signal. Open debt rose from 639 to 660 during this session. The hourly law-warden beat and four concurrent seats are filing faster than any single seat can eat rows one at a time. That is the argument for building class-eaters (below) rather than grinding the list.

Law warden — live state and trend

Eleven mechanically-enforced laws, re-measured hourly with zero human involvement. 9/11 currently breaching; enforcement coverage 1000‰. The trend across three consecutive beats is the part that matters:

LawDetector178501920117850228011785026401TrendWorst offender
L001inlinelit1868313576falling −5107_f64_kat_vectors.nx
L002token4646flatwasm
L003unregistered235237rising +2mv.elf
L004token00CLEAN
L005tokendir181181flatnx_sni_route_gate.nx
L006inlinelit3183928923falling −2916nx_hll_bias_table_ds.nx
L007segamp000CLEAN ×3
L008tokendir155915591558flatnx_janitor_sprawl_gate.nx
L009gatedry192419271934rising +10deployclass_gate.nx
L010helperdup316316319rising +3nx_accesswall_research.nx
L011scancap818181flatnx_browser_profile_gate.nx

Read that carefully. Magic-number debt (L001, L006) is falling — it is being actively eaten. Gate-DRY debt (L009) is rising: new gates are being authored that do not inherit the shared verdict library, faster than old ones are migrated. L009 is therefore the highest-leverage target in the ecosystem, and it is now the top-severity row.

Rung closed: the compiler (seq715)

The deepest defect in the tree. obj.fn_field(args) compiled cleanly but emitted the function’s address and discarded the argument list — so the entire OOP vtable pattern was silently broken tree-wide. It failed open.

The filed diagnosis was wrong

The debt row said “restore the parse.c postfix TY_FN branch.” But parse.c:1498 already carries that branch, correctly. The real fault is a parity gap: the self-hosted runtime/nx_parse.nx never had it. A session following the row would have edited an already-correct file and proved nothing. Corrected in the workstream journal.

Four layers were wrong, not one

LayerDefect foundFailure mode
parse_field_chainno TK_LPAREN branch at allsilent — returns fn address, drops args
ir_emit_call_indirectset n_operands = n_args+1 but only wrote op1..op6silent — backends read never-written slots
x86ctx_emit_call_indirectloaded only rdi..r9, dropped arg 7+silent — same bug that SEGV’d TLS server-hello and HTTP header parse on the direct path
rv_emit_call_indirectreused op1 for arg 8+silent — now fails loud

Regression proof

A compiler change has unbounded blast radius, so the oracle had to be established first: the compiler is deterministic (same input, same compiler, byte-identical output — verified), which makes byte-diffing valid.

CheckResult
Corpus swept, old compiler vs new464 files
Byte-identical output453
Changed4 — exactly the blast-radius files named in the row
Uncompilable7 — pre-existing, fail identically on both compilers
Self-host fixpointstage2 == stage3, byte-identical (2 620 661 B)
Indirect-call sites in nx_media_session.nx0 → 6
Monitor gate through the normal build driver13/13 GREEN
Same gate under the old compilerRED — parser desync, 0-byte output

Why it went unnoticed for two months

A monitor for exactly this defect existed — bench/nx_fn_ptr_struct_call_smoke.nx, the MONITOR pillar of the 2026-05-19 four-pillar fix. But bench/ is not one of the four directories the build driver probes, so it resolved to SOURCE-NOT-FOUND and was never once runnable.

Law banked: a guard the build cannot reach is not a guard. The replacement lives at runtime/_hdl_build/nx_fnptr_call_gate.nx, where the driver does look, and it is self-testing by construction — it is compiled by the compiler it tests, so a regression makes the gate itself go red. It is also a D001 nx_gate_verdict adopter, so it pays down L009 rather than adding to it.

Two false results caught by controls

  1. The first hub probe bound the call with let r = p.f(1,2,3). That form compiles clean on the defective compiler (it silently binds the address) — the probe would have reported a fixed hub that was not fixed. The call must sit in an if condition, where the defect desyncs the parser and the build fails outright. Verified against the banked previous compiler before trusting any hub result.
  2. A staged artifact left over from the earlier build read as a valid ELF and nearly passed as proof. A clean rebuild returned BUILD-FAILED with the real error.

Rung closed: a false sev 9

The ecosystem’s single highest-severity row (seq682, seg-store segment amplification, “a plane accumulating unbounded segments until reads OOM the host”) was measured against the live hub rather than inherited:

The row was stale. Because nx_seat boot surfaces the top-severity row as every seat’s “eat most important first” pointer, every seat booting into the ecosystem was being aimed at a non-problem. Row eaten with the beat epochs as evidence; sev 9 count is now zero.

The real finding underneath it (filed seq899). The warden autofiles a debt row when a law breaches, but nothing ever closes that row when the law goes clean — the warden’s own note says “filed once and never re-filed; the journal carries movement.” So the journal knows the truth and the ledger does not. The ledger is a filing cabinet where it should be a measurement. The fix is a reconciler that closes law-derived rows after N clean beats and re-opens on re-breach — strictly for law-derived symptom rows, never for root-cause rows.

Rung closed: the L009 class-eater

L009 (gate-verdict DRY) was the top-severity row and the only one measurably growing. The filed remedy was MIGRATE-ON-TOUCH — hand-migrate ~2553 gate organs. Reading the detector, and then the offender it names, showed that framing was wrong.

What the detector actually counts

lw_gatedry flags any *_gate.nx that contains verdict= or GREEN but none of gv_head / gv_check / gv_verdict. So the question is simply: does this gate inherit the shared verdict library?

The offender is machine-authored

The worst offender the warden names, deployclass_gate.nx, opens with:

// AUTHORED BY nx_compose_builder (X-AUTH-EXT-001 composition shape) from a DATA spec.

nx_compose_builder.nx — 94 lines — stamps its own _p/_pn print helpers and a hand-rolled verdict line into every organ it authors. Every gate it emits is therefore an L009 custom-verdict breach and an L010 helperdup breach by construction.

That is why both laws were rising while migration ate the backlog. A generator was manufacturing the debt faster than humans removed it. You cannot out-migrate a generator by hand. The class-eater is the generator, not the 1934 files.

Fixed at the source, proven end to end

The generator now emits import "nx_gate_verdict.nx" and gv_ctr/gv_head/gv_check/gv_verdict, with no per-organ helpers. It can no longer author a non-DRY gate.

StepResult
Generator buildsOK
Authors a gate from a data speccomposedry_probe_gate
Authored gate compiles and runs2/2 verdict=GREEN, exit 0
L009 detector inputs on the authored sourcehasgv=4 → not counted as custom
L010 duplicated print helpers0
Pushed to buildroot and built on the hubBUILT, 17544 B

This stops the inflow. The existing backlog still needs migrating — but regenerating the generated share now migrates in bulk rather than one file at a time.

Rung closed: the second compiler defect was already fixed

seq521 (sev 8) held that nx_cc laid out nx_int-aliased struct fields as size 0, collapsing field offsets — with an exposure of 2292 alias field declarations across 337 organs. Re-measured rather than acted on, three ways:

EvidenceResult
Executed the row’s own repro locallyP0:o0=a o1=b o2=c / P1 ok / P2 ok, exit 0
The row predictsP0 o0/o1/o2 all BAD, P1 BUG — the exact inverse
Hub sourceprepass_register_aliases defined and called
Deployed hub compiler binarycontains "too many module type aliases", a literal unique to that pass

The row’s own stated ROOT FIX — “resolve type aliases to concrete size BEFORE computing field offsets” — is exactly what that pass does. Row eaten. That is the third stale premise this session caught by re-measuring first.

The class had no guard, so one was built

The artifact that proved seq521 only prints. No verdict means no judge and no build driver can ever fail on it — the same shape as the seq715 monitor that sat unreachable in bench/. So the probe became a real gate, shipped complete:

source → /api/build → /api/promote → /api/tools/register → /api/cap/mint → reconcile → run it

6/6 GREEN on the hub. That run matters beyond the gate: when seq521 was eaten, the hub evidence was source plus binary inspection, and was labelled as such. This gate is compiled by the hub compiler and executes on the hub, so the fix is now proven functionally there rather than inferred.

Its teeth are discriminating by construction — every one reads raw i64 offsets off the struct base, which is precisely what collapses under the defect. T4 is a deliberate negative control: pointer-first layout survived even under the bug, so it proves the gate exercises layout rather than passing everything. The fn-pointer half is left to nx_fnptr_call_gate and referenced, not copied.

Law banked. seq521 and seq715 were the same class — self-hosted-parser parity gaps against the C anchor — and one had been fixed while the other had not, because nobody swept for siblings when the first was found. A parity gap is never a single row: sweep the class, and leave a reachable monitor behind.

Rung closed: the ledger can now close its own rows

The stale sev 9 above had a mechanism behind it. The warden autofiles a debt row when a law breaches, but nothing ever closed one when the law went clean. Reading the source showed why, and it was worse than “missing feature”.

Filing was a one-way door

lw_filed_has tested whether a FILED frame existed anywhere in law_filed.jrnl. Two consequences:

Fixed by comparing the last FILED offset against the last CLOSED offset, so FILED → CLOSED → FILED cycles correctly. Position decides rather than count, which also makes it robust to the duplicate frames already in the live journal (L006 is filed twice at one timestamp).

The close handle was being thrown away

nx_debt answers an add with DEBT-ADDED seq=<n>, and nx_debt eats by id only. The warden was capturing that reply and discarding it — so no reconciler could ever have had a handle to close a row. The id is now parsed and stamped as a fifth column, returning -1 when absent so a frame is never stamped with a wrong id (a wrong id would eat another lane’s row). Additive, so existing four-column readers are unaffected.

CheckResult
Warden gate before18/18 GREEN
Warden gate after20/20 GREEN — zero regression
T19 FILED→CLOSED→FILED cyclePASS — discriminating by construction
T20 debt-id parse, hit and absentPASS
Staged binary proven to be this sourcenew CLOSED literal found in its string table
What is deliberately not shipped. The reconcile pass itself — walk clean laws, require N consecutive clean beats, eat, append CLOSED — is specified but not built, because today it would be a no-op: 9 of 11 laws are breaching and must stay open, L004 was never filed, and L007’s row is already eaten. It could not be demonstrated end to end, and shipping undemonstrable code is exactly the synthetic-pass defect this ecosystem already outlawed. The foundation it needs — a reversible cycle and a recorded id — is now live and gated.

Grade by layer

LayerRungStateEvidence
L0 compilerseq715 indirect callsFIXED + PROVEN (local)464-file diff, fixpoint, gate 13/13
L0 compilerseq715 landed on hubBLOCKED → seq891/api/build returns BUILD-FAILED on hub
L0 compilerseq521 nx_int field layoutrepro exists; 337 files exposed
L1 storageseq682 seg-amp (sev 9)EATEN — was stalemanifest = 1 seg; L007 CLEAN ×3
L1 storageseq727 quadratic writer (root)compaction cadence holds it; writer unchanged
L2 verificationD001 / L009 inflow (the generator)FIXED AT SOURCEauthored gate hasgv=4, 2/2 GREEN, built on hub
L2 verificationD001 / L009 existing backlogwas 1924 → 1934 rising; regeneration now migrates in bulk
L2 verificationL010 helperdup inflowFIXED AT SOURCEsame generator; 0 duplicated helpers emitted
L3 lawsL001/L006 magic numbers−5107 / −2916 over 2h
L4 source integrityseq207/seq701 dual copiesOPEN29 divergent; compiler itself is one
L5 honestyL011 scanner coverageOPEN81 scanners hide coverage
Infrastructureseq891 toolchain deployNEW — blockingsee below

The seg-store can give memory back

The cache invalidation leak is closed — and closed in the shape that is sound by construction rather than sound by auditing ~180 callers.

Why the obvious fix was refused

The stale-signature branch re-opened the store and overwrote the cached handle, orphaning an entire mapping set on every edit. Dropping a close into that branch would have been one line — and would have converted a bounded leak into an unbounded use-after-free, because the cached open hands back a raw handle with no refcount and no generation. The sibling who built the cache had already flagged exactly this in their own comment and deliberately deferred it.

Retire, then reap

ToothProvesResult
T6the invalidated handle is retired, not lostPASS
T7the retired handle is still readable — reads the original key back after invalidation, which is what proves retiring is not a freePASS
T8reap frees and empties the ringPASS

Teeth were added to the sibling's existing cache gate rather than built as a second gate. 8/8 GREEN on the hub.

A lying instrument, created and then fixed. The gate's verdict line carried a hardcoded /5 while its pass test compared a separate literal, so the new teeth printed passes=8/5 — a gate misreporting its own denominator. Both readers now come from one constant and cannot drift.

First consumer wired — and why no number is claimed

The hub gateway now calls the reap at the top of its accept loop, immediately before accepting a connection. That point was chosen because it is structurally quiescent, not because it was convenient: the previous request's frames have all returned, the next has not begun, and both of this daemon's store readers bind their handle to a function-local binding that never escapes into a static, a struct, or a return value. Reaping anywhere a handle is held would be the exact use-after-free the design exists to avoid — so the reason is written into the call site, to stop anyone moving it.

It compiles (416 955 B). In steady state the call returns zero and costs nothing; orphans appear only when a store's manifest changes — a roles or maturity edit — and then it hands back the whole previous mapping set instead of leaking it for the life of the daemon.

Blocked, measured rather than assumed — and no number is claimed. The hub gateway is not a supervised service: it appears in neither the supervisor snapshot nor the status listing, so there is no deploy target for it, and the promote path refuses daemon names by design. The wiring is correct and compiled but cannot be deployed or measured here, so no before/after memory figure is reported, because none was taken. To finish: either give the gateway a deploy target — now cheap, since the toolchain arc proved that path — or wire a consumer that is supervised. The document portal daemon is the better candidate: it is in the service list, and its own history of per-request opens marks it as a heavy seg-store reader.

How the sev 9 was re-scoped

The remaining sev 9 says the seg-store loads an entire store into anonymous RAM per open and nothing ever frees it — and asks for ss_close to be built. Before building it, the state was re-measured. It already exists, written by a sibling lane, and it is careful work: sizes derived from the handle so no layout change, merged-index interior-slice detection so it cannot free three sub-slices of one mapping as three mappings, frees the reported blob size rather than the padded one so it can never release a neighbouring mapping, pointers nulled as freed, handle released last.

None of it was rebuilt. That is the fifth time this session that measuring before acting avoided duplicating a sibling's work.

One figure in the row is also stale: the headline 6.58 GiB leak on one daemon came from re-opening the store twice per HTTP request, and native-config reads now route through a cached open. That number should not be quoted forward.

What actually remains — and why the obvious fix is a trap

ss_close has zero production call sites: its only two callers are inside a selftest. The live leak now sits in one precise place — the cache's stale-signature branch re-opens the store and overwrites the cached handle without closing the previous one, orphaning an entire mapping set every time that store's manifest changes.

The one-line fix would be worse than the bug. The cached open returns a raw handle and promises the same handle semantics as a plain open, with no refcount and no generation counter. A caller that obtained the handle before an invalidation is still dereferencing it. Dropping a close into that branch converts a bounded leak into an unbounded use-after-free in the most-shared primitive in the ecosystem — exactly the catastrophe the row predicted when it asked for a handle-generation guard. That edit was deliberately not made.

The correct shape is recorded instead: per-slot generation and refcount, acquire/release for readers, and a gate that invalidates while a caller still holds the old handle and asserts no fault — mutation-proven by removing the refcount check and watching it crash.

The deeper lesson: the row was right that this must not be bolted onto the end of another task, but the reason is sharper than "it is big." The dangerous part is not writing ss_close. It is deciding who is allowed to call it.

The compiler is landed

The deepest defect in the program — the one every other layer inherits — is now fixed on the hub, proven by behaviour rather than inspection:

Same discriminator, same hubResult
Before the toolchain deployBUILD-FAILED — parser desync
After the toolchain deployBUILT, 9583 bytes
Health throughout14/14, zero down
Rollback point_offc/nx_cc_sovereign.elf.prev banked

The pipeline was entirely sovereign, with no shell transport: pack on ext4 (never the 9p mount, which is documented to corrupt about 1% of the time) → round-trip verified byte-identical locally before sending → upload over TLS 1.3 with a minted session token → /api/unpack/api/deploy target=toolchain.

The binary shipped was not the one originally proved. The local compiler had changed from 537779 to 544275 bytes after the earlier promote. Rather than ship it blind, the full 464-file sweep was re-run against the banked pre-fix compiler: 449 identical, 8 changed, 7 uncompilable on both. Four changed files were the known blast radius; the other four differed only by .byte with no operand becoming .byte 0 — a sibling lane's empty-string-literal fix. Delta fully explained and strictly better, so both fixes shipped together.

The new compiler immediately found a real leak

The first regression rebuild failed with a message the old compiler could never have produced:

module const used before its declaration: SS_MF_MAGIC
-- it would silently read 0; move the const ABOVE its first reader

In nx_seg_store.nx the writer segs[mc] = SS_MF_MAGIC sat ~29 lines above the constant's declaration. Under the old compiler it stamped 0, while ss_manifest_free compared against the real 0x53534D46. The sentinel could never match, so the stashed manifest buffer was never unmapped — a leak on every manifest read, in the most-shared primitive in the ecosystem, in the same memory class as the open sev 9 that this file's own comments already reference.

Not a compiler regression — the compiler refusing to silently read 0 is what surfaced it. Fixed by hoisting the constant above its first reader; the failing organ then built clean. Blast radius was checked first: the affected free path has exactly one caller.

A mistake, caught in the same pass. The first edit pair had its ADD anchor fail to match while the REMOVE succeeded — leaving the constant undeclared, strictly worse than the original bug. Re-anchored on an unambiguous top-level line and verified exactly one declaration now precedes both readers. When an edit pair adds and removes, verify the add landed before trusting the remove.

How the toolchain capability was built

seq891 is closed and live. The supervisor carrying the new toolchain-deploy path was deployed over the sovereign API and came back DEPLOYED-GREEN, with health 14/14 and zero services down before and after. The management log records it plainly:

[hostctl] selfswap: atomic-install new supervisor (sites.elf untouched)
  install rename rc=0
  killed old supervisor procs=2
  new supervisor daemonized (re-exec'd live binary as `supervise`)

Rows eaten: seq891, seq983, seq992, seq998.

The missing piece was a rename bridge

/api/build stages <target>.sov.elf.new, but the deploy plane wants per-target names, and nothing reachable over the API bridged them. That is why the established workaround was to build off-hub and upload — i.e. to leave the sovereign API. So nx_stage_alias was built as the narrowest thing that closes the gap:

Shipped complete — build, promote, register, cap, reconcile, and a hub selftest at 6/6 GREEN.

Order was the whole safety argument

The seq992 fail-safe guard had to be inside the binary being deployed, and the deploy itself had to be made safe first by staging nx_hostctl.new through the bridge — because deploying with it absent is precisely the brick. The staged binary was proven to carry the guard by grepping its string table for the REFUSED literal before promoting.

Honest evidence limit. The seq992 REFUSED path is compiled into the live supervisor and string-proven, but it was not exercised on production. Exercising it means removing both staged artifacts and betting the supervisor on the guard working — the same risk as the bug itself. It is recorded as deployed-and-reviewed, not as runtime-proven.

What remains for the compiler is now mechanical: place a proven nx_cc_sovereign.elf at buildroot/runtime/nx_cc_sovereign.elf.new, run /api/deploy target=toolchain, and prove the landing by /api/build target=nx_fnptr_min_probe returning BUILT instead of BUILD-FAILED.

How seq891 looked before it landed

The toolchain deploy path is now written and compiling on the hubcmd_toolchaindeploy and cmd_toolchainrollback, built clean at 195 949 B. They reuse hc_promote_to, the same primitive the torrent and gallery cross-dir promotes already use, which:

That last point is why this is the right mechanism and the tempting /api/unpack shortcut is not: nx_treepack writes 0644 and unlinks, which would strip the executable bit off the live compiler and break every build (seq903).

A second finding shrank the job considerably: a new deploy target needs only a config row, not a mgmt-API rebuild. md_resolve_target reads deploy_targets.conf and the file wins over the compiled-in table — the file’s own header says that is precisely what lets a target be registered without root.

Why it is not flipped yet

/api/build stages <name>.sov.elf.new, but cmd_selfswap renames a hardcoded nx_hostctl.new. There is no API-reachable rename or copy to bridge them: nx_fs_write is text-only, md_promote_staged only maps <n>.new → <n>, /api/promote maps to <t>.elf, and /api/unpack writes only under buildroot/runtime at 0644.

This explains a longstanding fact: no hostctl deploy has landed since 07-09. It was read as a health-probe problem; it is a naming gap with no bridge. Filed as seq983 with two small fixes: (A) nx_mgmt_client runs on the NAS, so it can re-stage a NAS file under the correct basename entirely over the API — blocked today only because it is not in the registry /api/cap/mint validates against, so the capability cannot be self-served; (B) teach cmd_selfswap to also accept the .sov.elf.new name, three additive lines that kill the trap permanently — shipped via (A) once.

Staging is never-brick; flipping the supervisor without room to verify and roll back is not. The work stops at the staged, reversible boundary by choice.

The most important thing found: the supervisor could brick itself

Pursuing seq891 surfaced a latent sev 8 hazard in the supervisor’s own self-update path. cmd_selfswap does this:

sys_renameat(HC_SELF, HC_SELF_PREV)          // live -> .prev
let rr: i64 = sys_renameat(HC_SELF_NEW, HC_SELF)   // .new -> live
... kill the running supervisor ...
... re-exec HC_SELF ...

There is no existence check on HC_SELF_NEW before the live binary is moved away. If nothing is staged under that name, the live supervisor is moved to .prev, nothing is installed, the running supervisor is killed, and the re-exec targets a path that no longer exists — no supervisor, and it cannot respawn itself.

This is the same outage hc_promote_to was rewritten to avoid. Its own comment says it “moved the live binary to .prev and installed NOTHING → the daemon could not respawn.” That function got an hc_exists guard. cmd_selfswap never did.

It is reachable by the documented sequence

/api/build stages <target>.sov.elf.new. The deploy row names nx_hostctl.new. No API-reachable rename bridges them. So the natural, documented API-first sequence — build hostctl, then /api/deploy target=hostctl — runs selfswap with the staged binary absent. Any seat following the standard pattern hits it. It is a plausible real cause of the standing fact that no hostctl deploy has landed since 07-09.

The fix is written into the source: resolve the staged binary before touching the live one, accept the /api/build name as a fallback, otherwise print REFUSED and return non-zero with the live binary untouched. That closes the naming trap permanently as a side effect.

Concurrent-edit finding (seq998). nx_hostctl.nx is currently unbuildablecall to undefined function: hc_file_age_s, called once at line 2802 and defined nowhere. Not from this workstream: an earlier hostctl build in the same session succeeded, and the file grew again between two consecutive calls, so it is under active concurrent edit. The missing function was deliberately not added here: if the owning lane lands its own definition, a second one collides as a duplicate and breaks the build a different way. Impact is source-only — the live supervisor is untouched and the failed build staged nothing.

The original framing of seq891

The proven compiler fix cannot be landed API-first. /api/upload gates on md_upload_target_ok, a hardcoded service basename allowlist. buildroot/_offc/nx_cc_sovereign.elf is not in it, and /api/build stages to nishihost/ with no allowlisted route into buildroot/_offc.

The ecosystem can build and deploy every service over its own API, but cannot update the compiler that builds them. Closing it means a never-brick toolchain deploy target mirroring the proven gallery/torrent recipe. That path touches nx_hostctl — the supervisor — which is operator-gated and is itself one of the 29 divergent dual copies, so it is sequenced behind source reconciliation rather than rushed.

RACI

RoleWhoScope
Responsibleseat debt-eatermeasure, fix, prove, journal, publish
Accountableoperatorgo/no-go on supervisor-class change (nx_hostctl, toolchain swap)
Consultednx_law_warden hourly beat; sibling seats via the active boardindependent measurement; contention avoidance
Informedall seatsnx_seat boot digest · ws_sync.jrnl · this page

Method and surfaces

Operated API-first over the sovereign control plane — no ssh, scp, curl-to-shell plumbing for ops. Tools driven as MCP tools/call against the sovereign edge with a least-authority scoped capability token.

SurfaceUsed for
MCP nx_seatboot / checkin / brief — 1 KB session boot instead of ~40 KB of reading
MCP nx_debt, nx_debt_view, nx_debt_hygieneledger read, show, eat, add
MCP nx_fs, nx_fs_write, nx_shelltoolhub source read/write, bounded greps and globs
API POST /api/buildcompile on hub — used as the seq715 discriminator
API POST /api/cap/mintself-served the scoped 26-tool capability for this workstream
API GET /api/healthblast-radius check after every transport anomaly
MCP nx_ws_syncappend-only workstream journal (the durable record)

Reproduce the compiler result

./_offc/nx_sov_build_run.elf nx_fnptr_slot_probe     # RED on a defective compiler
./_offc/nx_sov_build_run.elf nx_fnptr_call_gate      # 13/13 GREEN on a fixed one
bash ./_regress_fnptr.sh                             # 464-file old-vs-new byte diff
bash ./_verify_fnptr.sh                              # arity ladder + self-host fixpoint

Re-measurement caught a near-duplication

The next rung in the plan was seq701 — reconcile the divergent dual-copy sources, starting with nx_hostctl, the supervisor. Earlier in this same session the detector read 44 basenames / 33 divergent, and that reading was used to sequence the whole compiler-landing chain.

Re-measured before touching anything:

MeasureEarlier this sessionNow
dup basenames4417
divergent (real clobber hazards)330
identical litter1111
out-of-probe-path (new class)6

nx_hostctl.nx no longer exists as a source file in the shadow tree — it has been renamed .dupe-reconciled, along with three nx_connect_* organs. A sibling lane ate the seq701 hazards while this workstream was running. Acting on the earlier reading would have duplicated or clobbered in-flight work.

Not claiming this work. A search of the workstream journals for both dupe-reconciled and F1127 returns zero frames — the reconcile landed without a journal entry, so it is unattributed on the coordination board. That is recorded as a coordination gap rather than credit assigned without evidence.

Consequence for the compiler chain: seq701 was named as the gate on seq891 precisely because nx_hostctl was divergent. It is not divergent any more, so that gate is cleared. What remains on seq891 is its blast radius, not its ordering.

A second finding fell out of the same re-measurement: nx_dup_source_check’s own self-test is flaky — one run failed T6b (“expected exactly 1 DIVERGENT, got 0”, verdict RED) and three immediately after passed. The only instrument for the whole dual-copy debt class intermittently declares itself broken; fixed-name fixtures in the shared working directory race between concurrent runs. Filed as seq963.

A method note: check the generator before you migrate

Two of the three rungs closed here were mis-filed, and in both cases following the row would have wasted the work:

The common thread: a debt row records what someone believed at filing time. Re-measure before acting on one. When a count is rising, look for a producer — rising debt is almost never a backlog problem.

What is next, in order

  1. seq899 warden→ledger reconciler — makes the ledger a measurement rather than a filing cabinet, so no seat is ever again aimed at a stale row.
  2. L009 backlog — inflow is stopped; now regenerate the generated share and migrate the hand-written remainder, gate-still-green.
  3. seq701 then seq891 — reconcile the divergent nx_hostctl copies first, then add the never-brick toolchain deploy target on the reconciled file, then land the compiler fix.
  4. seq521 — the second compiler defect: nx_int struct fields lay out SIZE-0.
  5. seq727 — the quadratic seg-store writer still under the eaten sev 9.