Content reachability — what was measured, and what was refuted

On 2026-09-01 the question "has the mesh fallen behind the repo?" was investigated against memex.meshweaver.cloud. The answer turned out to be no — but the investigation surfaced a different, real defect, and refuted two plausible checks along the way.

This page is the durable record. The invariant itself is pinned by a unit test, not by anything here: SkillFileParserTest (ASkillInAPluginPartition_IsItsOwnMainNode). There is deliberately no live-mesh gate — see Why there is no sentinel below.

The defect: imported, Active, and invisible

get    @Hosting/Skill/deployment          →  Active, version 7, full content
search  path:Hosting/Skill/deployment     →  count: 0

The node is there. It simply cannot be found. The catalog's is:main projection is SQL n.main_node = n.path, and these nodes carry mainNode: Skill/{id} instead of their own path — so they are hidden by the same rule that hides _-satellites. Nothing errors, nothing goes red, and the skill never reaches the composer's /-menu or any query that resolves skills.

Root cause and fix: #1053 / MeshWeaver#2939, fixed in #1064. SkillMarkdown.cs mints new MeshNode(id, SkillNodeType.RootNamespace), freezing the stored, non-nullable MainNode at Skill/{id}; SkillFileParser.cs then rebases with node with { Namespace = ns } — and a record with copy does not re-run the MainNode initializer.

The A/B proof is the sibling parser: AgentFileParser.cs constructs with the real namespace, so its default is right the first time. That is why .md AGENTS are fine and .md SKILLS are not — and why Hosting/Agent/platform-update resolves while Hosting/Skill/platform-update does not.

Measured blast radius — 7 nodes, not 6

34 declared Skill/Agent nodes across 53 packages, each read twice (once by get, once by search). 33 existed; 26 were findable. The seven that diverged:

Node get search stored mainNode
Hosting/Skill/deployment Skill/deployment
Hosting/Skill/deployment-activity Skill/deployment-activity
Hosting/Skill/instance Skill/instance
Hosting/Skill/platform-update Skill/platform-update
Essentials/Skill/email Skill/email
Store/Skill/ci-policy Skill/ci-policy
RemoteControl/Skill/remote Skill/remote

🚨 RemoteControl/Skill/remote is not listed in #1053 — it was found by this sweep. Verifying the fix means checking all seven, not the six the issue names.

The set of "get ✅ / search ❌" is EXACTLY the set of mainNode != path — no false positives, no unexplained cases. That equivalence is what makes a static test a sound substitute for a live probe: the source already determines the property. Every .json-authored skill (Hosting/Skill/setup-environment, Store/Skill/plugin, Essentials/Skill/models) is fine, because a .json node carries its mainNode explicitly. The two conventions coexist inside the same partitions, which is why this stayed invisible: Hosting/Skill looks half-populated rather than broken.

Live-only nodes, at risk

Five nodes exist on the mesh that no commit declares. AGENTS.md is explicit that a GitSynced space is rewritten from main, so these are queued for destruction; they have survived only because a node newer than the sync's conflict horizon is protected from the prune, and that protection ends when the horizon advances.

🚫 Two checks were investigated and REJECTED

1. "Commits behind" is NOT measurable from GitHubSyncConfig

A drift check reading lastSyncedAt / lastSyncCommitSha was built, run, and thrown away. It was wrong, and it would have been worse than no check:

🚨 There is no field on GitHubSyncConfig meaning "this partition last successfully imported commit X". Closing that gap in the platform would be worth doing. Until then, staleness cannot be measured from outside, and no gate should claim to measure it.

2. A single read path cannot detect this class of defect

The first version of the check asked only get @Hosting/Skill/* — a child listing — and reported the short answer as proof of absence. That listing goes through the very is:main projection that has the bug, so it reported seven live nodes as dropped. Six confident false positives, in a tool built to detect silent failures.

The lesson generalises. AGENTS.md already records that an unreadable list passes every check while verifying nothing. This is its mirror: a list that HIDES rows reports them as absent. Both are the same failure — trusting a query beyond what it can see. Absence reported by a query that shares the defect is not absence.

Detecting the divergence at all required reading the mesh by two independent paths and comparing them. That is a useful diagnostic technique; it is not, as it turned out, something that needs to run on a schedule.

Why there is no sentinel

A scheduled live prober was built for this and then deleted, along with the MESH_READ_TOKEN secret it needed. The reasoning, recorded because the pull toward "add a monitor" is strong:

What genuinely cannot be expressed statically is the live-only node check (§ Live-only nodes): nothing in the repo can know what someone created directly on a mesh. That is real, and it is the one thing lost by deleting the prober. It is not worth a production credential on a PR gate — a mesh-side concern belongs in a mesh-side tool, and the underlying hazard is better removed by making live edits land in the repo the same session, which AGENTS.md already requires.

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