The lean.ref grammar and the package registry it resolves against.
Mechanism, not content. This module knows that a block may cite a formal
artefact as package:Declaration, how to parse one, and how to look up the
package a folio has declared. It does not know which packages exist — a
folio injects those with configureLeanPackages.
Why this is core and not the science layer
BlockBase carries an optional lean field, in schemas/types.ts, and
schemas/constraints.ts validates its ref against
LEAN_REF_PATTERN. The field is on shared block kinds by design —
remark, example, algorithm and simulator all declare it and the
document profile forbids its use (pipeline/profile-check.ts). So
the grammar belongs wherever the field does, which is core; only the
package list is a property of a particular folio.
Seven core modules import from here for exactly that reason — the ref
grammar and the lookup, never the list.
Unconfigured is not empty
The registry starts empty and stays empty until a folio configures it, and
those two states are different facts: nobody has said is not there are
none. leanPackagesConfigured is how a caller tells them apart, so
a pipeline can report "not checked" rather than silently skipping every
library-tree lean.ref and looking clean while doing so.
That distinction replaces a hardcoded default. Until 2026-09-18 this module
shipped three qou-family folios — qou, ugb, fred2005, with their
content directories — as DEFAULT_LEAN_PACKAGES, applied at import. Its own
comment said the list "is injected by the content repo; keeping it here as a
default unbreaks the pipeline without a config-discovery mechanism". It was
one folio family's data living in the platform, which is the genericity
failure this repository is organised against, and no platform test covered
it: the whole suite passes with the defaults removed, because the platform
carries no corpus to skip.
The
lean.refgrammar and the package registry it resolves against.Mechanism, not content. This module knows that a block may cite a formal artefact as
package:Declaration, how to parse one, and how to look up the package a folio has declared. It does not know which packages exist — a folio injects those with configureLeanPackages.Why this is core and not the science layer
BlockBasecarries an optionalleanfield, inschemas/types.ts, andschemas/constraints.tsvalidates itsrefagainst LEAN_REF_PATTERN. The field is on shared block kinds by design —remark,example,algorithmandsimulatorall declare it and the document profile forbids its use (pipeline/profile-check.ts). So the grammar belongs wherever the field does, which is core; only the package list is a property of a particular folio.Seven core modules import from here for exactly that reason — the ref grammar and the lookup, never the list.
Unconfigured is not empty
The registry starts empty and stays empty until a folio configures it, and those two states are different facts: nobody has said is not there are none. leanPackagesConfigured is how a caller tells them apart, so a pipeline can report "not checked" rather than silently skipping every library-tree
lean.refand looking clean while doing so.That distinction replaces a hardcoded default. Until 2026-09-18 this module shipped three qou-family folios —
qou,ugb,fred2005, with their content directories — asDEFAULT_LEAN_PACKAGES, applied at import. Its own comment said the list "is injected by the content repo; keeping it here as a default unbreaks the pipeline without a config-discovery mechanism". It was one folio family's data living in the platform, which is the genericity failure this repository is organised against, and no platform test covered it: the whole suite passes with the defaults removed, because the platform carries no corpus to skip.Graph Node
schema