Skip to content

A PluginCatalog node over a local node-repo checkout lists nothing — BuildSource never selects the node-repo source, and the content has no format field #3384

Closed

Description

@rbuergi

Split out of #3359 (its fix option 3), where it was found and measured — it is its own defect and reaches every checkout-served source, not only the self-registry mode.

What happens

A PluginCatalog node created over a local node-repo checkout (sourceRepoPath: /plugin-repos/Education, the format memex-local mounts and NodeRepoPackageSource reads) creates fine, its Catalog area activates, and it renders "No installable packages found."

Why

CatalogLayoutAreas.BuildSource builds the area's source with

PackageSources.FromRepo(host.Hub, sourceRepoPath, sourceSubdir, Logger(host));

and never passes nodeRepo: true, so a LOCAL path falls through to GitPackageSource — the package.json format — which lists nothing for a node-repo tree. The factory's own comment names the outcome ("before this, a local path silently fell through to the package.json source below and listed nothing"). PluginCatalogContent carries only SourceRepoPath / SourceRef / SourceSubdir / Description — no format field — so a catalog node cannot select the node-repo source even deliberately.

Consequence

The documented human fallback for a stale install — "a human opening the catalog page … offers the same Update" — is unreachable for every checkout-served source. On a self-registry memex-local there is no catalog page at all out of the box (it seeds no PluginCatalog node), and creating one by hand does not help until this is fixed. #3359's fix (the mounted checkouts reconcile on every boot) removes the need for the fallback in that mode; this issue is what stands between an operator and the catalog page over any local checkout.

Fix shape

Either a Format member on PluginCatalogContent (node-repo default, package-json opt-in — the same knob PluginCatalog:Sources:N:Format already has), or detect the node-repo shape (a depth-2 <Folder>/index.json with a root nodeType — the predicate memex-local's is_node_repo and NodeRepoPackageSource already share) in BuildSource. Then memex-local can seed one PluginCatalog node per mounted repo so the page exists on a fresh install.

Measured on 2026-09-05 by the #3359 investigation (two catalog nodes over /plugin-repos/Education and /plugin-repos/Plugins, both empty).

Activity

  1. rbuergi commented on Sep 6, 2026

    @rbuergi
    ContributorAuthor

    Fixed on main by #3387 (the merge queue does not fire Closes links here, so closing by hand after
    verifying the code actually landed):

    $ git show origin/main:src/MeshWeaver.PluginCatalog/PackageSources.cs      | grep -c IsNodeRepoFormat  → 3
    $ git show origin/main:src/MeshWeaver.PluginCatalog/PluginCatalogContent.cs | grep -c Format            → 3
    

    PluginCatalogContent now carries Format — same values and same node-repo default as the
    PluginCatalog:Sources:N:Format configuration knob — and both readers resolve it through the one
    shared rule PackageSources.IsNodeRepoFormat. The browse view stops taking nodeRepo's false
    default, and PluginUpdateWatcher stops hardcoding true, so the two readers of a catalog node can
    no longer disagree about the same repository.

    CatalogSourceFormatGuard pins it mechanically: every FromRepo call site must pass
    IsNodeRepoFormat(...), with a floor on the number of call sites so a renamed factory fails loudly
    rather than reporting a clean tree, plus a self-test that the matcher sees both a hardcoded and a
    resolved call including one split across lines. Verified it can fail — restoring both pre-fix call
    sites reddens it and names CatalogLayoutAreas.cs:410 and PluginUpdateWatcher.cs:169 exactly.

    Also corrected FromRepo's own summary, which claimed "A local path always uses the git-CLI
    package.json source"
    — untrue since the local node-repo source landed, and the sentence that made
    this defect easy to miss.

    🤖 Filed from Claude Code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions