hex_fit source

← hex_fit · API reference · version 0.1.5

5 file(s), 1166 lines. This is the source the published version ships, and it is loft — the library is written in the same language you call it from.

Public items

A worked example is a call site the author chose as the thing to read first. Call sites are every line naming the item, found mechanically over the source with comments excluded — so an item with no worked example is not an item nobody uses.

ItemDefinedWorked exampleCall sites
Draft struct42—53 54 59 82 93 112 … (11 total)
draft_new fn53—82 144 238 246 249 250 … (16 total)
draft_has_run fn59—187
draft_write fn93HXI-001259 124 125 188
draft_read fn112HXI-003185 191 193 196 199 203 … (14 total)
draft_draw fn149—79 111 114 156 164
draft_interior fn179—210
draft_rebuild_text fn207HXI-00280 120 121 158 168 169
draft_canon fn236HXI-001259
draft_canon_text fn258HXI-00180 129 130 134
FIT_OK const274—285 325 331 105 149 215 … (28 total)
FIT_NO_FORM const275—286 324
FIT_BAD_DIR const276—287 326 239
FIT_BAD_P const277—288 327 242
FIT_NO_VERTEX const278—289 328 247 248
FIT_NOT_LEGAL const279—290 329
FIT_OUTSIDE const280—291 330 248 253 257
draft_fit_reason fn284—76
draft_fits fn323HXI-00477 106 107 239 242 247 … (10 total)
draft_fit_p fn339HXI-004254
FIT_NO_SIDE const48—58 103 316
FIT_BAD_T const49—59 106 306
FIT_BAD_SPAN const50—62 104 314 315
FIT_BAD_SHELL const51—63 150 332
FIT_BAD_HEIGHT const52—66 274 54 56 79 410 … (7 total)
FIT_BAD_MAT const53—73 236 372 373 374
FIT_BAD_SCALE const54—70 272 75 76 77 78 … (7 total)
fit_reason fn57—19 78 79 77 248 249
feature_grid fn88HXI-005101 113 282 283
feature_fits fn100HXI-005305 306 314 315 316
feature_fit_t fn112—127 307 308
feature_fit_residual fn126—309 311
arc_is_shell fn139—149 27
arc_fits fn148—13 14 18 331 332
arc_fit_n fn161HXI-006178 26 334 346
arc_fit_residual fn177—28 335
arc_snap_n fn191HXI-006200 336 342
arc_snap_residual fn200—337
level_fits fn214HXI-00836 37 402 403 404
MAT_MAX const225—53 236 371 372 379 380 … (10 total)
mat_fits fn235HXI-007370 371 372 373 374
HEIGHT_SCALE const250—290 293 296 299 302 65 … (8 total)
height_units_at fn253—273 280 290 67
height_from_units_at fn261—273 280 293
seat_fits_at fn271—296 54 55 56 57 65 … (9 total)
seat_fit_z_at fn278—285 299 60 61 66
seat_fit_residual_at fn285—302 62
height_units fn290—43 67 408
height_from_units fn293—43 409
seat_fits fn296HXI-008305 65 407 410 413
seat_fit_z fn299—66 411 414
seat_fit_residual fn302—412
seat_is_integral fn305—415

src/hex_fit.loft

// Copyright (c) 2026 Jurjen Stellingwerff
// SPDX-License-Identifier: LGPL-3.0-or-later
// hex_fit — the doorstep — refuse at authoring time what would not round-trip.
//
// `fits?` and `snap`. A continuous model parameter must be quantised to what the field
// distinguishes; off that grid a value is silently SNAPPED, not rejected, so the doorstep
// refuses it up front with a named reason, an offer of the nearest fitting alternative, and the
// residual. Also the `Draft` — a form carrying an embedded wall run.
//
// Entry point: re-exports `hexfit`, `hexdraft`.
pub use hexfit::*;
pub use hexdraft::*;

src/hexdraft.loft

// Copyright (c) 2026 Jurjen Stellingwerff
// SPDX-License-Identifier: LGPL-3.0-or-later
// hexdraft — A STENCIL DESCRIPTION THAT CARRIES LINEWORK, AND A ROUND TRIP THAT NOTICES (`OD-13`).
//
// A stencil needs linework in all 24 directions to describe a believable city or castle.  A round
// trip that recovers only the form drops the embedded run, and then reports success on a model
// missing its content.  So a `Draft` is a **form plus an embedded run**: it writes and reads as one
// text, it draws as one field, and it rebuilds from that field **including the run** — so a
// dropped run fails the trip instead of passing it.
//
// THE SLOT DISCIPLINE, unchanged from `X51`/`X58`/`X59`/`X60`: the run is a material on **interior**
// edges (both cells in the footprint), so the footprint is untouched and the form recovery reads a
// slot the run never writes.  The two recoveries read disjoint slots and compose without
// interacting — which is why this is wiring rather than redesign.
//
// ⚠ ONE NEIGHBOUR CONVENTION: `hex_neighbor` with `hex_edge_corners`, never `nb_q`/`nb_r` — the
// two number neighbours differently, and mixing them marks the wrong edge (`SPEC` **L11**).
//
// ⚠ NAME: this is the **description** side — a `Form` plus linework, the thing a canonical text
// spells.  `hex_field::Stencil` is the **field** side (cells, heights, edges, layers, with
// rotate/mirror/stamp).  Both are legitimate and they are exactly `OD-6`'s two halves — *"is a
// stencil a field or a generative description?"*, answered *"the foxel is the stored truth; a
// description is admissible only if it draws into the schema exactly"*.  They must not share a
// name, so this one is `Draft`.
//
// SCOPE: **one** embedded run per stencil.  Several would need the interior edges split into
// connected components first, which is a separate step and is not pretended here.
//
// AND ONE SPELLING PER MODEL: a model must have exactly ONE text or a `diff` stops meaning *the
// model changed*.  The form half gets that from `form_canon`; a run has two spellings that mark the
// identical edges, and `draft_canon` picks by asking the field which one it answers with.
use hex_field::*;
use hex_grid::*;
use hex_form::*;
use hex_recover::*;
use hex_draw::*;
use hex_shape::*;

// A form plus an embedded run, written, read and drawn as one: the form, the run's direction
// (`df_d`, -1 for none), its anchor `(df_a, df_b)` and its periods.  `draft_new`,
// `draft_read` and `draft_canon` make one.
pub struct Draft {
  pub df_form: Form,
  pub df_d:    integer,     // embedded run direction, or -1 for none
  pub df_a:    integer,     // anchor, triangle coordinates
  df_b:    integer,
  pub df_p:    integer,     // periods
}

// A stencil description: the form, plus the linework run it carries (`d` = -1 for none).  The
// run is part of the value rather than something a caller keeps beside it, so a rebuild that
// drops it is caught by the text diff.
pub fn draft_new(f: Form, d: integer, a: integer, b: integer, p: integer) -> Draft {
  Draft { df_form: f, df_d: d, df_a: a, df_b: b, df_p: p }
}

// Does this draft carry a linework run?  Check before reading the run's fields, which are
// only meaningful when it does.
pub fn draft_has_run(s: Draft) -> boolean { s.df_d >= 0 }

fn nth_word(line: text, i: integer) -> text {
  ws = line.split(' ');
  ws[i] ?? ""
}
fn word_int(line: text, i: integer) -> integer { nth_word(line, i) as integer ?? 0 }

// How many space-separated fields the line has.  The layout fixes this per record, so a line
// carrying MORE is a different line — trailing junk and a trailing space both land here.
fn word_count(line: text) -> integer { len(line.split(' ')) }

// Is field `i` an integer SPELLED THE WAY `draft_write` spells one?  Not a character class: the
// parse has to reproduce the original characters, which refuses ``, `x`, `007` and `+1` in one
// test — see `draft_read`.
fn word_is_int(line: text, i: integer) -> boolean {
  w = nth_word(line, i);
  v = w as integer ?? 0;
  "{v}" == w
}

// A refusal, in the one shape this reader has for one: a stencil with an EMPTY form.  Nothing in
// `-> Draft` says the parse can fail, so the caller's check is `form_sides(s.df_form) == 0`.
fn draft_refused() -> Draft { draft_new(form_new(0, [], []), 0 - 1, 0, 0, 0) }

// The text of a stencil: the form's spelling, then — if there is one — a single `wall` line.
// One line, one record, same shape as `side`: the reader refuses anything else rather than
// repairing it (`X39`).
//
// ⚠ THIS IS NOT THE CANONICAL TEXT.  It writes the spelling it is GIVEN, and both the form's
// start corner and the run's direction are choices the model does not fix — so two calls can
// spell one stencil two ways.  A round trip diffs against `draft_canon_text`.
//
// Example: @HXI-001
pub fn draft_write(s: Draft, name: text) -> text {
  base = form_write(s.df_form, name);
  if s.df_d < 0 { return base; }
  base + "\nwall d {s.df_d} a {s.df_a} b {s.df_b} p {s.df_p}"
}

// Parse.  The `side` lines go to `form_read` unchanged; a trailing `wall` line is this layer's.
// A malformed record yields a stencil with an empty form — REFUSED, never repaired.
//
// It refuses exactly what `draft_write` cannot emit: a trailing space, an extra field, `+3`,
// `003`, a field that is not a number at all, or a `wall` line that is not last.  Repairing any
// of those would admit a model nobody wrote — `wall d x …` read as `d 0` is a wall pointing
// somewhere else.
//
// The rule is a RE-SPELLING IDENTITY: a field is an integer only if printing the
// parse reproduces the original characters, a line is a record only if it carries exactly the
// fields the writer emits, and the `wall` line is LAST because that is where the writer puts it.
//
// Example: @HXI-003
pub fn draft_read(t: text) -> Draft {
  lines = t.split('\n');
  nl = len(lines);
  ftext = "";
  d = 0 - 1;
  a = 0;
  b = 0;
  p = 0;
  nwall = 0;
  for i in 0..nl {
    ln = lines[i] ?? "";
    if nth_word(ln, 0) == "wall" {
      nwall = nwall + 1;
      if i != nl - 1 { return draft_refused(); }             // the writer appends it LAST
      if word_count(ln) != 9 { return draft_refused(); }     // `wall d <d> a <a> b <b> p <p>`
      if nth_word(ln, 1) != "d" || nth_word(ln, 3) != "a" || nth_word(ln, 5) != "b"
         || nth_word(ln, 7) != "p" {
        return draft_refused();
      }
      if !word_is_int(ln, 2) || !word_is_int(ln, 4) || !word_is_int(ln, 6)
         || !word_is_int(ln, 8) {
        return draft_refused();                              // integers, spelled as we spell them
      }
      d = word_int(ln, 2);
      a = word_int(ln, 4);
      b = word_int(ln, 6);
      p = word_int(ln, 8);
    } else {
      if i == 0 { ftext = ln; } else { ftext = ftext + "\n" + ln; }
    }
  }
  if nwall > 1 { return draft_refused(); }
  draft_new(form_read(ftext), d, a, b, p)
}

// Draw the whole stencil into one field: the fill, its own boundary walls, and the embedded run as
// material on INTERIOR edges only.  Returns the number of interior edges the run marked.
pub fn draft_draw(s: Draft, cq: integer, cr: integer, cells: HexSet, edges: EdgeSet,
                    wallmat: integer, embedmat: integer) -> integer {
  form_fill(s.df_form, cq, cr, cells);
  draw_walls(cells, edges, wallmat);
  if s.df_d < 0 { return 0; }
  q0 = hexset_q0(cells);
  r0 = hexset_r0(cells);
  gw = hexset_w(cells);
  gh = hexset_h(cells);
  ew = edgeset_new(q0, r0, gw, gh);
  w = wall_from_run(s.df_d, s.df_a, s.df_b, s.df_p, embedmat);
  wall_write(w, ew, q0, r0, gw, gh);
  n = 0;
  for r in r0..r0 + gh {
    for q in q0..q0 + gw {
      for dd in 0..3 {
        (nq, nr) = hex_neighbor(q, r, dd);
        if edge_mat(ew, q, r, nq, nr) != 0
           && hexset_get(cells, q, r) && hexset_get(cells, nq, nr) {
          edge_set_mat(edges, q, r, nq, nr, embedmat);
          n = n + 1;
        }
      }
    }
  }
  n
}

// The INTERIOR edges carrying `embedmat`, isolated — what the run reader consumes.  Boundary edges
// (one cell out) are the stencil's own walls and are never part of a run.
pub fn draft_interior(cells: HexSet, edges: EdgeSet, embedmat: integer) -> EdgeSet {
  q0 = hexset_q0(cells);
  r0 = hexset_r0(cells);
  gw = hexset_w(cells);
  gh = hexset_h(cells);
  ei = edgeset_new(q0, r0, gw, gh);
  for r in r0..r0 + gh {
    for q in q0..q0 + gw {
      for dd in 0..3 {
        (nq, nr) = hex_neighbor(q, r, dd);
        if edge_mat(edges, q, r, nq, nr) == embedmat
           && hexset_get(cells, q, r) && hexset_get(cells, nq, nr) {
          edge_set_mat(ei, q, r, nq, nr, embedmat);
        }
      }
    }
  }
  ei
}

// REBUILD, INCLUDING THE RUN.  The form comes from the cells (constructive recovery, `X45`); the
// run comes from the interior edges (`wall_read_run`, `X60`) — two recoveries reading disjoint
// slots.  An unreadable run is REFUSED, so it is dropped loudly by a text diff rather than silently.
//
// ⚠ DIFF THIS AGAINST `draft_canon_text`, NOT against `draft_write`.  What comes back is the
// spelling the FIELD answers with, and for the run half that is one of two — see the note there.
//
// Example: @HXI-002
pub fn draft_rebuild_text(cells: HexSet, edges: EdgeSet, name: text, embedmat: integer) -> text {
  base = rebuild_construct_text(cells, name);
  if base == "" { return ""; }
  ei = draft_interior(cells, edges, embedmat);
  (d, a, b, p, ok) = wall_read_run(ei, hexset_q0(cells), hexset_r0(cells),
                                   hexset_w(cells), hexset_h(cells));
  if !ok { return base; }
  base + "\nwall d {d} a {a} b {b} p {p}"
}

// ── ONE MODEL, ONE TEXT — the canonical spelling ───────────────────────────
//
// The format's premise is that a `diff` means *the model changed*, which needs every model to
// have exactly ONE text.  The form half has that: a shape has n cyclic spellings and `form_canon`
// picks the smallest, which is why `rebuild_construct_text` and `form_canon_text` agree.
//
// THE RUN HALF HAD NO SUCH RULE, and a run has exactly TWO spellings — `(d, A, p)` and
// `(d + 12, B, p)` — because A-to-B and B-to-A mark the identical edges and the field stores no
// orientation (`wall_read_run`'s own note).  Measured over all 24 directions: the two spellings
// draw fields that differ in ZERO edges, and **exactly one of them survives a text round trip**,
// never both and never neither.  So an author who wrote the wall from the other end got *the
// model changed* out of a byte diff on a model that had not changed at all.
//
// The canonical spelling is therefore READ OFF THE FIELD rather than chosen by a rule — the same
// discipline `hexfit`'s feature grid is built on (`SPEC` **L11**: consult the table that owns the
// answer), and the only definition that cannot drift from what `draft_rebuild_text` will answer,
// since it is that same reader.
//
// Example: @HXI-001
pub fn draft_canon(s: Draft, cells: HexSet) -> Draft {
  cf = form_canon(s.df_form);
  if s.df_d < 0 { return draft_new(cf, 0 - 1, 0, 0, 0); }
  q0 = hexset_q0(cells);
  r0 = hexset_r0(cells);
  gw = hexset_w(cells);
  gh = hexset_h(cells);
  ew = edgeset_new(q0, r0, gw, gh);
  w = wall_from_run(s.df_d, s.df_a, s.df_b, s.df_p, 1);
  if wall_write(w, ew, q0, r0, gw, gh) <= 0 {
    return draft_new(cf, s.df_d, s.df_a, s.df_b, s.df_p);
  }
  (rd, ra, rb, rp, ok) = wall_read_run(ew, q0, r0, gw, gh);
  if !ok { return draft_new(cf, s.df_d, s.df_a, s.df_b, s.df_p); }
  draft_new(cf, rd, ra, rb, rp)
}

// The one text a round trip can be diffed against.  A run that does not FIT is left as written —
// the canon is a spelling rule, not a doorstep, and refusing here would hide which of the two is
// wrong.
//
// Example: @HXI-001
pub fn draft_canon_text(s: Draft, cells: HexSet, name: text) -> text {
  draft_write(draft_canon(s, cells), name)
}

// ── THE DOORSTEP (`fits?`, law C₁ / `K-FIT`) ───────────────────────────────
//
// `X50`/`I-QUANT`: a value off the grid the field distinguishes is **silently snapped, not
// rejected** — so the refusal has to happen at authoring time or the round trip reports success on
// a model nobody wrote.  `K-FIT` also fixes the FORM of a refusal: it **names its restriction** and
// **offers the nearest fitting alternative**; never a silent snap, never a blank no.
//
// An embedded run inherits the line doorstep (§10.10: anchor on a hex VERTEX, a whole number of
// periods, endpoint also a vertex — `wall_run_ok`) and adds one requirement world linework does not
// have: **it must lie wholly INSIDE the footprint**.  A run that pokes out is not an embedded wall
// at all — part of it lands on boundary edges, which belong to the stencil's own outline, and the
// reader would recover something the author did not write.
pub const FIT_OK        = 0;
pub const FIT_NO_FORM   = 1;   // the form itself is not admissible (closed ∧ simple ∧ convex)
pub const FIT_BAD_DIR   = 2;   // the direction is not one of the 24
pub const FIT_BAD_P     = 3;   // a run of zero or negative periods
pub const FIT_NO_VERTEX = 4;   // the anchor is a hex CENTRE, not a vertex
pub const FIT_NOT_LEGAL = 5;   // whole periods, but the endpoint is not a vertex
pub const FIT_OUTSIDE   = 6;   // the run leaves the footprint

// The FIT_ code as a sentence, for showing a person why a draft did not fit.  Keep the
// code for logic and use this only at the edge, so the reason never becomes the test.
pub fn draft_fit_reason(code: integer) -> text {
  if code == FIT_OK { return "ok"; }
  if code == FIT_NO_FORM { return "the form is not admissible (closed, simple, convex)"; }
  if code == FIT_BAD_DIR { return "the direction is not one of the 24"; }
  if code == FIT_BAD_P { return "a run needs at least one period"; }
  if code == FIT_NO_VERTEX { return "the anchor is a hex centre; a run must start on a vertex"; }
  if code == FIT_NOT_LEGAL { return "that many periods does not end on a vertex"; }
  if code == FIT_OUTSIDE { return "the run leaves the footprint; an embedded wall must be interior"; }
  "unknown"
}

// Every marked edge of the run is interior to `cells` — the containment test, in one place so the
// doorstep and the reader cannot disagree about what "inside" means.
fn run_is_inside(cells: HexSet, d: integer, a: integer, b: integer, p: integer) -> boolean {
  q0 = hexset_q0(cells);
  r0 = hexset_r0(cells);
  gw = hexset_w(cells);
  gh = hexset_h(cells);
  ew = edgeset_new(q0, r0, gw, gh);
  w = wall_from_run(d, a, b, p, 1);
  n = wall_write(w, ew, q0, r0, gw, gh);
  if n <= 0 { return false; }
  ins = 0;
  for r in r0..r0 + gh {
    for q in q0..q0 + gw {
      for dd in 0..3 {
        (nq, nr) = hex_neighbor(q, r, dd);
        if edge_mat(ew, q, r, nq, nr) != 0
           && hexset_get(cells, q, r) && hexset_get(cells, nq, nr) { ins = ins + 1; }
      }
    }
  }
  ins == n
}

// THE DOORSTEP.  `cells` is the form's own footprint.  Returns a reason code — `FIT_OK` or the
// specific restriction, never a bare false.
//
// Example: @HXI-004
pub fn draft_fits(s: Draft, cells: HexSet) -> integer {
  if !form_admissible(s.df_form) { return FIT_NO_FORM; }
  if s.df_d < 0 { return FIT_OK; }
  if s.df_d >= 24 { return FIT_BAD_DIR; }
  if s.df_p <= 0 { return FIT_BAD_P; }
  if !tri_is_vertex(s.df_a, s.df_b) { return FIT_NO_VERTEX; }
  if !wall_run_ok(s.df_d, s.df_a, s.df_b, s.df_p) { return FIT_NOT_LEGAL; }
  if !run_is_inside(cells, s.df_d, s.df_a, s.df_b, s.df_p) { return FIT_OUTSIDE; }
  FIT_OK
}

// AND THE ALTERNATIVE THE REFUSAL OWES (`K-FIT`): the longest run from this anchor, in this
// direction, that IS admissible and fits — searching downward so the offer is never longer than
// what was asked for.  0 when nothing fits, which is itself a usable answer: move the anchor.
//
// Example: @HXI-004
pub fn draft_fit_p(s: Draft, cells: HexSet) -> integer {
  if s.df_d < 0 || s.df_d >= 24 { return 0; }
  if !tri_is_vertex(s.df_a, s.df_b) { return 0; }
  want = s.df_p;
  if want < 1 { want = 1; }
  for k in 0..want {
    try = want - k;
    if try >= 1 && wall_run_ok(s.df_d, s.df_a, s.df_b, try)
       && run_is_inside(cells, s.df_d, s.df_a, s.df_b, try) {
      return try;
    }
  }
  0
}

src/hexfit.loft

// Copyright (c) 2026 Jurjen Stellingwerff
// SPDX-License-Identifier: LGPL-3.0-or-later
// hexfit — THE DOORSTEP, for the parameters `draft_fits` does not cover.
//
// `SPEC` **K-FIT**: *"`fits?(m)` and `snap(m)` are ONE chokepoint, consulted by the round-trip gate
// AND by the editor. The limit sits at the doorstep: the editor refuses at authoring time — never a
// warning, never a downstream check. A refusal NAMES its restriction and offers the nearest fitting
// alternative with its residual — never a silent snap, never a blank rejection."*
//
// `hexdraft::draft_fits` implements that for the turtle form and one embedded run.  This module
// covers the rest — features, arcs, levels, material ids and heights — so `I-QUANT` has a doorstep
// everywhere it has a grid.
//
// THE RULE THIS MODULE IS BUILT ON, and it is not the obvious one: **the admissible set is READ OFF
// THE FIELD, never computed from a formula.**  `X48` recorded a feature's grid as the edge centres
// `(2i+1)/2n`.  Measured, that is true for only ONE of the two side families: the sides whose edges
// tile the whole side.  On the other family the edges are INSET — they span exactly `√3/2` of the
// side, uniformly spaced by `(√3/2)/(n−1)` — so `(2i+1)/2n` would refuse every legal position and
// offer illegal ones.  Consulting `side_edges` cannot make that mistake, and it is the same lesson
// as `SPEC` **L11**: consult the table that owns the answer, never keep a private copy of it.
//
// AND WHERE THERE IS NO GRID, THIS MODULE SAYS SO.  A doorstep that refuses more than the field
// distinguishes is worse than none — it makes legal models unauthorable.  Levels and terrain are
// measured to have nothing to refuse, and `level_fits` / `seat_fits` say that in code rather than
// inventing a restriction to look thorough.
// ── Using it ─────────────────────────────────────────────────────────────────
//
// Everything here answers one shape of question: DOES THIS MEASUREMENT LAND ON THE GRID,
// and if not, what is the nearest one that does?  Each quantity has the same three:
//
//   u = height_units(z);          // to the grid's own units
//   z2 = seat_fit_z(z);           // the nearest seating height
//   d = seat_fit_residual(z);     // how far off it was — 0.0 means it already fitted
//
// Ask the residual when you want to WARN rather than move the value: a builder that snaps
// silently loses the author's intent, and one that refuses cannot place anything.
//
// The `*_at` twins take the scale explicitly, for a consumer working at a scale other than
// the default; the short names are those twins at `HEIGHT_SCALE`.

use hex_field::*;
use hex_draw::*;
use hex_shape::*;
use hexdraft::*;
use hex_form::*;

// Continuing `hexdraft`'s codes (0..6), so one `fit_reason` covers the whole doorstep.
pub const FIT_NO_SIDE    = 7;    // the side index is not a side, or carries no edges
pub const FIT_BAD_T      = 8;    // a feature `t` that is not one of that side's edge centres
pub const FIT_BAD_SPAN   = 9;    // a feature covering zero edges, or more than the side has
pub const FIT_BAD_SHELL  = 10;   // an arc radius that is not a realisable shell (3k^2 + m^2)
pub const FIT_BAD_HEIGHT = 11;   // a height off the voxel's integer grid — it would truncate
pub const FIT_BAD_MAT    = 12;   // a material id the slot cannot hold (see MAT_MAX)
pub const FIT_BAD_SCALE  = 13;   // a height quantum that is not positive — there is no grid

// One reason table for the whole doorstep — `hexdraft`'s codes and these.
pub fn fit_reason(code: integer) -> text {
  if code == FIT_NO_SIDE { return "that side has no edges to carry a feature"; }
  if code == FIT_BAD_T {
    return "a feature sits at an edge centre; that t is between two edges and would snap";
  }
  if code == FIT_BAD_SPAN { return "a feature covers at least one edge and at most the side"; }
  if code == FIT_BAD_SHELL {
    return "that radius is not a realisable shell; the disk would be the next shell down";
  }
  if code == FIT_BAD_HEIGHT {
    // ⚠ THE QUANTUM IS THE CALLER'S, so this cannot name a number — see `seat_fits_at`.
    return "the voxel stores height as a whole number of units; that value would truncate";
  }
  if code == FIT_BAD_SCALE {
    return "a height quantum must be positive; there is no grid to test a value against";
  }
  if code == FIT_BAD_MAT {
    return "that material id is outside the wall slot's range and would erase the wall";
  }
  draft_fit_reason(code)
}

// ── FEATURES ────────────────────────────────────────────────────────────────
//
// `X48`: the model stores `(side, t)`; the field stores a material on an EDGE.  So `t` is
// recoverable only where an edge centre already is, and every other `t` snaps silently.

// The admissible positions on a side, in the order the run stores them — which is NOT t order
// (`A5`: index a feature by its exact `t`, never by its position in the `SideRun`).
//
// Example: @HXI-005
pub fn feature_grid(p: Plan, cells: HexSet, side: integer) -> vector<float> {
  out: vector<float> = [];
  if side < 0 || side >= 4 { return out; }
  sr = side_edges(p, cells, side);
  for i in 0..side_run_len(sr) { out += [sr.sr_t[i] ?? 0.0]; }
  out
}

// THE DOORSTEP.  `t` must be exactly an edge centre of this side — no tolerance (`P4`), because in
// regime R1 an epsilon is a defect signal and not a knob.
//
// Example: @HXI-005
pub fn feature_fits(p: Plan, cells: HexSet, side: integer, t: float, nedges: integer) -> integer {
  g = feature_grid(p, cells, side);
  n = len(g);
  if n <= 0 { return FIT_NO_SIDE; }
  if nedges <= 0 || nedges > n { return FIT_BAD_SPAN; }
  for i in 0..n { if (g[i] ?? -1.0) == t { return FIT_OK; } }
  FIT_BAD_T
}

// AND THE ALTERNATIVE THE REFUSAL OWES: the nearest admissible `t`.  This is what an editor calls
// with a raw mouse position — the snap is EXPLICIT and returns a value the author can see, rather
// than happening silently inside `place_opening`.
pub fn feature_fit_t(p: Plan, cells: HexSet, side: integer, t: float) -> float {
  g = feature_grid(p, cells, side);
  n = len(g);
  if n <= 0 { return t; }
  best = g[0] ?? 0.0;
  bestd = abs((g[0] ?? 0.0) - t);
  for i in 1..n {
    d = abs((g[i] ?? 0.0) - t);
    if d < bestd { bestd = d; best = g[i] ?? 0.0; }
  }
  best
}

// The residual the editor must SHOW (`K-FIT`): how far the offer is from what was asked.
pub fn feature_fit_residual(p: Plan, cells: HexSet, side: integer, t: float) -> float {
  abs(feature_fit_t(p, cells, side, t) - t)
}

// ── ARCS ────────────────────────────────────────────────────────────────────
//
// `X49`: an arc's CENTRE is exact but its RADIUS is not — it quantises to SHELLS, the realisable
// values of `3k^2 + m^2`.  Out to 64 those are 0, 12, 36, 48.  A radius between two shells draws
// the same disk as the shell BELOW it, so it round-trips as a different model with rho = 0 — the
// exact `I-QUANT` failure this doorstep exists to prevent.

// Does `n24` land on a shell — one of the realisable values of `3k^2 + m^2` — so an arc of
// that radius round-trips as itself?
pub fn arc_is_shell(n24: integer) -> boolean {
  if n24 < 0 { return false; }
  sh = arc_shells_upto(n24);
  for i in 0..len(sh) { if (sh[i] ?? -1) == n24 { return true; } }
  false
}

// Does this arc land on the grid?  Answers a FIT_ code rather than a boolean, so a caller
// can tell the reader WHY it did not — see `draft_fit_reason`.
pub fn arc_fits(n24: integer) -> integer {
  if arc_is_shell(n24) { return FIT_OK; }
  FIT_BAD_SHELL
}

// The nearest realisable shell — `K-FIT` says *nearest*, so this can offer a LARGER disk than the
// author asked for (N = 11 is offered 12, not 0).  That is deliberate and differs from what the
// unrefused value would have drawn: an off-grid N silently draws the shell BELOW it, so `arc_fill`
// would have given 0.  Offering the nearest and showing the residual is the point — the author sees
// both candidates' cost — `arc_snap_n` is the other one — instead of being quietly rounded down.
// Ties go DOWN, to the smaller shell.
//
// Example: @HXI-006
pub fn arc_fit_n(n24: integer) -> integer {
  if n24 <= 0 { return 0; }
  sh = arc_shells_upto(n24 * 2 + 4);
  best = 0;
  bestd = n24;
  for i in 0..len(sh) {
    v = sh[i] ?? 0;
    d = v - n24;
    if d < 0 { d = 0 - d; }
    if d < bestd { bestd = d; best = v; }
  }
  best
}

// How far the arc is from the nearest fitting one.  0 means it already fits; anything else
// is what a warning would quote.
pub fn arc_fit_residual(n24: integer) -> integer {
  d = arc_fit_n(n24) - n24;
  if d < 0 { return 0 - d; }
  d
}

// THE OTHER CANDIDATE, and the reason the comment above can say *both*.  This is the shell an
// UNREFUSED radius actually draws — the largest realisable one at or below `n24` — so an editor
// can show the author what the silent snap would have cost beside what the offer costs.  The two
// are not close: `N = 35` is offered 36 at a residual of 1 and would have drawn **12**, an error
// of 23 in the same units, because 12 and 36 are neighbouring shells.  Verified against
// `arc_fill` over every radius 0..64 rather than against the formula it shares with `arc_fits`.
//
// Example: @HXI-006
pub fn arc_snap_n(n24: integer) -> integer {
  if n24 <= 0 { return 0; }
  sh = arc_shells_upto(n24);
  best = 0;
  for i in 0..len(sh) { if (sh[i] ?? 0) > best { best = sh[i] ?? 0; } }
  best
}

// How far snapping WOULD move it — signed, so a caller can see which way.
pub fn arc_snap_residual(n24: integer) -> integer { n24 - arc_snap_n(n24) }

// ── LEVELS — MEASURED TO HAVE NOTHING TO REFUSE ─────────────────────────────
//
// A level is the topological SHEET (`X58`), stored as an integer (`ha_cy` / `ck_cy`) and used as a
// FILTER BEFORE THE CUT.  There is no continuous parameter here, so `I-QUANT` has nothing to say:
// nothing exists *between* two levels to be snapped to one of them.  Measured over the full range
// an integer holds — the behaviour at ±10^6 is identical to the behaviour at 0.
//
// This returns `FIT_OK` unconditionally, and that is a RESULT, not an omission.  @HXI-008 keeps it
// honest the only way an always-true predicate can be kept honest: by showing that the SAME
// doorstep refuses the other parameters, so "accepts every level" is not "accepts everything".
//
// Example: @HXI-008
pub fn level_fits(lv: integer) -> integer {
  if lv == lv { return FIT_OK; }
  FIT_OK
}

// ── MATERIAL IDS — the edge slot is one byte ─────────────────────────────────
//
// `hex_field`'s `EdgeSet.eg_mat` is a **`u8`**, and the HXF `EDGE` section is one byte per slot —
// so a wall material of 256 does not merely quantise, it becomes **0, which means NO WALL**:
// `edge_set_mat(e, .., 256)` reads back `0`.  Silent deletion, not a snap, so the doorstep names
// the bound.
pub const MAT_MAX = 255;

// ⚠ NO OFFER, AND THAT IS THE POINT.  `K-FIT` says a refusal offers *the nearest fitting
// alternative* — which presumes an ORDINAL parameter, where "nearest" means "almost what you
// asked for".  A material id is NOMINAL: it is a name, not a magnitude.  The nearest admissible id
// to 256 is 255, and 255 is a *different material* — offering it would be worse than a blank no,
// because it looks like a small correction and is not.  So this refusal names its restriction and
// stops there.  The author must pick a material, not accept a rounding.
//
// Example: @HXI-007
pub fn mat_fits(m: integer) -> integer {
  if m <= 0 || m > MAT_MAX { return FIT_BAD_MAT; }
  FIT_OK
}

// ── TERRAIN — HEIGHTS ON THE VOXEL'S GRID ───────────────────────────────────
//
// A voxel stores height as an **integer** number of units, and the world says how big one unit
// is.  A height off that grid would truncate in storage, so the doorstep refuses it.
//
// `HEIGHT_SCALE` is moros's default unit (0.25 world units per height unit).  It is only a
// default: a world carries its own unit (moros's `VoxelWorld.w_unit` is 0.25, 0.125 or 1.0), and
// testing a height against a grid the world does not have gives the wrong verdict.  So every
// height call has an `_at` form taking the unit; the short names are those forms at
// `HEIGHT_SCALE`.
pub const HEIGHT_SCALE = 0.25;

// The voxel's own value for a height, at a given quantum: what `h_height` would hold.
pub fn height_units_at(z: float, scale: float) -> integer {
  if scale <= 0.0 { return 0; }
  k = z / scale ?? 0.0;
  if k < 0.0 { return (k - 0.5) as integer; }
  (k + 0.5) as integer
}

// Grid units back to a world height at a given scale — the inverse of `height_units_at`.
pub fn height_from_units_at(u: integer, scale: float) -> float { (u as float) * scale }

// THE DOORSTEP, at the caller's quantum.  A height must land exactly on the voxel's grid; off
// it, the store truncates and `X59`'s returned residual would be wrong by the truncation —
// which is the one thing `SPEC` **G5** says must never happen silently.
//
// ⚠ **A NON-POSITIVE QUANTUM IS REFUSED BY NAME RATHER THAN DIVIDED BY.** loft's division by
// zero yields null and keeps running, so an unchecked `z / scale` would discharge to `0.0` and
// this would answer *on the grid* for `z = 0` and *off it* for everything else — a wrong verdict
// dressed as a real one, which is exactly what a doorstep exists not to produce.
pub fn seat_fits_at(z: float, scale: float) -> integer {
  if scale <= 0.0 { return FIT_BAD_SCALE; }
  if height_from_units_at(height_units_at(z, scale), scale) == z { return FIT_OK; }
  FIT_BAD_HEIGHT
}

// The offer, and the residual the editor must show — in world units.
pub fn seat_fit_z_at(z: float, scale: float) -> float {
  if scale <= 0.0 { return z; }
  height_from_units_at(height_units_at(z, scale), scale)
}

// How far a height is from the nearest seating level at a given scale.  Warn on this
// rather than snapping, when the author's exact value matters.
pub fn seat_fit_residual_at(z: float, scale: float) -> float { abs(seat_fit_z_at(z, scale) - z) }

// ── the same five at moros's own quantum, unchanged for every existing caller ─

// A world height in grid units at the default scale.
pub fn height_units(z: float) -> integer { height_units_at(z, HEIGHT_SCALE) }

// Grid units back to a world height at the default scale.
pub fn height_from_units(u: integer) -> float { height_from_units_at(u, HEIGHT_SCALE) }

// Example: @HXI-008
pub fn seat_fits(z: float) -> integer { seat_fits_at(z, HEIGHT_SCALE) }

// The nearest seating height at the default scale.
pub fn seat_fit_z(z: float) -> float { seat_fit_z_at(z, HEIGHT_SCALE) }

// How far off that seating height the value was; 0.0 means it already fitted.
pub fn seat_fit_residual(z: float) -> float { seat_fit_residual_at(z, HEIGHT_SCALE) }

// True when `z` lies on the voxel's grid at `HEIGHT_SCALE`.
pub fn seat_is_integral(z: float) -> boolean { seat_fits(z) == FIT_OK }

tests/01-hex-fit.loft

// Copyright (c) 2026 Jurjen Stellingwerff
// SPDX-License-Identifier: LGPL-3.0-or-later
// hex_fit — the conformance tests: the doorstep refuses at authoring time what would not
// round-trip, with a named reason, an offer, and a residual.
//
// Contract only; the exhaustive measurement is hexbody's `tests/fit.loft`.
use hex_fit::*;
use hex_field::*;


fn main() {
  // a valid arc shell is admitted, an off-shell radius is refused -- the doorstep DISTINGUISHES.
  assert(arc_fits(36) == FIT_OK, "shell 36 is admitted");
  assert(arc_fits(37) != FIT_OK, "off-shell 37 is refused");
}

fn test_a_refusal_names_its_reason() {
  code = arc_fits(37);
  reason = fit_reason(code);
  assert(reason.len() > 0, "a refusal carries a named reason, not a blank no");
}

fn test_an_off_shell_radius_offers_the_nearest_that_fits() {
  // K-FIT: a refusal offers the nearest admissible alternative. For an ORDINAL parameter (a
  // radius) an offer is owed -- unlike a material id, which is nominal (X68).
  n = arc_fit_n(37);
  assert(arc_is_shell(n), "the offered radius is itself a shell, got {n}");
  res = arc_fit_residual(37);
  assert(res >= 0, "and the residual is reported, got {res}");
}

fn test_a_level_has_nothing_to_refuse_and_that_is_the_result() {
  // A level is an integer index -- nothing exists between two levels to snap to -- so the
  // doorstep accepts every level. A doorstep that refused more than the field distinguishes
  // would make legal models unauthorable (X66).
  assert(level_fits(0) == FIT_OK, "level 0 fits");
  assert(level_fits(1000000) == FIT_OK, "and so does level 1e6 -- levels are identical at any n");
}

fn test_the_height_slot_is_an_integer_grid() {
  // moros's h_height is an integer at HEIGHT_SCALE wu (X67). A height off that grid truncates
  // silently, so the doorstep refuses it -- and an on-grid height round-trips.
  u = height_units(height_from_units(3));
  assert(u == 3, "an on-grid height round-trips through the voxel, got {u}");
}

fn test_the_height_quantum_is_the_callers() {
  // ⛔ THE CONSTANT CANNOT SERVE A DOORSTEP. A world carries its own height unit, and a
  // consumer measured this package giving the WRONG VERDICT on 40 of 81 sampled heights at
  // 0.125 and 30 of 81 at 1.0 (moros probe/b7). X66 says a doorstep wrong about the grid is
  // worse than none -- the case it did not cover is testing against a grid the field lacks.
  //
  // A HALF-UNIT AT ONE QUANTUM IS A WHOLE UNIT AT ANOTHER, which is the whole of it.
  assert(seat_fits_at(0.125, 0.25) == FIT_BAD_HEIGHT, "0.125 is half a unit at 0.25");
  assert(seat_fits_at(0.125, 0.125) == FIT_OK, "...and a whole one at 0.125");
  assert(seat_fits_at(0.5, 1.0) == FIT_BAD_HEIGHT, "0.5 is half a unit at 1.0");
  assert(seat_fits_at(2.0, 1.0) == FIT_OK, "...and 2.0 is two whole ones");

  // The offer and the residual follow the quantum they were given.
  assert(seat_fit_z_at(0.3, 0.125) == 0.25, "the offer at 0.125 is 0.25, got {seat_fit_z_at(0.3, 0.125)}");
  assert(seat_fit_z_at(0.3, 1.0) == 0.0, "...and at 1.0 it is 0.0, got {seat_fit_z_at(0.3, 1.0)}");
  assert(abs(seat_fit_residual_at(0.3, 1.0) - 0.3) < 1e-12, "with the residual to match");

  // The default is unchanged for every existing caller -- the wrappers ARE the old behaviour.
  assert(seat_fits(0.3) == seat_fits_at(0.3, HEIGHT_SCALE), "the wrapper is the _at form at 0.25");
  assert(seat_fit_z(0.3) == seat_fit_z_at(0.3, HEIGHT_SCALE), "and so is the offer");
  assert(height_units(0.75) == height_units_at(0.75, HEIGHT_SCALE), "and the unit count");
}

fn test_a_quantum_that_is_not_a_grid_is_refused_by_name() {
  // ⚠ loft's division by zero yields null and keeps running, so an unchecked `z / scale`
  // discharges to 0.0 -- and the doorstep would answer "on the grid" for 0 and "off it" for
  // everything else. A wrong verdict dressed as a real one is what a doorstep exists not to
  // produce, so a non-positive quantum has its own code.
  assert(seat_fits_at(1.0, 0.0) == FIT_BAD_SCALE, "a zero quantum is not a grid");
  assert(seat_fits_at(0.0, 0.0) == FIT_BAD_SCALE, "...and zero height does not excuse it");
  assert(seat_fits_at(1.0, 0.0 - 0.25) == FIT_BAD_SCALE, "nor does a negative one");
  assert(fit_reason(FIT_BAD_SCALE) != "", "and the refusal carries a reason");
  assert(fit_reason(FIT_BAD_SCALE) != fit_reason(FIT_BAD_HEIGHT),
         "...which is not the height reason wearing a different code");
}

tests/02-worked-examples.loft

// Copyright (c) 2026 Jurjen Stellingwerff
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Worked examples for `hex_fit` (@PLN141).  Each `test_*` below is a REAL,
// run-every-CI demonstration of a contract the signature cannot state; the
// function documents itself by CITING the tag with `// Example: @HXI-00N`, and
// `check_doc_drift.sh examples` fails if a citation goes dangling.  These are
// teaching examples, distinct from the conformance suite in `01-hex-fit.loft`.
//
// WHAT THIS PACKAGE IS FOR.  Everything a caller authors here is CONTINUOUS —
// a radius, a position along a wall, a height, a direction — and the field it
// is stored in is not.  An off-grid value is therefore SNAPPED, silently, and
// the round trip then reports success on a model nobody wrote.  `hex_fit` is
// the doorstep that refuses such a value at authoring time, with a NAMED
// reason, an OFFER, and the RESIDUAL to show the author.
//
// Two things follow that a signature cannot carry, and both are worked below:
//
//   a refusal is DATA, not an error   every `fits` map returns an integer code,
//                                     never a bare false and never a raise
//   the grid is READ OFF THE FIELD    never computed from a formula — the field
//                                     owns the answer, and a private copy of it
//                                     has already been wrong once (see @HXI-005)
use hex_fit::*;
use hex_field::*;
use hex_form::*;
use hex_draw::*;
use hex_grid::*;
use hex_shape::*;
use hex_recover::*;

const W  = 41;
const H  = 41;
const Q0 = 0 - 20;
const R0 = 0 - 20;
const WALLMAT = 1;      // the stencil's own outline
const EMBED   = 5;      // the embedded run — a DIFFERENT material, on interior edges only

// The stencil every draft example is written on: a regular hexagon, six sides of six steps.
// It is written the way `form_write` writes one, so it is already its own canonical text.
fn hexagon() -> text {
  "stencil h4 h0 0\nside 0 len 6 turn 2\nside 1 len 6 turn 2\nside 2 len 6 turn 2"
  + "\nside 3 len 6 turn 2\nside 4 len 6 turn 2\nside 5 len 6 turn 2"
}

// A patch of lattice big enough to hold the hexagon well clear of its edges.
fn patch() -> HexSet { hexset_chunk(Q0, R0, W, H) }

// How many edges the two fields disagree about — 0 means they are the same drawing.
fn edge_diff(ea: EdgeSet, eb: EdgeSet) -> integer {
  n = 0;
  for r in R0..R0 + H {
    for q in Q0..Q0 + W {
      for d in 0..3 {
        (nq, nr) = hex_neighbor(q, r, d);
        if edge_mat(ea, q, r, nq, nr) != edge_mat(eb, q, r, nq, nr) { n = n + 1; }
      }
    }
  }
  n
}

// Is `t` one of the admissible positions?  A membership test, because `feature_grid` returns
// them in the order the field stores them and NOT in `t` order.
fn grid_has(g: vector<float>, t: float) -> boolean {
  for i in 0..len(g) { if abs((g[i] ?? -1.0) - t) < 1e-12 { return true; } }
  false
}

// The smallest call that does something real: author a stencil, ask the doorstep, draw it,
// and check the drawing spells the same stencil back.
fn main() {
  f = form_read(hexagon());
  cells = patch();
  form_fill(f, 0, 0, cells);
  s = draft_new(f, 3, 0 - 6, 9, 1);                       // one period of direction 3
  assert(draft_fits(s, cells) == FIT_OK, "the doorstep admits it: {fit_reason(draft_fits(s, cells))}");
  edges = edgeset_new(Q0, R0, W, H);
  draft_draw(s, 0, 0, cells, edges, WALLMAT, EMBED);
  assert(draft_rebuild_text(cells, edges, "h4", EMBED) == draft_canon_text(s, cells, "h4"),
         "what was drawn spells the stencil back");
}

// @HXI-001 — ONE MODEL, ONE TEXT, and a run has two spellings.  The whole format
// exists so that a `diff` means *the model changed*: a project file is diffable
// and an undo history is exact only because one model has exactly one text.
//
// A run breaks that on its own.  A wall from A to B and the same wall from B to A
// mark the IDENTICAL edges — the field stores no orientation — so `draft_write`
// can spell one wall two ways, and only one of the two comes back out of the
// field.  Measured over all 24 directions: the two spellings differ in ZERO
// edges, and exactly one of them survives the round trip, never both.
//
// So the text to diff against is `draft_canon_text`, never `draft_write`.  The
// canonical spelling is READ OFF THE FIELD — it is what the reader answers —
// because any other rule could drift from the reader and this one cannot.
fn test_a_run_has_two_spellings_and_the_field_answers_one() {
  f = form_read(hexagon());
  cells = patch();
  form_fill(f, 0, 0, cells);

  // The same wall, named from each of its two ends.  One period of direction 3
  // from (-6,9) ends at (9,15); direction 15 is direction 3 reversed.
  fwd = draft_new(f, 3, 0 - 6, 9, 1);
  rev = draft_new(f, 15, 9, 15, 1);
  assert(draft_fits(fwd, cells) == FIT_OK, "the forward spelling is a legal wall");
  assert(draft_fits(rev, cells) == FIT_OK, "and so is the reverse — the doorstep admits both");

  c1 = patch();
  e1 = edgeset_new(Q0, R0, W, H);
  n1 = draft_draw(fwd, 0, 0, c1, e1, WALLMAT, EMBED);
  c2 = patch();
  e2 = edgeset_new(Q0, R0, W, H);
  n2 = draft_draw(rev, 0, 0, c2, e2, WALLMAT, EMBED);
  assert(n1 == 8 && n2 == 8, "each marks the same 8 interior edges, got {n1} and {n2}");
  assert(edge_diff(e1, e2) == 0, "and the two fields are the same drawing, edge for edge");

  // The field answers with ONE of the two spellings, and it is the forward one here.
  want = hexagon() + "\nwall d 3 a -6 b 9 p 1";
  assert(draft_rebuild_text(c1, e1, "h4", EMBED) == want, "the field spells the wall this way");
  assert(draft_rebuild_text(c2, e2, "h4", EMBED) == want, "from either authoring — one field, one text");

  // …so the naive round trip FAILS on the reverse spelling, with nothing wrong.
  assert(draft_write(fwd, "h4") == want, "the forward author's own text matches");
  assert(draft_write(rev, "h4") != want,
         "the reverse author's does not — and the model is byte-identical in the field");

  // The canon is what makes the diff mean something again.
  assert(draft_canon_text(fwd, cells, "h4") == want, "canon of the forward spelling");
  assert(draft_canon_text(rev, cells, "h4") == want, "canon of the reverse spelling — the same text");

  // A stencil with no run at all canonicalises to the form alone.
  none = draft_new(f, 0 - 1, 0, 0, 0);
  assert(draft_canon_text(none, cells, "h4") == hexagon(), "no run, no wall line");
}

// @HXI-002 — THE ROUND TRIP HAS TO NOTICE A DROPPED RUN.  A stencil carries its
// linework as material on INTERIOR edges — edges whose two cells are both in the
// footprint — so the footprint and the form recovery read a slot the run never
// writes.  That orthogonality is what makes the run cheap to add, and it is also
// what makes losing it invisible: the cells are all still there, the form still
// recovers, and a trip that compares only the form reports SUCCESS on a model
// missing its content.
//
// `draft_rebuild_text` reads the run back as well, so a dropped run is a text
// difference — loud, and in the same diff as everything else.
fn test_the_round_trip_notices_a_dropped_run() {
  f = form_read(hexagon());
  cells = patch();
  form_fill(f, 0, 0, cells);
  with_run = draft_new(f, 3, 0 - 6, 9, 1);
  want = hexagon() + "\nwall d 3 a -6 b 9 p 1";

  c1 = patch();
  e1 = edgeset_new(Q0, R0, W, H);
  n1 = draft_draw(with_run, 0, 0, c1, e1, WALLMAT, EMBED);
  assert(n1 == 8, "the run marks 8 interior edges, got {n1}");
  assert(draft_rebuild_text(c1, e1, "h4", EMBED) == want, "and the trip returns the whole stencil");

  // The SAME stencil drawn without its run: the footprint is identical, and the text is not.
  no_run = draft_new(f, 0 - 1, 0, 0, 0);
  c2 = patch();
  e2 = edgeset_new(Q0, R0, W, H);
  n2 = draft_draw(no_run, 0, 0, c2, e2, WALLMAT, EMBED);
  assert(n2 == 0, "nothing embedded, got {n2}");
  assert(rebuild_construct_text(c2, "h4") == rebuild_construct_text(c1, "h4"),
         "the FORM recovery cannot tell the two apart — that is the hole");
  assert(draft_rebuild_text(c2, e2, "h4", EMBED) == hexagon(), "the run half can: no wall line");
  assert(draft_rebuild_text(c2, e2, "h4", EMBED) != want, "so dropping the run FAILS the trip");
}

// @HXI-003 — THE READER ACCEPTS EXACTLY WHAT THE WRITER EMITS, and a refusal is
// a stencil with an EMPTY FORM, not an error: nothing in `-> Draft` says the
// parse can fail, so the check is yours to write and it is
// `form_sides(s.df_form) == 0`.
//
// Strictness here is not fussiness.  The text IS the contract, so a text this
// library cannot write is a text it will not read — otherwise a `diff` could be
// defeated by a trailing space.  Every refusal below was ADMITTED and silently
// re-written before this was measured, and one of them was not a spelling at
// all: `wall d x …` parsed as `d 0`, which is not a missing wall but a wall
// pointing SOMEWHERE ELSE, admitted into the model without a word.
fn test_the_reader_takes_exactly_what_the_writer_emits() {
  good = hexagon() + "\nwall d 3 a -6 b 9 p 1";
  g = draft_read(good);
  assert(form_sides(g.df_form) == 6, "the canonical text reads six sides");
  assert(draft_has_run(g) && g.df_d == 3 && g.df_a == 0 - 6 && g.df_p == 1, "and the run it names");
  assert(draft_write(g, "h4") == good, "and it re-writes byte for byte");

  // A trailing space is invisible in an editor and is not the layout.
  assert(form_sides(draft_read(good + " ").df_form) == 0, "a trailing space is refused");
  // So is an extra field, however harmless it looks.
  assert(form_sides(draft_read(good + " note").df_form) == 0, "an extra field is refused");
  // The sharp one: a field that is not a number.  Repaired to 0 it is a wall in
  // direction 0 — a different wall, in a different place, drawn without comment.
  assert(form_sides(draft_read(hexagon() + "\nwall d x a -6 b 9 p 1").df_form) == 0,
         "a non-integer direction is refused, not read as direction 0");
  // A double space is the same defect wearing different clothes: field 2 is empty.
  assert(form_sides(draft_read(hexagon() + "\nwall d  a -6 b 9 p 1").df_form) == 0,
         "an empty direction is refused");
  // One integer, one spelling — `+3` and `003` name the same direction as `3`,
  // and two texts for one model is exactly what the format forbids.
  assert(form_sides(draft_read(hexagon() + "\nwall d +3 a -6 b 9 p 1").df_form) == 0, "`+3` is refused");
  assert(form_sides(draft_read(hexagon() + "\nwall d 003 a -6 b 9 p 1").df_form) == 0, "`003` is refused");
  // The writer appends the wall line LAST, so a wall line between two `side`
  // lines is a line order it cannot emit — and re-writing it would move it.
  middle = "stencil h4 h0 0\nside 0 len 6 turn 2\nside 1 len 6 turn 2\nwall d 3 a -6 b 9 p 1"
           + "\nside 2 len 6 turn 2\nside 3 len 6 turn 2\nside 4 len 6 turn 2\nside 5 len 6 turn 2";
  assert(form_sides(draft_read(middle).df_form) == 0, "a wall line in the middle is refused");
  // The scope is ONE run per stencil, so two records are refused rather than one of them chosen.
  assert(form_sides(draft_read(good + "\nwall d 5 a 0 b 0 p 1").df_form) == 0, "two wall lines are refused");
  assert(form_sides(draft_read(good + "\n").df_form) == 0, "and a trailing newline is refused");

  // …and the good text still reads, which is what makes the eight refusals above
  // a narrowing rather than a wall.
  assert(form_sides(draft_read(good).df_form) == 6, "the writer's own text still reads");
  assert(form_sides(draft_read(hexagon()).df_form) == 6, "a stencil with no run reads too");
}

// @HXI-004 — SPELLING IS THE READER'S JOB; LEGALITY IS THE DOORSTEP'S.  These are
// two different gates and it is worth knowing which one you are asking.
// `draft_read` answers *is this the text we write?* and nothing more: it admits
// `wall d 99 … p -1`, because 99 and -1 are spelled exactly as this library
// spells an integer.  `draft_fits` answers *is this a wall the field can hold?*
// and refuses both, each with its own reason.
//
// And a refusal owes an OFFER: `draft_fit_p` returns the longest run from the
// same anchor in the same direction that does fit, searching DOWNWARD so the
// offer is never longer than what was asked for.  0 is a usable answer too — it
// means move the anchor.
fn test_spelling_is_one_gate_and_legality_is_another() {
  f = form_read(hexagon());
  cells = patch();
  form_fill(f, 0, 0, cells);

  // Spelled correctly, and not a wall the field can hold.
  wide = draft_read(hexagon() + "\nwall d 99 a -6 b 9 p 1");
  assert(form_sides(wide.df_form) == 6 && wide.df_d == 99, "the reader admits direction 99");
  assert(draft_fits(wide, cells) == FIT_BAD_DIR, "the doorstep refuses it");
  back = draft_read(hexagon() + "\nwall d 3 a -6 b 9 p -1");
  assert(form_sides(back.df_form) == 6 && back.df_p == 0 - 1, "the reader admits -1 periods");
  assert(draft_fits(back, cells) == FIT_BAD_P, "the doorstep refuses that too");

  // Each refusal NAMES its restriction, and the names are different — a doorstep
  // whose every no is the same no tells the author nothing.
  centre = draft_new(f, 3, 0, 0, 1);                       // (0,0) is a hex CENTRE
  assert(draft_fits(centre, cells) == FIT_NO_VERTEX, "an anchor on a centre is refused");
  assert(fit_reason(FIT_NO_VERTEX) != fit_reason(FIT_OUTSIDE), "and the reasons are distinct");
  assert(fit_reason(draft_fits(centre, cells)).len() > 0, "a refusal is never a blank no");

  // The offer.  A 9-period run leaves the hexagon; 3 periods is the longest that stays inside.
  long_run = draft_new(f, 3, 0 - 6, 9, 9);
  assert(draft_fits(long_run, cells) == FIT_OUTSIDE, "a run that pokes out is refused");
  offer = draft_fit_p(long_run, cells);
  assert(offer == 3, "the offer is the longest that fits, got {offer}");
  assert(draft_fits(draft_new(f, 3, 0 - 6, 9, offer), cells) == FIT_OK, "and the offer itself fits");
  assert(draft_fits(draft_new(f, 3, 0 - 6, 9, offer + 1), cells) == FIT_OUTSIDE,
         "one period longer does not — so the offer is the boundary, not a guess");
}

// @HXI-005 — THE ADMISSIBLE POSITION IS READ OFF THE FIELD, NEVER COMPUTED.  A
// feature is authored as `(side, t)` with `t` running 0..1 along the side; the
// field stores a material on an EDGE.  So the only `t` that survives is one an
// edge centre already sits at, and the doorstep's whole job is knowing which.
//
// The design note that recorded those centres as `(2i+1)/2n` was measured and is
// true for ONE of the two side families.  A hexagonal lattice gives a rectangle
// two kinds of side: one whose edges tile it, and one whose edges are INSET,
// spanning exactly `sqrt(3)/2` of the side.  A formula fitted to the first
// refuses every legal position on the second — which is why `feature_grid`
// consults `side_edges` and cannot make that mistake.
//
// The cost of the difference is not academic: the middle of the side, `t = 0.5`,
// is the most natural place to put a door, and it is legal on one family and
// refused on the other.
fn test_the_admissible_position_is_read_off_the_field() {
  p = plan_new(0, 0, 5, 4, 0, false);
  cells = patch();
  lb = labels_new(Q0, R0, W, H);
  draw_floor(p, cells, lb, 9);

  g0 = feature_grid(p, cells, 0);            // a -u/+u face: the INSET family
  g1 = feature_grid(p, cells, 1);            // a -v/+v face: the TILING family
  assert(len(g0) == 9, "side 0 carries 9 edges, got {len(g0)}");
  assert(len(g1) == 10, "side 1 carries 10, got {len(g1)}");

  // The tiling family IS the formula: every `(2i+1)/2n` is a position on it.
  for i in 0..len(g1) {
    t = ((2.0 * (i as float) + 1.0) / (2.0 * (len(g1) as float))) ?? 0.0;
    assert(grid_has(g1, t), "side 1 carries the formula position {t}");
  }
  // The inset family is not, and the number that says so is its SPAN.
  lo = 2.0;
  hi = 0.0 - 1.0;
  for i in 0..len(g0) {
    v = g0[i] ?? 0.0;
    if v < lo { lo = v; }
    if v > hi { hi = v; }
  }
  assert(abs((hi - lo) - 0.8660254037844386) < 1e-12,
         "the inset family spans exactly sqrt(3)/2 of its side, got {hi - lo}");
  assert(!grid_has(g0, (1.0 / 18.0) ?? 0.0), "so the formula's first position is not on it");

  // The middle of the side: legal on the odd-count family, refused on the even one.
  assert(feature_fits(p, cells, 0, 0.5, 1) == FIT_OK, "a door in the middle of side 0 fits");
  assert(feature_fits(p, cells, 1, 0.5, 1) == FIT_BAD_T, "the same door on side 1 does not");
  assert(abs(feature_fit_t(p, cells, 1, 0.5) - 0.45) < 1e-12,
         "and the offer is the nearest edge centre, got {feature_fit_t(p, cells, 1, 0.5)}");
  assert(abs(feature_fit_residual(p, cells, 1, 0.5) - 0.05) < 1e-12,
         "with the residual the author has to be shown");
  assert(feature_fit_residual(p, cells, 0, 0.5) == 0.0, "on side 0 there is nothing to move");

  // A span, and a side that is not a side, are refused by NAME rather than by false.
  assert(feature_fits(p, cells, 0, 0.5, 0) == FIT_BAD_SPAN, "a feature covering no edge");
  assert(feature_fits(p, cells, 0, 0.5, 99) == FIT_BAD_SPAN, "or more than the side has");
  assert(feature_fits(p, cells, 9, 0.5, 1) == FIT_NO_SIDE, "side 9 is not a side");
}

// @HXI-006 — AN OFF-GRID RADIUS IS REFUSED, AND THE TWO CANDIDATES COST DIFFERENT
// AMOUNTS.  An arc's CENTRE is exact and its RADIUS is not: only the shells
// `3k^2 + m^2` exist, which out to 64 are 0, 12, 36 and 48.  Ask for anything
// else and `arc_fill` draws the shell BELOW it, so the model round-trips as a
// different model with a residual of zero — the silent snap this doorstep is for.
//
// The refusal offers the NEAREST shell, which can be LARGER than what was asked
// for, and that is deliberate: it is a different candidate from the one an
// unrefused call would have drawn, and the author should see both prices.
// `N = 35` is the case that makes it concrete — the offer is one unit away and
// the silent snap is twenty-three, because 12 and 36 are neighbouring shells.
fn test_an_off_shell_radius_shows_both_candidates() {
  assert(arc_fits(36) == FIT_OK, "36 is a shell");
  assert(arc_fits(35) == FIT_BAD_SHELL, "35 is not");

  assert(arc_fit_n(35) == 36, "the offer is the nearest shell, got {arc_fit_n(35)}");
  assert(arc_fit_residual(35) == 1, "one unit away");
  assert(arc_snap_n(35) == 12, "what an unrefused 35 draws, got {arc_snap_n(35)}");
  assert(arc_snap_residual(35) == 23, "twenty-three units away — the price nobody quotes");

  // …and that is measured against the drawing, not against the shell formula.
  disk = patch();
  arc_fill(0, 0, 35, disk);
  assert(arc_shell_max(disk, 0, 0) == arc_snap_n(35), "the field agrees with arc_snap_n");
  assert(arc_shell_max(disk, 0, 0) != 35, "and the 35 is stored nowhere");

  // Ties go DOWN, so an offer is never a promotion the author did not ask for.
  assert(arc_fit_n(24) == 12, "24 is equidistant from 12 and 36; the offer is 12");
  sh = arc_shells_upto(64);
  assert(len(sh) == 4, "four shells exist out to 64, got {len(sh)}");
  assert((sh[0] ?? -1) == 0 && (sh[1] ?? -1) == 12 && (sh[2] ?? -1) == 36 && (sh[3] ?? -1) == 48,
         "and they are 0, 12, 36, 48");
}

// @HXI-007 — A MATERIAL ID IS NOMINAL, SO ITS REFUSAL OFFERS NOTHING.  Every other
// refusal in this package offers the nearest fitting alternative, because every
// other parameter is ORDINAL — "nearest" means "almost what you asked for".  A
// material id is a NAME.  The nearest admissible id to 256 is 255, and 255 is a
// different material: offering it would look like a small correction and would
// not be one.  So this refusal names its restriction and stops there.
//
// What it is protecting you from is not a rounding either.  The wall slot is one
// byte, and the store's narrowing cast is CHECKED: a value it cannot hold does not
// truncate to its low byte.  It used to become 0 — and 0 means NO WALL, so an
// out-of-range id DELETED the wall it was setting, before storage was involved at
// all.  `hex_field` 0.1.1 refuses that write instead (@PLN141 row 10), so the slot
// now keeps what it held and `edgeset_refused` counts the attempt.  The doorstep
// below is not thereby redundant: it names the restriction where the author can
// still act on it, and it refuses 0, which the SLOT accepts as the absence of a
// wall rather than as a material.
fn test_a_material_id_is_a_name_not_a_magnitude() {
  assert(mat_fits(1) == FIT_OK, "1 is a material");
  assert(mat_fits(MAT_MAX) == FIT_OK, "and so is the largest the slot holds");
  assert(mat_fits(MAT_MAX + 1) == FIT_BAD_MAT, "one more is refused");
  assert(mat_fits(0) == FIT_BAD_MAT, "0 is not a material — it is the absence of one");
  assert(mat_fits(0 - 1) == FIT_BAD_MAT, "nor is a negative id");

  // The measurement behind the refusal, on a real edge.
  eg = edgeset_new(Q0, R0, W, H);
  (nq, nr) = hex_neighbor(0, 0, 0);
  edge_set_mat(eg, 0, 0, nq, nr, MAT_MAX);
  assert(edge_mat(eg, 0, 0, nq, nr) == MAT_MAX, "255 is stored as 255");
  edge_set_mat(eg, 0, 0, nq, nr, MAT_MAX + 1);
  assert(edge_mat(eg, 0, 0, nq, nr) == MAT_MAX,
         "256 is refused: the wall it would once have erased still reads 255");
  edge_set_mat(eg, 0, 0, nq, nr, MAT_MAX + 2);
  assert(edge_mat(eg, 0, 0, nq, nr) == MAT_MAX, "and 257 likewise — no low-byte truncation");
  assert(edgeset_refused(eg) == 2, "and both refusals are counted rather than silent");
}

// @HXI-008 — A DOORSTEP WITH NOTHING TO REFUSE SAYS SO, and that is a result
// rather than an omission.  A level is the topological SHEET a plan sits on,
// stored as an integer and used as a filter before the cut.  Nothing exists
// BETWEEN two levels, so there is nothing to snap and nothing to refuse: a
// doorstep that invented a restriction here would make legal models unauthorable,
// which is worse than having none.
//
// An always-true predicate can only be kept honest one way — by showing the SAME
// doorstep refusing something — so a height is measured beside it.  A height DOES
// have a grid, an invisible one: the voxel stores it as a whole number of
// quarter-units, so 0.3 is not a height, it is 0.25 with the difference thrown
// away where nobody would look for it.
fn test_a_level_has_nothing_to_refuse_and_a_height_does() {
  assert(level_fits(0) == FIT_OK, "level 0 fits");
  assert(level_fits(1000000) == FIT_OK, "so does level 1e6");
  assert(level_fits(0 - 1000000) == FIT_OK, "and so does level -1e6 — every level, at any n");

  // The same doorstep, on the parameter that does have a grid.
  assert(seat_fits(0.75) == FIT_OK, "0.75 is three whole units");
  assert(height_units(0.75) == 3, "which is what the voxel stores");
  assert(height_from_units(3) == 0.75, "and it reads back exactly");
  assert(seat_fits(0.3) == FIT_BAD_HEIGHT, "0.3 is not on the grid");
  assert(seat_fit_z(0.3) == 0.25, "the offer is the height the voxel would have kept");
  assert(abs(seat_fit_residual(0.3) - 0.05) < 1e-12, "and the residual is what it would have thrown away");
  assert(seat_fits(0.0 - 0.3) == FIT_BAD_HEIGHT, "below the datum is the same story");
  assert(seat_fit_z(0.0 - 0.3) == 0.0 - 0.25, "with the offer rounded the same way");
  assert(seat_is_integral(1.0) && !seat_is_integral(1.1), "the predicate form of the same test");
}