The declared course list
The Learning app's catalog (Edu/Courses, type Edu/CourseCatalog) used to derive its list
entirely from live queries: every Edu/Course, every Store/Plugin root in the Education category,
the bridge paths and the package-source feed. Whatever those queries did not find simply did not
exist, and the page said "No courses published yet." That sentence was printed on an enterprise
client instance (2026-11-01) whose catalog was empty for a reason that had nothing to do with
publishing: none of the course packages were installed there.
What the catalog does now
CourseCatalogContent.Coursesis the declared list: the ids of the course package roots, in display order.Edu/Courses.jsonships it. The declaration is the source of truth for what the Learning app offers (policydeclared-not-derived).- Each declared id is resolved against the course-root lane (
Store/Pluginroots on this mesh). A declared root is listed whatever its category says, and declared courses come first, in the declared order. - The live lanes stay additive: a course installed but not declared still appears, after the declared ones.
- A declared course with no root on this mesh is named on the page: "Not yet installed on
this instance: …. An administrator installs them from the Store." The link goes to the Store's
Education page (
/Store/Catalog/Catalog?category=Education, built the way the Store builds its category links; a bare/Store/Catalogis the NodeType node). That page's cards carry the admin-only Provision action. The line appears only after the lane has answered, so the cold first frame never names every course as missing. - Absence is decided by the confirmed installed lanes only. A package-source manifest or a bridge entry shows a card, but it never hides a "not installed" line.
- A faulted lane is no answer. The page names the read failure and calls nothing "not installed".
- "No courses published yet" is said only when the catalog has nothing at all: no listed course, no declared course and no fault. A catalog that declares courses never says it, not even before its lane has answered.
Why a learner sees no "Get" for an uninstalled course
The Store shows a package that is listed by a source but not installed on the mesh to
administrators only (StoreCatalogLayoutAreas.IsVisibleTo). Its one action is Provision, a
system install, and the per-user funnel (Subscribe → Get → Start) only exists once the package
root is on the mesh. The catalog therefore names the missing course and points to the
administrator's route; it does not invent a learner-side install.
Diagnosing an empty catalog
- Is any course root installed?
search nodeType:Store/Plugin category:Education partitions:allon the instance's MCP server. - Does the Store's feed list the course packages?
get @Store/data/StoreFeedStatusshows each source and whether it polls;@Store/data/StorePackagelists what the sources offer. A course that is absent from both is not supplied to the instance at all, and that is a deployment (source) question, not a catalog defect. - Is the instance running the current Edu build?
get @Edu/CourseCatalog→adoptedModuleVersion/compiledPlatformVersion. An instance whose platform lags keeps the older Edu, which has no declared list. - An MCP
get @Edu/Courses/area/Catalogreturns the first paint only. An empty list there proves nothing. Read the page as a viewer, or read Loki for theEdu.CourseCatalogwarning "could not read its courses".