New Project

Diagnostics#

Every ww::stage::name code a compile can report, scanned from the compiler's sources. A scene carries them in diagnostics with a severity, the line, and the message. Where the stage declares a message template, it is shown ({braces} are filled in at run time) with its help line.

Stage analysis#

ww::analysis::unaccounted_contact#

Reported by the compiler with a message built at run time.

Stage check#

ww::check::below_floor#

Reported by the compiler with a message built at run time.

ww::check::empty_assembly#

Reported by the compiler with a message built at run time.

ww::check::extra_root#

Reported by the compiler with a message built at run time.

ww::check::floating#

Reported by the compiler with a message built at run time.

ww::check::slide_clearance#

Reported by the compiler with a message built at run time.

ww::check::travel_foul#

Reported by the compiler with a message built at run time.

ww::check::travel_invalid#

Reported by the compiler with a message built at run time.

ww::check::travel_unchecked#

Reported by the compiler with a message built at run time.

Stage dsl#

ww::dsl::bad_choice#

A choice set to a word its declaration does not allow, or declared without words. Message: choice `{choice}`: {problem}

Help: {allowed}

ww::dsl::bad_import_path#

Message: `{path}` is not a usable import path

Help: `from=` is `std:name` for an embedded library, or a `/`-separated path relative to this file

ww::dsl::bad_reference#

Message: `{raw}` is not a valid reference

Help: a reference is `Part@Mark` (ADR-0002); either half may interpolate a name in braces (`Rail_{i}@Slot_{i}`), but braces must pair up around it

ww::dsl::bad_value#

Message: `{node}` has a `{key}` of the wrong type

Help: expected {expected}

ww::dsl::collection_cycle#

Message: collections extend each other in a cycle: {chain}

Help: `extends=` must lead back to a collection with no `extends=`

ww::dsl::collection_unknown_key#

A derived collection setting a param, choice or slot its bases never declared. Message: collection `{collection}` sets {what} `{name}`, which `{base}` does not declare

Help: a derived collection lists only differences; declare it in the base collection first

ww::dsl::duplicate#

Message: `{name}` is declared more than once in this scope

ww::dsl::import_conflict#

Message: import conflict: {what}

Help: {hint}

ww::dsl::import_cycle#

Message: import cycle: {chain}

Help: a file cannot import itself, directly or through others

ww::dsl::import_load_failed#

Message: cannot import `{path}`: {reason}

ww::dsl::import_too_deep#

[crate::Limits::max_import_depth]. Message: imports chain more than {limit} files deep

Help: a chain of files importing files may be at most {limit} long (docs/KDL_AUTHORING.md §13)

ww::dsl::kdl_syntax#

Message: file does not parse as KDL v2

Help: woodwerx uses KDL v2. Note that `(` after `=` starts a type annotation, not a tuple, and backtick is a legal identifier character (ADR-0002).

ww::dsl::missing_field#

Message: `{node}` is missing {what}

ww::dsl::missing_project#

Message: expected a single top-level `project` node

ww::dsl::nothing_exported#

Message: `{path}` exports nothing

Help: a file opts in to being imported by writing `export=Name` on a top-level `assembly` or `component`

ww::dsl::slot_contract#

A slot bound to something that is missing, of the wrong kind, or lacks a param the slot's contract names. Points at the collection line that made the binding. Message: slot `{slot}` of collection `{collection}`: {problem}

Help: a slot binds a name of its kind, and a component or assembly slot must declare every param in its `requires=`

ww::dsl::source_too_large#

[crate::Limits::max_source_bytes]. Checked before the file is parsed at all. Message: the file is {size} bytes; the limit is {limit}

Help: a project file may be at most {limit} bytes (docs/KDL_AUTHORING.md §13). The largest example is about a sixth of that

ww::dsl::too_deep#

[crate::Limits::max_depth], counted in { … } blocks. Checked before the file is parsed, because the KDL parser recurses once per level. Message: blocks nest more than {limit} deep

Help: `{ … }` blocks may nest at most {limit} levels, counting `project` as the first (docs/KDL_AUTHORING.md §13)

ww::dsl::too_many_imports#

[crate::Limits::max_imports]. Message: more than {limit} distinct files imported

Help: a project may pull in at most {limit} distinct files (docs/KDL_AUTHORING.md §13)

ww::dsl::unexpected_entry#

An argument or property in a slot the typed IR has nowhere to put. Stage 1 reports these rather than discarding them: silently dropping a property the author wrote is how a file compiles into something other than what it says. Message: `{node}` does not take {what}

Help: {expected}

ww::dsl::unexpected_node#

Message: `{node}` is not valid at this scope

Help: {expected}

ww::dsl::unknown_collection#

project collection=X or extends=X naming a collection that does not exist. Message: no collection named `{name}`

Help: {available}

ww::dsl::unknown_export#

Message: `{path}` does not export `{name}`

Help: it exports: {available}

ww::dsl::unknown_slot#

@name where no slot of that name is in force. Message: no slot `@{name}` in force

Help: {available}

ww::dsl::unknown_unit#

A (unit) annotation on a number that is not mm or in (ADR-0021). Message: `({unit})` is not a known unit

Help: the unit annotations are `(mm)` and `(in)`; bare numbers are millimetres

Stage eval#

ww::eval::cel_runtime#

Message: expression could not be evaluated

ww::eval::cel_syntax#

Message: expression is not valid CEL

Help: {hint}

ww::eval::cycle#

Message: `{name}` is defined in terms of itself

Help: the cycle is: {cycle}

ww::eval::expression_too_complex#

An expression has more operators and brackets than [crate::guard::MAX_EXPR_OPERATORS] — a bound on how deep its tree can nest, which cel walks recursively. Checked before it is parsed. Message: expression has {count} operators and brackets

Help: at most {limit} in one expression; split it into named parameters

ww::eval::expression_too_long#

An expression's source text is longer than [crate::guard::MAX_EXPR_BYTES]. Checked before it is parsed. Message: expression is {len} bytes long

Help: at most {limit} bytes; split it into named parameters

ww::eval::fractional_count#

Message: `count` is {value}, so this `repeat` runs {iterations} time(s)

Help: `repeat count=` is floored (ADR-0005). Write `ceil(…)` for {next_up}, or make the count come out whole

A linked parameter (solves= / inverse=, ADR-0035) that cannot work: the target is derived, the link loops, or the inverse reads what it is trying to set. Message: `{name}` is a badly linked parameter: {message}

Help: a linked parameter is a derived one whose `solves=` names a literal parameter it depends on; see docs/adr/0035-linked-parameters.md

ww::eval::non_positive#

Message: `{name}` is {value}, which is not a positive dimension

ww::eval::not_finite#

Message: `{name}` evaluates to {value}

Help: a dimension must be a finite number; check for a division by zero

ww::eval::not_in_language#

Something CEL parses but woodwerx's expression language does not include: a comprehension macro, a method call, a list or map, field selection. See [crate::guard]. Message: {construct} is not part of woodwerx's expression language

Help: {hint}

ww::eval::out_of_range#

Message: `{name}` is {value}, outside its declared range {min}..={max}

ww::eval::repeat_count_too_large#

repeat count= resolved to more iterations than Stage 2 will enumerate. Stage 2 binds the loop index for each iteration, so a count is a bound on work. A furniture project does not have ten thousand of anything; a count that large is a units mistake or a runaway expression, and diagnosing it beats hanging. Message: `repeat` asks for {count} iterations

Help: at most {limit} are resolved; check the units on this count

ww::eval::text_too_long#

An expression can build text longer than [crate::guard::MAX_TEXT_BYTES]. Usually found before evaluation, from the lengths of what the expression concatenates, in which case len is that upper bound. Message: `{name}` can build {len} bytes of text

Help: text in an expression is limited to {limit} bytes

ww::eval::too_many_instances#

Limits::max_parts, reached by nested repeats: this one's count times every enclosing one's. Diagnosed before the loop is unrolled, not after. Message: nested `repeat`s unroll to {product} instances; the limit is {limit}

Help: this count multiplied by every enclosing `repeat`'s is {product}; a project may expand to at most {limit} parts (docs/KDL_AUTHORING.md §13)

ww::eval::too_many_parts#

Limits::max_parts, reached by the part nodes walked with every repeat unrolled. Resolution stops here. Message: more than {limit} `part`s, counting each `repeat` iteration

Help: a project may expand to at most {limit} parts (docs/KDL_AUTHORING.md §13)

ww::eval::too_many_specialisations#

Limits::max_specialisations: distinct override sets across instances of assemblies. Message: more than {limit} distinct assembly specialisations

Help: each distinct set of overrides on an `instance=` of an assembly is one specialisation; at most {limit} (docs/KDL_AUTHORING.md §13). An assembly that instances itself with changing overrides never settles

ww::eval::unknown_name#

Message: unknown name `{name}`

ww::eval::unknown_override#

Message: `{key}` is not a parameter of `{component}`

Help: {}`{component}` declares no parameters, so it has nothing to override`{component}` declares: {},

ww::eval::unsupported_operator#

An operator CEL parses but woodwerx's numeric domain cannot apply. The one that matters is %: cel reports it as UnsupportedBinaryOperator("rem", Float, Float), which tells an author writing shelf_pitch % 2.0 nothing at all. No example in examples/ uses it outside a comment, but an author will. Message: `{op}` cannot be used on dimensions

Help: {hint}

Stage expand#

ww::expand::assembly_anchor#

An assembly has no stock box, so of D6's anchors only the origin means anything. Message: an assembly instance cannot be anchored `by {anchor}`

Help: an assembly has no board to take a bounding-box anchor from, so it is placed by its own origin: `by top_sw`, or no `by` at all. Move the parts inside the assembly instead

ww::expand::bad_dimension#

Message: `{what}` is {value}, which cannot be a dimension

Help: a board has three finite, positive extents (D4)

ww::expand::bad_interpolation#

Message: `{text}` cannot be interpolated

Help: {help}

ww::expand::bad_mark#

Message: `mark` needs {what}

ww::expand::bad_mirror#

RFC-0012 / proposal 0202: mirror reflects across exactly one axis. Message: `mirror` needs {what}

Help: `mirror` reflects the part across the plane `<axis> = <value>` in the parent frame: exactly one of `x=`, `y=` or `z=` (RFC-0012, proposal 0202)

ww::expand::bad_normal#

Message: `{found}` is not a face direction

Help: `normal=` is one of pos_x neg_x pos_y neg_y pos_z neg_z, pointing out of the material (D6)

ww::expand::bad_stock#

Message: `stock` is malformed

Help: {help}

ww::expand::bad_travel#

A travel child of a join that cannot be read (ADR-0075). Message: bad `travel`: {detail}

Help: `travel [kind=slide|angle] [axis=x|y|z, optionally -signed] [min=] [max=] [rest=] [step=] [body=part|assembly] [pivot=<mark>]`

ww::expand::duplicate_axis#

pos x=1 x=2: KDL keeps the last, and the first would be lost without a word. Message: `{node}` gives `{key}=` twice

Help: each of `x=`, `y=`, `z=` appears at most once on a `{node}`; the second would silently replace the first

ww::expand::duplicate_id#

Message: `{id}` names two things in one assembly

Help: ids are unique among the parts and sub-assemblies of one assembly. Inside a `repeat`, interpolate the loop variable: `id="Name_{i}"`

ww::expand::duplicate_mark#

Message: mark `{name}` is declared more than once on one part

ww::expand::duplicate_node#

Message: `{node}` is given more than once

ww::expand::inline_override#

Message: `{key}` is not a parameter — part `{id}` instantiates no component

Help: only a component instance takes parameter overrides; an inline part's expressions see the enclosing scope directly

ww::expand::instance_cycle#

Message: assembly `{name}` contains itself

Help: the chain is: {cycle}

ww::expand::instance_with_stock#

Message: part `{id}` has both `instance=` and its own `stock`

Help: a `part` either instantiates a component or carries an inline `stock`, never both (docs/KDL_AUTHORING.md §9). The component's `stock` is the board

ww::expand::material_refusal#

ADR-0076: a substance= / tempered= that is malformed, or a feature the material cannot take (a cut in tempered glass). Message: a material cannot be made or cut that way

ww::expand::missing_stock#

Message: {what} has no `stock`

Help: every part is cut from a board: `stock <material> <x> <y> <z> [grain]` (ADR-0007)

ww::expand::not_a_number#

Message: `{what}` is {found}, not a number

ww::expand::not_a_part#

Message: `{part}` is a sub-assembly, not a part

Help: a join mates two boards; name a part inside the sub-assembly from within it

ww::expand::not_text#

RFC-0122's finish=: a genuine string literal needs the CEL single-quote escape hatch (ADR-0004) — finish "'danish oil'", not finish "danish oil", which CEL reads as an (unknown) identifier. Message: `{what}` is {found}, not text

Help: a genuine string literal is a CEL expression that evaluates to one: `finish "'danish oil'"`, not `finish "danish oil"` (ADR-0004)

ww::expand::one_sided_join#

join joint=X male=Part@Mark with no female=, for a joinery that joins two parts (RFC-0128, ADR-0030): only a hardware_mount mounts onto one. Message: `join joint={joint}` names no `female=`, but a `{kind}` joint joins two parts

Help: only a `hardware_mount` joinery may be fired with `male=` alone (one item on one part)

ww::expand::skeleton#

ADR-0081: a malformed locus, a part … in= naming an unresolved locus, a trimmed_by { … }/outline that cannot be reconciled with its carrier, a joints { rule … } that is malformed or ambiguous, or a structural contact joints {} does not cover. One catch-all variant, like BadStock: the message and help carry the specifics, which differ by case far more than they repeat. Message: {message}

Help: {help}

ww::expand::stray_argument#

A bare word where only x=/y=/z= belong: nearly always a second node written on the same line (pos x=1 mirror x=2), which KDL reads as one pos carrying the argument mirror and a repeated x=. Refused rather than silently misplaced. Message: `{node}` takes no bare argument, but `{found}` was written after it

Help: {help}

ww::expand::too_deep#

Limits::max_depth, counted in assemblies: a root, every assembly nested inside it, and every sub-assembly placed with instance=, all the way down. Diagnosed before anything is placed, and before the check itself recurses past the limit. Message: assemblies nest more than {limit} deep

Help: counting nested `assembly` blocks and sub-assemblies placed with `instance=`, a part may sit at most {limit} assemblies deep (docs/KDL_AUTHORING.md §13)

ww::expand::too_many_parts#

Limits::max_parts, counted with every sub-assembly instance multiplied out. Diagnosed from per-assembly counts, before any part is placed. Message: the project places {total} parts; the limit is {limit}

Help: a project may expand to at most {limit} parts, counting every part each `instance=` of a sub-assembly places (docs/KDL_AUTHORING.md §13)

ww::expand::unexpected_node#

Message: `{node}` is not valid here

Help: {expected}

ww::expand::unexpected_property#

Message: `{node}` does not take `{key}`

Help: {expected}

ww::expand::unknown_anchor#

Message: `{name}` is not one of the standard anchors

Help: D6's anchors are top_/bottom_ followed by sw, se, ne, nw, n, s, e, w or center, plus `center` for the body centre

ww::expand::unknown_hardware#

hardware_use <Name> naming no hardware catalogue item (ADR-0017). Message: `{name}` is not a declared hardware item

Help: {help}

ww::expand::unknown_instance#

Message: `{name}` is not a component or a top-level assembly

Help: `instance=` names a `component`, or an `assembly` declared at the top level

ww::expand::unknown_interpolation#

Message: `{name}`, interpolated in `{text}`, names nothing in scope

Help: `{…}`/`<…>` interpolates a name visible where the id is written — usually a `repeat` variable. It is a name, not an expression

ww::expand::unknown_joint#

Message: `{name}` is not a declared joinery

Help: {help}

ww::expand::unknown_mark#

Message: part `{part}` has no mark `{mark}`

Help: {help}

ww::expand::unknown_material#

Message: `{name}` is not a declared material

Help: {help}

ww::expand::unknown_part#

Message: no part `{part}` for `{part}@{mark}`

Help: {help}

Stage joinery#

ww::joinery::not_yet_synthesized#

Reported by the compiler with a message built at run time.

Stage lattice#

ww::lattice::degenerate_grid#

Message: `lattice rows={rows} cols={cols}` needs both at least 1

Help: `rows`/`cols` count compartments (§6.8): at least one of each

ww::lattice::missing_prop#

Message: `lattice` has no `{key}=`

Help: `lattice` needs `rows=`, `cols=`, `bar_th=`, `wall_height=`, `fit_clearance=`, `border_th=`, `inner_width=` and `inner_length=`, all literal numbers

ww::lattice::non_literal_prop#

Message: `lattice`'s `{key}=` must be a literal number, not a CEL expression

Help: the grid's own shape (how many parts/joins exist) is decided before any CEL expression is evaluated (docs/superpowers/plans/2026-10-29-drawer-dividers-698-plan.md): write the resolved number directly

ww::lattice::omit_out_of_range#

Message: `omit {form}` names a grid line outside the lattice

Help: a single-coordinate `omit x= y=` needs `x` in `1..cols-1` and `y` in `1..rows`; a region `omit from_x= from_y= to_x= to_y=` needs its bounds inside `0..cols` and `0..rows`

Stage length#

ww::length::ambiguous#

Reported by the compiler with a message built at run time.

ww::length::bad_fraction#

Reported by the compiler with a message built at run time.

ww::length::bad_number#

Reported by the compiler with a message built at run time.

ww::length::bad_unit#

Reported by the compiler with a message built at run time.

ww::length::empty#

Reported by the compiler with a message built at run time.

ww::length::out_of_range#

Reported by the compiler with a message built at run time.

ww::length::zero_denominator#

Reported by the compiler with a message built at run time.

Reported by the compiler with a message built at run time.

Stage lower#

ww::lower::wasteful_stock#

Reported by the compiler with a message built at run time.

Stage override#

ww::override::conflict#

Reported by the compiler with a message built at run time.

ww::override::derived#

Reported by the compiler with a message built at run time.

ww::override::inverse#

Reported by the compiler with a message built at run time.

ww::override::inverse_unknown#

Reported by the compiler with a message built at run time.

ww::override::length#

Reported by the compiler with a message built at run time.

ww::override::range#

Reported by the compiler with a message built at run time.

ww::override::step#

Reported by the compiler with a message built at run time.

ww::override::type#

Reported by the compiler with a message built at run time.

ww::override::unknown#

Reported by the compiler with a message built at run time.

ww::override::unresolved#

Reported by the compiler with a message built at run time.

Stage plan#

ww::plan::ambiguous_ref#

Message: `{name}` is ambiguous in this plan

Help: {detail}

ww::plan::cladding_of_edge#

Message: `of={name}` names an `edge`, not a `wall`

Help: an `edge` bounds a room without being a wall and has no face to clad

ww::plan::cladding_of_shares_wall#

Message: `of={name}` names a `shares=`'d wall, which has no face of its own

Help: a `shares=`'d wall has no endpoints of its own to build a face from (RFC-0154's own adversarial review, item 5, left open) — clad the wall it shares, or the other room's own side of it, if that has an exterior face

ww::plan::cladding_of_unknown_wall#

Message: `of={name}` names no wall of this room

Help: `cladding`'s `of=` must name one of this room's own `wall` sides

ww::plan::clearance_outside_room#

Reported by the compiler with a message built at run time.

ww::plan::clearance_overlap#

Reported by the compiler with a message built at run time.

ww::plan::clearance_too_close#

Reported by the compiler with a message built at run time.

ww::plan::cover_of_forward_layer#

Message: `of={name}` names a layer declared later (or self) in this room

Help: `cover`/`upstand`'s `of=` must name a layer already declared earlier in the same room (#656 §2.3)

ww::plan::cover_of_wrong_body#

Message: `of={name}` names a `{kind}`-bodied layer, which `cover`/`upstand` cannot derive a footprint from

Help: `cover`/`upstand` derive a footprint from a layer's placed geometry, which only a `path`-bodied layer has (#656 §2.3): `of=` must name a `path` layer, not another `cover`, `upstand` or `roof` layer

ww::plan::direction_on_freestanding_path#

Message: `direction=` on a `path` whose `{node}` leaves the room perimeter

Help: `direction=` has no meaning once a `path` leaves the perimeter — remove it, or address `{node}` with `corner=` instead (final consolidation §1/§6.1)

ww::plan::duplicate_interface#

Message: a second `interface` on this assembly

Help: an assembly may declare at most one `interface`

ww::plan::duplicate_name#

Message: `{name}` is declared more than once in this plan

Help: walls, openings, features, obstacles, runs, places and marks share one namespace per plan

ww::plan::duplicate_plan#

Message: a second `plan`/`site` in one project

Help: at most one `plan`/`site` per project (ADR-0060 Q2); a project needing two unrelated plans is two files

ww::plan::empty_layer#

Message: layer `{layer}` has no `path`

Help: a `layer` needs at least one `path` (or, once Task 5 lands, a `roof`/`cover`/`upstand`)

ww::plan::exclude_forward_instance#

Message: `exclude {name}` names an instance placed in this layer or a later one

Help: `exclude <InstanceId>` may only name an instance placed in an *earlier* layer of the same room (final consolidation §3.2)

ww::plan::expose_unknown#

Message: `expose {name}` names neither a param of `{design}` nor a project param of its file

ww::plan::fill_without_stretch#

Message: `fill` names `{design}`, which has no `stretch` param

Help: a `fill` solves a `stretch` param to close the run; expose and `stretch` one on `{design}`'s interface

ww::plan::footprint_outside#

Message: `{design}`'s built solids ({built}) reach outside its declared footprint ({footprint})

Help: the footprint is an envelope (ADR-0060 §4.6, Q8): enlarge it, or bring the build inside it

ww::plan::forward_layer_ref#

height=/offset=/anchor= naming <Layer>_bottom/_top/_height of a layer declared later (or of itself) in the same room (#653 §6.4, #647/#657 Task 3). Named ww::plan::forward_layer_ref, not ww::eval::*, deliberately: this diagnostic is part of the ww::plan::* family the rest of the layer/path grammar's diagnostics belong to (crates/ww-dsl/src/error.rs), even though the check itself can only run here — it needs Program::references().variables(), which only this crate's cel dependency provides (ww-dsl has none). Message: `{expr}` names a layer declared later in this room

Help: a `height=`/`offset=`/`anchor=` expression may only reference `<Layer>_bottom`/`_top`/`_height` of a layer declared earlier in the same room (#653 §6.4)

ww::plan::forward_path_ref#

Message: `{name}` names a path declared later (or self) in this room

Help: `path_start=`/`path_end=`/`between=` naming `{name}_start`/`{name}_end` need that path declared earlier in the same room (first synthesis §3.1)

ww::plan::layer_overflow#

A sequentially-packed segment (module doc: the independently-packed run exclude splits a path into) sums to more than the path's own available length — a wall or room-perimeter run, for a segment this module fully resolved (module doc's own "stand-in, not final" discipline: a path mixing sequential packing with an unresolved mode such as anchor= never reaches this check at all, because lower_path bails the whole path to None before any segment is measured; this variant only ever sees a segment this module is fully confident in). Message: {segment} packs to {packed_mm:.1}mm, {overshoot_mm:.1}mm past its {available_mm:.1}mm available length

ww::plan::mark_shadows_face#

Message: `mark {name}` shadows a face name

Help: a mark may not be named `front`, `back`, `left`, `right`, `top` or `bottom`: those name faces

ww::plan::missing_roof#

Message: room `{room}` has `layer`s but no `Roof` layer and no `roof_of`

Help: say so explicitly: give this room its own `layer Roof` with a `roof` child (Task 5), or `roof_of room=<RoomName>` naming the room whose roof covers it (final consolidation §3.4) — never an implicit default

ww::plan::missing_wall_thickness#

Message: wall `{wall}` bears room `{room}`'s shed roof but declares no `thickness=`

Help: the roof's bearing/seat math (2026-10-25-roof-truss-lowering-683.md) needs this wall's thickness — add `thickness=<CEL>` to `wall {wall}` (2026-10-25-wall-thickness-683.md §2); only a shed roof's `high_side=` is checked here, a gable roof's bearing walls are not yet determined structurally and so are not enforced by this diagnostic

ww::plan::mount_needs_wall#

Message: `{design}` mounts to a wall but `{place}` has neither a `run` nor an `against`

Help: a wall-mounted design needs a wall to hang from: put it in a `run`, or give it an `against <Wall>`

ww::plan::no_footprint#

Message: `interface` has no `footprint`

Help: a placeable design needs `footprint w= d= h=` (ADR-0060 §4.6)

ww::plan::no_interface#

Message: `{design}` has no `interface`

Help: only a design with an `interface` can be placed (ADR-0060 §4.6)

ww::plan::no_layer_height#

Message: layer `{layer}` has no `height=`

Help: `height=` is required on every `layer` (#653 §3): it is the layer's bottom elevation

ww::plan::not_abuttable#

Message: `{design}` has no `abut` faces, so it cannot sit mid-run

Help: declare `abut left right` (or whichever faces touch a neighbour) on `{design}`'s interface

ww::plan::not_exposed#

Message: `{key}` overrides a param `{design}` does not expose

Help: only params an `interface`'s `expose` lists may be overridden on a `place`

ww::plan::op#

Reported by the compiler with a message built at run time.

ww::plan::opening_off_wall#

Message: `{name}` sits off the end of wall `{wall}`

Help: `at=` plus `width=` must fit between the wall's two ends

ww::plan::packing_prop_outside_path#

Message: `{key}=` on a `place` that is not inside a `path`

Help: `offset_pin=`, `offset=`, `corner=`, `between=` and `anchor=` only mean something on a `place` inside a `path` (#653 §5); a `run` has its own sequential/`fill` packing

ww::plan::path_endpoint_ambiguous#

Message: more than one addressing form on this `{node}`

Help: a `path`'s `start`/`end` takes exactly one of `corner=`, `x=`/`y=`, or `path_start=`/`path_end=` (final consolidation §6.1)

ww::plan::path_endpoint_incomplete_xy#

Message: `{node}` has `{given}=` without its pair

Help: `x=` and `y=` on a `path`'s `start`/`end` must both be given (final consolidation §1/§6.1)

ww::plan::path_endpoint_off_wall#

Message: `{node}` is not on `wall={wall}`

Help: on a `wall=`-scoped `path`, `start`/`end` are interpreted as the two ends of that one wall (final consolidation §4): a `corner=` must be one of that wall's own two ends, and an `x=`/`y=` point must lie on it

ww::plan::path_wall_unknown#

Message: `wall={wall}` names no wall or edge of this room

Help: a `path`'s `wall=` must name one of the room's own `wall`/`edge` sides (final consolidation §4)

ww::plan::plan_in_import#

Message: `{path}` declares a `plan`, which an imported file cannot do

Help: plans are not importable (ADR-0060 Q15); move the `place` of this design into the importing file's own plan

ww::plan::reserved_param#

Message: `expose {name}` collides with the reserved override `{reserved}`

Help: `label`, `finish`, `mirror` and `role` are reserved on `place`; expose a different name

ww::plan::rev#

Reported by the compiler with a message built at run time.

ww::plan::roof_missing_high_side#

Message: `roof kind=shed` has no `high_side=`

Help: `high_side=<WallName>` is required for `kind=shed` (#653 §8): it names the wall the ridge runs along

ww::plan::roof_missing_ridge_axis#

Message: `roof kind=gable` has no `ridge=`

Help: `ridge=along_x|along_y` is required for `kind=gable` (#653 §8)

ww::plan::roof_mixed_with_path#

Message: a `layer` mixes `{a}` with `{b}`

Help: a `layer` uses exactly one mechanism: `path`, `roof`, `cover` or `upstand` — never more than one

ww::plan::roof_pitch_conflict#

Message: `roof` gives both or neither of `pitch=` and `rise_in_12=`

Help: exactly one of `pitch=<deg>` or `rise_in_12=<ratio>` is required

ww::plan::roof_ref_not_shared_room#

Message: `roof_of room={name}` names a room this one does not share a wall with

Help: `roof_of=` may only name a room this one is wall-connected to via `shares=` (final consolidation §3.4)

ww::plan::room_not_closed#

Message: room `{room}` is not a closed polygon

Help: the last `wall`/`edge` must return to `start x= y=`

ww::plan::room_self_intersecting#

Message: room `{room}`'s walls cross themselves

Help: list a room's sides in order round the room, either direction, with no crossing

ww::plan::shares_dimension_mismatch#

Message: `shares` wall `{name}` is a different length than `{room}.{wall}`

Help: without `span=`, a `shares`'d wall must be the same length as the wall it shares

ww::plan::shares_opening_mismatch#

Message: `shared_with`'s restated `{key}=` disagrees with `{room}.{opening}`'s own value

Help: `at=`/`width=` are optional on a `shared_with` opening (derived from the counterpart); restated anyway, they must agree (final consolidation §3.3)

ww::plan::shares_span_out_of_range#

Message: `shares`'s `span` exceeds `{room}.{wall}`'s own length

Help: `span`'s `at=`/`length=` must fit inside the named wall's own length

ww::plan::shares_wall_has_coordinates#

Message: a `shares`'d wall also gives its own `x=`/`y=`/`thickness=`

Help: a `shares`'d wall's position and thickness are both derived from the named wall, never independently stated (final consolidation §3.1; thickness per 2026-10-25-wall-thickness-683.md §3) — remove `x=`/`y=`/`thickness=`, or remove `shares`

ww::plan::span_self_reference#

Message: `between=` names the same anchor twice

Help: `between=<AnchorA> <AnchorB>` needs two distinct anchors

ww::plan::standard_out_of_range#

Message: `standard` value for `{name}` is outside `{min}..{max}`

ww::plan::unknown_design#

Message: `{design}` names no top-level assembly in scope

Help: a `place`/`fill`/`needs design=` names a top-level assembly of this file or an imported one

ww::plan::unknown_ref#

Message: `{name}` names nothing in this plan

Help: {available}

Stage preset#

ww::preset::derived#

Reported by the compiler with a message built at run time.

ww::preset::duplicate#

Message: preset `{name}` is declared more than once in this project

Help: two presets may not share a name; rename one of them

ww::preset::range#

Reported by the compiler with a message built at run time.

ww::preset::step#

Reported by the compiler with a message built at run time.

ww::preset::type#

Reported by the compiler with a message built at run time.

ww::preset::unknown#

Reported by the compiler with a message built at run time.

Settings

Region

A region picks sensible defaults; change any of these separately.

Units

In inches, type lengths the way you say them: 34 1/2, 3/4", 1'-2" or 12.7mm. A length that can't be read is flagged, never rounded to something else.

Paper
Date order
Clock