Every number comes from the analyzer
Measured values off the folder's shape, cut-offs off the thresholds, the drawing off the scoring pass itself. Nothing is re-derived here, so the tool cannot disagree with the panel or with the quality report.
Structure
Drawing a graph of badly organised code produces a picture of badly organised code. Past a certain messiness no amount of colouring, filtering or zooming brings the reading back — readers who can follow one graph and not another are not reacting to size, they are reacting to shape. So Mezzanine scores it.
In Mezzanine 1.3.0 and later. Every block of output below is verbatim from the published 1.4.0 binary, run against the repository you can clone.
Why a second question
Every metric in Mezzanine until this one answered the first: complexity, coupling, cohesion, the smells, the composite score that sorts a refactor list. None of them answered the second, which is a question about how the files are organised rather than about what is inside them. A folder can be immaculately arranged and full of terrible code, or the exact reverse, and one number moving for both reasons could be acted on for neither.
So shape is computed and reported beside the refactor score, never folded into it. Higher is better here, against the grain of every other number in the tool — which is stated in the type, the JSON, the panel and the agent output rather than left to be inferred.
The measure
Scored over the graph the canvas actually draws — a folder's immediate children, each subfolder standing as one node. Not every descendant flattened together: that sees more, but it scores a picture nobody looks at, and a reader told “this folder is tangled” has to be able to look at the folder and see the tangle.
Children depend on each other in a loop. There is no order to read the drawing in, and no other property means anything measured on top of it.
Break the loop — usually by moving the shared piece down into a child both can depend on.
Acyclic, so there is an order — but edges jump levels instead of stepping down one at a time. The drawing has no layers to follow.
Either the intermediate layer is not carrying the traffic it should, or the shortcuts around it are the real design.
A clean layered DAG. Readable at this level, and says nothing at all about whether the folders inside it are.
Readable here. What holds it short of fractal is breadth, merging, the doors, or a folder one level down.
The shape holds at more than one zoom level. Few enough children to take in at once, branching rather than merging, entered from outside through few doors, and made of children that are themselves at least hierarchical.
Nothing to do — the shape holds at every level.
Fractal is recursive by construction. Its last clause is a claim about the children, so a folder cannot earn it while sitting on top of a mess — which is what makes the measure self-similarity across zoom levels rather than one level's opinion. It is also what makes the work order fall out for free: a parent held back by a tangled subfolder cannot move until that subfolder does, so the report lists the deepest actionable folder first.
The gates
Six are readings of the drawing. The seventh is a count, and it is the one with a story — see below. Own drawing marks the gates a reader can settle by looking at the picture in front of them, as against the ones answered only by the subfolders, the callers, or the blend; that split decides which folder to work on first.
| Gate | Bar | What it reads | Own drawing |
|---|---|---|---|
| Acyclicity | 1.00 | No loop among the children. Anything short of a clean 1.00 leaves the folder cyclic. | yes |
| Layering | ≥ 0.70 | The share of edges advancing exactly one level. Deliberately not tree-ness — a diamond scores perfectly, and a transitive shortcut past the middle layer does not. | yes |
| Branching | ≥ 0.70 | The share of edges that would survive in a spanning forest. Everything past the first edge reaching a child is a merge: two siblings leaning on the same third one. outside the compliance blend | yes |
| Breadth | ≤ 8 children | Immediate children, files and subfolders together. The one gate that is a convention rather than a reading of the drawing, and the only one whose fix moves files instead of edges. outside the compliance blend | yes |
| Entry concentration | ≥ 0.60 | How much of the traffic arriving from outside lands on one file — the door. Fixable, but the work is in the callers and is not visible in the drawing being shown. | — |
| Child compliance | ≥ 0.80 | The mean compliance of the subfolders. This is the recursive gate, and the reason fractal is a claim about self-similarity rather than about one level in isolation. | — |
| Compliance | ≥ 0.85 | The weighted blend of the four above it. Reported last because it is the blocker only when every gate passed and several terms were a little low — several small shortfalls rather than one clear defect. | — |
Branching and breadth gate the tier and stay out of compliance deliberately, so
a folder can blend well and still be held back by one of them. A blend cannot carry the
reason: two folders at 0.72 can need opposite fixes, so the tool names the binding
constraint instead — why rather than how much.
The number
The breadth bar started at seven, taken straight from the span of what a reader holds at once. The decision record said plainly that the project could not validate it: every folder over the bar was already cyclic or tangled, so the gate never fired. It named the evidence that would settle it — “the first codebase to feel it will be one whose wide folders are otherwise clean.”
Two days of use produced exactly that. Once several folders had been taken up the ladder,
breadth became the most common blocker among the graphs that were already clean — and one
of them, parser/rust/declarations, was a spanning tree:
acyclic, properly layered, branching 1.00, every child reached from exactly one parent. It
was held off fractal by a single file.
A bar that stops a spanning tree is measuring the wrong thing. The bar is eight. It still refuses the twelve-, eighteen- and thirty-nine-child folders nobody takes in at a glance, and non-trivial fractal folders went from four to five the moment it changed.
Seven survives one level down, as the authoring rule for entities in a file and elements in an entity. The reference repositories below are built to it.
Seven was a guess about readers; eight is what the guess costs when checked.
ADR 0018 — the-breadth-bar-is-eight
The number is evidence-backed rather than asserted, and the evidence is in the file that changed it. The next revision is expected to come from the same place.
Where it comes out
It is part of the quality report rather than a command you have to know about. The folders short of fractal are split by whether their blocker is in their own drawing, and ranked deepest-first within that — because clearing a deep one can clear a parent's child gate too.
## Folder shape (40 folders)
6 cyclic · 4 tangled · 16 hierarchical · 14 fractal
### Start here *for shape* — the blocker is in the folder's own drawing (10 of 23 shown)
- [hierarchical] parser/dart/declarations — held back by children reaching
outside from its middle (out-at-the-bottom 0.50); compliance 0.81, acyclic
1.00, layered 0.71, branching 0.71, one-door-in 0.50, 6 children
- [cyclic] parser/groovy — held back by a loop among its children (acyclic
0.83); compliance 0.78, acyclic 0.83, layered 0.59, branching 0.59,
one-door-in 1.00, 12 children
- [tangled] parser/go — held back by edges skipping levels (layered 0.57);
compliance 0.83, acyclic 1.00, layered 0.57, branching 0.57, one-door-in
0.75, 9 children
- [hierarchical] parser/rust — held back by more children than a reader holds
at once (9 of them); compliance 0.90, acyclic 1.00, layered 0.89, branching
0.89, one-door-in 0.67, 9 children
### Answered elsewhere — blocked on children, callers or the blend (3)
- [hierarchical] parser/typescript/bodies — held back by too many doors in
(one-door-in 0.40)Twenty-two of thirty-nine folders hold their shape; five are cyclic. That is the engine's own tree, unedited — a tool that only ever showed clean output on its own code would be worth less, not more.
The tool
A line reading “tangled, layered 0.61” names a defect without naming any of the six edges
that caused it. reshape hands over the drawing behind the verdict — the
children with their levels, every edge with its reading, the doors and the traffic through
them — plus an instruction scoped to exactly one rung of the ladder.
## Verdict
**cyclic** — held back by a loop among its children (acyclic 0.20).
- acyclicity 0.20 (must be 1.00 to clear `cyclic`)
- layering 1.00 (needs ≥ 0.70 to clear `tangled`)
- branching 1.00 (needs ≥ 0.70 for `fractal`; NOT part of compliance)
- entry concentration 0.50 (needs ≥ 0.60 for `fractal`) — **2 ways in**,
which the ratio does not say
- out at the bottom 0.60 (needs ≥ 0.70 for `fractal`; NOT part of
compliance) — **4 exits from the middle**, which the ratio does not say
- compliance 0.54 (needs ≥ 0.85 for `fractal`)
- 5 immediate children (needs ≤ 8 for `fractal`; NOT part of compliance)
## Your task: cyclic → tangled
Break the loops among these children. 6 of 9 edges run inside one, so the
drawing has no reading order at all — every other property is measured on
top of this one.
**One loop**, 4 children and 6 edges:
- `src/check/mod.rs → src/check/count.rs` — carries 1 entity: `violations`
- `src/check/count.rs → src/check/mod.rs` — carries 2 entities:
`Violation`, `repo_relative`
- `src/check/report.rs → src/check/mod.rs` — carries 3 entities: `Cited`,
`Outcome`, `Violation`
Cut the cheapest edge that is genuinely a back edge. An edge carrying one
entity is usually a definition sitting in the wrong file, and moving that
definition into a file both ends can depend on breaks the loop without
touching either caller. An edge carrying twenty is the folder's real
structure, and inverting it is a rewrite that will not survive review.
Stop there. The tiers are a ladder and `tangled` is the next rung — the
gates above it are measured on top of this one and are not worth chasing
until it clears.Measured values off the folder's shape, cut-offs off the thresholds, the drawing off the scoring pass itself. Nothing is re-derived here, so the tool cannot disagree with the panel or with the quality report.
The blocker has already decided which of the gates it was; this expands that one into the specific files and edges behind it. Picking a different one to talk about would send an agent after something that would not move the verdict.
A cyclic folder is asked to break its loop and nothing else. The tiers are a ladder, each defined as the one below plus a property — so a four-part instruction is one that cannot be finished, and usually is not started.
In CI
mezz check grades a tree against rules the project wrote down. Every failure it
can produce traces to a line somebody in the checked repo authored, and a repo with no
rules file passes and says so.
{
"rules": {
"max_entities_per_file": 7,
"max_elements_per_entity": 7,
"max_doors_per_folder": 1
},
"exempt": ["**/tests.rs"]
}$ mezz check . # a fresh clone, no rules file
no rules declared in .mezz/rules.json # exit 0
$ mezz check . # after declaring the bars above
src/analyzer/mod.rs:1 — max_entities_per_file: 54 declared, bar is 7
src/analyzer/mod.rs:79 — max_elements_per_entity: Analyzer has 34 elements, bar is 7
src/config.rs:13 — max_elements_per_entity: Config has 16 elements, bar is 7
src/diff.rs:1 — max_entities_per_file: 106 declared, bar is 7Exit 0 when every declared rule holds or none was declared, 1 when one does not, 2 when no verdict could be computed — a gate that passed because it could not understand its own configuration is the failure the command exists to stop.
| Rule | Counts |
|---|---|
| max_entities_per_file | Declarations a reader meets on opening the file, minus what a class-like entity owns. |
| max_elements_per_entity | Members of a class-like entity; parameters of a callable. |
| max_doors_per_folder | Files outside the folder land on, ties included — how many front doors it really has. |
| max_importers_per_file | Other files depending on this one, counted against the file that declares what they use rather than the one they named. |
A tool may hand you a diagnosis you are free to disagree with; it may not fail your build with one.
ADR 0024 — a-check-fails-on-the-projects-rules-not-mezzs
This is why min_shape: fractal is not a rule anybody can declare, and its
absence is a decision rather than an omission. The tiers are Mezzanine's, and three separate
decision records have each conceded that its gates can be wrong about a specific folder.
Rules are expressed over Mezzanine's measurements — but the threshold is arbitrary, arguable, and
the project's to argue over.
What it looks like when it holds
The ladder measures; it does not tell you how to write. These four rules are what the engine is developed against — held to across seven languages, in seven copies of the same small program, every folder of every one of them scoring fractal. They are language-independent. What changes between them is only which file the convention makes the door.
The first two make the picture a tree; the last two keep each node small enough that the tree is worth drawing. In practice rule 2 is the one with teeth, and it always lands in the same place: two sibling subtrees want to share a type. The answer is never to let one import the other — it is for the parent to translate, which costs about four lines and buys a drawing that branches instead of merging.
The graph tells you what the code is. The ladder tells you whether it can be read — and names the one move that makes it more readable than it was.