Landscape

tx-rails

Landscape

Every known open issue, and what the position adds up to.
Short title Landscape
Scope Open work only. Items that have closed have been removed rather than marked closed.

FieldOfFlowers

How to read this document

What is here, what is deliberately not, and why the distinction matters.
Only open work appears below. Closed items have been deleted, not annotated. A list that keeps its successes becomes a list nobody finishes reading, and the successes are recorded in the commit history and in Integrity Criteria where they belong. The one exception is the short Permanent residuals section near the end: facts that are neither open nor fixable, kept only so they are not rediscovered as though new.
Each item says what it affects, what was measured, and what state it is in. “Measured” means read from a live system or from the source, with the method stated where the method is the interesting part. Where a figure is as-of a date, the date is given, because several figures in earlier versions of this document drifted out of true while nobody edited them.
Three states are used. Hazard is live — it is wrong now, or it will be wrong the next time something touches it. Built, not in service means the code exists and is correct as far as it is exercised, and nothing runs it; this is the single largest category in this estate and the one most easily mistaken for done. Decision means engineering is not the blocker.

The position in one page

Six things, which between them explain most of the list below.
Almost nothing has traffic, and most “blocked” items are blocked on that one fact. xpyr.pending_transfer and xpyr.ledger_journal both hold zero rows on all eight gov replicas, so there is no money anywhere in the system. The registry’s claims tree holds two party locations, seeded on 24 September purely to unblock the proof path, and idloc_claims.federation_identity_claims holds none at all. The chains themselves are busy — the gov meshes are past 779,000 and 728,000 blocks respectively and the registry mesh carries hundreds of thousands of app-hashes — so the meshes work and the pipelines above them have barely been exercised. That is the single most useful thing to know when reading the rest.
The recurring defect is not failure. It is silence that reads as health. This is the organising theme of the whole document and it has three distinct shapes, which are worth separating because they need different fixes. The looking is broken: a check whose target is fine and whose verification compares nothing with nothing. The wiring was never finished: a binary reading a setting no charm can supply, so a correct capability is unreachable and every local test passes. The writing lands nowhere readable: a grant to a role that does not exist, a table no auditor can select from, a record nothing ever reads back. In all three the component is correct, every signal says fine, and the property the component exists to establish does not hold.
The third shape was measured on 1 October and it had been live for weeks. Two separate gov mechanisms granted audit read access to cc_auditor_ro — a role that exists on member-classes and on the registry and on none of the eight gov Patroni clusters. Both gate their GRANT on the role existing, because an absent role is legitimately normal on some databases. So both ran clean DDL, granted nobody, and reported it accurately in a startup line nothing was reading: settlement auditor grants SKIPPED: role not present on this database. The catalog confirmed it — zero grants to any audit role on all four xpyr settlement tables, including xpyr.transfer_commitment, whose entire purpose is selective disclosure to an auditor. The role that works is cc_gov_ro, holding SELECT on 13 gov_coord tables. The log line was true and useless, because it never said which names it had tried, so a wrong constant and an undeployed audit tier read identically.
Nothing can put money into an account, and the obstacle is delivery rather than code. fund_position is the only production funding path and it requires a slab proof against a root in xpyr.anchored_root, which holds zero rows on all eight gov replicas. merkle-funnel has a real Hedera submitter, rolled to all four replicas and verified from /proc, so ANCHOR_CHAIN accepts hedera and not only filestub. It is inert for three reasons at once: anchor_chain is unset so the producer does not start; the deployed charm carries anchor_chain but none of the four hedera_* options the binary reads, so it cannot be switched on until that charm is repacked; and gov’s anchor relay is unconfigured. Neither half works alone — the funnel publishing with gov not looking, or gov reading a topic nothing publishes to, both leave the table empty.
The same source is checked out twice in several places, and the copy that compiles is often not the copy people edit. This has produced four distinct failures so far: fixes written to Go that never builds, a stale orgsnode charm deployed over a current one, a wrong conclusion that two auditor tiers were unaffected by a shared-package fix, and a determinism fix landing in the uncompiled copy. The guard that exists checks the directories builds run from, not the modules those builds compile in, so it is blind to exactly the case that bites.
The independence claim is the load-bearing thing that is not engineering. The custody arrangement with an arm’s-length agency is unsigned. Until a second organisation runs the checkers, holds keys we never see and operates its own control plane, the audit tier is independent of the consensus and not of the operator, and should be described that way in every document that touches it. Most of the code this implies is built or building; the gap is organisational. The Emergency Brake being 1-of-1 and Game Day drills being run by the party under test are the same gap wearing different clothes.

What gates everything else

Six items whose resolution unblocks disproportionately more than their size suggests.
Gate What it blocks State
An anchored root in xpyr.anchored_root Every transfer that involves money. fund_position is the only production funding path and demands a slab proof against an anchored root, so with none the ledger cannot be credited, no ESCROW_INITIATE can succeed, and GOV_PROOF_GATE_HEIGHT must stay disarmed — an armed proof gate with no anchored roots rejects every transfer. Built and rolled; inert, and blocked on its own charm. The submitter publishes to a real HCS topic and was verified running on all four replicas from /proc rather than from a file on disk. The credentials were found to exist already — operator 0.0.7238677, ECDSA_SECP256K1, with a topic per mesh — so the thing believed missing was documentation, not a key. What is missing is the four hedera_* charm options and gov’s relay configuration.
A2 — the concrete CommitmentPlaintextProvider All of Aperture II’s A3, and therefore A5. cc-bpd-040 exists, is registered and is tested, and reports “not configured” on every transaction until something constructs this interface. Critical path. The key-scope question that gated it is settled; what remains is the mirror of commitment_comparison_provider.go plus a Recompute backed by the deployment’s Committer. A3 is the irreversible one: the plaintext cannot be preserved, but the attested fact that the commitments matched it can be, and only before sealing.
The custody arrangement The independence claim entirely, the ISRS 4400 engagement, the 2-of-2 Emergency Brake, and any honest description of the audit tier. Unsigned. A 5% equity transfer is under discussion; nothing is signed. This gates a claim, not a component.
The leaked gov credential Closing the oldest live exposure. The rotation runbook cannot run until recover-gov-node0.vm.sh is split into --snapshot-only and --restore-only, because the credential drop must happen between the halves. Outstanding, and blocked. DROP OWNED BY on a role owning 30 tables means the restore is not optional.
The first completed off-site pull Every snapshot in the estate still sitting on the disk it is meant to protect. Never completed. newest_copy has never read anything but NONE. The transport is proven end to end; the tier does not yet exist.
Which registry tables are consensus-written All registry schema work, which is four further items in this document. A constraint on a table written inside FinalizeBlock turns bad data into a halted mesh rather than a rejected row. Unestablished. Raised 17 September; nothing has classified the write paths. Until it is done, every proposed constraint is a coin flip between a safety improvement and an outage.

Live security exposure

Item What was measured State
The leaked gov credential is still in use Re-verified from pg_stat_activity on gov-commercial: the role relation_id_16, exposed on 2026-09-03, still exists and holds live connections to gov-api-node0. It also still holds SELECT on 14 gov_coord tables and 4 xpyr tables — more settlement access than any audit role has. Outstanding, and blocked on the runbook split above. The verification method had to change and that is worth recording: since gov’s DSN moved into a 0600 file it no longer appears in pebble plan, argv or the environment, so the old check now returns nothing — and that silence must not be read as rotation. The server’s own view of its live connections is the check that cannot go stale.
The Agency’s database path is open to the whole tailnet Eight interceptor databases reachable at 100.71.149.69:15432–15439, bound to the tailnet interface only. No Tailscale ACL scopes which devices may reach them. Outstanding. pg_hba admits +internal_access from any address and that group contains the superusers operator and backup. Tightening pg_hba cannot substitute: measured, a tailnet connection arrives as 10.238.202.x because the LXD proxy rewrites the client address, so no CIDR narrowing distinguishes it. The ACL is the only effective control.
gov’s admin surface admits any verified subject Measured on the live meshes: AUTH_MODE=elastos-did is in force and the gate is real — an unauthenticated call to ListRegulatedFederations returns unauthenticated: gov: this operation requires a bearer token. But admin_dids is EMPTY, and an empty allowlist means every subject that passes DID verification is admitted rather than none. Outstanding. The authentication layer works; the authorisation layer is a list nobody has filled in. Worth stating precisely because an earlier reading of this called the gate inert, which was wrong — it was based on a pebble plan grep that filtered out uppercase environment names. The gate authenticates and does not restrict.
The snapshot custody key is not offline Present on ground-1 and ground-3, both as the passphrase-protected export. Outstanding. Two machines in one room is redundancy against a failed disk, not against the room.
Origin key registration accepts any length A key of the wrong length stores successfully and then fails every signature verification it is ever used for. Outstanding. The failure is silent at the point where it could be caught and permanent afterwards: nothing re-validates a stored key, so a mis-registered signer looks enrolled and never works. A length check at registration is the whole fix.
The org tier commits under an unnamed empty scope Authorisation attribution. A commitment carries no scope name, so a grant that was wrong is indistinguishable from a commitment fault. Outstanding. This is an evidence defect as much as a security one — when the scope is empty there is nothing in the record to say which authority was relied on, so a post-hoc review cannot tell a mis-scoped grant from a bug in the committer.

Evidence that is written where nothing can read it

The third shape of the silence pattern, and the one with the most instances. In each case a record exists or is being produced, and the thing that was supposed to consume it cannot or does not.
Item What was measured State
Settlement’s audit grants went to a role that does not exist on gov Measured 1 October from the catalog on all eight gov clusters. cc_auditor_ro is absent from every one; the only cc_ role present on all eight is cc_gov_ro. The grant code hardcoded the former, gated on it existing, and therefore granted nobody — while logging role not present on this database, which reads as an undeployed audit tier rather than a wrong constant. Zero grants to any audit role on all four xpyr tables. Fixed, rolling. The fix is not a corrected constant: the role to grant is a runtime fact about the database, not a compile-time fact about the binary, so both gov grant paths now loop over an allowlist and target every role that is both allowlisted and present, with the report naming them. One binary is then correct on gov, on the registry and on member-classes. cc_agency_ro is deliberately excluded and a test fails if it appears, because agency access is a separate decision that must not move as a side effect of a refactor. Not closed until the catalog shows cc_gov_ro holding USAGE on xpyr plus SELECT on the three whole tables and the intended column subset on pending_transfer, read back per node.
Aperture II is inert estate-wide — zero commitments have ever been written Three tiers of correct code, every one switched off. No commitment key is configured anywhere, so the commitment table does not exist and no row has ever been produced. Built, not in service. This is the largest single block of complete-and-unused code in the estate, and it is what cc-bpd-040 reports “not configured” about. The blind-index key scope per column is also undecided, and the checks that would detect a sealed-away field need to fail loudly rather than skip — otherwise switching sealing on would quietly reduce coverage while every report stayed green.
The baseline data has never been consulted The gateway and baseline-interceptor-national are both deployed and active, so the record IS being written. Nothing has ever read it back. No check, criterion or report consults it. Outstanding, and it is the only half left. It is the only record captured outside the workload, which makes it the load-bearing evidence under the independence claim — and an independent record that is never compared against anything establishes nothing.
Nothing counts expected attesting identities against reporting ones Every staleness signal that exists — escalation’s overdue states, the health document — is SELF-reported, announced by the affected auditor over the channel that has been cut. Outstanding. Silence is currently indistinguishable from nothing-to-report, which is the single most useful thing an adversary can buy and also happens without one: a tier once sat with its checkers stopped while appearing deployed, and four gov auditors ran active and committing while not one could log in to the database it was supposed to read. A denominator held outside the reporting party is the fix.
Customer content binding is built and nothing produces it contentbind is a shared module, the claim and detached attestation are on the wire at CoreMeta 66–68, the ABCI records them, and cc-bpd-041 is registered with its provider wired. Built, not in service — the producing end is missing. The three frontends sign a DID token proving who they are and never what they sent. cc-bpd-041 correctly reports every transaction as unattested, which is a coverage gap and is deliberately distinguished from tampering.
No working database path to the LXD auditor models funnel_checker tables cannot be cleared or inspected from anywhere. Outstanding. An audit tier whose own state cannot be read is one that cannot be debugged when it disagrees with the workload, which is the exact moment its state matters most.

Built, correct, and unreachable

The supply-side twin of the silence pattern. A binary reads a setting; no charm can supply it; every test passes and the capability is dead. There is still no guard comparing the settings a binary reads against the options its charm declares, so the next instance will again be found by trying to use the feature.
Item What was measured State
No guard compares what a binary reads against what its charm declares Five instances so far, and the prediction that a further one would appear was answered within a day — twice. Each binary was correct, each charm valid, each passed its own tests, and the capability was dead. One of them was created the same day it was found, which is the clearest evidence available that the gap is structural rather than historical. The root cause of this whole section. Until build-canonical refuses on a mismatch, every item below is a symptom and more will be added.
The agg-transfer relay’s charm cannot supply its credentials The binary is complete and rolled. The charm cannot provide the service credential it needs, so the relay cannot be configured into service by the supported path. Built, not in service. Auto-compensate for failed transfers is also unimplemented on this path, so a transfer that fails after partial progress has no automatic reversal.
The funnel’s Hedera options are absent from its charm The deployed charm carries anchor_chain but none of the four hedera_* options the submitter reads. Separately, the charm has carried a _hedera_operator_key() reader for hedera_operator_key_secret since it was written, while charmcraft.yaml defines no such option. Blocks the anchor gate above. Two independent instances of the same defect in one charm.
cc114’s consensus-RPC client is written and not enabled Consensus RPC is already published and already reachable from the audit tier — confirmed by ops/preflight-auditor-rpc.sh on 24 of 24 endpoints on each of the two meshes, carrying full commit records, a complete validator set and data_hash. The client is written, tested and committed. Wiring change only. It needs a charm option that does not yet exist — the same shape as the relay above.
Gateway and login JWT key out of the environment The code is complete and was deliberately deferred to the next gov roll rather than shipped mid-sequence. Built, awaiting a roll.
SpiceDB in FinalizeBlock: source 2 is built and not armed Source 1 is closed. The mechanism for source 2 exists and is switched off. Built, not armed. Arming changes what the mesh agrees on, so it is height-gated and must follow a cross-replica measurement rather than precede one.
Both governance gates are disarmed, and the app hash has never been measured across replicas for this purpose GOV_CLAIM_GATE_HEIGHT and GOV_PROOF_GATE_HEIGHT are unset; settlement is deployed with every gate off. Outstanding, and the two are blocked differently. Arming is height-gated and cannot be rolled back, so it must follow a measurement. GOV_CLAIM_GATE_HEIGHT waits on that measurement and on content — idloc_claims.federation_identity_claims is empty, and ClaimFederationIdentity hard-refuses unless the verifier is exactly elastos-did, in the handler rather than the interceptor, so federation claims need a DID credential that does not exist; arming against a tree this sparse would refuse on the federation leg even though the party leg works. GOV_PROOF_GATE_HEIGHT is blocked harder and by something unbuilt: with xpyr.anchored_root empty, arming it would reject every transfer outright.
Baseline Interceptor as a reduced Mode B A hash-committed, minimal-metadata variant intended to be trialled for baseline-only fault classes. Proposed, not built.
The regime evaluation for Level 2 is unwritten Level 2 host scope is armed and proven on both gov meshes, in both directions, and every decision is now recorded per node. What is not built is the evaluation that decides which regime a given cross-sector transfer falls under. Mechanism is mine, rules are not. The rules are policy — set here in PoC and by customers themselves in production — so the mechanism is built to be told, not to decide. Narrowing admin_dids from “any verified subject” to named DIDs is the other half and is listed under security exposure above.
Escalation on No Response is built and nothing runs it Per-tier response windows, domain-separated ed25519 acknowledgements, a sweep wired into the attester, an anchoring primitive and a pull transport. WithEscalation is defined and never called. Built, not in service. All four properties the specification demanded hold in the code — the clock runs on the auditor’s own chain, escalation triggers on the absence of a valid signature, acknowledgement is not agreement, and a dispute has a bounded resolution path. What remains is deployment, not design.
The power-funnel artifacts have never been shipped to the dev VM The rock and the k8s charm are built; the deploy script exists; the merged model was created. Built, not delivered.
chubbychecker-funnel has no k8s charm variant Every other checker family has both a machine and a k8s charm. Blocks GCE colocation for that tier.

Correctness defects in code that runs

These compute or record the wrong answer today, as opposed to not running at all.
Item What it affects State
power-funnel still votes on unenumerated errors Consensus safety. An infrastructure error that is not in the enumerated set is voted on rather than halting, which means a node with a local fault can vote differently from its peers and fork the mesh. Reopened — the defect survived under a safer name. The correct polarity is to halt by default and vote only on explicitly enumerated, deterministic outcomes; a rename made the code read as though that had been done. This is the highest-severity item in this section because its failure mode is a fork, not a wrong row.
The anchor submitter has no claim step, and every node submits the same anchor Hedera cost and the integrity of the anchor record. It submits to Hedera when it cannot record the result, so a submission can succeed externally with nothing local to prove it; and all replicas submit the same anchor rather than one on behalf of the mesh. Outstanding. Both halves are the same missing primitive: a claim that one node takes before it acts outwardly. A down node still acts on the outside world, so this cannot be solved by liveness assumptions.
The determinism guard is blind outside FinalizeBlock bodies Every non-determinism that enters consensus through a helper rather than directly. The largest ABCI app in the estate is unchecked. Outstanding. A guard that covers the obvious call site and not the call graph beneath it reports clean on exactly the code most likely to be wrong.
The AppHash / randomised-sealing dependency is unpinned Whether sealing can be switched on without forking. Nothing fails when the relationship between the digest and randomised sealing breaks. Outstanding. Needs a test that fails when it breaks, which is the only form in which this kind of dependency is ever actually maintained.
The transfer amount is baked into the step definition rather than taken from the caller Ledger correctness across reuse. Moving a different sum means publishing a new process version; a process definition reused across transactions carries a stale amount into the ledger with nothing reporting it. Outstanding. The per-transaction re-registration is the accepted pattern today and is also the defect.
federationId is asked for rather than derived from the member’s own LEI Data quality at the entry point. A caller-supplied identifier that could be derived is an identifier that can disagree with the registry. Outstanding.
The .NET SDK proto is three fields behind the server Any .NET client, and the reproducibility of the hash. The hash is only reproducible while those three fields stay empty. Outstanding, with a trigger. This is latent until the first .NET client populates one of them, at which point hashes stop matching with no obvious cause.
Two check ids are used by different checks in different families Any reasoning that treats a check id as an identity — coverage counts, exclusions, and the criteria that cite ids. Outstanding. An id that means two things cannot be cited unambiguously, and the Integrity Criteria cite ids rather than titles precisely so they stay stable.
Seven checks read time.Now() to decide what to examine Determinism of what gets audited. Two replicas running the same check at different wall-clock instants may examine different windows. Outstanding. The auditor’s committed clock should be the block header timestamp, which every replica agrees on, not each process’s own idea of now.
A deliberate TransientFailure is counted as errored rather than as a verdict Coverage arithmetic. A check that correctly reports a transient condition is scored as one that could not run. Outstanding. “Errored” is the bucket that means we do not know, and a check that deliberately reported something does know.
The checker’s resume position lives in /tmp Audit continuity. A /tmp clean silently restarts the audit from the beginning and leaves an unreported gap. Outstanding. The gap is the problem rather than the restart: nothing records that a range was skipped, so coverage reads as complete.
The funnel checker’s two DSNs are not kept distinct Separation of audit-side state from the read-only workload connection. Conflating them lets the auditor write where it should only read. Outstanding.

Duplicated source, and builds that cannot see it

One family, because every item here has the same consequence: a correct fix that does not reach the artefact, with a successful build either way.
Item What it affects State
The duplicate-checkout gate only checks directories builds run FROM The entire family below. A replace written in one repo names a path in another, so the module a build compiles in can be a different checkout from the directory it was invoked from — and that is the case the gate cannot see. The root cause of this section. Widening it is what would turn the items below from recurring surprises into build failures.
chubbychecker exists in two checkouts and the submodule’s Go packages are shadowed Any fix to the checker families. go.work uses ./tx-rails/chubbychecker, not the top-level ./chubbychecker, so the module path resolves to the former while edits land in the latter. Outstanding, and it has bitten three ways: fixes written to Go that never builds, a wrong conclusion that two auditor tiers were unaffected by a shared-package fix, and the joint checker’s top-level module not importing the health package at all while the binary actually built does.
orgsnode exists in two checkouts and the stale one was deployed member-classes. The stale copy was deployed over a current one. Outstanding.
cca04’s determinism fix landed in the copy that is not compiled One specific determinism defect that is believed fixed and is not. Outstanding. This is the clearest single illustration of why the gate above matters: the work was done correctly and has no effect.
The whole national-meta-federation tree cannot compile Every build and every piece of tooling in that repo. A replace points at a contentbind that does not exist. Outstanding. Related and separately recorded: org-gateway builds only from the root ./connectrpc — identical Go, and one of the two checkouts cannot compile it.
The root go.work omits orgnodes-overseer All root-level tooling, which is therefore blind to the largest workload module in the estate. Outstanding. Every cross-repo guard that walks the workspace silently excludes it.
build-canonical’s completeness check is blind to machine-charm binaries The claim “every binary the rocks organize is present”, which is true and narrower than it reads. A binary shipped only by a machine charm appears in no rockcraft.yaml and is outside the check. Outstanding.
build-charm.sh all silently omits a charm Any fix packed by all. Measured: all --pack built agg, joint, tophats, governance and registry and left chubbychecker-funnel at the previous day’s timestamp, with a successful exit and nothing naming the sixth — though the script packs funnel correctly when named. Outstanding. Caught only by comparing artefact timestamps against the build log. A pack that skips a charm is indistinguishable from one that covered everything unless you check what came out.
The build tag does not identify its content Tracing a running artefact back to a source state. A tag that does not change when the content does is how a corrected image stays invisible. Outstanding. Partially mitigated in practice — the gov rock version now embeds a content hash of its staged binaries — but it is a local convention rather than something the build enforces everywhere.
Twelve charm directory names collide across repositories Any lookup that prefix-globs rather than exact-matches. chubbychecker-joint appears in five. Latent, and it bites. The bare chubbychecker-joint_amd64.charm — a stale copy with no ABCI application at all — was once deployed in place of the maintained variant, producing a four-node auditor mesh that could never commit. The collision itself remains.
The top-level README exists twice and the copies have drifted Two copies owned by different repositories. Latent. Worth noting that the line count measures diff alignment, not divergence, so the figure moves when unrelated edits shift blocks. Two copies diverging with nothing comparing them is the shape behind most of this estate’s incidents, and it needs a decision rather than another edit.

Operational fragility

Item What was measured State
The off-site copy holds nothing Built outside the estate: pull-only, NAT’d, no sshd, firewall trusting only the tailnet interface. Verified that the store reaches both grounds and neither reaches back. Standing hazard. The mechanism is proven end to end — a 3 MB test subvolume survived btrfs send byte-identically — and no real pull has ever completed.
A partial backup reads as a complete one btrfs receive creates the destination subvolume at the start of the stream, so presence proves a receive began, not that it finished. A run inspected a half-written 1.6 GB subvolume against a 2.2 GB source and logged up to date. Fixed in code, not deployed. Completion is now tested by readonly plus a non-empty Received UUID rather than by presence. This was never merely a symptom of concurrency: any interrupted pull leaves a truncated subvolume that every later run skips forever while the store reports itself fresh.
The backup store is a VM on a laptop, and it is off It left the tailnet mid-pull with four pullers and two concurrent receive streams running. The concurrency came from Persistent=true on a timer that had never run, which systemd treats as a missed window and fires immediately. Outstanding. The puller now takes an exclusive lock and the timer is deliberately left unstarted. The siting is the larger point: a store that is off whenever the machine is closed raises the effective recovery point above the stated 24 hours for as long as it is off.
Most meshes have no snapshot Nine of fourteen had none when counted. Two — member-classes and the registry — have since gained hourly height-stamped copy-on-write snapshots. The remainder has not been recounted. Standing hazard. Restore is proven; what is missing is something to restore from. The figure is as-of its date and is not current.
gov-api-node1 was left half-shut-down Diagnosed: the ABCI app restarted under a live goldbftd, which lost its link to it. The same shape once cost a 44,988-block resync on an overseer node. Open. The general lesson is recorded and acted on — never restart an ABCI app beneath a running consensus process, and never kill a BFT pod mid-commit — but this node’s own state needs confirming rather than assuming.
pfnode0 is down and its chunked clone is unexercised merkle-funnel’s fault tolerance. The recovery path written for it has never been run. Outstanding. The orphaned producer must be disarmed first, or the recovery writes while something else is still producing.
Image GC is exhausted, not idle Every remaining image is pinned, so the next growth has no absorber. Outstanding. This reads as healthy on every metric — GC runs, GC succeeds, nothing is reclaimed because nothing is reclaimable.
ground-1 is not capped OOM-kill hazard across every model on it. Swap was raised to 32 GiB, which closed the immediate hazard. Mitigated, not fixed. Capping the 80 GiB VM is the real fix. Related and measured separately: charm exec probes starve under I/O on a loaded host, which presents as a charm bug and is not one.
The runc AppArmor profile makes pods on 24.04 undeletable Every pod lifecycle operation on affected hosts. Outstanding, and the sweep has not covered every environment.
containerd charm rev 95 cannot work with containerd 2.x Every fresh deploy on 24.04. Latent. It will present as a new cluster failing to come up rather than as a change to a running one — so it will be found by whoever next builds an estate from scratch, at the least convenient moment.
PostgreSQL 16 needs destroy-and-rebuild of the seven k8s models The upgrade path. In-place is not available. Outstanding. This is a planned outage per mesh rather than a migration, and it interacts with the snapshot gap above: rebuilding a mesh with no snapshot to restore from is not a recoverable operation.
Twelve VM-side ops scripts still use python3 The “no toolchain in the VM” constraint. The sweep that was reported as complete was not. Outstanding. Honest correction to an earlier closure rather than a new finding.
ship-artifacts.sh targets k3d and nothing in the estate runs k3d Nothing today. It is a tool pointed at an environment that no longer exists. Needs a decision: retire it, or re-point it at a target that exists. Leaving it is the option that eventually wastes somebody’s afternoon.
Audit-host log flood Disk and legibility on the audit hosts. The code fix is built and not rolled; the kube-apiserver half is untouched. Half built, half unexamined.
Work is handed between stages through database tables rather than pipes Throughput and the honesty of the evidence trail. A table used as a work queue is also the table read as evidence. Outstanding. The intended shape is continuous credit-based pipes with the database as evidence, never as buffering. Polling loops currently do both jobs, so backpressure and audit share a mechanism and neither is clean.
The gov-side id-location-claims service is still deployed Two implementations of the same capability. The registry is the successor and the one being kept. Outstanding. Validators must be re-pointed at the registry first, then the services model destroyed. Its own auth wiring is broken — the charm carries service_auth_mode=elastos-did and the running process has no claims-auth flag in its argv at all — and fixing that would be work on something being deleted.
CLAIMS_AUTH_MODE is on jwt and must revert The federation leg of the claims tree. The registry runs in jwt mode because no DID credential exists, so only party locations can be seeded. Deliberate, and must not be forgotten. It reverts to elastos-did once a credential exists.
The auditor signing-key handover is a third done The custody claim in practice. aud-m-c is complete; five tiers remain, and the charm differs per mesh so it is five separate operations rather than one. In progress.
The action-catalog seed writes a table nothing reads Anyone loading the dump to populate the Studio, seeing it succeed, and finding no change. Outstanding. convey_it.sql carries CREATE TABLE overseer.action_catalog and COPY overseer.action_catalog, while the code reads gov.action_catalog. The dump’s own comments say “Schema: gov” directly above DDL saying overseer. — the rename was followed in the comments only. Verified against the live database: gov.action_catalog exists and is the only one.
Ten charms build per-pod DNS with the plain <app> form Peer addressing. Kubernetes resolves pod DNS against the StatefulSet’s governing service, which Juju names <app>-endpoints; the plain form is unresolvable. Latent, partially fixed. tophats’ peer addressing has been corrected; the pattern survives elsewhere. The failure mode is specific and nasty: a DNS-named peer that does not resolve isolates the node rather than erroring visibly.

Assurance gaps

The reason a green audit result is not yet evidence. Of the items Integrity Criteria records, those below have not closed.
Item What was measured State
The block source supplies four fields of a consensus header, and five checks read it The provider is named for a federation RPC service and was one, until that layer was removed; the name survived and the implementation became a block-stream adapter that populates Height, Time, DataHash and the transactions and returns not-implemented from the rest. Outstanding, cause known. Four fields are enough to look like agreement and not enough to verify anything — this single provider was the shared cause of the three checks that actively misled, two of which are now fixed. The fix is a wiring change, not an infrastructure one: consensus RPC is already published and reachable, confirmed on 24 of 24 endpoints on each mesh, carrying full commit records, a complete validator set and data_hash.
Five checks still ask a CometBFT RPC that is now a blockstream shim Federation-era residue. They address an interface that no longer means what they assume. Outstanding. Same root as the row above, counted separately because re-pointing the adapter does not by itself correct checks written against the old semantics.
Eight exclusions where nothing establishes the property Criteria excluded from continuous checking with no substitute. Outstanding. An exclusion with a stated substitute is a design choice; an exclusion with none is an unmeasured claim.
Seventeen criteria resting on something other than a continuous check A one-off test, a code reading, or an argument. Outstanding. Each was true when written and none is re-established by anything that runs.
The joint checker emits no coverage line at all Seeing which checks ran. aud-m-c reports “checks passing” with no way to distinguish a check that passed from one that never executed. Outstanding. Measured: zero occurrences of never invoked, not-applicable or errored in its log, and no coverage height= line. The funnel checker already emits exactly this, with ids named in each bucket, so the fix is to give the joint checker the same reporting.
The funnel tier re-runs the whole joint family Attribution. Checks are scoped by tier rather than by subject, so a finding does not identify what it is about. Outstanding. Same reporting surface as the coverage line and the colliding ids.
Funnel audit coverage is uneven across endpoints What is actually audited. Two of four endpoints sat at height 4 while the others were at 446,678. Outstanding. Aggregate coverage figures average over this, so the tier reports partial coverage as uniform coverage.
No check-recovery programme Knowing what the retired and vacuous checks were ever meant to establish. Outstanding. The work is to decode original intent, recode it, and prove each guard in BOTH directions — every guard in this estate tested only in the passing direction has eventually been found to pass when it should have refused.
The Overseer Studio offers nothing to compose with The executive-facing half of the platform. The Studio is the only path by which an executive sequences atoms into a business process. Outstanding. The backend is live — overseer-api answers GetActionCatalog with HTTP 200 — and the body is {}. Counted: 807 atom implementations, one file each, across 31 domain directories. Meanwhile gov.action_catalog, the table the Studio reads, holds zero rows, and nothing in Go ever writes it. The catalog is the publication boundary between coding an atom and sequencing it, so it cannot simply be generated from the source tree: doing so would put all 807 into an executive’s picker and remove the programmer’s judgement about what is fit to hand over. Its columns — friendly_name, description, required_parameters_schema — are authoring metadata no Go identifier supplies.
Empty windows are attested by one tier and skipped by another The slab baseline path declines to request a commitment when a slab holds no transactions, on the reasoning that a signed attestation over nothing is a permanent record of nothing. The auditor tier attests empty windows deliberately, on the reasoning that “nothing happened” is the claim most worth forging. Outstanding — both positions are defensible alone and cannot both be right. Together, an absent baseline_root conflates three different facts: no transactions; transactions with the baseline tier unreachable; transactions with the baseline suppressed. Not biting today only because there is no transaction traffic.
Sybil detection across member companies does not exist M-of-N executive consent, the regulated-federation gate, regulator veto and pyramid membership — all of which one beneficial owner registering many entnums would attack. Measured: the OpenSearch cluster is healthy, secured and reachable only from the estate VM, and NO shipper exists anywhere; nothing in the repo references it; the linkage component is unwritten. Outstanding, and the design must split. Entity resolution and behavioural anomaly are different problems and OpenSearch is not the whole answer to either — it carries anomaly-detection, alerting, security-analytics and knn but no graph plugin, so multi-hop entity resolution cannot happen in-engine at all. The intended shape is behavioural detection in OpenSearch paired with linkage over national-registry in SQL, where transitive closure is a WITH RECURSIVE. The ceiling is worth stating plainly because it is not a tooling limit: behavioural correlation is evidence of COORDINATION, never proof of common control, and two companies run by one owner through nominees are indistinguishable from two independent companies to every layer this platform operates. What IS measurable is the effect rather than the cause — if a federation’s votes consistently resolve as though fewer independent parties were deciding than its membership implies, that is computable from consensus data already held.

The registry’s shape

Read from the live registry rather than the repository, because the schema is not in the checkout: national-registry/registry is the charm directory, and a repo-wide search for registry_coord in Go returns nothing. Nine application schemas and 27 tables as at the last re-measurement. Two business rows exist in the entire registry — the party locations seeded to unblock the proof path — against hundreds of thousands of rows of consensus bookkeeping. The findings below are structural and none has closed.
Finding What was measured Consequence
The registry forgets party_location_registrations is keyed on entnum alone with upsert semantics; the test is named ReregisterAlwaysUpserts. federation_identity_claims is keyed on federation_id and reclaim overwrites the location fields. The highest-value functional gap. When a party moves country the previous registration is destroyed. There is no history table, no validity interval, no event log, so “where was this party registered on 3 June” is unanswerable. For a platform whose proposition is tamper-evident audit, a registry that silently overwrites its own prior state works against the product. The asymmetry gives it away: pyramid_deregistrations keeps full history while pyramid_memberships keeps only current state — removal is recorded and addition is not.
There is no countries table country_id appears in federation_identity_claims, party_location_registrations and data_centres. Nothing anywhere defines a valid country. Standing hazard. A mistyped country is accepted in silence. verify.go already carries TestVerifyClaimRefusesAnUnassertedCountry, so the rule exists in code and not in the schema. This is also the reference data expected to persist into production.
Four foreign keys in the whole registry The same four across re-measurements: dc_registry.data_centre_locations and dc_registry.data_centre_precise_locations both to data_centres, and executive_consent.votes and regulator_veto.votes both to vote_tallies. voter_did, entnum, federation_id, pyramid_id, sector_id and data_centre are all unenforced. Standing hazard. A vote can be cast by a DID belonging to no registered regulator or officer; a claim can name a data centre that does not exist. data_centre is text in idloc_claims while dc_code is the primary key in dc_registry — the same concept under two names with no link.
cr04 — six pyramid-membership referential gaps Found by the registry auditor once it could read the workload. Outstanding. Nothing has yet looked at them. The row above is the structural explanation for why gaps of this kind are possible at all.
Constraints are nearly absent, and adding them is not free Three CHECK constraints in the application schemas, and twelve indexes beyond the primary keys — the index count has grown with the consensus work, the constraint count has not moved. Counted from pg_constraint rather than information_schema, which reports every NOT NULL as a CHECK and returns 145. Sequencing matters, and the window is closing. A foreign-key violation inside FinalizeBlock is not a rejected row but a storage error, and this estate halts on those. Constraints must therefore land after handler-side validation, so the constraint asserts the handler is correct rather than being what catches bad input. The affected tables still hold two rows between them, so this remains a schema edit rather than a migration — a fact with an expiry date rather than a standing condition.
The registry stores are unclassified Which stores hold consensus state and which do not, and therefore which may be sealed. The dc_registry seal pattern already exists and has not been extended. Outstanding. This and the consensus-write classification in the gates section are the two pieces of knowledge all the registry work waits on.
Missing FK indexes Query plans on the few foreign keys that do exist. Outstanding, and bundled with the constraint-hardening phase rather than done separately.

Blocked on decisions

Engineering is not the blocker on any of these.
Item What is at stake State
The arm’s-length custody arrangement is unsigned A 5% equity transfer is under discussion with a company that would take custody of a ChubbyChecker installation and hold a key set separately. Gates the independence claim entirely. Most of the engineering it implies is built. What it gates is whether a second organisation exists at all.
The Emergency Brake is 1-of-1 The release protocol requires a signed release after forensic analysis, by us, alone. Decision required. Under custody this should become 2-of-2: the brake stays with the operator, because an external party able to halt the business is unacceptable and a new attack surface, but release requires both signatures. The shape already exists here as executive-consent plus regulator-veto.
Game Day drills are run by the party being tested The oversight strategy has us scheduling and running our own compromise drills. Outstanding. Same shape as the brake and the 1-of-1 approver.
Independent practitioner under ISRS 4400 External assurance over the audit tier. Not engaged. The custody negotiation is the nearest live route to it.
Route A, Route C and two further re-keying decisions Recorded and unanswered. Route C’s open question is the node key. Not built, gated on decisions rather than on effort.
Two wanted schema renames are app-hash changes, not migrations Fixing the catalog mismatch, and improving how origin keys are trusted. Both were asked for as renames; both touch what the overseers mesh agrees on. Understood and sequenced, not done. gov.action_catalog is folded into the overseers app hash — measured, along with thirteen other gov.* tables — so renaming it changes the digest, and replicas running old and new code at the same height compute different hashes and fork. It needs height-gating: ship dual-reading code with the gate UNSET, roll every replica, verify agreement, populate the new table, then set the height everywhere. Rolling the binary and setting the height in one operation is the shortcut that breaks it, because a slow-restarting replica crosses the height on the old code. gov_coord.origin_keys is NOT folded, and that exclusion is deliberate: it is per-node state, “this node’s own trust list”. Making it mesh-agreed would remove the class of failure where a partial enrolment reads as a consensus bug — and would make it consensus state, so that too becomes height-gated, and needs an enrolment authority decided first, because “who may add a trusted signer” is the entire security content.
The audit role name across tiers Whether the estate wants one audit role name everywhere or keeps the per-tier names it has: cc_gov_ro, cc_registry_ro, cc_auditor_ro. Nothing is blocked on it. The allowlist handles every current tier, so this is a tidiness decision rather than a dependency. Recorded because the wrong answer — creating cc_auditor_ro on gov to make the old code work — would produce a role nothing connects as, collecting grants and reading as fixed.
The duplicated top-level README Two copies owned by different repositories. Needs a decision, not another edit.
The WordPress publication is blocked on three pre-existing items Rung numbering, no-customer wording, the sector rename, the medical corrections and three A4 figures. Blocked. The medical page is still refused by correct-medical-page.py on three items that predate this round of work.

Naming and transport: what should replace plain DNS

A position, not a decision already taken. The question is what clients should trust when they connect, and the honest answer is that today they trust the wrong thing.
The defect is not that DNS is old. It is that DNS is load-bearing for identity. A domain-validated certificate is issued on proof of domain control, so the chain runs registrar → TLD → DNS → certificate issuance → TLS identity. Every link is a party that can be compelled, and several are jurisdictional. For a platform whose proposition is cross-jurisdictionally verifiable proof, that is a hole in the transport that the cryptography above it cannot close: a single registrar or government can decide who a user reaches, regardless of how sound the consensus and the anchoring are.
Encrypted DNS and DIDs fix different halves, and neither is redundant. DNS-over-HTTPS or DNS-over-TLS closes the privacy and on-path tampering legs: an observer no longer sees which names are resolved, and a hostile local network cannot forge answers. It does nothing about authority — the record can still be revoked or seized, and issuance is still tied to domain control. An Elastos DID closes exactly the leg encrypted DNS leaves open, by removing DNS from the identity path altogether. Verified against the live network on 2026-08-09: EID mainnet is reachable at api.elastos.io/eid (chain ID 22) and resolution through the custom did_resolveDID JSON-RPC method is free and already works, needing no funds and no contract knowledge. Only publishing costs ELA.

kademlia

Where Kademlia fits, and where it does not. Kademlia is a distributed hash table: instead of asking one authority where something lives, a client routes the question through other peers, hopping progressively “closer” to whichever node is responsible for the key. Closeness is the XOR of two identifiers, so a node’s ID decides which keys it answers for — and that one property is the source of both its appeal and its central weakness.
The failure mode is eclipse, and it is targeted rather than random. A Sybil attack is simply the observation that node identifiers are cheap, so one party can run thousands. Eclipse is what that buys: because responsibility is determined by XOR distance to a key, an adversary can grind identifiers — generate them until enough land near the key, or near the victim — until the peers a client would consult are all its own. Every routing table entry the victim holds points into attacker-controlled space. The attack is not probabilistic and does not require majority control of the network; it requires only enough identifiers positioned in one small region of the keyspace, aimed at one target.
For an audit platform this is the worst available failure, because it lies by omission and produces no error. An eclipsed client is not disconnected and sees nothing malformed. It sends lookups, receives well-formed answers, and gets a complete-looking view of a reality the adversary selected. The damage is specific to what auditing is for: an auditor that cannot see a finding reports no findings, and absence of evidence is indistinguishable from evidence of absence. A hijacked DNS record at least tends to fail loudly — a certificate mismatch, a refused connection, an outage somebody notices. An eclipse is quiet by construction, and a clean audit report produced under one is worse than no report at all, because it will be believed. This is the same defect that recurs throughout this document in other clothes: a check whose target is real but whose looking is broken.
The bootstrap problem survives the change. A DHT cannot be joined from nothing; something must supply the first peer. In practice that is a hardcoded address list, a signed bootstrap file, or DNS seed names — which is how DNS tends to reappear underneath the very system adopted to replace it. Adopting a DHT as the naming layer therefore does not remove the dependency it was chosen to remove; it moves it somewhere less examined.
The operational objections are mundane and decisive. Enterprise networks block peer-to-peer traffic as a matter of policy, inbound connections die at corporate firewalls and behind NAT, and a DHT lookup costs several round trips where a resolver cache costs none — a poor trade on an interactive submission a user is waiting on. None of this is fatal to a background process; all of it is fatal to a naming layer that every client must traverse before it can do anything at all.
What changes when identity comes from keys. Every objection above is an objection to trusting the DHT. Once the platform’s identity is a public key and the response is signed, the routing layer is untrusted by construction and eclipse degrades from deception to denial: an adversary who controls every peer a client can reach still cannot produce a signature it does not hold, so the worst it achieves is preventing a connection. Denial is survivable, detectable and recoverable — another discovery path, a cached address, a different network. Deception is none of those things. That difference is the whole argument, and it is why the role matters more than the technology.
The rule that keeps it safe: a discovery channel may tell you where, never who or what. Answers that are self-authenticating — a signed DID Document, a content-addressed slab, an attestation carrying its own did:key signature — may be routed through anyone, because the recipient verifies them without reference to how they arrived. Answers that would be believed on the strength of their source must never be. In particular, no query whose meaning depends on completeness may be served this way: “every attestation for this height” or “all findings against this federation” cannot be answered over a DHT, because omission is undetectable and the honest-looking short answer is exactly what an eclipse produces. Those questions belong to a quorum that can be counted, which is what the BFT meshes already are. As one discovery path among several, feeding identities that are verified afterwards, Kademlia is a good fit and being eclipsed costs a connection attempt rather than integrity. As the naming layer, or as the transport for any completeness claim, it is not.
A permissioned DHT changes the analysis, and the two DID methods do opposite jobs. Everything above concerns an open DHT, where eclipse is cheap because identifiers are free. Bind a node identifier to an admitted DID and minting a thousand identities means obtaining a thousand credentials — issuance being a governed, on-chain, auditable act that leaves evidence in the same ledger the auditors read. Grinding is closed the rest of the way by deriving the identifier from the registered DID and rate-limiting registration, plus per-bucket diversity caps that only a permissioned network can enforce, because only there can you tell who is who. The bootstrap regress becomes void: peers come from the on-chain directory the platform already operates, so DNS never reappears underneath. Here the two DID methods are complementary rather than alternatives. A did:key cannot be revoked — it is purely generative, the identity is the key, which is exactly why an attestation signed under one verifies offline and forever with no registry to reach. An Elastos DID is an on-chain document with rotation and revocation, which is exactly what membership needs and what did:key structurally cannot express. So: Elastos DID for admission, did:key for attestation, Kademlia for routing alone.
What a closed perimeter does not buy: private is not trusted. The members of a permissioned network are the parties being audited. The entire reason for BFT meshes and independent auditor tiers is that participants may be compromised or hostile; if members could be trusted, none of it would be needed. An admitted member holding enough node identifiers can still eclipse a peer, with better cover than an outsider, because every entry in the routing table is legitimate. Two consequences survive the perimeter unchanged. Completeness claims remain unservable over a DHT, so “every attestation for this height” belongs to a quorum that can be counted. And an insider who cannot forge will instead try to silence: partition an auditor and it stops seeing, whereupon it reports no findings, which reads as nothing wrong. Denial is only safe when it is detected, and today it is not — see the row above on counting expected attesters against reporting ones.
Member-level Sybil is a different problem and it does NOT lead to eclipse. Everything preceding concerns NODE identifiers, where cheap identities buy XOR-adjacency and therefore eclipse. Binding node IDs to admitted DIDs closes that. The remaining Sybil surface is a different population entirely: member companies, covered under assurance gaps above. It buys votes, not routing-table entries, so it eclipses nobody — and conflating the two understates both. Permissioning does not remove it; it converts it from a compute problem into a due-diligence problem, executed on paperwork before it ever reaches the network.
Whether a DHT is the right answer at all is a question of scale, not of security. Kademlia earns its complexity where membership is large, unknown and churning. This membership is governed and enumerable, and the meshes themselves are 7 to 13 nodes — a list, not a routing problem. For a few hundred stable organisations a signed membership list distributed over the consensus already running is simpler and strictly safer, because there is no routing table to poison. A permissioned DHT begins to pay for itself at thousands of endpoints with real churn, where keeping that list current everywhere becomes the harder problem. The decision turns on endpoint count and turnover and should be taken on those numbers.
The shape that follows. Identity is the public key; the platform already runs this, with auditor attestations signed under did:key identities and verifiable straight off the chain with no schema and no build of ours. Discovery — DNS, a DHT, a signed bootstrap list, a configuration file — becomes a hint rather than a trust anchor, and the same rule governs all of them equally: they may route, they may not attest. A hijacked record can then stop a client connecting and can never impersonate the platform, because the name was never what authenticated it. Nearly all of the risks DNS forces onto clients are identity risks wearing naming clothes; remove DNS from the identity path and what remains is a routing optimisation that may be duplicated, replaced or lost without consequence — which is also the test for admitting any new discovery mechanism, Kademlia included. If losing it entirely would cost only reachability, it is safe to add. If losing it would change what a client believes, it is in the wrong layer.
What would still be required, in rough order of difficulty.
Requirement Why State
Bind the DID key to the session Resolving a DID yields keys; a TLS session is authenticated by a certificate. Unless the two are bound there are two unrelated identities and the DID is decoration. The crux, and not built. Of the three options — pin the certificate to the DID Document, use a certificate whose key is the DID key, or perform an application-layer challenge-response after an ordinary handshake — the third is the one to take. It needs no cooperation from any certificate authority, works in a browser, and survives the TLS-inspecting proxies every enterprise customer runs, which would break any pinning scheme.
No DID credential exists, so federation identity cannot be claimed anywhere Both paths to ClaimFederationIdentity, and therefore the federation half of every proof. On the registry — the successor path, and the one being kept — the wiring is sound and the handler hard-refuses unless the verifier is exactly elastos-did, which is why the registry runs in jwt mode and only party locations can be seeded. Outstanding. What unblocks the capability is a DID credential, after which the registry reverts to elastos-did and the federation leg of the claims tree can be populated for the first time.
Resolution availability If clients resolve DIDs through a single endpoint, the single point of control returns one layer up. Undecided. Needs multiple EID paths or cached, signature-verified DID Documents with an explicit freshness policy, and a decision on whether an unreachable chain fails closed or falls back to cache.
A mainnet publish EVMPublisher builds and signs a real EIP-155 transaction and is fully unit-tested offline, including ABI encoding, signature recovery and a fake-node round trip. Never broadcast. The one untested path, pending funded ELA. cmd/eidpublish is the runnable tool and defaults to -dry-run=true.

Permanent residuals

Neither open nor fixable. Recorded only so they are not rediscovered as though new, and so nobody spends effort trying to recover what the arithmetic says is gone.
Fact Why it cannot be recovered What still holds
Every anchor written before 2026-09-11 is unverifiable Anchors recorded only (start_batch_id, batch_id) from a selection ordered by something unrelated to batch_id — not a range, and inverted on 34% of rows. Of 237 single-candidate intervals sampled, 205 matched no formulation of the stored root. Membership is now recorded. Mutation in place is excluded — both insert paths are ON CONFLICT DO NOTHING — which is also why anchors from 2026-09-11 onward stay verifiable.
The interceptor tiers’ older baseline rows cannot be back-filled honestly 53 records split 19/12/10/12 across bi0–bi3, because the gateway fans to every interceptor but requires only a quorum, so a tier that missed a write kept missing it. 53 copies cannot come from a 3-of-4 quorum over 19 transactions, which needs 57. Repair is pull-only and marked with its source peer, because a back-filled baseline says “a peer held this”, not “this tier saw it happen”. That distinction is why the older rows are left alone rather than reconstructed.
Two agg-transfer rows are permanently burned They were resolved failed from transport errors that never reached gov at all, so the relay recorded a terminal verdict on gov’s behalf for a request gov never saw. Nothing re-opens a row already resolved. The relay now leaves a row pending when delivery fails and resolves it only on a permanent refusal, so a dropped connection is retried and a rejected request is not retried forever. The burned rows are lost evidence rather than pending work.
pfnode1 holds divergent ABCI results for one height It cannot be repaired by copying, because the divergence is in results rather than in missing data. The correct lineage was established by computation rather than by vote, and the rebuild and WAL-restore procedure for this class of fault is written and committed.

What to do next

Four observations that follow from the list rather than from preference.
Three missing guards would convert most of this document from recurring surprises into build failures. They are: a check that every setting a binary reads is declarable by its charm; a duplicate-checkout gate that looks at the modules builds compile in rather than the directories they run from; and a rule that no grant, no gate and no digest may name a role, table or column as a compile-time constant where it is really a runtime fact about the deployment. Each of the three has already produced multiple independent incidents. None of them is more than a day’s work, and each one retires a whole category rather than an item.
Prove every guard in both directions, without exception. Every guard in this estate that was tested only in the passing direction has eventually been found to pass when it should have refused — a check comparing nothing with nothing, a pack that skipped a charm, a gate piped into grep that took the pipe’s exit status, a role check asking about a role that did not exist. The discipline that works is mechanical: inject the defect, watch the named guard fail, revert, watch it pass. A guard nobody has seen fail is not a guard.
Several irreversible windows are open only because nothing has traffic yet, and they are closing. Aperture II’s A3 can attest that commitments matched the plaintext only before sealing. The registry schema can gain foreign keys, history tables and constraints as a schema edit only while its tables are empty — and they are no longer quite empty. Two rows are trivially migratable and the point is the direction, not the number. Doing this now is cheap; doing it later is a migration under load, on tables whose constraint violations inside FinalizeBlock halt a mesh rather than reject a row.
The naming question should be settled before the client surface is built, not after. Deciding that identity comes from keys rather than names changes what the client does at connection time, and retrofitting it means re-issuing every client. The directory already exists in the registry schema, resolution already works on mainnet, and the one genuinely unbuilt piece is the session binding. That is a small, well-defined piece of work sitting in front of a decision that gets more expensive to reverse with every client shipped.

Tx-Rails — Built by IT/OT Chain & Cloud Australia (ITOTCCA). Sydney · London.