A test fake is scoped to its subject, not to an API

The rule. A stand-in store, client or transport fails the OPERATION the test is named for β€” never the whole method it happens to arrive through. Every other caller of that method is a collaborator the test is not about, and the day core starts asking the same method a different question, the test reds for a reason nobody wrote down.

What it cost (measured, 2026-09-17)

MeshWeaver.Plugins main was dark from 14:38Z. Two roots, both satellite halves owed by core changes β€” the #2689 dependent-suite gap: core merges, its own CI is green, and the first thing that sees the break is a satellite's suite hours later. This page is about the second one.

BulkSaveInstallTest.WhenTheBulkReadFails_EveryNodeFallsBackToTheRequestPath pins a real resilience property: when the install's ONE bulk existence read fails, bulk routing is disabled entirely and every node takes the validating request path. Its stand-in armed that with a flag:

public IObservable<MeshNode> ReadMany(IReadOnlyCollection<string> paths, JsonSerializerOptions o)
    => FailReadMany
        ? Observable.Throw<MeshNode>(new InvalidOperationException("simulated bulk-read failure"))
        : ((IStorageAdapter)_inner).ReadMany(paths, o);

ReadMany is not "the installer's bulk read". It is the store's read-by-path API, and a single-path ReadMany is how a collaborator asks a point question without the repair proxy a plain Read carries. So the flag did not simulate a failed bulk read β€” it simulated a store with no read-by-path at all. Measured in one local run, it was taking down three things the test is not about:

collaborator what the blanket failure did
StorageAdapterMeshQueryProvider.ExactScope every exact-scope query threw
InstalledPackageRepairService's completeness sweep reported NOT VERIFIED (NotObserved)
PartitionOwningTypes.OwnsPartition (core #4449) its ONE-path read answered "cannot tell", so every create was refused

The third is what reddened main:

Validator rejected node creation at BulkPack/Deep: Whether 'BulkPack/Thing' owns its partition
could not be established β€” its NodeType definition could not be read within 10 s.

🚨 That refusal is correct. Core resolves partition ownership by reading the NodeType's durable row, and an ownership question that cannot be answered fails closed and is retryable β€” not a verdict (access.partitionCreate.undetermined). It reads through ReadMany deliberately, because a plain Read of a partition-root-shaped path goes through LegacyUserPartitionRepair, which may WRITE a repaired root β€” and an ownership CHECK may not write anything. Nothing here is core's bug. The fake was simply wider than its own sentence.

The fix is one predicate β€” fail a bulk read, which is what the test is named for β€” and the flag takes the operation's name rather than the method's:

public bool FailBulkRead { get; set; }   // was FailReadMany
…
=> FailBulkRead && paths.Count > 1 ? … : …

The installer's seven-path existence read still fails, so the property under test is unchanged; a collaborator's one-path question still gets an answer.

How to tell whether your fake is too wide

Before arming a failure in a stand-in, ask who else calls this method on a live mesh β€” not who calls it in this test. If the answer is "anything that reads a node by path", the flag is a statement about the whole store and the test is silently asserting far more than its name.

The other half of that day, for the record

The first root was the same class one level up: core 4e7e9fd182 removed @@("area/Search") from SpaceNodeType.WelcomeMarkdown ("the welcome page stops restating the index"), and the gate that appends the default bottom catalog lives HERE β€” so the default body was read as "no catalog authored yet" and given one at the bottom, the restatement core had just removed from the top. Fixed in SpaceLayoutAreas.TakesDefaultBottomCatalog.

Both halves were invisible to core's own CI by construction. The compensating control is this repository's daily run and its PR lanes β€” which is why a dark main is urgent rather than tidy: while it is red, every pull request here resolves a platform set main has passed on, and once that set ages out of the runner volume nothing in the repository can run its gate at all. That deadlock, and the platform:newest opt-out that breaks it, is in Platform resolution.

Reconnecting…
The server was updated. Reloading the page to pick up the latest version.