Skip to main content

check and validate

koyu splits "correct" in two.

Structural diagnosticsArchitectural judgement
Commandkoyu checkkoyu validate
Return typeDiagnostic { code, severity }Finding { rule, level }
IdentifierBND04, SUF01 — three letters plus two digitskoyu.schematic.site.escape, koyu.schematic.access.unreachable — chapter.rule
Weighterror / warningviolation / caution
PopulationThe diagnostic ledgerThe validation rule ledger
Versionfreezesdoes not freeze; grows
What it sayswhat is written does not contradict itself as datathis is (probably) architecturally sound

They are spelled differently on purpose. No reader will confuse SIT03 with koyu.schematic.site.escape.

Even the types are separate​

Add --json and the fact that these two are not the same shape is visible directly.

npx tsx src/cli.ts check b1.muro --json
[
{
"code": "BND04",
"severity": "error",
"message": "The spaces do not touch, so no boundary can be derived: /L1/a | /L1/b",
"line": 6,
"file": "b1.muro",
"path": [
"/L1/a",
"/L1/b"
]
}
]
npx tsx src/cli.ts validate caution.muro --profile koyu.profile.schematic-screen --as-of 2026-08-03 --json
{
"schema": "koyu-assessment",
"profile": { "id": "koyu.profile.schematic-screen", "revision": "1" },
"findings": [
{
"rule": { "id": "koyu.schematic.daylight.unknown", "revision": "1" },
"level": "caution",
"outcome": {
"id": "/L1/a",
"status": "fail",
"message": "Window area is not fully counted: /L1/a has a window without h: (write h: on it)"
}
}
],
"summary": {
"state": "complete",
"rules": { "evaluated": 5, "notApplicable": 10, "indeterminate": 0, "error": 0 },
"outcomes": { "pass": 4, "fail": 1, "indeterminate": 0 }
}
}

Being unmixable is the job of these types. For a downstream tool to pour both into one array, it must first flatten the types — and that flattening is visible at the moment it happens.

Why split — the quality demanded is different​

Judgement is a domain where what is correct is not settled yet. How to treat daylight correction factors, where to cut off a cramped stair, how to count egress routes — every one of these varies by jurisdiction, by era and by building use. Freeze before they settle and you freeze the mistake.

Structural diagnostics, by contrast, are settled. Is the path unique? Does the referent exist? Do two regions overlap? These are part of reading, and admit no opinion.

So they are treated differently.

Structural diagnosticsArchitectural judgement
Cost of addinghigh — parsing, composition, machine format, spec and docs all at oncelow — one ledger line and one page section
Cost of being wrongvery high — the error sits on a frozen surfacelow — rewrite it
Precisionmust be completemay be coarse
Can it be thrown away?noyes

There is one condition on being allowed to be messy: the result of a judgement must never be mistaken for a guarantee about the source. Spelling, type and output wording all defend that condition.

Validation — 2 violations / 0 cautions
✔ Nothing caught by validation (this is a judgement, not a guarantee about the composition)

Green judgement means only that judgement is green.

Coarseness in practice​

koyu.schematic.stair.proportion calls a derived step cramped against a band taken from ordinary practice. The band is not law and does not follow the reader to another country.

That is fine — the rule can afford to be this coarse because fixing the coarseness is cheap: a threshold moves and no file changes meaning. Were the same rule in core, it could not have shipped this coarse, because core's numbers are frozen.

core returns numbers; judgement draws lines​

Aggregate and graph queries live in core. They never say pass or fail.

QuestionWhat core returnsWhat judgement says
Daylightfloor area and effective window areadoes it meet 1/7 (koyu.schematic.daylight.ratio)
Sitesite area, frontage, footprint, gross floor area and their ratios2 m of frontage (koyu.schematic.site.frontage), escaping the site (koyu.schematic.site.escape)
Vertical circulationriser count, rise, tread, slopecrampedness (koyu.schematic.stair.proportion), slope (koyu.schematic.ramp.declared-slope / koyu.schematic.escalator.usual-slope)
Circulationfewest-door routes and passabilitycan you get out (koyu.schematic.access.unreachable and the rest)
Columns and openingscolumns standing on grid crossings, openings on segmentsdo they overlap (koyu.schematic.column.blocksdoor)

The thresholds belong to architecture. 1/7, 2 m and 240 mm are not invariants the composition must satisfy. core goes as far as returning the number; judgement draws the line on it.

Because of that split, adding a judgement for another jurisdiction touches not one line of core. Add a rule to the ledger, write a page, and you are done; the language version does not move.

Judgement is a surface that grows​

The rule set is not finished. Fire compartmentation, shadow studies, setback envelopes, travel distances, accessibility, whether services can be made to work — there is a great deal left that could be written as judgement.

All of it goes onto this surface. Adding it does not change what .muro means, existing files still read, and canonical JSON still emits the same bytes.

Adding to the language is expensive; adding to judgement is cheap. Creating that asymmetry is precisely why the two are kept apart.

Next​