Skip to content
Skip to main content
Novel Systems home
Decision log
D-092August 6, 2026

A second diagram, and a toolchain that discovers diagrams instead of listing them

Affects: docs/cpq-subsystem.mmd, render-diagram.command, scripts/publish-diagram.mjs, scripts/check-diagram-current.mjs, scripts/check-evidence-tracing.mjs, lib/engineering-evidence.ts, components/engineering/diagram-figure.tsx, components/engineering/request-flow-figure.tsx, components/engineering/cpq-subsystem-figure.tsx, components/engineering/evidence-index.tsx, app/engineering/page.tsx, next.config.mjs, .gitignore

Decision

Draw the CPQ subsystem as its own diagram rather than enlarging the existing one, and make every part of the diagram toolchain discover docs/*.mmd rather than name a file.

Why a second diagram and not a bigger first one

A review listed "CPQ subsystem layout" as a missing artifact while standing on a page that served /architecture.png. That reads at first like the ninth variant of this repository's recurring failure — the artifact is there and the reviewer cannot see it — and it is not. architecture.mmd draws the whole platform and gives pricing four boxes: the sandbox, the browser engine, the proxy route, the server engine. That is the correct resolution for "how does a request get from a browser to Postgres" and it is the wrong resolution for "how is the pricing subsystem laid out." Zooming in on a picture drawn at a different scale does not answer a different question. The reviewer was reading correctly.

So docs/cpq-subsystem.mmd draws exactly one call to calculateQuote(): what is read and inside which transaction, the margin gate that runs before any price exists, the five component costs with every constant on the node that uses it, both rounding modes and why they differ, the cut list derived from the finished opening alone, the totalling rule, the assertion that should be unreachable, and the row of parity checks that hold two engines together which are forbidden from importing each other. Every constant on it is declared in backend/src/services/cpq-engine.ts or lib/cpq-engine.ts and checked by one of those scripts, so the diagram is a drawing of the code rather than a description of the intent.

Why the toolchain now discovers rather than lists

Adding the second diagram was supposed to cost a source file. It cost edits in six places, every one of which named architecture literally: the render script, the publisher, the currency check, the traced-artifact list in two files, and the .gitignore entry for the render transcript. Each of those is a place to forget, and a diagram forgotten in any of them fails differently and quietly — it renders but is never published, or is published but never checked, or is checked but never traced into the lambda that serves it. The last one is D-089 exactly.

The convention is now the list. Every docs/*.mmd is a diagram; docs/<stem>.png is its render, docs/<stem>.render.json its stamp, and public/<stem>.mmd / public/<stem>.png the published pair. render-diagram.command, scripts/publish-diagram.mjs and scripts/check-diagram-current.mjs each discover that set independently from the same directory, so no two of them can disagree about what a diagram is. The traced-artifact list holds public/*.mmd and docs/*.render.json as globs, which meant teaching check:evidence-tracing to evaluate a glob rather than strip a /** suffix — before this it checked public/*.mmd as a file literally named *.mmd and failed, which was the right answer by accident and would have become the wrong one the moment anyone "fixed" it by resolving the directory instead.

The .mmd content-type header is matched by pattern for the same reason. It named /architecture.mmd, and a second published source would have been served as application/vnd.chipnuts.karaoke-mmd — a save dialog where a reader asked to read the source, which is the same unhelpful answer as a 404 and is the defect this repository has now made ten times.

What was rejected

A manifest listing the diagrams. It is a fourth place to forget, and a diagram absent from it would be unguarded rather than absent — which on a green build looks exactly like guarded.

Enlarging architecture.mmd to cover the pricing internals. The request-flow diagram is already 2160 × 4273 with 10px labels; adding the arithmetic would make one picture that answers neither question at the resolution it needs.

Copying RequestFlowFigure for the second diagram. That would have copied five hardcoded paths, the loud missing-artifact branch and the D-089 lesson inside it, and the copy would then have drifted from the original. The mechanics live in one DiagramFigure that takes a stem; each named figure supplies only its alt text and caption, which are the two things that genuinely differ.

What would make this wrong

If diagram count grows past about half a dozen, the evidence index stops being an index — it is already at thirteen entries against a stated ceiling of roughly a dozen, and the next artifact does not get a row by default. At that point the index grows headings, or the diagrams get a page of their own, and this entry needs a successor that says which.

If a diagram is ever generated rather than hand-authored, the byte-count stamp and the manual render step stop being the right mechanism, because CI could produce and verify it directly.