When a node exists but cannot be found
get and search can disagree, and when they do, get is right. A node whose MainNode does
not equal its Path is excluded from every search β deliberately, because that is exactly what
makes a node a satellite. The catalog's is:main projection is SQL n.main_node = n.path.
So a node with a wrong MainNode is not broken in any way you can see. It is Active, it has
current content, get returns it in full β and it does not exist to anyone searching. Nothing
errors, nothing logs, no status flips.
π¨ "The sync dropped it" is the wrong first conclusion. It is the natural one, and it cost a full investigation on 2026-09-01. Four
Hosting/Skillnodes had vanished from the/-menu; the partition'slastSyncedAtread 13 days stale; the obvious story was an import that reported success and silently failed. Every part of that was wrong.
The two-minute diagnostic
Before theorising about the importer, ask the node directly:
get @{partition}/{path} # does it exist?
search "path:{partition}/{path}" # can it be found?
get |
search |
What it is |
|---|---|---|
| returns the node | count: 0 |
A MainNode defect. Compare mainNode against path on the node get returned. |
Not found |
count: 0 |
A genuine import gap β now go and read the import activity. |
| returns the node | returns the node | Whatever you are chasing is elsewhere. |
Read mainNode on the returned node. On a main (non-satellite) node it must equal path. If it
names a path in a different partition, that is the bug.
What the 2026-09-01 case actually was
Hosting/Skill/deployment had path: Hosting/Skill/deployment, namespace: Hosting/Skill β and
mainNode: Skill/deployment, pointing at the platform skill partition. Same for
deployment-activity, instance, platform-update, plus Essentials/Skill/email and
Store/Skill/ci-policy.
The discriminator was the file format, not the date: every skill authored as .md was corrupted;
every .json skill was fine. MeshNode.MainNode is a stored init property whose default is
computed once, at construction. The skill markdown parser minted every skill in the platform Skill
partition and then rebased it with with { Namespace = ns } β which does not re-run the initializer,
so Path moved and MainNode stayed frozen. AgentFileParser constructs with the real namespace up
front, which is why the .md Agent nodes in the same folders were unaffected.
It was latent for two days. CreateOrUpdateNode could not move a stored MainNode at all until
MeshWeaver#2652 (2026-08-29) made it upsertable β so until then the wrong value was silently
discarded on every re-import and the correct stored value survived. That PR is correct; it unmasked
this. Tracked as #1053 here and MeshWeaver#2939 in core.
Four traps this produced
lastSyncedAtis not "when the sync last ran". It is the two-way conflict horizon β when mesh and repo were last actually reconciled β and it is deliberately NOT advanced by a no-op update, nor by an import that preserved server-newer nodes. A stale value therefore means "recent imports have been preserving local changes", which is information, not a fault.lastSyncCommitShais not per-partition import evidence either. It records which repo commit the sync configuration last saw, not what this partition imported: on 2026-09-01, 33 of 34 partitions carried the identical sha while theirlastSyncedAtvalues spanned 25 days. Neither field answers "did this partition import?" β only the import activities do (search namespace:{partition}/_Activity sort:lastModified-desc). Read those before calling a partition stale, and never conclude a node is missing from a sync stamp.- A green sync proves the sync ran, not that the content is right. The import wrote these nodes successfully. Every one of them.
- A node that exists ONLY on the mesh is living on borrowed time. The same investigation found
four nodes created live on 2026-08-26 that were never in the repo. They had survived only because
the conflict horizon happened to sit behind them β a node whose
LastModifiedis newer thanlastSyncedAtis protected from the Bidirectional prune. The moment an import lands cleanly the horizon advances and the next prune deletes them. That is an artifact, not a safety property.
Repair
Re-importing does not fix a corrupted MainNode β it writes through the same path. The only
route that restores a main node is an explicit re-stamp on the node stream (a full-instance upsert
provably cannot):
GetMeshNodeStream(path).Update(n => n with { MainNode = n.Path })
Apply it to every non-satellite node where main_node <> path and main_node does not resolve
inside the node's own partition. Fix the parser first, or the next import re-corrupts them.