Skip to content

v4.189.0

@jessegall jessegall tagged this 25 Jul 06:33
The layer rule is inert until a project declares its layers, and nobody writes that
from a blank file. This reads it off the code instead.

By default it proposes TODAY'S SHAPE: every orderable namespace with what it uses now.
Everything already there passes, so the declaration costs nothing to adopt and refuses
the next arrow pointing somewhere new. `--floor` proposes only the namespaces others
depend on that depend on nothing — a smaller start.

The floor was the default until end-to-end testing showed it barely bites: a declared
layer may always use an UNDECLARED namespace, so declaring only the bottom leaves it
free to reach anywhere you have not named yet. A declaration bites in proportion to
how much of the tree it covers, hence today's-shape by default.

`--write` splices the block into .commandments/config.php by node offset, importing
the detector it tunes — the same splice `ensurePlanExecution` uses, so the human's own
lines are untouched. A config that already declares layers is left alone: the stack is
theirs to decide, and this proposes rather than seizes.

Namespaces in a cycle can be ordered by nothing, so they are reported separately and
pointed at `judge --sin=namespace-cycle` — break those first, then re-run.

NamespaceGraph gained `foundation()`: depended ON, depending on nothing. Both halves
matter — a namespace nothing depends on is merely isolated, and pinning it down buys
no one anything.

Verified end to end on a scratch project: propose -> write -> a new upward arrow is
caught by judge; and on prep-labels (103 namespaces, 26 floor, 62 cyclic).
Assets 2
Loading