diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 485ead1c3..9992ad9c6 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -31,7 +31,7 @@ jobs: with: fetch-depth: 0 # A Markdown file counts as prose unless a suite reads it: the kernel - # and bun suites read spec/ and the guide under packages/, and a dune + # and bun suites read docs/reference/ and the guide under packages/, and a dune # file can name a decision as a test dependency. - name: Decide whether the pull request changes more than prose id: files @@ -39,11 +39,11 @@ jobs: BASE: ${{ github.event.pull_request.base.sha }} HEAD: ${{ github.event.pull_request.head.sha }} run: | - read_by_suites=$(grep -rhoE 'decisions/[^ )]+\.md' --include=dune packages | sort -u) + read_by_suites=$(grep -rhoE 'docs/decision/[^ )]+\.md' --include=dune packages | sort -u) code=false while read -r f; do case "$f" in - spec/* | packages/*) code=true ;; + docs/reference/* | packages/*) code=true ;; *.md) if grep -qxF "$f" <<<"$read_by_suites"; then code=true; fi ;; *) code=true ;; esac diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 969e8e8f1..24a70dd47 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -15,7 +15,7 @@ on: - 'packages/core/tests/**' # The reference documents are symlinked into the site, and their figures # are generated from them by scripts/build-api-docs.sh. - - 'spec/**' + - 'docs/reference/**' # check-all compares the README drawings with the programs they show. - 'examples/**' - 'scripts/**' diff --git a/.vale/styles/config/vocabularies/Beloch/accept.txt b/.vale/styles/config/vocabularies/Beloch/accept.txt index 50d95c2d5..57960546f 100644 --- a/.vale/styles/config/vocabularies/Beloch/accept.txt +++ b/.vale/styles/config/vocabularies/Beloch/accept.txt @@ -518,3 +518,4 @@ XOR'd Zakharevich zarith Zenodo +Spalier diff --git a/CLAUDE.md b/CLAUDE.md index 19ed2b9ef..b326d7a8d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,9 +2,9 @@ Beloch writes origami folding sequences as programs over the Huzita-Justin axioms. It evaluates `.bel` source into one FOLD file with the folded state after -every step; crease patterns and YR-style folding diagrams are renderings of it. Architecture decisions live in `decisions/` (ADRs); read those -before proposing anything structural. Design journal in `notes/`, dead ends in -`notes/antipatterns.md`. The contracts live in `spec/`: `MODEL.md` what a +every step; crease patterns and YR-style folding diagrams are renderings of it. Architecture decisions live in `docs/decision/` (ADRs); read those +before proposing anything structural. Design journal in `docs/notes/`, dead ends in +`docs/notes/antipatterns.md`. The contracts live in `docs/reference/`: `MODEL.md` what a program means, `BELOCH.md` the language, `FOLD.md` the output. Beside them, binding no other implementation: `KERNEL.md` what `packages/core` realizes, `CLI.md` the `beloch` command. `SPECIFICATION.md` is being dissolved into @@ -17,8 +17,8 @@ Per-slice design documents are not kept in the working tree. They were point-in-time records of how one slice was built, they went stale as the code moved on, and code comments pointing into them taught readers things that had stopped being true. What a slice decided belongs in an ADR, what it contracts -in `spec/`, and what it is worth remembering about a dead end in -`notes/antipatterns.md`. The documents themselves stay in the Git history; +in `docs/reference/`, and what it is worth remembering about a dead end in +`docs/notes/antipatterns.md`. The documents themselves stay in the Git history; `git log --diff-filter=D --stat -- docs/superpowers/specs` finds them. A skill that writes a spec or a plan to `docs/superpowers/` writes it to the @@ -77,7 +77,7 @@ for `dune build`. CI runs `check` on every pull request, in the job `build-and-test` of `.github/workflows/build-and-test.yml`, and skips it when the pull request changes only Markdown that no suite reads. A push to `main` that touches the -site, the kernel, `spec/`, `examples/`, `scripts/` or the flake runs +site, the kernel, `docs/reference/`, `examples/`, `scripts/` or the flake runs `check-all` in the deploy job, which deploys the site when it passes; any other push to `main` runs only the commit subject check. @@ -143,7 +143,7 @@ list of what needs Toph's decision or action, or say that nothing does. ## Math notation -In `notes/`, `docs/` and memos, formulas are LaTeX math (`$...$` inline, +In `docs/` and memos, formulas are LaTeX math (`$...$` inline, `$$...$$` display); GitHub, Forgejo and the VS Code preview render KaTeX. Symbol names (`AL8`), code identifiers and paths go in backticks, never bare. Chat gets words instead of LaTeX, since the terminal does not render it. diff --git a/README.md b/README.md index 20e2ea0c9..4e351ff2e 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Five verbs write to the paper. `mark` scores a crease and moves nothing, `flip` turns the paper over, and `flatten` folds a vertex flat along several rays at once; given an odd number of them, it derives the one ray that is missing. The evaluator works out where every layer goes and which creases end -up mountain or valley. The full grammar is in [`spec/BELOCH-GRAMMAR.md`](spec/BELOCH-GRAMMAR.md) +up mountain or valley. The full grammar is in [`docs/reference/BELOCH-GRAMMAR.md`](docs/reference/BELOCH-GRAMMAR.md) and on the [grammar page](https://belochlang.org/language/grammar/). ## Related work @@ -118,7 +118,7 @@ is one. Both rest on the language: a program is a finite sequence of constructions and folds, with no loops, no recursion (a `def` sees only earlier `def`s) and no host language -([decision 0009](decisions/0009-relationship-to-rabbit-ear.md)). Every program +([decision 0009](docs/decision/0009-relationship-to-rabbit-ear.md)). Every program terminates, its statements are its folding sequence, and every crease in the FOLD output names the statement and the construction that made it. @@ -130,12 +130,12 @@ FOLD output names the statement and the construction that made it. state, and the test suite checks assertions on them. Programs for the jumping frog, the flapping bird and the traditional frog are drafts; each stops at a step the kernel cannot fold yet. -- **Formalized:** [`spec/MODEL.md`](spec/MODEL.md) defines folded states and +- **Formalized:** [`docs/reference/MODEL.md`](docs/reference/MODEL.md) defines folded states and the operations on them. Its first sections are reviewed; the section on operations is a draft, and two of its lemmas, among them that a fold introduces no crossing, have pending proofs. - **Not yet:** Yoshizawa-Randlett folding diagrams, 3D states - ([decision 0015](decisions/0015-flat-folded-states-only.md)), and + ([decision 0015](docs/decision/0015-flat-folded-states-only.md)), and measurements on programs longer than a few dozen statements. ## Running it diff --git a/decisions/0001-ocaml-core-typescript-edge.md b/docs/decision/0001-ocaml-core-typescript-edge.md similarity index 100% rename from decisions/0001-ocaml-core-typescript-edge.md rename to docs/decision/0001-ocaml-core-typescript-edge.md diff --git a/decisions/0003-restart-from-minimal-core.md b/docs/decision/0003-restart-from-minimal-core.md similarity index 100% rename from decisions/0003-restart-from-minimal-core.md rename to docs/decision/0003-restart-from-minimal-core.md diff --git a/decisions/0004-menhir-then-treesitter.md b/docs/decision/0004-menhir-then-treesitter.md similarity index 100% rename from decisions/0004-menhir-then-treesitter.md rename to docs/decision/0004-menhir-then-treesitter.md diff --git a/decisions/0005-name-beloch.md b/docs/decision/0005-name-beloch.md similarity index 97% rename from decisions/0005-name-beloch.md rename to docs/decision/0005-name-beloch.md index f16e24cf4..bf6fed19b 100644 --- a/decisions/0005-name-beloch.md +++ b/docs/decision/0005-name-beloch.md @@ -22,7 +22,7 @@ Name the language **Beloch**, after **Margherita Piazzolla Beloch**. - Her 1936 work showed origami constructions solve general cubic equations, making paper-folding more powerful than straightedge-and-compass. - The **Beloch fold is axiom 7** in the Huzita-Justin numbering this project - uses (see "Numbering" in `spec/SPECIFICATION.md`). Justin ordered the seven + uses (see "Numbering" in `docs/reference/SPECIFICATION.md`). Justin ordered the seven axioms by algebraic power, so the Beloch fold is the last and strongest one: the single hardest thing in the language to handle, with up to three solutions, no closed form, and the disambiguation problem the design keeps diff --git a/decisions/0006-permissive-license-mit.md b/docs/decision/0006-permissive-license-mit.md similarity index 100% rename from decisions/0006-permissive-license-mit.md rename to docs/decision/0006-permissive-license-mit.md diff --git a/decisions/0007-evaluator-not-compiler.md b/docs/decision/0007-evaluator-not-compiler.md similarity index 100% rename from decisions/0007-evaluator-not-compiler.md rename to docs/decision/0007-evaluator-not-compiler.md diff --git a/decisions/0008-exact-rational-arithmetic.md b/docs/decision/0008-exact-rational-arithmetic.md similarity index 100% rename from decisions/0008-exact-rational-arithmetic.md rename to docs/decision/0008-exact-rational-arithmetic.md diff --git a/decisions/0009-relationship-to-rabbit-ear.md b/docs/decision/0009-relationship-to-rabbit-ear.md similarity index 100% rename from decisions/0009-relationship-to-rabbit-ear.md rename to docs/decision/0009-relationship-to-rabbit-ear.md diff --git a/decisions/0011-action-model.md b/docs/decision/0011-action-model.md similarity index 100% rename from decisions/0011-action-model.md rename to docs/decision/0011-action-model.md diff --git a/decisions/0012-real-algebraic-number-kernel.md b/docs/decision/0012-real-algebraic-number-kernel.md similarity index 100% rename from decisions/0012-real-algebraic-number-kernel.md rename to docs/decision/0012-real-algebraic-number-kernel.md diff --git a/decisions/0013-flint-qqbar-backend.md b/docs/decision/0013-flint-qqbar-backend.md similarity index 95% rename from decisions/0013-flint-qqbar-backend.md rename to docs/decision/0013-flint-qqbar-backend.md index 3e16b2bfa..942baa6ec 100644 --- a/decisions/0013-flint-qqbar-backend.md +++ b/docs/decision/0013-flint-qqbar-backend.md @@ -14,7 +14,7 @@ the `Mpoly` elimination pipeline of 0012 remain) ADR 0012's `Alg` (squarefree polynomial + isolating interval, resultant arithmetic) was correct but had two walls, measured in -`notes/2026-07-03-flint-kernel-spike.md`: cross-field chains grow degree +`docs/notes/2026-07-03-flint-kernel-spike.md`: cross-field chains grow degree multiplicatively without normalization (comparing (∛2+√2)² against ∛2+√2: >120 s), and composite extensions of degree ≥ 4 were not representable without a polynomial factorizer. Building the D5-style fix ourselves @@ -64,4 +64,4 @@ wired through the flake. libraries (nix development shell / flake). `to_float` gains a sibling (`Qqbar.to_float`), still output-only. - #33's stacked-cubic ceiling question is re-answered by benchmark - (`notes/2026-07-03-flint-kernel-spike.md` + the #33 verdict note). + (`docs/notes/2026-07-03-flint-kernel-spike.md` + the #33 verdict note). diff --git a/decisions/0014-crease-is-a-bundle-of-segments.md b/docs/decision/0014-crease-is-a-bundle-of-segments.md similarity index 95% rename from decisions/0014-crease-is-a-bundle-of-segments.md rename to docs/decision/0014-crease-is-a-bundle-of-segments.md index 010ea8573..34bc3f56e 100644 --- a/decisions/0014-crease-is-a-bundle-of-segments.md +++ b/docs/decision/0014-crease-is-a-bundle-of-segments.md @@ -51,8 +51,8 @@ not the line, is the durable referent of a crease name. The surface mechanisms (`at`, `pinch`) and their exact syntax are a specification/slice concern, not this decision; the durable decision is the bundle model itself. Full design: -`notes/2026-07-03-crease-segment-at-operator.md` and -`notes/2026-07-03-crease-layer-selection.md`. +`docs/notes/2026-07-03-crease-segment-at-operator.md` and +`docs/notes/2026-07-03-crease-layer-selection.md`. ## Alternatives considered - **Keep "crease = line", add a separate segment type.** Rejected: it denies what @@ -82,5 +82,5 @@ bundle model itself. Full design: - Implementation is mostly additive: `fold_state` edges already carry `crease_id` + endpoints, so `at` is a query over the existing subdivision; `pinch` is a narrowed `subdivide` plus a display flag on the edge. -- The spec (`spec/SPECIFICATION.md`) is extended only when the implementing slice +- The spec (`docs/reference/SPECIFICATION.md`) is extended only when the implementing slice lands; until then this feature sits in Appendix B. diff --git a/decisions/0015-flat-folded-states-only.md b/docs/decision/0015-flat-folded-states-only.md similarity index 97% rename from decisions/0015-flat-folded-states-only.md rename to docs/decision/0015-flat-folded-states-only.md index f1ea4fea4..bcbc86361 100644 --- a/decisions/0015-flat-folded-states-only.md +++ b/docs/decision/0015-flat-folded-states-only.md @@ -31,7 +31,7 @@ is stacking order (`faceOrders`). This is the **all-layers simple-fold** model, most restricted class in Demaine and O'Rourke's simple-fold taxonomy (one-layer / all-layers / some-layers) [demaine2007, §14.1.1]. -Nothing in `decisions/` recorded this scope, and the design doc's "already carried" +Nothing in `docs/decision/` recorded this scope, and the design doc's "already carried" phrasing invited building on a 3D guarantee that does not exist. ## Decision diff --git a/decisions/0016-typed-operands-bundle-values-singleton-slots.md b/docs/decision/0016-typed-operands-bundle-values-singleton-slots.md similarity index 98% rename from decisions/0016-typed-operands-bundle-values-singleton-slots.md rename to docs/decision/0016-typed-operands-bundle-values-singleton-slots.md index 84e1876b5..8f9bae884 100644 --- a/decisions/0016-typed-operands-bundle-values-singleton-slots.md +++ b/docs/decision/0016-typed-operands-bundle-values-singleton-slots.md @@ -79,5 +79,5 @@ One operand model for the whole language: ## References - ADR 0011 (action model), ADR 0014 (crease = bundle of segments) -- `notes/2026-07-03-crease-layer-selection.md` (pinch/at convergence) +- `docs/notes/2026-07-03-crease-layer-selection.md` (pinch/at convergence) - [demaine2007, §14] for the simple-fold models motivating fold scope diff --git a/decisions/0017-flap-is-coplanar-not-precrease-partition.md b/docs/decision/0017-flap-is-coplanar-not-precrease-partition.md similarity index 99% rename from decisions/0017-flap-is-coplanar-not-precrease-partition.md rename to docs/decision/0017-flap-is-coplanar-not-precrease-partition.md index e6a685741..bc4775330 100644 --- a/decisions/0017-flap-is-coplanar-not-precrease-partition.md +++ b/docs/decision/0017-flap-is-coplanar-not-precrease-partition.md @@ -260,7 +260,7 @@ already face-granular and unchanged. - ADR 0014 (a crease is a bundle of segments: why faces stay fine-grained) - ADR 0016 (typed operands: the flap operand type this ADR redefines) -- `spec/SPECIFICATION.md` §4.6 (`@` / `@fold` / `moving` / `up to`), §4.8 (`at`) +- `docs/reference/SPECIFICATION.md` §4.6 (`@` / `@fold` / `moving` / `up to`), §4.8 (`at`) - `packages/core/tests/cases/bases/rabbit-ear.bel` (the repro for both findings) - `lib/fold_state.ml` (`flap_of_points` :352, `select_scope` :385, `type assign`, `subdivide`); `lib/eval.ml` (`resolve_flap_face`, diff --git a/decisions/0018-core-module-boundaries.md b/docs/decision/0018-core-module-boundaries.md similarity index 100% rename from decisions/0018-core-module-boundaries.md rename to docs/decision/0018-core-module-boundaries.md diff --git a/decisions/0019-attribution-carried-by-construction.md b/docs/decision/0019-attribution-carried-by-construction.md similarity index 100% rename from decisions/0019-attribution-carried-by-construction.md rename to docs/decision/0019-attribution-carried-by-construction.md diff --git a/decisions/0020-multifold-research-package.md b/docs/decision/0020-multifold-research-package.md similarity index 100% rename from decisions/0020-multifold-research-package.md rename to docs/decision/0020-multifold-research-package.md diff --git a/decisions/0023-the-mark-is-a-beloch-program.md b/docs/decision/0023-the-mark-is-a-beloch-program.md similarity index 100% rename from decisions/0023-the-mark-is-a-beloch-program.md rename to docs/decision/0023-the-mark-is-a-beloch-program.md diff --git a/decisions/0024-the-web-client-holds-its-state-in-a-composable-runtime.md b/docs/decision/0024-the-web-client-holds-its-state-in-a-composable-runtime.md similarity index 100% rename from decisions/0024-the-web-client-holds-its-state-in-a-composable-runtime.md rename to docs/decision/0024-the-web-client-holds-its-state-in-a-composable-runtime.md diff --git a/decisions/0025-construction-candidate-selection-material-stand-alone.md b/docs/decision/0025-construction-candidate-selection-material-stand-alone.md similarity index 95% rename from decisions/0025-construction-candidate-selection-material-stand-alone.md rename to docs/decision/0025-construction-candidate-selection-material-stand-alone.md index c3bc495bd..602f05692 100644 --- a/decisions/0025-construction-candidate-selection-material-stand-alone.md +++ b/docs/decision/0025-construction-candidate-selection-material-stand-alone.md @@ -9,7 +9,7 @@ status: accepted ## Context -`spec/MODEL.md` defines four things inside the body of one definition. Read +`docs/reference/MODEL.md` defines four things inside the body of one definition. Read `def-motion`: an *alignment* is an incidence on the table between two objects, one of them reflected across the line sought; a *construction* is a finite set of alignments that determines the line, with finitely many solutions and no @@ -69,7 +69,7 @@ refinements of one state yields two states with a common refinement. That statement is recorded as an open question beside the definition. `motion` keeps its meaning and is not reused. The word is already load-bearing -twice in `spec/MODEL.md`, both times for movement the model does not model: +twice in `docs/reference/MODEL.md`, both times for movement the model does not model: "the model checks the end state and never the motion", and "immaterial for the state up to a motion of the table". A third meaning would have made the first of those read as if the model skipped checking its own writes. @@ -106,7 +106,7 @@ and `line` as partial from a state and a bundle to a table line. ## Consequences - The model, the language reference and the core rename together. - `spec/SPECIFICATION.md` carries `` as a syntax category in about ten + `docs/reference/SPECIFICATION.md` carries `` as a syntax category in about ten places, so the rename is a documentation change before it is a code change. - A glossary entry can now disagree with the definition that owns it: a signature naming a sort the model does not define, or a kind that contradicts diff --git a/decisions/0027-the-meet-is-an-intersection-of-point-sets.md b/docs/decision/0027-the-meet-is-an-intersection-of-point-sets.md similarity index 98% rename from decisions/0027-the-meet-is-an-intersection-of-point-sets.md rename to docs/decision/0027-the-meet-is-an-intersection-of-point-sets.md index 581b295d3..0e79f988a 100644 --- a/decisions/0027-the-meet-is-an-intersection-of-point-sets.md +++ b/docs/decision/0027-the-meet-is-an-intersection-of-point-sets.md @@ -12,7 +12,7 @@ status: accepted The meet, `--x * --y` and its n-ary form `.[--x --y …]`, names the point where creases cross. Until v0.19 it intersected the operands' table lines and resolved the table point to the topmost layer covering it. That rule is -recorded as a dead end in `notes/antipatterns.md` (Q2-B) for two reasons. +recorded as a dead end in `docs/notes/antipatterns.md` (Q2-B) for two reasons. Paper is opaque, so the topmost layer may carry neither crease, and the rule named points that no layer of the paper shows. And a point construction came to depend on the folded state, while a crease is a scar whose crossings in the diff --git a/decisions/0028-an-error-carries-its-hint-apart-from-its-message.md b/docs/decision/0028-an-error-carries-its-hint-apart-from-its-message.md similarity index 97% rename from decisions/0028-an-error-carries-its-hint-apart-from-its-message.md rename to docs/decision/0028-an-error-carries-its-hint-apart-from-its-message.md index eca8284ca..588efc031 100644 --- a/decisions/0028-an-error-carries-its-hint-apart-from-its-message.md +++ b/docs/decision/0028-an-error-carries-its-hint-apart-from-its-message.md @@ -44,7 +44,7 @@ Every reader carries both halves to its reader: No message carries a suggestion of its own. The existing suggestions move into hints in the same change that introduces them, and the error table in -`spec/SPECIFICATION.md` quotes message and hint in separate columns. +`docs/reference/SPECIFICATION.md` quotes message and hint in separate columns. ## Alternatives considered diff --git a/decisions/0029-annotations-pass-through-and-each-output-is-a-library.md b/docs/decision/0029-annotations-pass-through-and-each-output-is-a-library.md similarity index 93% rename from decisions/0029-annotations-pass-through-and-each-output-is-a-library.md rename to docs/decision/0029-annotations-pass-through-and-each-output-is-a-library.md index 56804b616..b78b1d852 100644 --- a/decisions/0029-annotations-pass-through-and-each-output-is-a-library.md +++ b/docs/decision/0029-annotations-pass-through-and-each-output-is-a-library.md @@ -22,7 +22,7 @@ knows these things, and today the program has no place to say them. ADR 0002 planned a small, versioned JSON schema for step-by-step diagrams, beside the FOLD. Since then the FOLD has grown what that schema would have -carried. It holds one frame per state (`spec/FOLD.md`), and ADR 0026 put every +carried. It holds one frame per state (`docs/reference/FOLD.md`), and ADR 0026 put every statement into `beloch:statements` with its kind, its source span and the frame it stands on. A consumer can walk the program and the states without parsing the source. @@ -33,7 +33,7 @@ no picture. A shared instruction schema would either take the smallest common part of these or grow a branch per medium, and in both cases the real layout work would still happen in each consumer. -The fused `step` construct (`notes/antipatterns.md`) shows the risk on the +The fused `step` construct (`docs/notes/antipatterns.md`) shows the risk on the language side: display grouping and scoping were one construct and came apart under pressure. Whatever marks a step for a diagram must group and do nothing else. @@ -42,7 +42,7 @@ else. **Annotations are written in the `.bel` source.** An annotation attaches to a statement or to a contiguous range of statements. Its syntax belongs to -`spec/BELOCH.md`; `#[ … ]` is the flap selector and is not available. +`docs/reference/BELOCH.md`; `#[ … ]` is the flap selector and is not available. **An annotation never changes the geometry.** The front end separates annotations from the program, and the geometric evaluation (ADR 0007, phase 2) @@ -77,7 +77,7 @@ annotations together are everything an output reads. The annotations live in one top-level field, one entry per annotation, each naming its target as a range of indices into `beloch:statements`. A range fits the step group, which spans statements and frames, and a single statement is a range of length one. -The field-level contract goes into `spec/FOLD.md`. +The field-level contract goes into `docs/reference/FOLD.md`. **Each output kind is a TypeScript library at the edge (ADR 0001).** A library offers two sets of primitives: @@ -126,12 +126,12 @@ favor of the libraries; its editor boundary, LSP, stands in ADR 0007 as ## Consequences -- The front end, the emitter, `spec/BELOCH.md` (syntax) and `spec/FOLD.md` +- The front end, the emitter, `docs/reference/BELOCH.md` (syntax) and `docs/reference/FOLD.md` (the annotation field) change together; the geometric evaluation does not change. - The invariance test becomes part of `check`. A kernel change that lets an annotation reach the geometry fails it. -- `spec/BELOCH.md` already calls the intent item `(mountain)`, `(valley)` an +- `docs/reference/BELOCH.md` already calls the intent item `(mountain)`, `(valley)` an annotation. Intent reaches the FOLD as `edges_assignment` and constrains a `flatten`, so it is part of the geometry and stays an item of its statement. The word in that table changes, so that "annotation" means one thing. @@ -154,7 +154,7 @@ favor of the libraries; its editor boundary, LSP, stands in ADR 0007 as the annotation would resolve names against the program without writing. It is the next entry for the vocabulary once the first three are in use. - **Values.** The first vocabulary needs text, numbers and label references. - Beloch has no text literal yet, and `spec/BELOCH.md` adds one with the + Beloch has no text literal yet, and `docs/reference/BELOCH.md` adds one with the syntax. - **How the CLI finds an author's own function** in place of a library's default. This belongs to the CLI once the first library exists. diff --git a/decisions/0030-the-fold-logs-the-program-flat.md b/docs/decision/0030-the-fold-logs-the-program-flat.md similarity index 97% rename from decisions/0030-the-fold-logs-the-program-flat.md rename to docs/decision/0030-the-fold-logs-the-program-flat.md index 3abc2b902..49f9f9edc 100644 --- a/decisions/0030-the-fold-logs-the-program-flat.md +++ b/docs/decision/0030-the-fold-logs-the-program-flat.md @@ -115,7 +115,7 @@ body to learn what happened. ## Consequences - One source span can now occur in several entries, one per `apply` that ran - its statement. Consumers join on the entry index, which `spec/FOLD.md` + its statement. Consumers join on the entry index, which `docs/reference/FOLD.md` already asks of `beloch:edges`. - A renderer finds a repetition by grouping the `apply` entries by the `def` they name. The diagram library draws the second one as a repeat of the @@ -128,5 +128,5 @@ body to learn what happened. - A FOLD written before this change carries no `apply` entries and no body bindings. A reader treats an entry without a parent as top-level, and an entry without a kind as a write, as ADR 0026 already required. -- The evaluator, `spec/FOLD.md`, the scene parser and the runtime core change +- The evaluator, `docs/reference/FOLD.md`, the scene parser and the runtime core change together. The stepper walks the writes as before and sees no difference. diff --git a/decisions/0031-toward-names-the-side-that-stays.md b/docs/decision/0031-toward-names-the-side-that-stays.md similarity index 98% rename from decisions/0031-toward-names-the-side-that-stays.md rename to docs/decision/0031-toward-names-the-side-that-stays.md index 468f34429..f3c392e28 100644 --- a/decisions/0031-toward-names-the-side-that-stays.md +++ b/docs/decision/0031-toward-names-the-side-that-stays.md @@ -168,8 +168,8 @@ leaves the construction. ## Consequences -- `def-selection` in `spec/MODEL.md` states the selection and the condition - every fold puts on its candidates. `spec/BELOCH.md` moves `toward` out of +- `def-selection` in `docs/reference/MODEL.md` states the selection and the condition + every fold puts on its candidates. `docs/reference/BELOCH.md` moves `toward` out of the construction, adds `heading` and `(x toward …)`, parenthesizes the parts of `align`, and gives bindings items. The prose form of axiom 5 loses its `toward`. diff --git a/decisions/0032-the-specification-binds-every-implementation.md b/docs/decision/0032-the-specification-binds-every-implementation.md similarity index 96% rename from decisions/0032-the-specification-binds-every-implementation.md rename to docs/decision/0032-the-specification-binds-every-implementation.md index 93ae3bdd4..3f0e303c7 100644 --- a/decisions/0032-the-specification-binds-every-implementation.md +++ b/docs/decision/0032-the-specification-binds-every-implementation.md @@ -55,7 +55,7 @@ catalog on pages of their own. It is never divided by layer into vocabulary, syntax and semantics: each construct keeps its syntax, resolution, errors and example together, and its meaning stays in the model. -The rule of `spec/README.md` holds: the documents are divided by role and +The rule of `docs/reference/README.md` holds: the documents are divided by role and reader, never by increment. A slice that changes the language edits the document whose role it touches. @@ -79,7 +79,7 @@ shrinks, so that at no point the grammar is nowhere. Version history moves to the changelog, the appendix of deferred features to issues, one per entry. 3. `SPECIFICATION.md` is deleted; the links to it in ADRs, notes, the README - and `spec/` are redirected to the section that now holds the content. + and `docs/reference/` are redirected to the section that now holds the content. Until step 3 completes, a section still in `SPECIFICATION.md` is authoritative for the surface syntax, never for the meaning. diff --git a/decisions/0033-a-line-reads-as-the-bundle-it-names.md b/docs/decision/0033-a-line-reads-as-the-bundle-it-names.md similarity index 97% rename from decisions/0033-a-line-reads-as-the-bundle-it-names.md rename to docs/decision/0033-a-line-reads-as-the-bundle-it-names.md index 288ef8972..ba18c6b0f 100644 --- a/decisions/0033-a-line-reads-as-the-bundle-it-names.md +++ b/docs/decision/0033-a-line-reads-as-the-bundle-it-names.md @@ -102,11 +102,11 @@ with its face. ## Consequences -- `def-selection` in `spec/MODEL.md` gives the objects of an alignment and +- `def-selection` in `docs/reference/MODEL.md` gives the objects of an alignment and the `toward` and `moving` lines their bundles in place of the material of their table lines. For creases this states what the kernel already does; for marks it changes the kernel, and the program of #62 folds `.c` onto the - center. The paragraph in `spec/KERNEL.md` that points at #62 goes. + center. The paragraph in `docs/reference/KERNEL.md` that points at #62 goes. - A program that moves a partial mark can lose the candidate it had. The pinch below runs from the middle of the bottom edge to the center. Of the two candidates, `moving` keeps the one that folds the pinch over, and it diff --git a/decisions/0034-action-is-the-sixth-core-module.md b/docs/decision/0034-action-is-the-sixth-core-module.md similarity index 100% rename from decisions/0034-action-is-the-sixth-core-module.md rename to docs/decision/0034-action-is-the-sixth-core-module.md diff --git a/decisions/0035-a-warning-reports-a-program-that-runs.md b/docs/decision/0035-a-warning-reports-a-program-that-runs.md similarity index 98% rename from decisions/0035-a-warning-reports-a-program-that-runs.md rename to docs/decision/0035-a-warning-reports-a-program-that-runs.md index f1563428f..f9c784d15 100644 --- a/decisions/0035-a-warning-reports-a-program-that-runs.md +++ b/docs/decision/0035-a-warning-reports-a-program-that-runs.md @@ -103,7 +103,7 @@ whatever the selection does without `moving`. A `moving` in a fold without log. A re-evaluation that reuses the result of unchanged statements reports their warnings again, in the command line's watch mode and in the playground alike. -- `spec/FOLD.md` gains `beloch:warnings`, and `spec/CLI.md` states how +- `docs/reference/FOLD.md` gains `beloch:warnings`, and `docs/reference/CLI.md` states how warnings print and that they leave the exit code at 0. The browser evaluator's answer gains `warnings`; an answer without the field reads as before. diff --git a/decisions/0036-a-write-reaches-every-layer-under-its-axis.md b/docs/decision/0036-a-write-reaches-every-layer-under-its-axis.md similarity index 96% rename from decisions/0036-a-write-reaches-every-layer-under-its-axis.md rename to docs/decision/0036-a-write-reaches-every-layer-under-its-axis.md index 71c9c768b..7d9a35a8e 100644 --- a/decisions/0036-a-write-reaches-every-layer-under-its-axis.md +++ b/docs/decision/0036-a-write-reaches-every-layer-under-its-axis.md @@ -89,10 +89,10 @@ belong to it. ## Consequences -- `def-fold` in `spec/MODEL.md` changes: without `up to` the depth is the +- `def-fold` in `docs/reference/MODEL.md` changes: without `up to` the depth is the deepest layer under the axis on the moving side, and the anchor condition goes, since the anchor names a side only. `def-mark` takes every layer its - line crosses when no flap is given. `spec/BELOCH.md` states `moving` as a + line crosses when no flap is given. `docs/reference/BELOCH.md` states `moving` as a side, and its example `fold (map .c onto .b) (up to .d)` keeps its meaning. - A program that folds one flap of a folded stack with `moving` alone now diff --git a/decisions/0037-a-fan-moves-its-tip.md b/docs/decision/0037-a-fan-moves-its-tip.md similarity index 98% rename from decisions/0037-a-fan-moves-its-tip.md rename to docs/decision/0037-a-fan-moves-its-tip.md index a0582b46d..1406c9afd 100644 --- a/decisions/0037-a-fan-moves-its-tip.md +++ b/docs/decision/0037-a-fan-moves-its-tip.md @@ -96,7 +96,7 @@ one it names. It is decided when a model needs it. ## Consequences -- `def-flatten` in `spec/MODEL.md` moves the tip of $\Phi$ in place of every +- `def-flatten` in `docs/reference/MODEL.md` moves the tip of $\Phi$ in place of every face of $C$, and `rem-all-layers` is settled by this record. `def-reverse` already moves its tip and keeps its definition. - `flatten-through-two-layers.bel` changes its result: the upper corner diff --git a/decisions/0038-squash-takes-a-bare-alignment-of-its-spine.md b/docs/decision/0038-squash-takes-a-bare-alignment-of-its-spine.md similarity index 96% rename from decisions/0038-squash-takes-a-bare-alignment-of-its-spine.md rename to docs/decision/0038-squash-takes-a-bare-alignment-of-its-spine.md index 82cb8f010..41ecf8890 100644 --- a/decisions/0038-squash-takes-a-bare-alignment-of-its-spine.md +++ b/docs/decision/0038-squash-takes-a-bare-alignment-of-its-spine.md @@ -89,8 +89,8 @@ at any point along it, so nothing in the write fixes a second condition, and ## Consequences - The grammar gains the verb `squash` and its item, a bare alignment beside - the side items. `spec/BELOCH.md` states it when the kernel folds it. -- `spec/MODEL.md` defines the squash as a fan (#52): its axis, its anchor and + the side items. `docs/reference/BELOCH.md` states it when the kernel folds it. +- `docs/reference/MODEL.md` defines the squash as a fan (#52): its axis, its anchor and the spine it opens. - A spine whose two ends both lie inside the paper has two vertices. Which one a bare alignment completes with is open until a model needs it. diff --git a/decisions/0039-on-marks-the-named-flap-alone.md b/docs/decision/0039-on-marks-the-named-flap-alone.md similarity index 96% rename from decisions/0039-on-marks-the-named-flap-alone.md rename to docs/decision/0039-on-marks-the-named-flap-alone.md index 3caa0a94e..dfc85c205 100644 --- a/decisions/0039-on-marks-the-named-flap-alone.md +++ b/docs/decision/0039-on-marks-the-named-flap-alone.md @@ -52,7 +52,7 @@ the program, and the write succeeds. ## Consequences -- `def-mark` in `spec/MODEL.md` keeps its reading for a mark with `on`. +- `def-mark` in `docs/reference/MODEL.md` keeps its reading for a mark with `on`. - A step that creases one layer of a flap hinged to others along the line cannot be drawn as a plain crease in a folding diagram; it needs the opening shown or noted. The test that finds such a step is whether the diff --git a/decisions/0040-a-fan-sits-at-a-table-point-on-names-its-flap.md b/docs/decision/0040-a-fan-sits-at-a-table-point-on-names-its-flap.md similarity index 95% rename from decisions/0040-a-fan-sits-at-a-table-point-on-names-its-flap.md rename to docs/decision/0040-a-fan-sits-at-a-table-point-on-names-its-flap.md index 088f17ec2..58cba4028 100644 --- a/decisions/0040-a-fan-sits-at-a-table-point-on-names-its-flap.md +++ b/docs/decision/0040-a-fan-sits-at-a-table-point-on-names-its-flap.md @@ -64,10 +64,10 @@ from their construction or spine, and `on` is not one of their items. ## Consequences -- `def-flatten` in `spec/MODEL.md` takes a table point and an anchor flap in +- `def-flatten` in `docs/reference/MODEL.md` takes a table point and an anchor flap in place of a paper point interior to $\Phi$. The paper point of a layer may lie on a folded edge. -- `spec/BELOCH.md` adds `on` to the items of `flatten`, with the meaning of +- `docs/reference/BELOCH.md` adds `on` to the items of `flatten`, with the meaning of `on` for `mark` unchanged: it names a flap by incidence. - `on` reads the same in both writes: the flap the write is done on. A mark scores that flap alone (ADR 0039); a fan moves its tip, since a flat state diff --git a/decisions/0041-a-fan-vertex-may-lie-off-the-paper.md b/docs/decision/0041-a-fan-vertex-may-lie-off-the-paper.md similarity index 97% rename from decisions/0041-a-fan-vertex-may-lie-off-the-paper.md rename to docs/decision/0041-a-fan-vertex-may-lie-off-the-paper.md index 396171b67..2c0bd726a 100644 --- a/decisions/0041-a-fan-vertex-may-lie-off-the-paper.md +++ b/docs/decision/0041-a-fan-vertex-may-lie-off-the-paper.md @@ -53,7 +53,7 @@ wherever that lies. ## Consequences -- `def-flatten` in `spec/MODEL.md` takes its vertex on the projective table +- `def-flatten` in `docs/reference/MODEL.md` takes its vertex on the projective table and states the closure condition for a vertex inside the paper. - Off the paper, that the lines of a fan meet in one point carries no physical meaning: any two creases meet somewhere or are parallel. Three creases diff --git a/decisions/0043-a-reverse-fold-turns-the-hinges-across-its-opening.md b/docs/decision/0043-a-reverse-fold-turns-the-hinges-across-its-opening.md similarity index 95% rename from decisions/0043-a-reverse-fold-turns-the-hinges-across-its-opening.md rename to docs/decision/0043-a-reverse-fold-turns-the-hinges-across-its-opening.md index a9e4c76a6..6b8d52ac8 100644 --- a/decisions/0043-a-reverse-fold-turns-the-hinges-across-its-opening.md +++ b/docs/decision/0043-a-reverse-fold-turns-the-hinges-across-its-opening.md @@ -12,7 +12,7 @@ This record supersedes ADR 0042, which is in `archive/`. ## Context -`def-reverse` in `spec/MODEL.md` picks one *spine*: a folded hinge of the +`def-reverse` in `docs/reference/MODEL.md` picks one *spine*: a folded hinge of the tip whose removal cuts the tip into two halves. It reflects the halves as two blocks, and every other hinge of the tip keeps its letter. @@ -77,7 +77,7 @@ spine (#119, ADR 0041). ## Consequences -- `def-reverse` and `cor-reverse-letters` in `spec/MODEL.md` define the +- `def-reverse` and `cor-reverse-letters` in `docs/reference/MODEL.md` define the opening and its blocks in place of the spine and its halves. - The acceptance case of #119 is the square with the opening between the two inner layers: 4, 3, 7, 6, 5, 8, 2, 1 along the top edge. The crane keeps diff --git a/decisions/0044-a-fan-moves-each-piece-along-its-paper-path.md b/docs/decision/0044-a-fan-moves-each-piece-along-its-paper-path.md similarity index 98% rename from decisions/0044-a-fan-moves-each-piece-along-its-paper-path.md rename to docs/decision/0044-a-fan-moves-each-piece-along-its-paper-path.md index 3cede1831..e1f88c623 100644 --- a/decisions/0044-a-fan-moves-each-piece-along-its-paper-path.md +++ b/docs/decision/0044-a-fan-moves-each-piece-along-its-paper-path.md @@ -107,7 +107,7 @@ medians of the preliminary base fold the quarter fold. ## Consequences -- `def-flatten` in `spec/MODEL.md` takes its motions from paper paths, its +- `def-flatten` in `docs/reference/MODEL.md` takes its motions from paper paths, its closure from closed paths and its sectors as pieces. On the flat sheet a piece's path crosses the rays between the stayer and it, so every flatten on one sheet keeps its result. diff --git a/decisions/0045-the-grammar-of-the-language-stands-on-one-page.md b/docs/decision/0045-the-grammar-of-the-language-stands-on-one-page.md similarity index 95% rename from decisions/0045-the-grammar-of-the-language-stands-on-one-page.md rename to docs/decision/0045-the-grammar-of-the-language-stands-on-one-page.md index bf93ab7cb..41a569c87 100644 --- a/decisions/0045-the-grammar-of-the-language-stands-on-one-page.md +++ b/docs/decision/0045-the-grammar-of-the-language-stands-on-one-page.md @@ -6,7 +6,7 @@ status: accepted issue: tophcodes/beloch#65 checks: - desc: Only the grammar page of the language carries grammar blocks - run: '! rg -l "^\`\`\`grammar" spec --glob "BELOCH*.md" --glob "!BELOCH-GRAMMAR.md"' + run: '! rg -l "^\`\`\`grammar" docs/reference --glob "BELOCH*.md" --glob "!BELOCH-GRAMMAR.md"' --- # 0045: The grammar of the language stands on one page diff --git a/decisions/0046-a-sheet-is-a-square-or-a-flap-cut-from-one.md b/docs/decision/0046-a-sheet-is-a-square-or-a-flap-cut-from-one.md similarity index 100% rename from decisions/0046-a-sheet-is-a-square-or-a-flap-cut-from-one.md rename to docs/decision/0046-a-sheet-is-a-square-or-a-flap-cut-from-one.md diff --git a/decisions/0047-a-trim-exports-the-names-it-lists.md b/docs/decision/0047-a-trim-exports-the-names-it-lists.md similarity index 100% rename from decisions/0047-a-trim-exports-the-names-it-lists.md rename to docs/decision/0047-a-trim-exports-the-names-it-lists.md diff --git a/decisions/0048-staying-names-a-sector-of-the-anchor.md b/docs/decision/0048-staying-names-a-sector-of-the-anchor.md similarity index 97% rename from decisions/0048-staying-names-a-sector-of-the-anchor.md rename to docs/decision/0048-staying-names-a-sector-of-the-anchor.md index 66416d43b..6768534cc 100644 --- a/decisions/0048-staying-names-a-sector-of-the-anchor.md +++ b/docs/decision/0048-staying-names-a-sector-of-the-anchor.md @@ -87,9 +87,9 @@ and two half-planes. ## Consequences -- The `staying` row of the selector table in `spec/BELOCH.md` moves from +- The `staying` row of the selector table in `docs/reference/BELOCH.md` moves from flap to a sort of its own, one or more points, and `def-flatten` in - `spec/MODEL.md` names the stayer by points with the errors above. + `docs/reference/MODEL.md` names the stayer by points with the errors above. - The fewest-mountains stage loses its effect on the stayer; tophcodes/beloch#99 removes the selection stages of `flatten` altogether. - `flatten-waterbomb-top-layer.bel` holds the rectangle with diff --git a/decisions/0049-examples-are-popular-models-beside-their-sources.md b/docs/decision/0049-examples-are-popular-models-beside-their-sources.md similarity index 100% rename from decisions/0049-examples-are-popular-models-beside-their-sources.md rename to docs/decision/0049-examples-are-popular-models-beside-their-sources.md diff --git a/decisions/0050-a-3d-state-is-flat-blocks-on-hinges.md b/docs/decision/0050-a-3d-state-is-flat-blocks-on-hinges.md similarity index 100% rename from decisions/0050-a-3d-state-is-flat-blocks-on-hinges.md rename to docs/decision/0050-a-3d-state-is-flat-blocks-on-hinges.md diff --git a/decisions/0051-a-program-states-its-author-design-and-sources.md b/docs/decision/0051-a-program-states-its-author-design-and-sources.md similarity index 100% rename from decisions/0051-a-program-states-its-author-design-and-sources.md rename to docs/decision/0051-a-program-states-its-author-design-and-sources.md diff --git a/decisions/0052-a-placed-fold-takes-the-layers-up-to-its-target.md b/docs/decision/0052-a-placed-fold-takes-the-layers-up-to-its-target.md similarity index 96% rename from decisions/0052-a-placed-fold-takes-the-layers-up-to-its-target.md rename to docs/decision/0052-a-placed-fold-takes-the-layers-up-to-its-target.md index 085614feb..71d4327fd 100644 --- a/decisions/0052-a-placed-fold-takes-the-layers-up-to-its-target.md +++ b/docs/decision/0052-a-placed-fold-takes-the-layers-up-to-its-target.md @@ -79,8 +79,8 @@ The closure under hinges off the axis is unchanged. ## Consequences -- `def-fold` in `spec/MODEL.md` states the closure for every placement, and - the paragraph after it and `up to` in `spec/BELOCH-WRITES.md` say that a +- `def-fold` in `docs/reference/MODEL.md` states the closure for every placement, and + the paragraph after it and `up to` in `docs/reference/BELOCH-WRITES.md` say that a placed fold takes the layers between its depth and its target. - Every program that places a fold folds to the same FOLD file as before: the samurai helmet (step 7 tucks the back corner, and no layer lies between it diff --git a/decisions/0053-unfold-turns-layers-over-a-crease-and-opens-its-hinges.md b/docs/decision/0053-unfold-turns-layers-over-a-crease-and-opens-its-hinges.md similarity index 95% rename from decisions/0053-unfold-turns-layers-over-a-crease-and-opens-its-hinges.md rename to docs/decision/0053-unfold-turns-layers-over-a-crease-and-opens-its-hinges.md index 7bf6c5b0e..da82072e4 100644 --- a/decisions/0053-unfold-turns-layers-over-a-crease-and-opens-its-hinges.md +++ b/docs/decision/0053-unfold-turns-layers-over-a-crease-and-opens-its-hinges.md @@ -34,7 +34,7 @@ fold (map .m onto .a) as --q ``` Turning the layer of `.b` back over `--q` opens hinges on `--q` and closes -none. `lem-toggle` in `spec/MODEL.md` says why: reflecting faces across a line +none. `lem-toggle` in `docs/reference/MODEL.md` says why: reflecting faces across a line toggles every hinge on the line between a moving and a stationary face, and where every layer lies on one side, each such hinge is folded. ADR 0017 plans the write as "`unfold` + layer selection". @@ -97,7 +97,7 @@ and its message names `unfold`. A fold along hinges with paper on both sides reflects the layers on the moving side, and by `lem-toggle` the flat hinges on the axis between moving and staying layers fold and the folded ones open. -**`spec/MODEL.md` gets a definition of its own**, `def-unfold`, beside +**`docs/reference/MODEL.md` gets a definition of its own**, `def-unfold`, beside `def-fold`. Its moving set with a depth is the one of `def-fold`; its moving set named by the layer that stays, and its domain, are its own. The domain asks that every hinge on the axis between the moving set and the stationary @@ -131,8 +131,8 @@ every such hinge opens. ## Consequences -- `spec/BELOCH-GRAMMAR.md` adds the verb and its item; `spec/BELOCH-WRITES.md` - states the write with a program; `spec/MODEL.md` adds `def-unfold`. +- `docs/reference/BELOCH-GRAMMAR.md` adds the verb and its item; `docs/reference/BELOCH-WRITES.md` + states the write with a program; `docs/reference/MODEL.md` adds `def-unfold`. - The trace records an unfold with the terms of a fold: axis, side, moving set and placement. The reflection is the one of `def-fold`. - Opening a hinge merges two flaps into one: the flaps of ADR 0017 are found diff --git a/docs/decision/0054-a-document-is-one-of-four-kinds-and-a-link-names-an-id.md b/docs/decision/0054-a-document-is-one-of-four-kinds-and-a-link-names-an-id.md new file mode 100644 index 000000000..5595e1623 --- /dev/null +++ b/docs/decision/0054-a-document-is-one-of-four-kinds-and-a-link-names-an-id.md @@ -0,0 +1,137 @@ +--- +id: "0054" +title: "A document is one of four kinds, and a link names an id" +date: 2026-10-08 +status: accepted +checks: + - desc: Every prose tree lives under docs/ + run: '[ -d docs/reference ] && [ -d docs/decision ] && [ -d docs/notes ] && [ ! -e spec ] && [ ! -e decisions ] && [ ! -e notes ]' +--- + +# 0054: A document is one of four kinds, and a link names an id + +This record keeps the division of ADR 0032 (the specification binds every +implementation, the kernel document describes one) and places it inside a +wider order. ADR 0032's manual, "a separate document with a separate reader, +ordered by the folder's tasks", gets its place here. + +## Context + +Beloch's prose lives in four places with four different orders. `spec/` +holds the reference, divided by role (ADR 0032). `decisions/` holds the +records of choices, numbered. `notes/` holds a dated design journal. The +site adds two guide pages of +its own and lists the reference under two headings, the specification and +the reference implementation, so its navigation sorts by what binds an +implementation. + +The content planned for the coming years does not fit that order. A manual +of the folder's tasks (fold a base, choose among candidate lines, read an +error) has no place: the guide holds tutorials, and a task page is no +tutorial. An explanation of a choice (why seven axioms, why exact numbers, +how layers are modeled) has no place either: a decision record is a +protocol of one moment, and a note is a journal entry nobody publishes. The +rendering libraries and tools need pages of both kinds, and an API +reference, for a reader who embeds Beloch and never folds. + +Diátaxis (diataxis.fr) sorts documentation by what the reader needs of it +along two axes, acting against understanding and learning against working, +into four kinds: tutorials, how-to guides, reference and explanation. Each +kind has its own form, and mixing two of them on one page serves neither +reader. Its own guidance warns against creating the four sections empty +and filling them by plan; the structure follows from the pages that exist. + +References between documents follow three conventions at once. The kernel's +`@see` tags name site URLs. Prose names decisions by number, "ADR 0032", +in 85 places, and by path in 3. The notes carry links in double +brackets to design documents that were deleted months ago, and nothing has +reported them, because nothing resolves such a link. + +## Decision + +**Every document under `docs/` is one of four kinds, or a record.** The +kinds are those of Diátaxis, and the compass decides which a page is: + +- A **guide** page teaches by doing. The reader follows it from top to + bottom and folds something they could not fold before. It carries + programs the site build evaluates, and it explains nothing the reference + states. +- A **manual** page gets one task done for a reader who already knows the + language or the libraries: fold a base, choose a candidate line, render a + FOLD file with the drawing library, adapt a diagram. It carries a program + or a script the build runs. +- A **reference** page states what a thing does. The specification and the + description of the reference implementation stay divided as ADR 0032 has + them, as two groups within the reference. An API reference of a package + is reference. +- An **explanation** page gives the reader an understanding of a choice or + a concept. It carries no syntax, cites the model statements and the + decisions it rests on, and restates neither. When a later record + supersedes a decision, the explanation page that cites it is the page + that follows. + +A **record** is a decision (`docs/decision/`) or a journal entry +(`docs/notes/`). Records are written once, for the project, and are no +page of the site. The brand documents live in their own repository, +`tophcodes/beloch-brand`. + +The site's navigation has one group per kind, and a group appears with the +first page of its kind. No group stands empty. Within a kind, an area that +has its own reader (the language, the rendering libraries) is a subgroup; +it becomes a group of its own when it outgrows the kind. + +**The layout follows the kinds.** `spec/` becomes `docs/reference/`, +`decisions/` becomes `docs/decision/`, `notes/` becomes `docs/notes/`; +`docs/guide/`, `docs/manual/` and `docs/explanation/` hold the pages of +their kind. The site's content directory links each page, as it links the +reference today, and every URL ADR 0032 fixed stays. + +**A link between documents names an id.** The id is the kind, which is +the directory name under `docs/`, and the document's file stem, with `#` +and an anchor where the link enters the document: `[[decision/0032]]`, +`[[reference/model#def-sheet]]`, `[[guide/first-folds]]`. A decision's +stem is its number. An id names its document for as long as the document +exists, through a rename and through a move into `archive/`; a tool that +reads the documents resolves the same id under its own base. A resolver +turns the id into a link on the site and in the rendered PDFs, and the +reference pages keep the URLs ADR 0032 fixed. A check in `check` fails on +an id that names no document or no anchor. In a file read on GitHub the id +stands unresolved and still names its target. A decision resolves to its +file in the repository. + +## Alternatives considered + +- **Keep the order of ADR 0032 and add the manual beside the guide.** + Rejected: the guide would mix tutorials with tasks, and explanations + would keep landing in decision records, where a reader of the site never + finds them. +- **Apply the four kinds to the site and leave the repository as it is.** + Rejected: two orders to maintain, and a link scheme that spans the site + and the repository needs one layout to resolve against. +- **Link by path.** Rejected: a path breaks on every move and every rename, + and the 85 references by number against 3 by path show that writers + already avoid it. +- **Links in double brackets without a resolver and a check.** Rejected: the notes show + the outcome, links to deleted documents that nobody noticed. + +## Consequences + +- The move touches about 60 files that name `spec/`, `decisions/` or + `notes/` as a path, 10 symlinks under the site's content directory and 5 + scripts. It lands in one change, with `check-all` reporting what it + broke. `CLAUDE.md` and the README of each moved tree follow. +- The resolver and the check are new code: a remark plugin for the site, a + Lua filter for the PDFs, and a step in `check`. +- A change to the language edits the reference, and the build reports + which guide or manual page it broke. An explanation page does not break, + because it carries no syntax. +- The manual starts with its first task page, and the explanation with its + first page; neither gets an empty section before that. +- Spalier, the decision harness under design in `aleph-garden/spalier`, + reads decision records from a directory its project profile names, and + resolves `[[decision/NNNN]]` under the project's base. Adopting it is a + record of its own: it needs a scope field per decision, `constrains`, and + a mapping for the frontmatter of the records as they are. +- This record is worth reopening when a second implementation or a second + author arrives, or when the rendering libraries have more pages than the + language. diff --git a/decisions/README.md b/docs/decision/README.md similarity index 93% rename from decisions/README.md rename to docs/decision/README.md index a5319d12e..7ab13f2df 100644 --- a/decisions/README.md +++ b/docs/decision/README.md @@ -6,7 +6,7 @@ ADR supersedes it and the old one **moves to `archive/`**. The directory carries the status, not a banner inside the file: a `Superseded by` line sits far from any `rg` hit and gets skipped, by people and by agents -alike. `decisions/*.md` is current truth; `decisions/archive/*.md` is not. +alike. `docs/decision/*.md` is current truth; `docs/decision/archive/*.md` is not. The successor names its predecessor going forward. Scope: semantic and architectural choices (layer model, output format, language @@ -48,4 +48,4 @@ A few records keep a `## Status` section as well, where the status carries narrative the single word cannot (0012, 0013, 0017, archive/0010). See also: `../notes/` (design journal), `../antipatterns.md` (dead ends), -`../spec/` (the language specification these decisions shape). +`../reference/` (the language specification these decisions shape). diff --git a/decisions/archive/0002-fold-extended-as-output.md b/docs/decision/archive/0002-fold-extended-as-output.md similarity index 97% rename from decisions/archive/0002-fold-extended-as-output.md rename to docs/decision/archive/0002-fold-extended-as-output.md index d0d048d04..f235f88cd 100644 --- a/decisions/archive/0002-fold-extended-as-output.md +++ b/docs/decision/archive/0002-fold-extended-as-output.md @@ -45,4 +45,4 @@ a different kind of artifact. Renderers (SVG, Three.js, print, YR diagrams) are downstream consumers in any language; the research contribution has a clean interface. - We owe a written, versioned spec for the `beloch:*` extension fields and for - the instruction schema. These live in `../spec/`. + the instruction schema. These live in `../reference/`. diff --git a/decisions/archive/0010-constructible-real-numbers.md b/docs/decision/archive/0010-constructible-real-numbers.md similarity index 100% rename from decisions/archive/0010-constructible-real-numbers.md rename to docs/decision/archive/0010-constructible-real-numbers.md diff --git a/decisions/archive/0021-reference-documents-replace-specification.md b/docs/decision/archive/0021-reference-documents-replace-specification.md similarity index 95% rename from decisions/archive/0021-reference-documents-replace-specification.md rename to docs/decision/archive/0021-reference-documents-replace-specification.md index bb19a85bc..cdf6f6dac 100644 --- a/decisions/archive/0021-reference-documents-replace-specification.md +++ b/docs/decision/archive/0021-reference-documents-replace-specification.md @@ -11,7 +11,7 @@ status: superseded ## Context -`spec/README.md` fixed one rule for the language documentation: there is one +`docs/reference/README.md` fixed one rule for the language documentation: there is one living specification, `SPECIFICATION.md`, and every implementation slice folds its language-facing content into it under a version tag. The rule was aimed at fragmentation by increment, which had produced a per-slice spec @@ -64,7 +64,7 @@ dissolved into them and deleted once empty. - Version history moves to the log and the changelog; the appendix of deferred features moves to issues, one per entry. -The rule of `spec/README.md` is restated: the documents are divided by role +The rule of `docs/reference/README.md` is restated: the documents are divided by role and reader, never by increment. A slice that changes the language edits the document whose role it touches and adds no file. @@ -103,7 +103,7 @@ shrinks, so that at no point the grammar is nowhere. ## Consequences -- `spec/README.md` changes from "one living specification" to the division +- `docs/reference/README.md` changes from "one living specification" to the division by role. This ADR is the record that reverses that rule. - `BELOCH.md` grows from a sketch into the reference and becomes the document a graphical editor binds its actions to, as it announces. @@ -111,7 +111,7 @@ shrinks, so that at no point the grammar is nowhere. has moved is gone from it, a section that has not is still authoritative for the surface, never for the meaning. - Links from 25 files have to be redirected at deletion. Design documents are - point-in-time and may keep dead section numbers; ADRs, notes and `spec/` + point-in-time and may keep dead section numbers; ADRs, notes and `docs/reference/` itself are updated. - The number 0021 was informally reserved for the diagram annotation schema; that decision takes the next number when it is written. diff --git a/decisions/archive/0022-constructions-are-alignment-sets.md b/docs/decision/archive/0022-constructions-are-alignment-sets.md similarity index 94% rename from decisions/archive/0022-constructions-are-alignment-sets.md rename to docs/decision/archive/0022-constructions-are-alignment-sets.md index 717af433a..c3c638f71 100644 --- a/decisions/archive/0022-constructions-are-alignment-sets.md +++ b/docs/decision/archive/0022-constructions-are-alignment-sets.md @@ -22,7 +22,7 @@ onto line, the fold line through a point, the fold line perpendicular to a line. The seven axioms are the seven such sets that determine one fold line with finitely many solutions, and the same alignments distributed over two fold lines give the 489 two-fold axioms [alperin2006, §3, §4]. The language -reference (`spec/BELOCH.md`, Constructions) and the model (`MODEL.md`, +reference (`docs/reference/BELOCH.md`, Constructions) and the model (`MODEL.md`, Definition 4.7) now state constructions in these terms: the alignment set is the canonical form, written `(align …)`, and the prose forms are sugar for it. `packages/multifold` (ADR 0020) enumerates the two-fold sets under @@ -84,7 +84,7 @@ constructor per axiom remains. untouched below `classify`. - The two-fold constructions of `packages/multifold` have a source-level object to bind to when they are wired into the kernel; the syntax for - naming fold lines inside `align` stays open in `spec/BELOCH.md` + naming fold lines inside `align` stays open in `docs/reference/BELOCH.md` (`#open-multifold-syntax`). -- `spec/MODEL.md` Definition 4.7 already states a construction as a set of +- `docs/reference/MODEL.md` Definition 4.7 already states a construction as a set of alignments; nothing in the model changes. diff --git a/decisions/archive/0026-a-program-has-two-axes.md b/docs/decision/archive/0026-a-program-has-two-axes.md similarity index 94% rename from decisions/archive/0026-a-program-has-two-axes.md rename to docs/decision/archive/0026-a-program-has-two-axes.md index 36038a331..b9203ecb2 100644 --- a/decisions/archive/0026-a-program-has-two-axes.md +++ b/docs/decision/archive/0026-a-program-has-two-axes.md @@ -11,7 +11,7 @@ status: accepted The timeline has one counter today. `beloch:statements` holds one entry per state-changing statement in source order, which means a `fold` or a `mark` -(`spec/FOLD.md`). A construction statement such as `.m = --v * --ab` changes no +(`docs/reference/FOLD.md`). A construction statement such as `.m = --v * --ab` changes no state and is not logged; a named point records the index of the next state-changing statement, "the first stop at which the point can matter". @@ -32,7 +32,7 @@ no notion of a program, a name or an order of statements. read, `--mid = (through .c .o)` binds another, `mark` writes without moving paper. All three advance the program. None of them moves the model's counter. -The naming environment appears nowhere in `spec/MODEL.md`, so the second axis +The naming environment appears nowhere in `docs/reference/MODEL.md`, so the second axis belongs to a layer the model does not have rather than being a distinction the interface invented. @@ -85,7 +85,7 @@ gives the runtime core a document slot rather than an evaluator. ## Consequences -- The emitter, `spec/FOLD.md`, the scene parser and the runtime core change +- The emitter, `docs/reference/FOLD.md`, the scene parser and the runtime core change together. The kind on a statement is the new field a consumer must read to tell the axes apart. - A FOLD written before this change carries fewer entries. The parser keeps diff --git a/decisions/archive/0042-a-reverse-fold-turns-every-spine-of-its-tip.md b/docs/decision/archive/0042-a-reverse-fold-turns-every-spine-of-its-tip.md similarity index 94% rename from decisions/archive/0042-a-reverse-fold-turns-every-spine-of-its-tip.md rename to docs/decision/archive/0042-a-reverse-fold-turns-every-spine-of-its-tip.md index 2687c8d4e..2b9ca6884 100644 --- a/decisions/archive/0042-a-reverse-fold-turns-every-spine-of-its-tip.md +++ b/docs/decision/archive/0042-a-reverse-fold-turns-every-spine-of-its-tip.md @@ -10,7 +10,7 @@ issue: tophcodes/beloch#119 ## Context -`def-reverse` in `spec/MODEL.md` picks one *spine*: a folded hinge of the tip +`def-reverse` in `docs/reference/MODEL.md` picks one *spine*: a folded hinge of the tip whose removal cuts the tip into two halves. It reflects the two halves as two blocks, one against each body, and every other hinge of the tip keeps its letter. The write is defined when exactly one admissible spine yields a @@ -59,7 +59,7 @@ crease. `inside` and `outside` are placements the write hands to the fan. ## Consequences -- `def-reverse` and `cor-reverse-letters` in `spec/MODEL.md` change to the +- `def-reverse` and `cor-reverse-letters` in `docs/reference/MODEL.md` change to the rule above; the halves and the admissible spine go. - The paper case above is the acceptance case of #119: `paper square`, two folds in half in the same direction, then `reverse (map .a onto .d)`, with diff --git a/decisions/figures/0043-crane-head.svg b/docs/decision/figures/0043-crane-head.svg similarity index 100% rename from decisions/figures/0043-crane-head.svg rename to docs/decision/figures/0043-crane-head.svg diff --git a/decisions/figures/0043-square.svg b/docs/decision/figures/0043-square.svg similarity index 100% rename from decisions/figures/0043-square.svg rename to docs/decision/figures/0043-square.svg diff --git a/docs/guide/first-folds.md b/docs/guide/first-folds.md new file mode 100644 index 000000000..a91f9fb3c --- /dev/null +++ b/docs/guide/first-folds.md @@ -0,0 +1,321 @@ +--- +title: First folds +description: A first program, one fold at a time, up to the preliminary base. For folders who have never read a grammar and programmers who have never folded a base. +tableOfContents: + minHeadingLevel: 2 + maxHeadingLevel: 2 +--- + +A Beloch program describes how a sheet of paper is folded. Each line is one +step, and the program's result is the paper after the last one. Beloch +reads the program step by step and computes where every layer of paper +goes, which creases come out mountain or valley, and draws the result. You +describe each fold by what it brings together, and Beloch works out the +lines. + +This page builds one program up to the preliminary base. A *base* is a +standard folded shape that many models start from; the preliminary base is +one of the most common, and the crane starts from it. Every figure shows two +drawings of the same moment. On the left is the *crease pattern*: the sheet +unfolded flat again, with every crease the folds have made so far. On the +right is the *folded form*: the paper as it lies on the table, each +*layer* of paper stacked on the one beneath. A crease is either a *valley*, +folded towards you so the paper forms a trough, or a *mountain*, folded +away from you so it forms a ridge. The drawings use the notation of origami +diagrams: a valley is dashed, a mountain dash-dotted, and a crease that was +made and left flat is dotted. + +The programs on this page are checked every time the site is built, so what +you read here is what the language does today. + +## The sheet + +Every program starts by naming its paper. + +::: {.figure #fig-guide-sheet caption="The unit square. Its corners are named `.a` to `.d`, counter-clockwise from the bottom left." views="cp" highlight=".a .b .c .d"} +paper square +::: + +`paper square` is a square of side 1 with its corners at $(0, 0)$, $(1, 0)$, +$(1, 1)$ and $(0, 1)$. It also names them: `.a` is the bottom left, and the +names continue counter-clockwise to `.d` at the top left. + +Names in Beloch carry their kind in front. A name starting with a dot is a +*point*. A name starting with two dashes is a *line* or a *crease*. The +four edges of the square are named after the corners they join: `--ab` is +the bottom edge, `--bc` the right one, `--cd` the top, `--da` the left. + +## One fold + +Folding the square corner to corner is one line. + +::: {.figure #fig-guide-triangle caption="`.a` folded onto `.c`. The crease runs along the other diagonal, from `.b` to `.d`, and the triangle covers the upper right half of where the square was." views="cp folded" highlight=".a .c"} +paper square +fold (map .a onto .c) +::: + +A statement starts with a verb, here `fold`, followed by *items* in round +brackets. The item `(map .a onto .c)` says where the fold line goes: it is +the line that carries `.a` onto `.c` when the paper is folded along it. You +never write coordinates for a fold line. You say what it has to bring +together, and Beloch works out the line. + +Origami geometry knows seven such ways to pin down a single fold line from +points and lines already on the paper: through two points, one point onto +another, one line onto another, and four more. They are the Huzita-Justin +axioms. Beloch writes each as a *construction* in round brackets, and the +language reference lists all seven under +[Constructions](/language/constructions/). + +The fold moves the side that holds `.a`, the first thing the construction +names, and lays it over the rest. A fold without further items is a valley +fold, which is what a folder means by "fold" unless they say otherwise. + +## Naming a crease + +A statement that makes a crease can give it a name with `as`: + +::: {.figure #fig-guide-named caption="The same fold, with its crease named `--bd` after the two corners it runs between." views="cp folded" highlight="--bd"} +paper square +fold (map .a onto .c) as --bd +::: + +Later statements can refer to `--bd` the way they refer to a corner. A name +is bound once; binding the same name again is an error, so a name always +means the thing it was first given. + +## Marking a line + +Folders often crease a line and unfold it again, to have a reference for a +later step. That is `mark`: it scores the paper and moves nothing. + +::: {.figure #fig-guide-mark caption="`mark` scores the diagonal from `.a` to `.c`. The paper stays flat, so the folded form is the square itself." views="cp folded" highlight="--ac"} +paper square +mark (through .a .c) as --ac +::: + +`(through .a .c)` is another of the seven axioms: the line through two +points. A marked crease is scored into the paper and moves nothing. It +splits the square into two *faces*, the regions of paper that the creases +and edges bound; the crease pattern shows every face of the sheet. Later +statements can fold along the mark, fold something onto it, or read points +off it. + +## The kite + +With a marked diagonal, the kite base is two more folds. Each lays an edge +of the square along the diagonal. + +::: {.figure #fig-guide-kite caption="The kite: the left edge and the bottom edge folded onto the diagonal `--ac`." views="cp folded" highlight="--ac"} +paper square +mark (through .a .c) as --ac +fold (map --da onto --ac) +fold (map --ab onto --ac) +::: + +`(map --da onto --ac)` is the axiom that folds one line onto another. Two +lines that cross have two fold lines that do this, the lines that halve the +angles between them. Here one of them runs across the paper, and the other +touches the square only at the corner `.a`. A line that creases no paper is +no fold at all, so one candidate is left, and that is the fold. + +## Choosing the side that moves + +Not every construction says which side of the fold line travels. A fold +line through two points is symmetric; nothing in `(through .a .c)` says +whether the half with `.b` or the half with `.d` goes over. Beloch does not +guess. This program fails: + +```{.bel} +paper square +fold (through .a .c) + +; expect error "this fold needs `moving .p` to choose the side" +``` + +The error points at the statement and says what is missing. A `moving` item +names a point on the side that travels: + +::: {.figure #fig-guide-moving caption="`(moving .b)` sends the half with `.b` over the diagonal." views="cp folded" highlight=".b"} +paper square +fold (through .a .c) (moving .b) +::: + +The opposite item is `toward`: it names a point on the side that stays. +`fold (through .a .c) (toward .d)` is the same fold. When a construction +has several solutions that all crease paper, the same two items choose among +them, and the reference explains how under +[Selection](/language/constructions/#selection). + +A crease that is already there can be the fold line itself. The crease goes +in round brackets like a construction, and it needs a side for the same +reason: + +::: {.figure #fig-guide-along caption="The marked diagonal `--ac` folded, with the half holding `.b` moving." views="cp folded" highlight="--ac .b" after="fig-guide-mark"} +fold (--ac) (moving .b) +::: + +Every error works this way. A program that asks for something the paper +cannot do, or that leaves a choice open, stops at the statement where that +happens, with a message and often a hint. + +## Which layers move + +Once the paper is folded, a fold line crosses more than one layer. A fold +takes every layer under its line on the side that folds over, as a finger +pressing a crease through the stack does. The point that says which side +moves, the named corner of a `map` or the point of a `moving` item, names +that side and nothing more. + +The book fold shows it. Folding the left edge onto the right edge puts the +left half on top, so `.a` is on the top layer and `.b` on the bottom one. +Folding the bottom onto the top takes both layers, whichever of the two +corners the program names: + +::: {.figure #fig-guide-book caption="The book fold, then the bottom onto the top. Both layers move." views="cp folded" highlight=".a .b"} +paper square +fold (map --da onto --bc) +fold (map .b onto .c) +::: + +`(map --da onto --bc)` folds one edge onto the opposite one. The two edges +are parallel, so there is one fold line, halfway between them. The same +second fold written as `fold (map .a onto .d)` gives the same state. + +To fold fewer layers, `(up to …)` names the deepest one the fold takes. That +layer moves with every layer on top of it, or beneath it for a mountain +fold. A layer joined to those by a crease away from the fold line goes +along too, because the paper would have to tear to leave it behind. Here +the corner of the top layer folds alone: + +::: {.figure #fig-guide-up-to caption="The sheet folded in half, then the corner of the top layer. `(up to .b)` names the top layer as the deepest the fold takes." views="cp folded" highlight=".b"} +paper square +fold (map .b onto .a) +.p = free on --bc from .b at 1/4 +.q = free on --ab from .b at 1/4 +fold (through .p .q) (moving .b) (up to .b) +::: + +A `mark` works the same way: it scores every layer its line crosses, and +`(on …)` confines it to one. + +The piece of paper that moves as a whole is a *flap*: faces joined by +creases that are not folded, so that they lie flat against each other. + +## A reverse fold + +The preliminary base starts from the triangle and needs a fold that is not +a plain valley or mountain: the *inside reverse fold*. The triangle's +corner `.b` is folded down between the two layers of the triangle, so that +it ends up inside. Along the old crease `--bd` the direction of the fold +flips where the corner turns in. + +::: {.figure #fig-guide-reverse caption="The corner `.b` reverse-folded inside, onto `.c`." views="cp folded" highlight="--h" after="fig-guide-named"} +reverse (map .b onto .c) as --h +::: + +This figure continues the program of the named triangle above; from here on +a figure shows only the lines it adds. `reverse` takes a construction the +way `fold` does. It needs no `moving`, because `(map .b onto .c)` already +says that `.b` travels. `(outside)` would wrap the corner +around the outside of the layers instead of tucking it between them. + +## The preliminary base + +One more reverse fold for the corner `.d` finishes the base. + +::: {.figure #fig-guide-prelim caption="The preliminary base. The paper is a square a quarter the size of the sheet, all four corners lie together at `.c`, and the creases `--h` and `--v` cross at the paper's center." views="cp folded" highlight="--v" after="fig-guide-reverse"} +reverse (map .d onto .c) as --v +::: + +The whole program is four lines: + +```{.bel} +paper square +fold (map .a onto .c) as --bd +reverse (map .b onto .c) as --h +reverse (map .d onto .c) as --v +``` + +`--h` is named for the horizontal line it was folded along, halfway up the +triangle, and `--v` for the vertical one. + +## Collapsing a vertex + +Folders often reach the preliminary base another way: crease the diagonals +and the middle lines first, then push the paper together so that all the +creases around the center fold at once. `flatten` does that. It folds every +crease through one point, the *vertex*, in a single step. + +::: {.figure #fig-guide-flatten caption="The preliminary base in one `flatten`. Six rays around the center fold; the diagonal from `.a` to `.c` stays flat. `(.q over .r)` puts the quarter with `.q` in front of the one with `.r`." views="cp folded" highlight=".q .r"} +paper square +mark (through .a .c) as --ac +mark (through .b .d) as --bd +mark (map --ab onto --cd) as --h +mark (map --da onto --bc) as --v +.q = free on --ab from .a at 1/4 +.r = free on --ab from .b at 1/4 +flatten (--h & --bc) (--v & --cd) (--h & --da) (--v & --ab) + (--bd & .b) (--bd & .d) (.q over .r) (toward .q) +::: + +The four `mark` lines score the creases. The items of `flatten` then name +the *rays*, the pieces of crease that run out from the vertex. Each marked +line through the center is two rays, and `&` picks one of them: +`--h & --bc` is the piece of `--h` that reaches the right edge `--bc`. + +The rays say where the paper folds; Beloch works out which of them become +mountains and which valleys, and how the layers stack, so that everything +lies flat. A ray can be pinned by writing its letter, as in +`(--h & --bc mountain)`. With an odd number of rays, Beloch adds the one +that is missing, since a flat vertex needs an even number. + +Several flat results can remain, and the other items choose among them. +`(.q over .r)` says that the paper around `.q` lies over the paper around +`.r`, and `(toward .q)` picks one of the results that are still left. Both +need points that lie in one quarter of the sheet and on none of the +creases through the center. The corners and crossings named so far all lie +on such a crease. `free on --ab from .a at 1/4` +is a point a quarter of the way along the bottom edge from `.a`; `free` +records that any spot on that stretch would do, and the program uses this +one. + +`flatten` handles one vertex per statement. The reference describes the +rest under [Write statements](/language/writes/). + +## Points from creases + +A point does not have to be a corner. `*` gives the point where two creases +cross on the paper: + +::: {.figure #fig-guide-center caption="`.o`, the point where `--h` and `--v` cross: the center of the sheet, and the closed tip of the base." views="cp folded" highlight=".o" after="fig-guide-prelim"} +.o = --h * --v +::: + +`=` binds a name to something computed from the paper as it is, and changes +nothing. That is the difference between the two ways to name: `as` names +the crease a statement makes, `=` names a value the program reads off the +paper. `--mid = (through .c .o)` binds a line with no crease under it yet, +which a later fold can use as its fold line or its target. + +A point name belongs to the paper. `.o` is a spot on the sheet, and it +travels with the paper wherever later folds take it. A construction such as +`(map .b onto .c)` works with where its points lie on the table at that +step, since that is where the fold happens. A crossing `*` is found on the +unfolded sheet, where the creases are scored. + +On the unfolded sheet, one crease can be several lines. `--h` was folded +through both layers of the triangle at once and left a *scar* in each. +Unfolded, the scar in the upper layer runs from the center to the right +edge, and the scar in the lower layer, which lay folded over the diagonal, +runs from the center down to the bottom edge. A crease is all of its scars +together, and `*` looks for a crossing among all of them. The crease pattern +of the preliminary base shows this: `--h` and `--v` each bend at the +center. + +## Where to go from here + +[Reading the crane](/guide/reading-the-crane/) continues this program into a +traditional crane and introduces the rest of what it needs along the way. +The [playground](/playground/) runs any program in the browser. The +[language reference](/language/) defines every statement this page used. diff --git a/docs/guide/reading-the-crane.md b/docs/guide/reading-the-crane.md new file mode 100644 index 000000000..4a290f848 --- /dev/null +++ b/docs/guide/reading-the-crane.md @@ -0,0 +1,171 @@ +--- +title: Reading the crane +description: The traditional crane as a Beloch program, read section by section. Introduces perpendiculars, moving flaps, mountain folds, filters and free points where the crane first needs them. +tableOfContents: + minHeadingLevel: 2 + maxHeadingLevel: 2 +--- + +This page reads a whole model: the traditional crane, folded flat, by the +sequence Ida gives in her book [@ida2020, Fig. 7.19]. It reaches the bird +base with reverse folds and uses no petal fold, so it differs from the +diagrams most folders learned the crane from, and ends in the same bird base. +It assumes +[First folds](/guide/first-folds/), and it adds the rest of what the crane +needs where it first appears. The full program is +[`examples/crane.bel`](https://github.com/tophcodes/beloch/blob/main/examples/crane.bel) +in the repository; the figures below build it up section by section, and +each shows only the lines it adds. + +Beloch describes paper that lies flat. The crane ends where its last flat +step ends, with the wings still closed; spreading them makes the model +three-dimensional, which the language does not model. + +## The base and its center line + +The program starts where the first page ended: the preliminary base, with +the center of the paper named `.o`. + +::: {.figure #fig-crane-base caption="The preliminary base. `--mid` runs from the loose corners at `.c` to the closed tip `.o`." views="cp folded" highlight=".o --mid"} +paper square +fold (map .a onto .c) as --bd +reverse (map .b onto .c) as --h +reverse (map .d onto .c) as --v +.o = --h * --v +--mid = (through .c .o) +::: + +On the table the base is a small square. The four corners of the sheet lie +together at one of its corners, `.c`, the *loose corners*. The center of the +sheet is the opposite corner, `.o`, the *closed tip*, where no paper edge +reaches. `--mid` is the line between them, the *center line* of the base. +It is bound with `=`, so it has no crease under it. The next folds bring +paper onto it, and a line you only fold onto never needs to be scored. + +## The side corners + +The two remaining corners of the base square are its *side corners*. Each +is two layers thick, one on the front of the base and one on the back, so +there are four: `.sr` and `.sl` on the front, right and left, `.br` and +`.bl` on the back. Each is reverse-folded inside, so that its edge lies +along the center line. + +::: {.figure #fig-crane-sides caption="The four side corners reversed onto the center line. Each crease runs from the loose corners at `.c`." views="cp folded" highlight="--mid" after="fig-crane-base"} +.sr = --ab * --h +reverse (map .sr onto --mid through .c) as --rsr +.sl = --da * --v +reverse (map .sl onto --mid through .c) as --rsl +.br = --bc * --h +reverse (map .br onto --mid through .c) as --rbr +.bl = --cd * --v +reverse (map .bl onto --mid through .c) as --rbl +::: + +`.sr = --ab * --h` finds a side corner as a crossing on the unfolded sheet. +[First folds](/guide/first-folds/#points-from-creases) showed that `--h` +left two scars, one of them running from the center down to the bottom +edge. That scar meets the bottom edge `--ab` at $(1/2, 0)$, the middle of +the bottom edge, and on the base this spot is the right side corner of the +front layer. `.sl`, `.br` and `.bl` are the other three the same way, each +where an edge of the sheet meets a scar of `--h` or `--v`. + +`(map .sr onto --mid through .c)` is the axiom that folds a point onto a +line with a fold line through a second point. It has up to two solutions. +Here only one of them crosses the folded paper, so the program needs no +item to choose. + +## The bird base + +The front flap and the back flap are folded over along the same line, +square to the center line through the side corners. That leaves the two long +points, the future neck and tail, standing up in the middle: the bird base. + +::: {.figure #fig-crane-bird caption="The bird base. `--pf` folds the front flap, `--pb` the back flap along the same line." views="cp folded" highlight="--pf --pb" after="fig-crane-sides"} +fold (perp --mid through .sr) (moving .a) (up to #[.a .o]) as --pf +fold (perp --mid through .sr) (moving .c) (up to #[.c .o]) (mountain) as --pb +::: + +`(perp --mid through .sr)` is the axiom for the line through a point, +square to another line. + +The two folds follow the rule of +[Which layers move](/guide/first-folds/#which-layers-move). Without `up to` +each would take every layer below the line, front and back together. +`#[.a .o]` is the flap that holds both the corner `.a` and the paper center +`.o`: the center face of the front. `(up to #[.a .o])` makes the valley +fold take that face and the layers on top of it. The side corners reversed +beneath it are joined to it by creases away from the fold line, so they go +along, and the front flap moves whole. The second fold names the center +face of the back, and `(mountain)` makes it fold away from the viewer, +taking that face and the layers beneath it. Seen from the front, its crease +is a ridge. + +The two long points left standing are the *legs* of the bird base. Their +tips are the corners `.b` and `.d`. + +## Narrowing the legs + +Each of the two long points gets narrower by folding its outer edges onto +the center line, on the front and on the back. That is four folds, and each +has to move exactly one layer. + +::: {.figure #fig-crane-legs caption="The legs narrowed. The front edges fold as valleys (`--n1`, `--n2`), the back edges as mountains." views="cp folded" highlight="--n1 --n2" after="fig-crane-bird"} +.e1 = (--rsr & .b) * --pf +fold (map --rsr & .b onto --mid) (moving .e1) (up to #[.e1 .b .o]) as --n1 +.e2 = (--rsl & .d) * --pf +fold (map --rsl & .d onto --mid) (moving .e2) (up to #[.e2 .d .o]) as --n2 +.e3 = (--rbr & .b) * --pb +fold (map --rbr & .b onto --mid) (moving .e3) (up to #[.e3 .b .o]) (mountain) as --n3 +.e4 = (--rbl & .d) * --pb +fold (map --rbl & .d onto --mid) (moving .e4) (up to #[.e4 .d .o]) (mountain) as --n4 +::: + +`&` does the work here, as it picked the rays of the collapse on the first +page: it narrows a crease to one of its pieces. Once a crease has been +folded over, its scars point in different directions, and "the line of +`--rsr`" no longer names one line. +`--rsr & .b` is the piece of `--rsr` that touches `.b`: the outer edge of +the leg that ends in `.b`. That piece is straight, so it can be folded onto +`--mid`. + +Each fold names its side with `moving` on a point bound on the line before +it, `.e1` to `.e4`: the point where that edge meets the crease of the flap +it lies on. Its `up to` names the layer of the leg that holds that point, +the leg's tip and the paper center, so the valley fold takes the front +layer and nothing beneath it. Without `up to` the fold would take the back +layers too, because the edge runs through them as well. The two back folds +name the back layer and fold as mountains. + +## Neck and tail + +Each narrowed leg is inside reverse-folded, so that it turns up between the +layers of the body: one becomes the neck, the other the tail. + +::: {.figure #fig-crane-neck caption="The neck and the tail, each reversed about a line square to its narrowed edge." views="cp folded" highlight="--neck --tail" after="fig-crane-legs"} +reverse (perp --n1 through .sr) (moving .b) as --neck +reverse (perp --n2 through .sr) (moving .d) as --tail +::: + +A perpendicular moves nothing by itself, so unlike a `map`, it does not say +which side goes, and the reverse fold needs `(moving .b)`: the tip of the +leg that becomes the neck. + +## The head + +The last fold bends the tip of the neck into a head. Where exactly it bends +is a choice the folder makes by eye, and the program says so. + +::: {.figure #fig-crane-head caption="The finished crane. `.hp` is where the head bends, `.ht` sets its angle." views="cp folded" highlight=".hp .ht --head" after="fig-crane-neck"} +.hp = free on --bd & .b from .b at 1/4 +.ht = free on --rsl & .a from .a at 1/2 +reverse (through .hp .ht) (moving .b) as --head +::: + +`free on --bd & .b from .b at 1/4` names a spot a quarter of the way along +the piece of `--bd` that touches `.b`, counted from `.b`, measured on the +paper. As in the collapse on the first page, `free` records that the +position was a choice and follows from no construction; the program folds +with the point like with any other. Two such points pin down the line of +the head fold. + +## References diff --git a/notes/2026-06-28-2.md b/docs/notes/2026-06-28-2.md similarity index 96% rename from notes/2026-06-28-2.md rename to docs/notes/2026-06-28-2.md index 6464f8235..1199b7b23 100644 --- a/notes/2026-06-28-2.md +++ b/docs/notes/2026-06-28-2.md @@ -7,7 +7,7 @@ parses, evaluates (exact ℚ), planarizes, and emits valid FOLD. - Exact rational geometry (`zarith`): axiom 1 (`through`), axiom 2 (`fold .x to .y`), line intersection, clip-to-square, segment intersection; no float, no - epsilon ([ADR 0008](../decisions/0008-exact-rational-arithmetic.md)). + epsilon ([ADR 0008](../decision/0008-exact-rational-arithmetic.md)). - sedlex lexer + menhir grammar → AST with source spans; `Beloch.parse`. - `Eval`: name resolution (4 corners pre-bound), named/anonymous creases, derived `cross` points, precondition errors (identical points, parallel/off-paper diff --git a/notes/2026-06-28-3.md b/docs/notes/2026-06-28-3.md similarity index 100% rename from notes/2026-06-28-3.md rename to docs/notes/2026-06-28-3.md diff --git a/notes/2026-06-28-blog-tooling-design.md b/docs/notes/2026-06-28-blog-tooling-design.md similarity index 97% rename from notes/2026-06-28-blog-tooling-design.md rename to docs/notes/2026-06-28-blog-tooling-design.md index a70a59212..73b8e185f 100644 --- a/notes/2026-06-28-blog-tooling-design.md +++ b/docs/notes/2026-06-28-blog-tooling-design.md @@ -26,7 +26,7 @@ renderer (`beloch render` is a stub). ## Architecture -A small TypeScript edge tool (per [ADR 0001](../decisions/0001-ocaml-core-typescript-edge.md)), +A small TypeScript edge tool (per [ADR 0001](../decision/0001-ocaml-core-typescript-edge.md)), living at `tools/blog/`. One user-facing command, `build`, plus an internal `fold2svg` module. diff --git a/notes/2026-06-28.md b/docs/notes/2026-06-28.md similarity index 82% rename from notes/2026-06-28.md rename to docs/notes/2026-06-28.md index 2c9908786..00c471c38 100644 --- a/notes/2026-06-28.md +++ b/docs/notes/2026-06-28.md @@ -6,7 +6,7 @@ starting point. What got captured today: -- Seven decision records ([0001](../decisions/0001-ocaml-core-typescript-edge.md) to [0007](../decisions/0007-evaluator-not-compiler.md)) +- Seven decision records ([0001](../decision/0001-ocaml-core-typescript-edge.md) to [0007](../decision/0007-evaluator-not-compiler.md)) for everything already decided: OCaml core / TS edge, FOLD-extended output, restart-from-minimal-core, Menhir-then-Tree-sitter, the name Beloch, MIT license, evaluator-not-compiler + CLI shape. @@ -14,7 +14,7 @@ What got captured today: Hull and Zakharevich 2023, FOLD. - `antipatterns.md` seeded with the 2018 dead ends (layer-number heuristic, region/layer conflation, accumulate-then-formalize, "unique fold"). -- `spec/` and `paper/` README stubs with the planned shape. +- `docs/reference/` and `paper/` README stubs with the planned shape. - OCaml/dune/menhir project skeleton + a Nix flake devshell (`nix develop` / `direnv allow`). @@ -26,7 +26,7 @@ points), one type (crease line), output = list of creases as FOLD-extended. No layers, no folded state, no regions, no composition. Goal: `beloch fold` runs end-to-end on a one-line program. -Open question to chew on before writing `spec/10-core-v0.md`: what *exactly* is +Open question to chew on before writing `docs/reference/10-core-v0.md`: what *exactly* is the geometric state the evaluator threads through? For axiom 1 alone it's just "the paper polygon + a set of crease segments", but pinning the type now, even minimally, is the design. diff --git a/notes/2026-06-29-axiom3.md b/docs/notes/2026-06-29-axiom3.md similarity index 94% rename from notes/2026-06-29-axiom3.md rename to docs/notes/2026-06-29-axiom3.md index 85920a1d3..fc6ecf622 100644 --- a/notes/2026-06-29-axiom3.md +++ b/docs/notes/2026-06-29-axiom3.md @@ -17,7 +17,7 @@ with correct `axiom3` provenance. 30+ tests green; `nix build` green. ## Numbering correction -The previous journal note (`notes/2026-06-28-3.md`) called "axiom 3" the angle +The previous journal note (`docs/notes/2026-06-28-3.md`) called "axiom 3" the angle bisector (line onto line). Wrong. The authoritative table is [justin1986] §8.1: - **axiom 3** = operation ③ "perpendicular drawn from P to D": fold through a @@ -30,7 +30,7 @@ reference. Spec §1, §4.4, §6, and Appendix B updated accordingly. ## ADR 0008 stands -[ADR 0008](../decisions/0008-exact-rational-arithmetic.md) already states that ℚ +[ADR 0008](../decision/0008-exact-rational-arithmetic.md) already states that ℚ closes at axioms 1 and 2; §6 now extends the closed set to axioms 1, 2, and 3. The ADR's "closure breaks at axioms 5 and 6" is correct and unchanged: that is the angle bisector and the cubic, exactly as described. diff --git a/notes/2026-06-29-axiom5.md b/docs/notes/2026-06-29-axiom5.md similarity index 94% rename from notes/2026-06-29-axiom5.md rename to docs/notes/2026-06-29-axiom5.md index 6b2cfa023..45537cfb4 100644 --- a/notes/2026-06-29-axiom5.md +++ b/docs/notes/2026-06-29-axiom5.md @@ -23,7 +23,7 @@ Version bump to `0.3.0-dev`. ## Geometry core migration: `Q` → `Num` -`Num` (landed in the preceding slice, `notes/2026-06-29-num.md`) is a recursive +`Num` (landed in the preceding slice, `docs/notes/2026-06-29-num.md`) is a recursive tower of quadratic extensions over ℚ: `Rat of Q.t` at the base, `Ext(a, b, d)` = a + b√d above it. The geometry migration is a type-level substitution: all `Q.t` scalars become `Num.t`. The existing tests serve as the @@ -57,5 +57,5 @@ Before the axiom 6 or 7 slice, check the numbering against [[justin1986]] §8.1. The cubic fold is Justin's operation ⑦ (the Beloch fold proper: fold two points onto two lines simultaneously). Current project ADRs say "axiom 6" for the cubic; if Justin's ⑥ is something else, the ADRs and spec will need a correction pass -before that code lands. The axiom-3/5 mislabel from `notes/2026-06-28-3.md` is +before that code lands. The axiom-3/5 mislabel from `docs/notes/2026-06-28-3.md` is a proof that this is worth checking early. diff --git a/notes/2026-06-29-crease-names.md b/docs/notes/2026-06-29-crease-names.md similarity index 100% rename from notes/2026-06-29-crease-names.md rename to docs/notes/2026-06-29-crease-names.md diff --git a/notes/2026-06-29-num.md b/docs/notes/2026-06-29-num.md similarity index 100% rename from notes/2026-06-29-num.md rename to docs/notes/2026-06-29-num.md diff --git a/notes/2026-06-30-axiom4.md b/docs/notes/2026-06-30-axiom4.md similarity index 100% rename from notes/2026-06-30-axiom4.md rename to docs/notes/2026-06-30-axiom4.md diff --git a/notes/2026-06-30-axiom6.md b/docs/notes/2026-06-30-axiom6.md similarity index 94% rename from notes/2026-06-30-axiom6.md rename to docs/notes/2026-06-30-axiom6.md index 0a142a266..0501e445f 100644 --- a/notes/2026-06-30-axiom6.md +++ b/docs/notes/2026-06-30-axiom6.md @@ -10,7 +10,7 @@ Beloch follows strict Justin numbering (verified against the §8.1 table in `refs/justin1986.md`: axioms 1–5 = Justin ① to ⑤). Hence **axiom 6 = Justin ⑥** `(P → D, P' → P')`, the **second-degree** operation (0/1/2 solutions). The project's earlier shorthand ("axiom 6 = the cubic") conflated ⑥ with ⑦ and was -wrong; the warning in `notes/2026-06-29-axiom5.md` was right. The cubic Beloch +wrong; the warning in `docs/notes/2026-06-29-axiom5.md` was right. The cubic Beloch fold is Justin ⑦ → Beloch **axiom 7**, a future slice needing a real-algebraic number kernel (cube roots; casus irreducibilis defeats real radicals). diff --git a/notes/2026-06-30-axiom7.md b/docs/notes/2026-06-30-axiom7.md similarity index 100% rename from notes/2026-06-30-axiom7.md rename to docs/notes/2026-06-30-axiom7.md diff --git a/notes/2026-06-30-real-algebraic-kernel.md b/docs/notes/2026-06-30-real-algebraic-kernel.md similarity index 100% rename from notes/2026-06-30-real-algebraic-kernel.md rename to docs/notes/2026-06-30-real-algebraic-kernel.md diff --git a/notes/2026-06-30-shared-field-rur.md b/docs/notes/2026-06-30-shared-field-rur.md similarity index 100% rename from notes/2026-06-30-shared-field-rur.md rename to docs/notes/2026-06-30-shared-field-rur.md diff --git a/notes/2026-07-03-33-verdict.md b/docs/notes/2026-07-03-33-verdict.md similarity index 98% rename from notes/2026-07-03-33-verdict.md rename to docs/notes/2026-07-03-33-verdict.md index ce0efda43..4631bb4b5 100644 --- a/notes/2026-07-03-33-verdict.md +++ b/docs/notes/2026-07-03-33-verdict.md @@ -32,7 +32,7 @@ combinatorial blowup, not a hang). ADR 0012's scaling concern is only **partially** addressed by ADR 0013, and not where #33 lives. ADR 0013 replaced `Num`'s raw arithmetic (`add`/`mul`/`div`/`sqrt`/`compare`) with FLINT `qqbar`, which is -fast (the spike note `notes/2026-07-03-flint-kernel-spike.md` measured +fast (the spike note `docs/notes/2026-07-03-flint-kernel-spike.md` measured sub-millisecond ops even at degree 27). But `Num.real_roots` (the routine `Geom.beloch7_creases` calls to solve axiom 7's cubic `F(t)`) only uses that fast path when every coefficient is already rational (`lib/num.ml:349-357`). @@ -242,7 +242,7 @@ full suite green, incl. a new sub-second regression test for the ## Update (2026-07-03): primitive-element tier landed `Num.real_roots` now has a Tier-3 primitive-element path (spec + spike: -`notes/2026-07-03-calcium-pe-spike.md`). Coefficients spanning a compositum of +`docs/notes/2026-07-03-calcium-pe-spike.md`). Coefficients spanning a compositum of independent folds are expressed over one generator γ (FLINT `qqbar_express_in_field`) and eliminated with a single `R = Res_x(μ_γ, F̃)` of degree `3·[ℚ(γ):ℚ]`. @@ -256,7 +256,7 @@ through the tier and verify exactly. **Estimated, not yet directly benchmarked through the landed path:** the #33 round-4 tripling-stack case (coefficients over a degree-9 field), previously `>300s killed`, is projected at ~0.5–2s from the spike's degree-scaling curve -(`notes/2026-07-03-calcium-pe-spike.md`). That spike measured a *doubling* +(`docs/notes/2026-07-03-calcium-pe-spike.md`). That spike measured a *doubling* stack via a standalone script, so the figure is an extrapolation to the *tripling* round-4 case, not a direct measurement. On that basis the interactive stacked-cubic ceiling is expected to move from round 3 to ~round 5; diff --git a/notes/2026-07-03-calcium-pe-spike.md b/docs/notes/2026-07-03-calcium-pe-spike.md similarity index 100% rename from notes/2026-07-03-calcium-pe-spike.md rename to docs/notes/2026-07-03-calcium-pe-spike.md diff --git a/notes/2026-07-03-crease-layer-selection.md b/docs/notes/2026-07-03-crease-layer-selection.md similarity index 100% rename from notes/2026-07-03-crease-layer-selection.md rename to docs/notes/2026-07-03-crease-layer-selection.md diff --git a/notes/2026-07-03-crease-segment-at-operator.md b/docs/notes/2026-07-03-crease-segment-at-operator.md similarity index 100% rename from notes/2026-07-03-crease-segment-at-operator.md rename to docs/notes/2026-07-03-crease-segment-at-operator.md diff --git a/notes/2026-07-03-flint-kernel-spike.md b/docs/notes/2026-07-03-flint-kernel-spike.md similarity index 100% rename from notes/2026-07-03-flint-kernel-spike.md rename to docs/notes/2026-07-03-flint-kernel-spike.md diff --git a/notes/2026-07-03-fold-sim-dof.md b/docs/notes/2026-07-03-fold-sim-dof.md similarity index 100% rename from notes/2026-07-03-fold-sim-dof.md rename to docs/notes/2026-07-03-fold-sim-dof.md diff --git a/notes/2026-07-03.md b/docs/notes/2026-07-03.md similarity index 100% rename from notes/2026-07-03.md rename to docs/notes/2026-07-03.md diff --git a/notes/2026-07-05-axiom5-paper-incidence.md b/docs/notes/2026-07-05-axiom5-paper-incidence.md similarity index 97% rename from notes/2026-07-05-axiom5-paper-incidence.md rename to docs/notes/2026-07-05-axiom5-paper-incidence.md index 0d77efd0b..be3e2a410 100644 --- a/notes/2026-07-05-axiom5-paper-incidence.md +++ b/docs/notes/2026-07-05-axiom5-paper-incidence.md @@ -78,6 +78,6 @@ When axiom 5 yields two bisectors and `toward` is omitted: ## Spec impact -`spec/SPECIFICATION.md` §5 (axiom 5 solutions/`toward`, ~lines 186–192) and +`docs/reference/SPECIFICATION.md` §5 (axiom 5 solutions/`toward`, ~lines 186–192) and the error catalog (~line 686) need the filter step and the new zero-candidate error. diff --git a/notes/2026-07-05-cross-material-paper-space.md b/docs/notes/2026-07-05-cross-material-paper-space.md similarity index 97% rename from notes/2026-07-05-cross-material-paper-space.md rename to docs/notes/2026-07-05-cross-material-paper-space.md index cd738decd..cf53d030b 100644 --- a/notes/2026-07-05-cross-material-paper-space.md +++ b/docs/notes/2026-07-05-cross-material-paper-space.md @@ -54,5 +54,5 @@ Table space survives *only* as transient geometry inside axiom evaluation precrease. Spec: §4.3 rewritten, §4.8/§5a.3/§8 touched. See also -`notes/2026-07-03-crease-layer-selection.md` ("all points are material") and +`docs/notes/2026-07-03-crease-layer-selection.md` ("all points are material") and ADR 0014/0016. diff --git a/notes/2026-07-05-toward-direction-semantics.md b/docs/notes/2026-07-05-toward-direction-semantics.md similarity index 100% rename from notes/2026-07-05-toward-direction-semantics.md rename to docs/notes/2026-07-05-toward-direction-semantics.md diff --git a/notes/2026-07-06-fold-as-operation-sequence.md b/docs/notes/2026-07-06-fold-as-operation-sequence.md similarity index 100% rename from notes/2026-07-06-fold-as-operation-sequence.md rename to docs/notes/2026-07-06-fold-as-operation-sequence.md diff --git a/notes/2026-07-06-fold-history-as-diff.md b/docs/notes/2026-07-06-fold-history-as-diff.md similarity index 100% rename from notes/2026-07-06-fold-history-as-diff.md rename to docs/notes/2026-07-06-fold-history-as-diff.md diff --git a/notes/2026-07-08-partial-creases-and-rational-landmarks.md b/docs/notes/2026-07-08-partial-creases-and-rational-landmarks.md similarity index 97% rename from notes/2026-07-08-partial-creases-and-rational-landmarks.md rename to docs/notes/2026-07-08-partial-creases-and-rational-landmarks.md index 536579912..3496357a6 100644 --- a/notes/2026-07-08-partial-creases-and-rational-landmarks.md +++ b/docs/notes/2026-07-08-partial-creases-and-rational-landmarks.md @@ -13,7 +13,7 @@ that starts and stops without spanning a whole face. **Under the law:** it scores paper → keyword verb. No notation question. **The catch:** this is exactly the "non-splitting reference edge" that the `pinch` -design *rejected* (`notes/2026-07-03-crease-layer-selection.md`, *Resolved* §3): an +design *rejected* (`docs/notes/2026-07-03-crease-layer-selection.md`, *Resolved* §3): an edge that is not a face boundary breaks the every-edge-is-a-face-boundary invariant (#26), and `pinch` chose full-chord subdivision precisely to keep that invariant intact. Hence partial creases **reopen** that rejected option and must pay diff --git a/notes/2026-07-15-folded-state-invariants-review.md b/docs/notes/2026-07-15-folded-state-invariants-review.md similarity index 100% rename from notes/2026-07-15-folded-state-invariants-review.md rename to docs/notes/2026-07-15-folded-state-invariants-review.md diff --git a/notes/2026-07-17-flatten-parity-origin.md b/docs/notes/2026-07-17-flatten-parity-origin.md similarity index 100% rename from notes/2026-07-17-flatten-parity-origin.md rename to docs/notes/2026-07-17-flatten-parity-origin.md diff --git a/notes/2026-07-20-default-fold-scope.md b/docs/notes/2026-07-20-default-fold-scope.md similarity index 100% rename from notes/2026-07-20-default-fold-scope.md rename to docs/notes/2026-07-20-default-fold-scope.md diff --git a/notes/2026-07-20-pinch-retired.md b/docs/notes/2026-07-20-pinch-retired.md similarity index 95% rename from notes/2026-07-20-pinch-retired.md rename to docs/notes/2026-07-20-pinch-retired.md index 269f08492..e10fb8517 100644 --- a/notes/2026-07-20-pinch-retired.md +++ b/docs/notes/2026-07-20-pinch-retired.md @@ -25,7 +25,7 @@ language changes that between them cover its use case: ## Edits made -- `spec/SPECIFICATION.md` §4.8, §4.10 (the landmark-interim paragraph), and +- `docs/reference/SPECIFICATION.md` §4.8, §4.10 (the landmark-interim paragraph), and Appendix B: dropped the "forthcoming `pinch`" promises, redirected to the partial mark. Header l.49 already framed v0.22 as "partial marks: the pinch"; left as-is. diff --git a/notes/2026-09-10-crane-path-reordered.md b/docs/notes/2026-09-10-crane-path-reordered.md similarity index 98% rename from notes/2026-09-10-crane-path-reordered.md rename to docs/notes/2026-09-10-crane-path-reordered.md index 0cb45a53f..fdcd73f9e 100644 --- a/notes/2026-09-10-crane-path-reordered.md +++ b/docs/notes/2026-09-10-crane-path-reordered.md @@ -122,7 +122,7 @@ from memory. [ida2020, Fig. 7.19]. Fisher takes edges plus a held face. Beloch has motion × disposition × extent; the open question is whether `fold …` with a scope that crosses a folded edge is enough, or whether the reverse needs its - own verb or a `flatten` item. `notes/ideas.md` and Appendix B list named + own verb or a `flatten` item. `docs/notes/ideas.md` and Appendix B list named maneuvers as sugar over `unfold` plus layer selection; the Eos route makes the reverse fold the first sugar to land, before `unfold`. - **Exactness.** The bird-base reverse folds carry $\sqrt{2}$ coordinates diff --git a/notes/2026-09-12-bird-base-oracle.md b/docs/notes/2026-09-12-bird-base-oracle.md similarity index 100% rename from notes/2026-09-12-bird-base-oracle.md rename to docs/notes/2026-09-12-bird-base-oracle.md diff --git a/notes/2026-09-14-assertions-as-statements.md b/docs/notes/2026-09-14-assertions-as-statements.md similarity index 94% rename from notes/2026-09-14-assertions-as-statements.md rename to docs/notes/2026-09-14-assertions-as-statements.md index 9a94e1580..29785ccf9 100644 --- a/notes/2026-09-14-assertions-as-statements.md +++ b/docs/notes/2026-09-14-assertions-as-statements.md @@ -31,7 +31,7 @@ not a refactor of the test harness; the harness shrinking is a consequence. alternative was to make it general: `faces` as an expression anywhere, `paper` and `table` as spaces any point expression can be read in, incidence as a predicate of the language. That would give Beloch a second half, one that -talks about results rather than constructing them, and `spec/MODEL.md` would +talks about results rather than constructing them, and `docs/reference/MODEL.md` would have to carry it. The gain did not justify that. Operands are the exception and get richer at no extra cost: as a statement, `assert` @@ -75,9 +75,9 @@ nothing asks for one yet. - What remains of `bel_assert.ml` once extraction and tokenizing are gone, and whether the checking belongs in the evaluator (an assertion is evaluated) or stays beside the runners. -- Whether `spec/MODEL.md` §5 has to name a judgment alongside its operations, +- Whether `docs/reference/MODEL.md` §5 has to name a judgment alongside its operations, given that every operation there produces state and an assertion does not. -- The migration: 89 corpus files, the tagged blocks in `spec/BELOCH.md`, the +- The migration: 89 corpus files, the tagged blocks in `docs/reference/BELOCH.md`, the tree-sitter grammar, the highlighting queries and the three runners. ## Sequencing diff --git a/notes/2026-09-17-model-tour-renderer.md b/docs/notes/2026-09-17-model-tour-renderer.md similarity index 96% rename from notes/2026-09-17-model-tour-renderer.md rename to docs/notes/2026-09-17-model-tour-renderer.md index 9d0135f45..d59c790ea 100644 --- a/notes/2026-09-17-model-tour-renderer.md +++ b/docs/notes/2026-09-17-model-tour-renderer.md @@ -44,7 +44,7 @@ Most of the machinery is in the repository: SVG in both directions, with a palette for multi-selection. - `@beloch/render-svg` renders folded frames with layer occlusion from `faceOrders`, so $\lambda$ is already in the renderer. -- The model page is generated from `spec/MODEL.md` by a plugin that turns +- The model page is generated from `docs/reference/MODEL.md` by a plugin that turns the `{.definition #id ...}` blocks into numbered, cross-referenced sections. The attribute syntax is a natural place for a "what to show" annotation, should the tour live in the spec page. @@ -92,7 +92,7 @@ follows the model review and changes with it. Not decided, deliberately. Two candidates: -- Inside the page generated from `spec/MODEL.md`, with the annotations in the +- Inside the page generated from `docs/reference/MODEL.md`, with the annotations in the definition blocks. Keeps text and picture together; puts presentation attributes into the specification document. - A separate page, possibly the Getting Started page itself, that quotes the diff --git a/notes/2026-09-25-crane-oracle.md b/docs/notes/2026-09-25-crane-oracle.md similarity index 100% rename from notes/2026-09-25-crane-oracle.md rename to docs/notes/2026-09-25-crane-oracle.md diff --git a/notes/2026-09-25-primitive-ladder.md b/docs/notes/2026-09-25-primitive-ladder.md similarity index 98% rename from notes/2026-09-25-primitive-ladder.md rename to docs/notes/2026-09-25-primitive-ladder.md index eaf950409..fc75025f2 100644 --- a/notes/2026-09-25-primitive-ladder.md +++ b/docs/notes/2026-09-25-primitive-ladder.md @@ -114,7 +114,7 @@ included; Eos executes named maneuvers as fixed commands. The same move happened at the construction level. The seven Huzita-Justin axioms are instances of alignment sets (ADR 0022, [alperin2006, §3]); the rung-3 maneuvers are instances of a flat-foldable fan ([hull2020, ch. 5], -`spec/MODEL.md`, definition of `flatten`). Both levels replace a list of +`docs/reference/MODEL.md`, definition of `flatten`). Both levels replace a list of named operations by the mathematical object the list enumerates. On provenance: `flatten` was generalized in July 2026, and Fisher entered the diff --git a/notes/README.md b/docs/notes/README.md similarity index 86% rename from notes/README.md rename to docs/notes/README.md index 162102c51..215adbc9a 100644 --- a/notes/README.md +++ b/docs/notes/README.md @@ -8,5 +8,5 @@ motivation section will need. Filename: `YYYY-MM-DD.md` (multiple entries per day → append, or `-2` suffix). -Keep it informal. Link to decisions (`../decisions/NNNN-*.md`), examples, and +Keep it informal. Link to decisions (`../decision/NNNN-*.md`), examples, and dead ends (`../antipatterns.md`) liberally. diff --git a/notes/antipatterns.md b/docs/notes/antipatterns.md similarity index 95% rename from notes/antipatterns.md rename to docs/notes/antipatterns.md index 8e9342abe..ec21480da 100644 --- a/notes/antipatterns.md +++ b/docs/notes/antipatterns.md @@ -5,7 +5,7 @@ research artifact: when you're stuck in eight months thinking "what if we just check here first. Raw material for the paper's design-discussion section. Append ruthlessly: a dead end recorded is a dead end you don't walk twice. -(For forward-looking decisions, see `decisions/`. This file is for what *didn't* +(For forward-looking decisions, see `docs/decision/`. This file is for what *didn't* work, including things inherited as warnings from the 2018 attempt.) ## Inherited from the 2018 design (OrigamiDL) @@ -26,7 +26,7 @@ work, including things inherited as warnings from the 2018 attempt.) `#region` to do both. We likely need both concepts, kept distinct. - **Accumulate features until expressive, then formalize.** This is how the 2018 design hit mutual inconsistency at the layer problem and stalled. Replaced by - the minimal-formal-core approach (see decisions/0003-restart-from-minimal-core.md). + the minimal-formal-core approach (see docs/decision/0003-restart-from-minimal-core.md). - **"The fold is unique" (from the axiom phrasing).** False in general: axioms 5 and 6 have up to 2 solutions, axiom 7 up to 3. Disambiguation must be first-class and ergonomic, not an afterthought. @@ -48,7 +48,7 @@ work, including things inherited as warnings from the 2018 attempt.) (Beloch axiom 4). Translate before comparing any Eos construction with a `.bel` program. - **ℚ stops being closed at axioms 5, 6 and 7.** Exact rational arithmetic - ([ADR 0008](../decisions/0008-exact-rational-arithmetic.md)) covers axioms 1–2 + ([ADR 0008](../decision/0008-exact-rational-arithmetic.md)) covers axioms 1–2 and line intersection perfectly, but square roots (axioms 5 and 6) and cubic roots (axiom 7) leave ℚ. Don't assume the rational engine extends to the full axiom set; that boundary needs a constructible/algebraic number representation, @@ -92,7 +92,7 @@ _(none yet; append as they happen)_ ## Axiom 3 is the perpendicular-through-a-point, not the angle bisector -An early journal note (`notes/2026-06-28-3.md`) labeled "axiom 3" as the +An early journal note (`docs/notes/2026-06-28-3.md`) labeled "axiom 3" as the angle bisector (line onto line). That is wrong. The authoritative classic table is [justin1986] §8.1: operation ③ `(P → P, D → D)` is "perpendicular drawn from P to D": the fold through a point perpendicular to a line (Hull's O5). The angle @@ -143,7 +143,7 @@ material.** Gospel writes a formal contract into the `.mli` as `(*@ requires / ensures *)` annotations; Ortac compiles that contract into runtime assertions and, via the `qcheck-stm` plugin, into a generated model-based test harness. The attraction -was placement: `spec/KERNEL.md` already pulls its content out of +was placement: `docs/reference/KERNEL.md` already pulls its content out of `fold_state.mli` through odoc, so the contract would live where the interface lives. @@ -196,7 +196,7 @@ line is a legal program that evaluates, and then both report the same line, so the key identifies nothing. Fix: the emitter names the statement itself, as an index into -`beloch:statements` (`beloch:edges[i].statement`; see `spec/FOLD.md`). The +`beloch:statements` (`beloch:edges[i].statement`; see `docs/reference/FOLD.md`). The name lookup was deleted rather than repaired. Rules of thumb since: a join key has to be unique under the grammar, and the diff --git a/notes/ideas.md b/docs/notes/ideas.md similarity index 100% rename from notes/ideas.md rename to docs/notes/ideas.md diff --git a/spec/BELOCH-ANNOTATIONS.md b/docs/reference/BELOCH-ANNOTATIONS.md similarity index 100% rename from spec/BELOCH-ANNOTATIONS.md rename to docs/reference/BELOCH-ANNOTATIONS.md diff --git a/spec/BELOCH-CONSTRUCTIONS.md b/docs/reference/BELOCH-CONSTRUCTIONS.md similarity index 100% rename from spec/BELOCH-CONSTRUCTIONS.md rename to docs/reference/BELOCH-CONSTRUCTIONS.md diff --git a/spec/BELOCH-GRAMMAR.md b/docs/reference/BELOCH-GRAMMAR.md similarity index 100% rename from spec/BELOCH-GRAMMAR.md rename to docs/reference/BELOCH-GRAMMAR.md diff --git a/spec/BELOCH-WRITES.md b/docs/reference/BELOCH-WRITES.md similarity index 100% rename from spec/BELOCH-WRITES.md rename to docs/reference/BELOCH-WRITES.md diff --git a/spec/BELOCH.md b/docs/reference/BELOCH.md similarity index 100% rename from spec/BELOCH.md rename to docs/reference/BELOCH.md diff --git a/spec/CLI-STAGES.md b/docs/reference/CLI-STAGES.md similarity index 100% rename from spec/CLI-STAGES.md rename to docs/reference/CLI-STAGES.md diff --git a/spec/CLI.md b/docs/reference/CLI.md similarity index 100% rename from spec/CLI.md rename to docs/reference/CLI.md diff --git a/spec/FOLD.md b/docs/reference/FOLD.md similarity index 100% rename from spec/FOLD.md rename to docs/reference/FOLD.md diff --git a/spec/KERNEL.md b/docs/reference/KERNEL.md similarity index 100% rename from spec/KERNEL.md rename to docs/reference/KERNEL.md diff --git a/spec/MODEL.md b/docs/reference/MODEL.md similarity index 99% rename from spec/MODEL.md rename to docs/reference/MODEL.md index 098dd517f..de16a5ea4 100644 --- a/spec/MODEL.md +++ b/docs/reference/MODEL.md @@ -1008,7 +1008,7 @@ state, a write yields two states with a common refinement, so it induces a map there, and a score induces the identity while an effective write does not. The text argues the intuition for scoring below, that a write may score every face its axis crosses because scoring changes nothing, and -`spec/KERNEL.md` records that the representation does not quotient. The +`docs/reference/KERNEL.md` records that the representation does not quotient. The statement is not proved here, and nothing in the model rests on it. ::: diff --git a/spec/README.md b/docs/reference/README.md similarity index 91% rename from spec/README.md rename to docs/reference/README.md index 0bbdf65cd..72c03c259 100644 --- a/spec/README.md +++ b/docs/reference/README.md @@ -28,9 +28,9 @@ the surface syntax until it moves, never for the meaning. Division of artifacts: -- **`spec/`**: *what* the language is, and how the reference implementation +- **`docs/reference/`**: *what* the language is, and how the reference implementation realizes it. Durable source of truth. -- **`../decisions/`** (ADRs): *why* a choice was made. Point-in-time. +- **`docs/decision/`** (ADRs): *why* a choice was made. Point-in-time. - **Design documents** (per slice, disposable): *how* a slice is built. They are obsolete once the slice has landed and the documents here reflect it, and they are not kept in the working tree; the Git history holds them. diff --git a/spec/SPECIFICATION.md b/docs/reference/SPECIFICATION.md similarity index 98% rename from spec/SPECIFICATION.md rename to docs/reference/SPECIFICATION.md index 9b25a1005..77b624bf4 100644 --- a/spec/SPECIFICATION.md +++ b/docs/reference/SPECIFICATION.md @@ -6,7 +6,7 @@ and not a design doc. - Each section is tagged with the version it was introduced in, e.g. *(since v0.0)*. - **What**, not **why** or **how**: rationale for a choice lives in an ADR - (`../decisions/`); how a slice is built lives in its (disposable) implementation + (`../decision/`); how a slice is built lives in its (disposable) implementation plan. This file is the durable source of truth for syntax, semantics, and the output contract. - Citations are clickable links to the [References](#references) section below; @@ -37,7 +37,7 @@ by several flaps seeds the whole contiguous run; `moving` now names the **deepest** flap of that prefix; a bare axiom-5 line-onto-line fold with no `moving` and no implied point still falls back to the all-layers set; `up to` is unchanged as the interim way to fold past the anchor flap; see -[`notes/2026-07-20-default-fold-scope.md`](../notes/2026-07-20-default-fold-scope.md)); +[`docs/notes/2026-07-20-default-fold-scope.md`](../notes/2026-07-20-default-fold-scope.md)); **v0.23-dev** (**`flatten` generalizes `collapse`, one solver pipeline, stayer convention** — single-vertex flat-folding is renamed `flatten`. Every statement runs one pipeline, no modes: `()` items state the @@ -88,7 +88,7 @@ selectors `.[] --[] #[]`), the one write was the keyword `through`); Beloch is a declarative language for origami. A `.bel` program is **evaluated** (not compiled to an executable) into a data artifact describing a paper state, -emitted as FOLD. See [ADR 0007](../decisions/0007-evaluator-not-compiler.md). +emitted as FOLD. See [ADR 0007](../decision/0007-evaluator-not-compiler.md). The language is built on the Huzita-Justin fold axioms [[justin1986]](#ref-justin1986), using them as primitive operations. *(since @@ -99,7 +99,7 @@ marking/folding actions on a stateful sheet (§4.6). The axioms (`map`, state, emitted as a dual-frame FOLD file — the flat **crease pattern** and the **folded form** (§7). The flat crease pattern (a program with no `fold` actions) is the special case. -See [ADR 0011](../decisions/0011-action-model.md). +See [ADR 0011](../decision/0011-action-model.md). ### A note on axiom numbering @@ -207,7 +207,7 @@ The meet is computed in **paper space**: a crease is a scar in the material, and two scars cross or miss each other independently of how the sheet happens to be folded. There are no table-space point values in the language. Paper is opaque, so layers that only overlap on the table show no crossing: no layer -carries both marks. (`Q2-B` in `notes/antipatterns.md` records the table-space +carries both marks. (`Q2-B` in `docs/notes/antipatterns.md` records the table-space rule this avoids.) The meet is the **intersection of the operands as sets of paper points**, @@ -560,10 +560,10 @@ Non-moving layers keep their flat crease mark (`"F"` in FOLD output, §7, since v0.21-dev — was `"U"` before); moving ones fold (their mark upgrades to `"M"`/`"V"`). -See [ADR 0016](../decisions/0016-typed-operands-bundle-values-singleton-slots.md) +See [ADR 0016](../decision/0016-typed-operands-bundle-values-singleton-slots.md) (typed operands: bundle values vs. singleton slots — the resolution rules behind `moving`, `up to`, and `#[...]`) and -[ADR 0014](../decisions/0014-crease-is-a-bundle-of-segments.md) (a crease is a +[ADR 0014](../decision/0014-crease-is-a-bundle-of-segments.md) (a crease is a bundle of segments — why folding along existing material checks for a bent crease and why `&` selection exists). @@ -960,9 +960,9 @@ at all: two of the fish-base vertex's three given rays are pinned explicitly, narrowing the Maekawa search until exactly one realization survives before selection is ever reached. -See [ADR 0016](../decisions/0016-typed-operands-bundle-values-singleton-slots.md) +See [ADR 0016](../decision/0016-typed-operands-bundle-values-singleton-slots.md) (flap operands), -[ADR 0014](../decisions/0014-crease-is-a-bundle-of-segments.md) (crease +[ADR 0014](../decision/0014-crease-is-a-bundle-of-segments.md) (crease bundles, rays split at a crossing — the same machinery `fold` and `&` build on, and what the emergent crease's bundle joins), and ADR 0012/0013 (the exact real-algebraic kernel the derive math needed no polynomial from, @@ -1362,7 +1362,7 @@ the first matching error wins and the process exits non-zero: The Menhir grammar is authoritative once written; this sketch is a guide. ```grammar -program := "paper" sheet stmt* ; spec/BELOCH-GRAMMAR.md, "Programs" +program := "paper" sheet stmt* ; docs/reference/BELOCH-GRAMMAR.md, "Programs" stmt := crease_stmt | point_stmt | flip_stmt | flatten_stmt | def_stmt | instance_stmt | apply_stmt | export_stmt ; since v0.16-dev crease_stmt := CREASE_NAME "=" "(" axiom ")" ; a read — binds a line value, scores nothing @@ -1382,11 +1382,11 @@ item_body := markable | "between" point_operand point_operand ; mark only | "at" point_operand ; mark only markable := axiom | align | line_operand ; since v0.21-dev; align since v0.23-dev -align := "align" CREASE_NAME* align_part+ ; see spec/BELOCH-CONSTRUCTIONS.md; `toward` and `moving` are items there +align := "align" CREASE_NAME* align_part+ ; see docs/reference/BELOCH-CONSTRUCTIONS.md; `toward` and `moving` are items there output := [ "as" CREASE_NAME [ "!" ] | "into" CREASE_NAME ] point_stmt := POINT_NAME "=" line_operand "*" line_operand ; meet (binary), bare at a binding's RHS: the point where two lines cross | POINT_NAME "=" ".[" line_operand+ "]" ; meet (n-ary): the point on all listed lines - | POINT_NAME "=" free_point ; free point: spec/BELOCH-GRAMMAR.md, "Free points" + | POINT_NAME "=" free_point ; free point: docs/reference/BELOCH-GRAMMAR.md, "Free points" flip_stmt := "flip" axiom := "through" point_operand point_operand ; axiom 1 — a read (construction, since v0.21-dev) | "map" point_operand "onto" point_operand ; axiom 2 @@ -1491,7 +1491,7 @@ folded-state runtime, derived mountain/valley, the dual `creasePattern` + `foldedForm` FOLD output, `flip`, and inline anonymous read operands (`.a * .b` join / `--x * --y` meet — spelled `--(.a .b)` / `.(--a --b)` before the v0.20-dev cutover). See -[ADR 0011](../decisions/0011-action-model.md). Mountain/valley is *derived* from +[ADR 0011](../decision/0011-action-model.md). Mountain/valley is *derived* from fold actions, not a separate annotation pass. *(v0.8-dev)* axiom 6 — fold a point onto a line with the crease through a fixed point (`map .p onto --d through .p'`, optional `toward` for disambiguation). *(v0.9-dev)* axiom 7 — the cubic diff --git a/examples/crane.bel b/examples/crane.bel index 348a9be95..4e736dd7c 100644 --- a/examples/crane.bel +++ b/examples/crane.bel @@ -6,7 +6,7 @@ ; bird base of packages/core/tests/cases/bases/bird-base.bel (Ida's steps 2-8), then her ; steps 9-17. Her steps 18 and 19 open the wings, which is 3D and out of ; scope (ADR 0015). Checked against her figures in -; notes/2026-09-25-crane-oracle.md. +; docs/notes/2026-09-25-crane-oracle.md. paper square diff --git a/examples/syntax/README.md b/examples/syntax/README.md index 183c353e4..80d35f3e1 100644 --- a/examples/syntax/README.md +++ b/examples/syntax/README.md @@ -10,7 +10,7 @@ assertions instead. Many of these will be ports of the 2018 issue examples (crane, bookmark, triangular dipyramid), used as the test suite that the ground-up core has to recover, not as design input (see -[decision 0003](../../decisions/0003-restart-from-minimal-core.md)). +[decision 0003](../../docs/decision/0003-restart-from-minimal-core.md)). The tell for success: the preliminary base, bird base, frog base, and a traditional crane all express cleanly and emit YR diagrams end-to-end. diff --git a/flake.nix b/flake.nix index 3bbbe1246..87012f61b 100644 --- a/flake.nix +++ b/flake.nix @@ -138,7 +138,7 @@ pkgs.bun # msolve subprocess driver (separate research package) pkgs.msolve - # spec/MODEL.md -> PDF with citations from bibliography/references.bib + # docs/reference/MODEL.md -> PDF with citations from bibliography/references.bib # (scripts/render-model.sh); typst is pandoc's PDF engine here pkgs.pandoc pkgs.typst diff --git a/packages/core/bench/README.md b/packages/core/bench/README.md index 7ffc2c7cf..a67f8f16d 100644 --- a/packages/core/bench/README.md +++ b/packages/core/bench/README.md @@ -70,7 +70,7 @@ stacked:6 16 6.600s 0.379 1.004 (48) 0.005 5.259 3 ← stacked:7 32 WALLS (intrinsic 3·d³ growth) ``` -Optimization targets (see `notes/2026-07-03-calcium-pe-spike.md`): +Optimization targets (see `docs/notes/2026-07-03-calcium-pe-spike.md`): 1. **resultant**: ✅ DONE. `Mpoly.resultant` → univariate eval-interpolation in t (`Poly.resultant` per sample, sampled only where `F̃(t_j)` keeps full formal x-degree). Measured **10.08s → 1.00s** on `stacked:6`; total 15.8s → 6.8s. diff --git a/packages/core/bin/main.ml b/packages/core/bin/main.ml index 480d3b073..0451a3df5 100644 --- a/packages/core/bin/main.ml +++ b/packages/core/bin/main.ml @@ -52,7 +52,7 @@ let eval_bel_file file = beloch-render's stdin over a real Unix.pipe. *) let eval_to_fold_json file = Yojson.Safe.to_string (eval_bel_file file) -(* A .bel file evaluated with its trace (spec/FOLD.md, "The trace"). A +(* A .bel file evaluated with its trace (docs/reference/FOLD.md, "The trace"). A program that fails still yields the file up to the failing statement; the diagnostic goes to stderr and [true] says it failed. *) let eval_bel_file_traced file = @@ -162,7 +162,7 @@ let run_fold file = print_endline (Yojson.Safe.pretty_to_string (eval_bel_file file)) (* `beloch fold --trace FILE`: the FOLD with every construction's candidates - (spec/FOLD.md, "The trace"). A program that fails still prints the file up + (docs/reference/FOLD.md, "The trace"). A program that fails still prints the file up to the failing statement, then the diagnostic, and exits 1. *) let run_fold_trace file = let json, failed = eval_bel_file_traced file in diff --git a/packages/core/lib/action.mli b/packages/core/lib/action.mli index 0ef3e0775..a066a59b3 100644 --- a/packages/core/lib/action.mli +++ b/packages/core/lib/action.mli @@ -26,18 +26,18 @@ val eval_mark : Error.span -> unit (** Evaluate a `mark` statement: record a crease without moving paper - (spec/BELOCH-WRITES.md). *) + (docs/reference/BELOCH-WRITES.md). *) val eval_fold : Ctx.ctx -> Ast.output -> Ast.markable -> Ast.fold_spec -> Error.span -> unit (** Evaluate a `fold` statement: reflect the moving flaps over the axis and - advance the fold state (spec/MODEL.md, def-fold). *) + advance the fold state (docs/reference/MODEL.md, def-fold). *) val eval_unfold : Ctx.ctx -> Ast.line_operand -> Ast.fold_spec -> Error.span -> unit (** Evaluate an `unfold` statement: turn the selected layers over a line that every one of them lies on one side of, opening the folded hinges on - it between them and the layers that stay (spec/MODEL.md, def-fold; + it between them and the layers that stay (docs/reference/MODEL.md, def-fold; ADR 0053). *) val eval_reverse : @@ -48,4 +48,4 @@ val eval_reverse : Error.span -> unit (** Evaluate a `reverse` statement: fold a flap's tip back over the spine - that joins it to the rest of the paper (spec/MODEL.md, def-reverse). *) + that joins it to the rest of the paper (docs/reference/MODEL.md, def-reverse). *) diff --git a/packages/core/lib/annotation.mli b/packages/core/lib/annotation.mli index c3076a73f..6788303c2 100644 --- a/packages/core/lib/annotation.mli +++ b/packages/core/lib/annotation.mli @@ -1,4 +1,4 @@ -(** Annotations (spec/BELOCH-ANNOTATIONS.md; ADR 0029): what a reader of the +(** Annotations (docs/reference/BELOCH-ANNOTATIONS.md; ADR 0029): what a reader of the program is told beside the geometry. An annotation belongs to the statement after it and never changes what the program evaluates to. *) diff --git a/packages/core/lib/ast.ml b/packages/core/lib/ast.ml index 375e3b33d..b6b4d8a19 100644 --- a/packages/core/lib/ast.ml +++ b/packages/core/lib/ast.ml @@ -151,7 +151,7 @@ type mv_constraint = MvFree | MvMountain | MvValley (ADR pending: collapse = simultaneous multi-crease fold). *) type collapse_elem = { cline : line_operand; cdir : mv_constraint } -(* A number of the source (spec/BELOCH.md, Sheets): an exact rational +(* A number of the source (docs/reference/BELOCH.md, Sheets): an exact rational literal, or a parameter of the shape whose body it stands in. *) type number = NLit of Q.t * Error.span | NParam of string * Error.span @@ -202,7 +202,7 @@ type raw_item = | RiStaying of point_operand list * Error.span | RiSelection of toward_item * Error.span -(* One argument of an annotation (spec/BELOCH-ANNOTATIONS.md): any read the +(* One argument of an annotation (docs/reference/BELOCH-ANNOTATIONS.md): any read the language has, a text in double quotes, a number, or a bare word. *) type annot_value = | AvPoint of point_operand diff --git a/packages/core/lib/axiom.mli b/packages/core/lib/axiom.mli index 4833268b6..4310d2775 100644 --- a/packages/core/lib/axiom.mli +++ b/packages/core/lib/axiom.mli @@ -49,7 +49,7 @@ type chosen = { val select : ?trace:bool -> Ctx.ctx -> Error.span -> pending -> fold:bool -> Ast.sides -> chosen -(** Keep one candidate (spec/MODEL.md, def-selection): those that cross the +(** Keep one candidate (docs/reference/MODEL.md, def-selection): those that cross the paper, those nearest in direction to the `heading`, those whose fold carries out every alignment with the side that stays named by `toward` or the side that folds over named by `moving`, and among several the diff --git a/packages/core/lib/beloch.ml b/packages/core/lib/beloch.ml index 9e7376429..1bdd4d759 100644 --- a/packages/core/lib/beloch.ml +++ b/packages/core/lib/beloch.ml @@ -1,10 +1,10 @@ (** Beloch: evaluator core. The library is intentionally empty until the minimal core (v0.0) is - specified in [spec/10-core-v0.md]: one square of paper, axiom 1 only, a + specified in [docs/reference/10-core-v0.md]: one square of paper, axiom 1 only, a crease-line type, output to FOLD-extended. See - [decisions/0003-restart-from-minimal-core.md] and - [decisions/0007-evaluator-not-compiler.md]. *) + [docs/decision/0003-restart-from-minimal-core.md] and + [docs/decision/0007-evaluator-not-compiler.md]. *) let version = Version.version @@ -14,7 +14,7 @@ let parse ~(filename : string) (src : string) : Ast.program = let fold_string ~(filename : string) (src : string) : Yojson.Safe.t = parse ~filename src |> Eval.eval_folded |> Fold_emit.to_json_folded -(** The FOLD with its trace (spec/FOLD.md, "The trace"), and the +(** The FOLD with its trace (docs/reference/FOLD.md, "The trace"), and the program's failure. A program that fails still yields the file up to the failing statement, with the failure in `beloch:error`. A parse error raises as in [fold_string]. *) diff --git a/packages/core/lib/ctx.mli b/packages/core/lib/ctx.mli index 2855ac224..ca2bfdc10 100644 --- a/packages/core/lib/ctx.mli +++ b/packages/core/lib/ctx.mli @@ -149,7 +149,7 @@ type ctx = { mutable annots_rev : annot_entry list; (** Annotations whose statement has run, newest first. *) mutable trace_rev : Trace.entry list; - (** Every construction's candidates, newest first (spec/FOLD.md, "The + (** Every construction's candidates, newest first (docs/reference/FOLD.md, "The trace"). *) mutable parent : int option; (** The log entry of the [apply] whose body is running, [None] at the diff --git a/packages/core/lib/eval.ml b/packages/core/lib/eval.ml index 22292de48..ef2f404c5 100644 --- a/packages/core/lib/eval.ml +++ b/packages/core/lib/eval.ml @@ -71,7 +71,7 @@ let number_value (ctx : Ctx.ctx) (n : Ast.number) : Q.t = let eval_free_point (ctx : Ctx.ctx) (n : string) (line : Ast.line_operand) (anchor : Ast.point_operand) (pos : Ast.free_pos option) (span : Error.span) : unit = (* `free on` measures along material, so its line slot is crease-sorted - (spec/BELOCH.md, Parameter types). *) + (docs/reference/BELOCH.md, Parameter types). *) let l, chords_opt = match line with | Ast.LNamed cr -> ( @@ -489,7 +489,7 @@ let run_stmts (ctx : Ctx.ctx) on_step (stmts : Ast.stmt list) : unit = on_step ctx) stmts -(* ---- Sheets (spec/BELOCH.md, "Sheets") ---- *) +(* ---- Sheets (docs/reference/BELOCH.md, "Sheets") ---- *) (* the physical units of the FOLD format, each a rational multiple of the millimeter *) diff --git a/packages/core/lib/eval.mli b/packages/core/lib/eval.mli index 41de0d721..f2ca52350 100644 --- a/packages/core/lib/eval.mli +++ b/packages/core/lib/eval.mli @@ -65,7 +65,7 @@ type folded = { of the statement it belongs to (ADR 0029) *) trace : Trace.entry list; (** every construction's candidates in the order they were evaluated - (spec/FOLD.md, "The trace") *) + (docs/reference/FOLD.md, "The trace") *) sheet : Sheet.t; (** The sheet the program opened; its unfolded state is the first frame of the output. *) diff --git a/packages/core/lib/flatten_solve.ml b/packages/core/lib/flatten_solve.ml index b791a53b8..1dcb72a53 100644 --- a/packages/core/lib/flatten_solve.ml +++ b/packages/core/lib/flatten_solve.ml @@ -539,7 +539,7 @@ let run (ctx : Ctx.ctx) ~(into : (int * (Geom.line -> unit)) option) in let surviving = List.filter (fun (_, r, _) -> r <> []) combo_runs in (* the candidate states and the stage of the selection that removed each - (spec/FOLD.md, "The trace"), recorded once, when a state lands or the + (docs/reference/FOLD.md, "The trace"), recorded once, when a state lands or the statement fails *) let candidates = List.concat_map (fun (_, r, _) -> r) surviving in let removed = ref [] in diff --git a/packages/core/lib/fold_emit.ml b/packages/core/lib/fold_emit.ml index b61e12ec1..e71051a99 100644 --- a/packages/core/lib/fold_emit.ml +++ b/packages/core/lib/fold_emit.ml @@ -285,7 +285,7 @@ let folded_frame_of_state (sheet : Sheet.t) mark statement embeds its OWN mark geometry as recorded at that point, independent of whether it later graduates into a real crease (which only ever happens at some LATER fold statement). The field is contracted in - spec/FOLD.md. *) + docs/reference/FOLD.md. *) (* The statement that bound a name, or null where none did: the four paper corners come with the sheet rather than from a statement. *) let stmt_json (stmt : int option) : Yojson.Safe.t = @@ -327,7 +327,7 @@ let is_program_annotation (a : Ctx.annot_entry) = a.Ctx.an_ns = None && List.mem a.Ctx.an_key Annotation.program_keys (* beloch:annotations: one entry per annotation read, in the order the - statements ran (ADR 0029, spec/FOLD.md). [target] is the range of + statements ran (ADR 0029, docs/reference/FOLD.md). [target] is the range of beloch:statements entries it belongs to: one entry, or for a step every entry up to the next step; the string "program" for a key of the program as a whole; null after the last statement of its list. *) diff --git a/packages/core/lib/num.ml b/packages/core/lib/num.ml index 25536aba8..63e9ab55b 100644 --- a/packages/core/lib/num.ml +++ b/packages/core/lib/num.ml @@ -7,7 +7,7 @@ [Qq] backed by FLINT's qqbar (canonical minimal polynomial + certified ball; cross-field arithmetic, composite extensions). Invariant: [Qq] is irrational: rationals collapse to [Rat]. [to_float] is the only float, - output-only. See decisions/0013-flint-qqbar-backend.md. *) + output-only. See docs/decision/0013-flint-qqbar-backend.md. *) type t = | Rat of Q.t diff --git a/packages/core/lib/parser.mly b/packages/core/lib/parser.mly index 86095a36c..ba519d5e5 100644 --- a/packages/core/lib/parser.mly +++ b/packages/core/lib/parser.mly @@ -186,7 +186,7 @@ body_stmts: | annotation body_stmts { Annotation $1 :: $2 } | trim_elsewhere body_stmts { $1 :: $2 } -(* spec/BELOCH-ANNOTATIONS.md. Which key takes which arguments is checked +(* docs/reference/BELOCH-ANNOTATIONS.md. Which key takes which arguments is checked after parsing (Annotation.check), so a key is a name the grammar does not reserve. *) annotation: diff --git a/packages/core/lib/prelude.ml b/packages/core/lib/prelude.ml index 7ca222038..eb395ab63 100644 --- a/packages/core/lib/prelude.ml +++ b/packages/core/lib/prelude.ml @@ -1,6 +1,6 @@ (** The standard library of sheets (packages/core/stdlib/shapes.bel), whose shapes every program sees as if they were defined before its first line - (spec/BELOCH.md, "Sheets"). *) + (docs/reference/BELOCH.md, "Sheets"). *) let filename = "stdlib/shapes.bel" diff --git a/packages/core/lib/qqbar.ml b/packages/core/lib/qqbar.ml index 73998ef94..da4686e25 100644 --- a/packages/core/lib/qqbar.ml +++ b/packages/core/lib/qqbar.ml @@ -1,7 +1,7 @@ (** Exact real algebraic numbers backed by FLINT 3's qqbar (Calcium): canonical minimal-polynomial representation with Arb ball certification. Values are immutable; the C finalizer frees the FLINT struct. ℚ crosses - the FFI as strings. See decisions/0013-flint-qqbar-backend.md. *) + the FFI as strings. See docs/decision/0013-flint-qqbar-backend.md. *) type t diff --git a/packages/core/lib/resolve.ml b/packages/core/lib/resolve.ml index c8a58bdef..7064b7a72 100644 --- a/packages/core/lib/resolve.ml +++ b/packages/core/lib/resolve.ml @@ -35,7 +35,7 @@ and fstr (fa : Ast.flap_arg) : string = | Ast.FlapSpec (Ast.FByPoints (pts, _)) -> Printf.sprintf "#[%s]" (String.concat " " (List.map pstr pts)) -(* The sort check (spec/BELOCH.md, Parameter types): a slot that wants a +(* The sort check (docs/reference/BELOCH.md, Parameter types): a slot that wants a crease reads the binding's constructor and nothing else. A [Frozen] name is a line, and a line has no material until a `mark` scores it. *) let crease_of (ctx : Ctx.ctx) (cr : Ast.crease_ref) ~(slot : string) @@ -170,7 +170,7 @@ let face_of_points (ctx : Ctx.ctx) (pts : Geom.point list) : Array.iteri (fun i _ -> if contains i then hits := i :: !hits) faces_arr; match !hits with [ i ] -> `Face i | [] -> `Zero | _ -> `Ambiguous -(* A meet operand as a set of paper points (spec/MODEL.md, def-meet): closed +(* A meet operand as a set of paper points (docs/reference/MODEL.md, def-meet): closed segments for anything with material, a whole line for a boundary operand (a paper edge, a markless `--[…]` selection, a crease that cut no face). [Pt] arises only while intersecting. *) @@ -339,7 +339,7 @@ and material_cid (ctx : Ctx.ctx) (cr : Ast.crease_ref) : int = table space: all points are material (paper) identities, so a point selector always names the one segment whose paper preimage it lies on: even when folding has stacked several segments onto the same table locus - (notes/2026-07-03-crease-layer-selection.md; ADR 0014's "table-space + (docs/notes/2026-07-03-crease-layer-selection.md; ADR 0014's "table-space selector can't disambiguate" is why table space is wrong here). *) and seg_line (s : Fold_state.crease_segment) = Geom.line_through s.Fold_state.pa s.Fold_state.pb @@ -437,7 +437,7 @@ and select_point (ctx : Ctx.ctx) (los : Ast.line_operand list) (span : Error.spa | [] | [ _ ] -> Error.fail span ".[…] needs at least two lines to meet" | _ -> ( (* the meet is the intersection of the operands as sets of paper - points, defined when it is exactly one point (spec/MODEL.md, + points, defined when it is exactly one point (docs/reference/MODEL.md, def-meet) *) let sets = List.map (meet_pieces ctx) los in let names = and_list (List.map lstr los) in diff --git a/packages/core/lib/resolve.mli b/packages/core/lib/resolve.mli index 74b949f20..dc938ccc0 100644 --- a/packages/core/lib/resolve.mli +++ b/packages/core/lib/resolve.mli @@ -16,7 +16,7 @@ val crease_of : (** The binding of [cr], when it is a crease. Fails with ["--l is a line; needs a crease"] when the binding is [Ctx.Frozen]. One sigil carries two sorts and the binding tells them - apart (spec/BELOCH.md, Parameter types); the check reads the + apart (docs/reference/BELOCH.md, Parameter types); the check reads the constructor and no geometry, and sits at the slot that wants a crease. *) val into_crease : Ctx.ctx -> string -> Error.span -> int * (Geom.line -> unit) @@ -24,7 +24,7 @@ val into_crease : Ctx.ctx -> string -> Error.span -> int * (Geom.line -> unit) the check that the write's axis lies on that crease's own material, which the caller runs before the write. Fails when the name is bound to a line, to a selection, to a paper edge, or is not bound at all - (spec/BELOCH-WRITES.md). *) + (docs/reference/BELOCH-WRITES.md). *) val resolve_point : Ctx.ctx -> Ast.point_operand -> Geom.point (** Resolve a point operand to its material PAPER coordinate. *) @@ -149,7 +149,7 @@ val placement_failure_message : val tip_faces : Ctx.ctx -> Geom.line -> anchor:Ast.flap_arg option -> ?side:int -> Error.span -> int * bool array -(** `reverse`'s tip (`spec/KERNEL.md`, "Reverse"): the moving side ([side] where the side +(** `reverse`'s tip (`docs/reference/KERNEL.md`, "Reverse"): the moving side ([side] where the side items fixed it, else from the anchor), and the mask of PARENT faces forming the connected material beyond the axis that carries the anchor: the anchor's faces with a move-side piece (every face with one when diff --git a/packages/core/lib/sheet.ml b/packages/core/lib/sheet.ml index 1c373a092..be406287c 100644 --- a/packages/core/lib/sheet.ml +++ b/packages/core/lib/sheet.ml @@ -61,7 +61,7 @@ let clip (sh : t) (l : Geom.line) : side option = |> List.filter_map (Geom.clip_line_to_convex l) |> Geom.material_bundle -(* ---- A sheet trimmed from a flap (spec/BELOCH.md, "Sheets") ---- *) +(* ---- A sheet trimmed from a flap (docs/reference/BELOCH.md, "Sheets") ---- *) let point_at ((p, q) : side) (t : Num.t) : Geom.point = { Geom.x = Num.add p.Geom.x (Num.mul t (Num.sub q.Geom.x p.Geom.x)); diff --git a/packages/core/lib/trace.mli b/packages/core/lib/trace.mli index 7e6a80b37..37b57c672 100644 --- a/packages/core/lib/trace.mli +++ b/packages/core/lib/trace.mli @@ -1,5 +1,5 @@ (** What a selection chose from: every candidate of a construction or a write - and the rule that removed each one it did not keep (spec/FOLD.md, "The + and the rule that removed each one it did not keep (docs/reference/FOLD.md, "The trace"). Recorded on every evaluation and written only on request. *) type removal = @@ -21,7 +21,7 @@ type removal = type segment = Geom.point * Geom.point -(** The stage of the selection that removed a candidate (spec/MODEL.md, +(** The stage of the selection that removed a candidate (docs/reference/MODEL.md, def-selection); [removal] says which item or rule did it. *) type stage = Paper | Heading | Side | Moved | Landing diff --git a/packages/core/tests/cases/bases/bird-base.bel b/packages/core/tests/cases/bases/bird-base.bel index 4a8810998..42700c0a8 100644 --- a/packages/core/tests/cases/bases/bird-base.bel +++ b/packages/core/tests/cases/bases/bird-base.bel @@ -11,7 +11,7 @@ ; ; The seven statements are Ida's steps 2-8; the finished state is her O_8 ; [ida2020, Fig. 7.20(h), p. 194]. Checked against her figures in -; notes/2026-09-12-bird-base-oracle.md. +; docs/notes/2026-09-12-bird-base-oracle.md. paper square diff --git a/packages/core/tests/dune b/packages/core/tests/dune index 098293c58..8579314bb 100644 --- a/packages/core/tests/dune +++ b/packages/core/tests/dune @@ -74,7 +74,7 @@ (modules test_reference_corpus bel_assert) (libraries beloch alcotest zarith) (deps - (source_tree ../../../spec) + (source_tree ../../../docs/reference) (source_tree ../../www/src/content/docs/guide))) (test @@ -108,9 +108,9 @@ (libraries beloch alcotest yojson) (deps ../stdlib/shapes.bel - ../../../spec/BELOCH.md - ../../../decisions/0046-a-sheet-is-a-square-or-a-flap-cut-from-one.md - ../../../decisions/0047-a-trim-exports-the-names-it-lists.md)) + ../../../docs/reference/BELOCH.md + ../../../docs/decision/0046-a-sheet-is-a-square-or-a-flap-cut-from-one.md + ../../../docs/decision/0047-a-trim-exports-the-names-it-lists.md)) ; property tests (QCheck, run as alcotest cases); arb.ml holds the generators (test diff --git a/packages/core/tests/test_annotation.ml b/packages/core/tests/test_annotation.ml index 10e7f90c3..6dcee2e36 100644 --- a/packages/core/tests/test_annotation.ml +++ b/packages/core/tests/test_annotation.ml @@ -1,4 +1,4 @@ -(* Annotations (spec/BELOCH-ANNOTATIONS.md; ADR 0029). *) +(* Annotations (docs/reference/BELOCH-ANNOTATIONS.md; ADR 0029). *) open Beloch diff --git a/packages/core/tests/test_e2e.ml b/packages/core/tests/test_e2e.ml index c5530359d..9e46aa0b2 100644 --- a/packages/core/tests/test_e2e.ml +++ b/packages/core/tests/test_e2e.ml @@ -1238,7 +1238,7 @@ let test_e2e_flatten_scores_under_fan () = (run (read_case "collapse/flatten-waterbomb-emergent-on-top-layer.bel")) (run (drop " (--v \\ --ab mountain)" both)) -(* ---- Sheets (spec/BELOCH.md, "Sheets"; spec/FOLD.md, `frame_unit`) ---- *) +(* ---- Sheets (docs/reference/BELOCH.md, "Sheets"; docs/reference/FOLD.md, `frame_unit`) ---- *) let coords_of json = let open Yojson.Safe.Util in diff --git a/packages/core/tests/test_parse.ml b/packages/core/tests/test_parse.ml index 9a6000bf2..1a014d7ab 100644 --- a/packages/core/tests/test_parse.ml +++ b/packages/core/tests/test_parse.ml @@ -1059,7 +1059,7 @@ let test_parse_at_retired () = expect_error "syntax error" (fun () -> parse_stmts ~filename:"t.bel" "paper square\n@fold --d moving .a\n") -(* ---- Numbers and sheets (spec/BELOCH.md, "Sheets") ---- *) +(* ---- Numbers and sheets (docs/reference/BELOCH.md, "Sheets") ---- *) let test_decimal_and_point_name () = match parse_stmts ~filename:"t.bel" "paper square\n.5 = free on --ab from .a at 0.25\n" with diff --git a/packages/core/tests/test_prop_axiom.ml b/packages/core/tests/test_prop_axiom.ml index ee7b15e56..1d7a7cd95 100644 --- a/packages/core/tests/test_prop_axiom.ml +++ b/packages/core/tests/test_prop_axiom.ml @@ -1,7 +1,7 @@ (* Property tests for the seven axioms: every crease a construction returns carries out the alignment that was asked for, checked by reflecting in the crease rather than by repeating the construction. Beloch numbers the - axioms as spec/BELOCH.md does: 5 maps a line onto a line, 6 a point onto a + axioms as docs/reference/BELOCH.md does: 5 maps a line onto a line, 6 a point onto a line through a point, 7 two points onto two lines (Huzita-Justin 3, 5 and 6). diff --git a/packages/core/tests/test_reference_corpus.ml b/packages/core/tests/test_reference_corpus.ml index f5fb120aa..d1a9ab5fc 100644 --- a/packages/core/tests/test_reference_corpus.ml +++ b/packages/core/tests/test_reference_corpus.ml @@ -1,5 +1,5 @@ (* tests/test_reference_corpus.ml: the guard that holds the kernel to the - pages of the language, spec/BELOCH*.md, and to the guide. Every tagged + pages of the language, docs/reference/BELOCH*.md, and to the guide. Every tagged block of a page is extracted, assembled with its prelude, evaluated in process, and checked against its own `; assert` / `; expect error` lines through [Bel_assert]: the same @@ -82,7 +82,7 @@ let parse_tag (info : string) : tag option = else None (* Scan [src] for fenced code blocks whose info string [parse_tag] resolves, - in document order. Every fence in spec/*.md opens and closes with a bare + in document order. Every fence in docs/reference/*.md opens and closes with a bare ``` line (no longer backtick run, no indentation); a block that never closes is a malformed document, not a block to silently drop. *) let extract_blocks (src : string) : block list = @@ -344,7 +344,7 @@ let failure_mode_tests = Alcotest.test_case "a clean block passes" `Quick test_success_case; ] -(* ---- The real corpus: the pages of the language, spec/BELOCH*.md ---- *) +(* ---- The real corpus: the pages of the language, docs/reference/BELOCH*.md ---- *) (* Block inventory of each language page, by tag; a page with no entry fails its inventory case. Ceiling: this catches the OCaml extractor drifting diff --git a/packages/core/tests/test_stdlib.ml b/packages/core/tests/test_stdlib.ml index 0e7279e19..a4d465353 100644 --- a/packages/core/tests/test_stdlib.ml +++ b/packages/core/tests/test_stdlib.ml @@ -98,9 +98,9 @@ let test_documented_rectangle () = [ [ 0.; 0. ]; [ 2.; 0. ]; [ 2.; 1. ]; [ 0.; 1. ] ] (corners json)) [ - ("spec/BELOCH.md", true); - ("decisions/0046-a-sheet-is-a-square-or-a-flap-cut-from-one.md", false); - ("decisions/0047-a-trim-exports-the-names-it-lists.md", true); + ("docs/reference/BELOCH.md", true); + ("docs/decision/0046-a-sheet-is-a-square-or-a-flap-cut-from-one.md", false); + ("docs/decision/0047-a-trim-exports-the-names-it-lists.md", true); ] let () = diff --git a/packages/core/tests/test_trace.ml b/packages/core/tests/test_trace.ml index 5101643bd..bd7a83c13 100644 --- a/packages/core/tests/test_trace.ml +++ b/packages/core/tests/test_trace.ml @@ -1,4 +1,4 @@ -(* The trace of a construction's candidates (spec/FOLD.md, "The trace"): +(* The trace of a construction's candidates (docs/reference/FOLD.md, "The trace"): `beloch fold --trace` output, read as JSON the way a figure reads it. *) open Yojson.Safe.Util diff --git a/packages/core/tools/blocks.ml b/packages/core/tools/blocks.ml index 5a1960015..712948a94 100644 --- a/packages/core/tools/blocks.ml +++ b/packages/core/tools/blocks.ml @@ -1,16 +1,16 @@ (* tools/blocks.ml: the build-side reference-corpus capture (design doc "The three runners", build side; Acceptance 10). Selects and assembles - the tagged blocks of each document it is given (spec/BELOCH.md when + the tagged blocks of each document it is given (docs/reference/BELOCH.md when given none) by the same rule packages/core/tests/test_reference_corpus.ml uses, evaluates each one in - process, and writes one entry per block to _build/spec/blocks.json, the + process, and writes one entry per block to _build/reference/blocks.json, the input packages/www/src/lib/remark-bel.ts reads to render the outcome under each program. Never exits nonzero over a block that fails to fold: that is what the kernel-side corpus test guards; this tool exists so the site still builds and shows the failure. Run from the repo root, with the documents as paths from there: - dune exec packages/core/tools/blocks.exe -- spec/BELOCH*.md … *) + dune exec packages/core/tools/blocks.exe -- docs/reference/BELOCH*.md … *) open Beloch @@ -33,7 +33,7 @@ type tag = malformed), but [compute_outcome] turns it straight into an [Error_result] without assembling or evaluating it: a malformed tag must not stop the rest of the document from building (test - coverage: a throwaway fixture, not spec/BELOCH.md). *) + coverage: a throwaway fixture, not docs/reference/BELOCH.md). *) type block = { tag : tag; body : string; fence_line : int (* 1-based, the line the opening fence is on *) } @@ -319,9 +319,9 @@ let entries_of (doc : string) : Yojson.Basic.t = let () = let docs = - match Array.to_list Sys.argv with _ :: (_ :: _ as docs) -> docs | _ -> [ "spec/BELOCH.md" ] + match Array.to_list Sys.argv with _ :: (_ :: _ as docs) -> docs | _ -> [ "docs/reference/BELOCH.md" ] in let json : Yojson.Basic.t = `Assoc (List.map (fun doc -> (doc, entries_of doc)) docs) in - mkdir_p "_build/spec"; - Out_channel.with_open_text "_build/spec/blocks.json" (fun oc -> + mkdir_p "_build/reference"; + Out_channel.with_open_text "_build/reference/blocks.json" (fun oc -> Out_channel.output_string oc (Yojson.Basic.pretty_to_string json)) diff --git a/packages/eval-web/beloch_web.ml b/packages/eval-web/beloch_web.ml index bf4d04db6..17066fa74 100644 --- a/packages/eval-web/beloch_web.ml +++ b/packages/eval-web/beloch_web.ml @@ -5,7 +5,7 @@ - [{"ok":true,"fold":}] on success. - [{"ok":false,"kind":"native","message":...}] when evaluation hit an irrational (qqbar) value, which the js_of_ocaml build can't compute - (see [qqbar_shim.js] and decisions/0013-flint-qqbar-backend.md); the + (see [qqbar_shim.js] and docs/decision/0013-flint-qqbar-backend.md); the caller should fall back to the native evaluator. - [{"ok":false,"kind":"error","message":...,"hint":...,"line":...,"column":..., "endLine":...,"endColumn":...}] for a [Beloch_error] (language/program diff --git a/packages/eval-web/qqbar_shim.js b/packages/eval-web/qqbar_shim.js index 6c8bc2f34..d05e647ea 100644 --- a/packages/eval-web/qqbar_shim.js +++ b/packages/eval-web/qqbar_shim.js @@ -1,5 +1,5 @@ // js_of_ocaml runtime shim for lib/qqbar.ml's C stubs (lib/qqbar_stubs.c, -// FLINT/Calcium — see decisions/0013-flint-qqbar-backend.md). jsoo cannot +// FLINT/Calcium — see docs/decision/0013-flint-qqbar-backend.md). jsoo cannot // compile C, so every `external ... = "ml_qqbar_*"` primitive is backed here // by calls into a real FLINT-wasm module (packages/eval-web/qqbar_wasm.c, built // by build-wasm.sh into packages/www/public/beloch/qqbar-wasm.js). diff --git a/packages/grammar/grammar.js b/packages/grammar/grammar.js index 3a0c8a8b4..009e4f6b3 100644 --- a/packages/grammar/grammar.js +++ b/packages/grammar/grammar.js @@ -203,7 +203,7 @@ module.exports = grammar({ comment: _ => token(seq(';', /[^\n]*/)), // an annotation opens with `@key` or `@ns:key` and runs to the end of its - // line (spec/BELOCH-ANNOTATIONS.md); its arguments are ordinary tokens + // line (docs/reference/BELOCH-ANNOTATIONS.md); its arguments are ordinary tokens annotation_key: _ => token(seq('@', /[A-Za-z0-9_]+/, optional(seq(':', /[A-Za-z0-9_]+/)))), // text in double quotes, an annotation's argument; `\"` and `\\` escape diff --git a/packages/render-2d/README.md b/packages/render-2d/README.md index 36036abf8..3d25c8a53 100644 --- a/packages/render-2d/README.md +++ b/packages/render-2d/README.md @@ -1,7 +1,7 @@ # render Bun workspace for Beloch's SVG rendering: FOLD JSON in, labeled crease-pattern -or folded-occlusion diagrams out. The input contract is `spec/FOLD.md`. +or folded-occlusion diagrams out. The input contract is `docs/reference/FOLD.md`. ## Packages diff --git a/packages/render-2d/render-svg/src/render-candidates.ts b/packages/render-2d/render-svg/src/render-candidates.ts index bffa4530d..98ba2ac4c 100644 --- a/packages/render-2d/render-svg/src/render-candidates.ts +++ b/packages/render-2d/render-svg/src/render-candidates.ts @@ -2,7 +2,7 @@ // the candidates are lines, each drawn on its own copy of the state the // construction read, as Ida draws the choices of a fold [ida2020, Fig. 2.17]; // for a write they are states, drawn by what tells them apart. Reads -// `beloch:trace` (spec/FOLD.md, "The trace"), so the file has to be written by +// `beloch:trace` (docs/reference/FOLD.md, "The trace"), so the file has to be written by // `beloch fold --trace`. import type { Conic, FoldScene, LineCoeffs, Removal, TraceCandidate, TraceEntry, Vec2, WriteEntry } from "@beloch/scene"; import { SceneError } from "@beloch/scene"; diff --git a/packages/render-2d/render-svg/src/render-faces.ts b/packages/render-2d/render-svg/src/render-faces.ts index 6123226c8..df44f06f4 100644 --- a/packages/render-2d/render-svg/src/render-faces.ts +++ b/packages/render-2d/render-svg/src/render-faces.ts @@ -1,5 +1,5 @@ // Face graphs: the two relations between the faces of a flat folded state -// (spec/MODEL.md, def-flat-state), each drawn as a graph. Adjacency joins two +// (docs/reference/MODEL.md, def-flat-state), each drawn as a graph. Adjacency joins two // faces that share a hinge, an edge of the paper they both bound; // superposition joins two faces that overlap on the table, the pairs // `faceOrders` lists, the upper one above the lower. Ida draws graphs of these @@ -59,7 +59,7 @@ export interface FaceGraphs { nodes: GraphNode[]; hinges: Hinge[]; layers: Layer // The levels and the covering pairs of an "above" relation on faces 0..n-1. // A flat-foldable state can have faces that lie over one another in a cycle -// (spec/MODEL.md, rem-linear-extension); the faces of one cycle share a level. +// (docs/reference/MODEL.md, rem-linear-extension); the faces of one cycle share a level. export function layerGraph(n: number, above: [number, number][]): { covers: [number, number][]; level: number[] } { const out: number[][] = Array.from({ length: n }, () => []); for (const [f, g] of above) if (!out[f]!.includes(g)) out[f]!.push(g); diff --git a/packages/render-2d/render-svg/src/render-operation.ts b/packages/render-2d/render-svg/src/render-operation.ts index 6c180689a..e2e0f2afb 100644 --- a/packages/render-2d/render-svg/src/render-operation.ts +++ b/packages/render-2d/render-svg/src/render-operation.ts @@ -1,9 +1,9 @@ // Operation view: one write drawn from its trace entry, as two panels. The // first is the state the write read with the terms of the write's definition -// on it (spec/MODEL.md, §5): the axis, the moving set and the target of a +// on it (docs/reference/MODEL.md, §5): the axis, the moving set and the target of a // fold; the axis, the tip, the spine, the halves and the bodies of a reverse // fold; the vertex, the rays and the stayer of a flatten. The second is the -// state the write yields. Reads `beloch:trace` (spec/FOLD.md, "The trace"). +// state the write yields. Reads `beloch:trace` (docs/reference/FOLD.md, "The trace"). import type { FoldScene, Frame, Region, Segment, Vec2, WriteCandidate, WriteEntry } from "@beloch/scene"; import { SceneError } from "@beloch/scene"; import { createDoc, el, SvgDoc } from "./svgdoc"; diff --git a/packages/render-2d/render-svg/src/render-stages.ts b/packages/render-2d/render-svg/src/render-stages.ts index fc4421dbb..c3df4b134 100644 --- a/packages/render-2d/render-svg/src/render-stages.ts +++ b/packages/render-2d/render-svg/src/render-stages.ts @@ -1,10 +1,10 @@ -// Stages view: how the selection of one construction went (spec/MODEL.md, -// def-selection), drawn as spec/CLI-STAGES.md states it. One column: the +// Stages view: how the selection of one construction went (docs/reference/MODEL.md, +// def-selection), drawn as docs/reference/CLI-STAGES.md states it. One column: the // program, one row per stage with the paper on the left and on the right the // title, the statement with the part the stage reads underlined, and the // text rows; then the outcome and, where several candidates or none remain, // what to write next; then the legend of the marks the figure uses. -// Everything drawn comes from `beloch:trace` (spec/FOLD.md, "The trace"): +// Everything drawn comes from `beloch:trace` (docs/reference/FOLD.md, "The trace"): // the view repeats no part of the selection, and computes only where a mark // sits on the page. import type { diff --git a/packages/render-2d/scene/src/face-graph.ts b/packages/render-2d/scene/src/face-graph.ts index e1f4e7961..c4d45b096 100644 --- a/packages/render-2d/scene/src/face-graph.ts +++ b/packages/render-2d/scene/src/face-graph.ts @@ -1,4 +1,4 @@ -// The face graph of a frame, read from `edges_faces` (spec/FOLD.md, "Standard +// The face graph of a frame, read from `edges_faces` (docs/reference/FOLD.md, "Standard // fields"). A node is a set of faces joined across `J` edges: a join edge only // divides a non-convex sheet into convex faces, and FOLD counts the faces on // its two sides as one. Every other edge with two faces, `M`, `V` or `F`, diff --git a/packages/render-2d/scene/src/orient.ts b/packages/render-2d/scene/src/orient.ts index 647f63bdd..4b6aca2d8 100644 --- a/packages/render-2d/scene/src/orient.ts +++ b/packages/render-2d/scene/src/orient.ts @@ -1,5 +1,5 @@ // How the model is turned on the page at a state: the `@orient` annotations -// of spec/BELOCH-ANNOTATIONS.md, read into one rotation of the table plane. +// of docs/reference/BELOCH-ANNOTATIONS.md, read into one rotation of the table plane. import type { Annotation, FoldScene, Frame, Vec2 } from "./types"; const DIRECTION: Record = { diff --git a/packages/render-2d/scene/src/types.ts b/packages/render-2d/scene/src/types.ts index 6cad9d975..b114a87d8 100644 --- a/packages/render-2d/scene/src/types.ts +++ b/packages/render-2d/scene/src/types.ts @@ -1,5 +1,5 @@ export type Vec2 = [number, number]; -export type Assignment = "B" | "M" | "V" | "F" | "J" | "U"; // J: a join edge, spec/FOLD.md +export type Assignment = "B" | "M" | "V" | "F" | "J" | "U"; // J: a join edge, docs/reference/FOLD.md export type LineCoeffs = [number, number, number]; // a·x + b·y = c export type Isometry = [number, number, number, number, number, number]; // [m00,m01,m10,m11,tx,ty] export type FaceOrder = [number, number, number]; // [f, g, s], FOLD faceOrders @@ -44,7 +44,7 @@ export type StatementKind = "fold" | "mark" | "bind" | "apply"; // entry embeds its OWN mark geometry as recorded at that statement (not a // beloch:marks lookup — a mark that later graduates into a real crease is // dropped from beloch:marks, but its Statement.mark here is unaffected). -// Contract: spec/FOLD.md. +// Contract: docs/reference/FOLD.md. export interface Statement { index: number; kind: StatementKind; @@ -80,7 +80,7 @@ export interface CreaseSegment { edgeIndex: number; a: Vec2; b: Vec2; } export interface Crease { name: string; segments: CreaseSegment[]; } // beloch:marks — non-subdividing record marks (dangling segments + points); -// see spec/FOLD.md. +// see docs/reference/FOLD.md. export interface SegMark { kind: "seg"; a: Vec2; b: Vec2; @@ -137,12 +137,12 @@ export interface Inspect { edges: Record; } -// beloch:trace, written by `beloch fold --trace` (spec/FOLD.md, "The trace"): +// beloch:trace, written by `beloch fold --trace` (docs/reference/FOLD.md, "The trace"): // every candidate line of a construction, in the table coordinates of the // frame the construction read (`frameIndex`; for a fold the state before it), // with the rule that removed it. export type Removal = "paper" | "heading" | "toward" | "moving" | "moved"; -// The stage of the selection that removed a candidate (spec/MODEL.md, def-selection). +// The stage of the selection that removed a candidate (docs/reference/MODEL.md, def-selection). export type Stage = "paper" | "heading" | "side" | "moved" | "landing"; // Where the side that folds over came from; "alone" and "first" are the default // of a write without side items. @@ -241,7 +241,7 @@ export interface TraceError { } // beloch:annotations: one entry per annotation, in the order the statements -// ran (spec/FOLD.md). A point or line argument was read against the state +// ran (docs/reference/FOLD.md). A point or line argument was read against the state // `frameIndex`, the one the annotated statement starts from. export type AnnotationArg = | { kind: "text"; text: string } diff --git a/packages/render-2d/yr/src/panels.ts b/packages/render-2d/yr/src/panels.ts index 09f32c8b7..9c3b0f135 100644 --- a/packages/render-2d/yr/src/panels.ts +++ b/packages/render-2d/yr/src/panels.ts @@ -1,5 +1,5 @@ // Which panels a program becomes: one per step group, one per write outside -// any group, and one for the final state (spec/BELOCH-ANNOTATIONS.md). +// any group, and one for the final state (docs/reference/BELOCH-ANNOTATIONS.md). import type { Annotation, FoldScene, Statement, Vec2 } from "@beloch/scene"; import { clipSegmentToPoly, pointInPolygon } from "@beloch/render-svg"; import { foldMotion, overlapArea, turnOver } from "./motion"; diff --git a/packages/www/astro.config.mjs b/packages/www/astro.config.mjs index 681904abd..6a071f53e 100644 --- a/packages/www/astro.config.mjs +++ b/packages/www/astro.config.mjs @@ -92,9 +92,9 @@ export default defineConfig({ // Highlight ```beloch fences with the tree-sitter highlighter before // Expressive Code sees them. // remark-model-blocks turns the `::: {.definition #id …}` fenced divs of - // spec/MODEL.md into numbered, cross-referenced sections; it runs before + // docs/reference/MODEL.md into numbered, cross-referenced sections; it runs before // remarkMath so the math inside a block body is still tokenized. - // remark-grammar turns the ```grammar fragments of spec/BELOCH.md into + // remark-grammar turns the ```grammar fragments of docs/reference/BELOCH.md into // linked rules and generates the collected grammar under `## Grammar`. remarkPlugins: [remarkBel, remarkGrammar, remarkModelBlocks, remarkMath], // `$...$` math and `[@key, §3]` citations, the same syntax pandoc reads @@ -134,8 +134,11 @@ export default defineConfig({ ], }, { - label: "Specification", + label: "Reference", items: [ + { + label: "Specification", + items: [ { label: "Model", link: "/model/" }, { label: "Language", @@ -148,14 +151,16 @@ export default defineConfig({ ], }, { label: "Output format", link: "/output/" }, - ], - }, - { - label: "Reference implementation", - items: [ + ], + }, + { + label: "Reference implementation", + items: [ { label: "The OCaml kernel", link: "/kernel/" }, { label: "Command-line interface", link: "/cli/" }, { label: "The stages view", link: "/cli/stages/" }, + ], + }, ], }, ], diff --git a/packages/www/src/content/docs/cli.md b/packages/www/src/content/docs/cli.md index 9af000b33..a8e4220e6 120000 --- a/packages/www/src/content/docs/cli.md +++ b/packages/www/src/content/docs/cli.md @@ -1 +1 @@ -../../../../../spec/CLI.md \ No newline at end of file +../../../../../docs/reference/CLI.md \ No newline at end of file diff --git a/packages/www/src/content/docs/cli/stages.md b/packages/www/src/content/docs/cli/stages.md index 75447d503..868f425d2 120000 --- a/packages/www/src/content/docs/cli/stages.md +++ b/packages/www/src/content/docs/cli/stages.md @@ -1 +1 @@ -../../../../../../spec/CLI-STAGES.md \ No newline at end of file +../../../../../../docs/reference/CLI-STAGES.md \ No newline at end of file diff --git a/packages/www/src/content/docs/guide/first-folds.md b/packages/www/src/content/docs/guide/first-folds.md deleted file mode 100644 index a91f9fb3c..000000000 --- a/packages/www/src/content/docs/guide/first-folds.md +++ /dev/null @@ -1,321 +0,0 @@ ---- -title: First folds -description: A first program, one fold at a time, up to the preliminary base. For folders who have never read a grammar and programmers who have never folded a base. -tableOfContents: - minHeadingLevel: 2 - maxHeadingLevel: 2 ---- - -A Beloch program describes how a sheet of paper is folded. Each line is one -step, and the program's result is the paper after the last one. Beloch -reads the program step by step and computes where every layer of paper -goes, which creases come out mountain or valley, and draws the result. You -describe each fold by what it brings together, and Beloch works out the -lines. - -This page builds one program up to the preliminary base. A *base* is a -standard folded shape that many models start from; the preliminary base is -one of the most common, and the crane starts from it. Every figure shows two -drawings of the same moment. On the left is the *crease pattern*: the sheet -unfolded flat again, with every crease the folds have made so far. On the -right is the *folded form*: the paper as it lies on the table, each -*layer* of paper stacked on the one beneath. A crease is either a *valley*, -folded towards you so the paper forms a trough, or a *mountain*, folded -away from you so it forms a ridge. The drawings use the notation of origami -diagrams: a valley is dashed, a mountain dash-dotted, and a crease that was -made and left flat is dotted. - -The programs on this page are checked every time the site is built, so what -you read here is what the language does today. - -## The sheet - -Every program starts by naming its paper. - -::: {.figure #fig-guide-sheet caption="The unit square. Its corners are named `.a` to `.d`, counter-clockwise from the bottom left." views="cp" highlight=".a .b .c .d"} -paper square -::: - -`paper square` is a square of side 1 with its corners at $(0, 0)$, $(1, 0)$, -$(1, 1)$ and $(0, 1)$. It also names them: `.a` is the bottom left, and the -names continue counter-clockwise to `.d` at the top left. - -Names in Beloch carry their kind in front. A name starting with a dot is a -*point*. A name starting with two dashes is a *line* or a *crease*. The -four edges of the square are named after the corners they join: `--ab` is -the bottom edge, `--bc` the right one, `--cd` the top, `--da` the left. - -## One fold - -Folding the square corner to corner is one line. - -::: {.figure #fig-guide-triangle caption="`.a` folded onto `.c`. The crease runs along the other diagonal, from `.b` to `.d`, and the triangle covers the upper right half of where the square was." views="cp folded" highlight=".a .c"} -paper square -fold (map .a onto .c) -::: - -A statement starts with a verb, here `fold`, followed by *items* in round -brackets. The item `(map .a onto .c)` says where the fold line goes: it is -the line that carries `.a` onto `.c` when the paper is folded along it. You -never write coordinates for a fold line. You say what it has to bring -together, and Beloch works out the line. - -Origami geometry knows seven such ways to pin down a single fold line from -points and lines already on the paper: through two points, one point onto -another, one line onto another, and four more. They are the Huzita-Justin -axioms. Beloch writes each as a *construction* in round brackets, and the -language reference lists all seven under -[Constructions](/language/constructions/). - -The fold moves the side that holds `.a`, the first thing the construction -names, and lays it over the rest. A fold without further items is a valley -fold, which is what a folder means by "fold" unless they say otherwise. - -## Naming a crease - -A statement that makes a crease can give it a name with `as`: - -::: {.figure #fig-guide-named caption="The same fold, with its crease named `--bd` after the two corners it runs between." views="cp folded" highlight="--bd"} -paper square -fold (map .a onto .c) as --bd -::: - -Later statements can refer to `--bd` the way they refer to a corner. A name -is bound once; binding the same name again is an error, so a name always -means the thing it was first given. - -## Marking a line - -Folders often crease a line and unfold it again, to have a reference for a -later step. That is `mark`: it scores the paper and moves nothing. - -::: {.figure #fig-guide-mark caption="`mark` scores the diagonal from `.a` to `.c`. The paper stays flat, so the folded form is the square itself." views="cp folded" highlight="--ac"} -paper square -mark (through .a .c) as --ac -::: - -`(through .a .c)` is another of the seven axioms: the line through two -points. A marked crease is scored into the paper and moves nothing. It -splits the square into two *faces*, the regions of paper that the creases -and edges bound; the crease pattern shows every face of the sheet. Later -statements can fold along the mark, fold something onto it, or read points -off it. - -## The kite - -With a marked diagonal, the kite base is two more folds. Each lays an edge -of the square along the diagonal. - -::: {.figure #fig-guide-kite caption="The kite: the left edge and the bottom edge folded onto the diagonal `--ac`." views="cp folded" highlight="--ac"} -paper square -mark (through .a .c) as --ac -fold (map --da onto --ac) -fold (map --ab onto --ac) -::: - -`(map --da onto --ac)` is the axiom that folds one line onto another. Two -lines that cross have two fold lines that do this, the lines that halve the -angles between them. Here one of them runs across the paper, and the other -touches the square only at the corner `.a`. A line that creases no paper is -no fold at all, so one candidate is left, and that is the fold. - -## Choosing the side that moves - -Not every construction says which side of the fold line travels. A fold -line through two points is symmetric; nothing in `(through .a .c)` says -whether the half with `.b` or the half with `.d` goes over. Beloch does not -guess. This program fails: - -```{.bel} -paper square -fold (through .a .c) - -; expect error "this fold needs `moving .p` to choose the side" -``` - -The error points at the statement and says what is missing. A `moving` item -names a point on the side that travels: - -::: {.figure #fig-guide-moving caption="`(moving .b)` sends the half with `.b` over the diagonal." views="cp folded" highlight=".b"} -paper square -fold (through .a .c) (moving .b) -::: - -The opposite item is `toward`: it names a point on the side that stays. -`fold (through .a .c) (toward .d)` is the same fold. When a construction -has several solutions that all crease paper, the same two items choose among -them, and the reference explains how under -[Selection](/language/constructions/#selection). - -A crease that is already there can be the fold line itself. The crease goes -in round brackets like a construction, and it needs a side for the same -reason: - -::: {.figure #fig-guide-along caption="The marked diagonal `--ac` folded, with the half holding `.b` moving." views="cp folded" highlight="--ac .b" after="fig-guide-mark"} -fold (--ac) (moving .b) -::: - -Every error works this way. A program that asks for something the paper -cannot do, or that leaves a choice open, stops at the statement where that -happens, with a message and often a hint. - -## Which layers move - -Once the paper is folded, a fold line crosses more than one layer. A fold -takes every layer under its line on the side that folds over, as a finger -pressing a crease through the stack does. The point that says which side -moves, the named corner of a `map` or the point of a `moving` item, names -that side and nothing more. - -The book fold shows it. Folding the left edge onto the right edge puts the -left half on top, so `.a` is on the top layer and `.b` on the bottom one. -Folding the bottom onto the top takes both layers, whichever of the two -corners the program names: - -::: {.figure #fig-guide-book caption="The book fold, then the bottom onto the top. Both layers move." views="cp folded" highlight=".a .b"} -paper square -fold (map --da onto --bc) -fold (map .b onto .c) -::: - -`(map --da onto --bc)` folds one edge onto the opposite one. The two edges -are parallel, so there is one fold line, halfway between them. The same -second fold written as `fold (map .a onto .d)` gives the same state. - -To fold fewer layers, `(up to …)` names the deepest one the fold takes. That -layer moves with every layer on top of it, or beneath it for a mountain -fold. A layer joined to those by a crease away from the fold line goes -along too, because the paper would have to tear to leave it behind. Here -the corner of the top layer folds alone: - -::: {.figure #fig-guide-up-to caption="The sheet folded in half, then the corner of the top layer. `(up to .b)` names the top layer as the deepest the fold takes." views="cp folded" highlight=".b"} -paper square -fold (map .b onto .a) -.p = free on --bc from .b at 1/4 -.q = free on --ab from .b at 1/4 -fold (through .p .q) (moving .b) (up to .b) -::: - -A `mark` works the same way: it scores every layer its line crosses, and -`(on …)` confines it to one. - -The piece of paper that moves as a whole is a *flap*: faces joined by -creases that are not folded, so that they lie flat against each other. - -## A reverse fold - -The preliminary base starts from the triangle and needs a fold that is not -a plain valley or mountain: the *inside reverse fold*. The triangle's -corner `.b` is folded down between the two layers of the triangle, so that -it ends up inside. Along the old crease `--bd` the direction of the fold -flips where the corner turns in. - -::: {.figure #fig-guide-reverse caption="The corner `.b` reverse-folded inside, onto `.c`." views="cp folded" highlight="--h" after="fig-guide-named"} -reverse (map .b onto .c) as --h -::: - -This figure continues the program of the named triangle above; from here on -a figure shows only the lines it adds. `reverse` takes a construction the -way `fold` does. It needs no `moving`, because `(map .b onto .c)` already -says that `.b` travels. `(outside)` would wrap the corner -around the outside of the layers instead of tucking it between them. - -## The preliminary base - -One more reverse fold for the corner `.d` finishes the base. - -::: {.figure #fig-guide-prelim caption="The preliminary base. The paper is a square a quarter the size of the sheet, all four corners lie together at `.c`, and the creases `--h` and `--v` cross at the paper's center." views="cp folded" highlight="--v" after="fig-guide-reverse"} -reverse (map .d onto .c) as --v -::: - -The whole program is four lines: - -```{.bel} -paper square -fold (map .a onto .c) as --bd -reverse (map .b onto .c) as --h -reverse (map .d onto .c) as --v -``` - -`--h` is named for the horizontal line it was folded along, halfway up the -triangle, and `--v` for the vertical one. - -## Collapsing a vertex - -Folders often reach the preliminary base another way: crease the diagonals -and the middle lines first, then push the paper together so that all the -creases around the center fold at once. `flatten` does that. It folds every -crease through one point, the *vertex*, in a single step. - -::: {.figure #fig-guide-flatten caption="The preliminary base in one `flatten`. Six rays around the center fold; the diagonal from `.a` to `.c` stays flat. `(.q over .r)` puts the quarter with `.q` in front of the one with `.r`." views="cp folded" highlight=".q .r"} -paper square -mark (through .a .c) as --ac -mark (through .b .d) as --bd -mark (map --ab onto --cd) as --h -mark (map --da onto --bc) as --v -.q = free on --ab from .a at 1/4 -.r = free on --ab from .b at 1/4 -flatten (--h & --bc) (--v & --cd) (--h & --da) (--v & --ab) - (--bd & .b) (--bd & .d) (.q over .r) (toward .q) -::: - -The four `mark` lines score the creases. The items of `flatten` then name -the *rays*, the pieces of crease that run out from the vertex. Each marked -line through the center is two rays, and `&` picks one of them: -`--h & --bc` is the piece of `--h` that reaches the right edge `--bc`. - -The rays say where the paper folds; Beloch works out which of them become -mountains and which valleys, and how the layers stack, so that everything -lies flat. A ray can be pinned by writing its letter, as in -`(--h & --bc mountain)`. With an odd number of rays, Beloch adds the one -that is missing, since a flat vertex needs an even number. - -Several flat results can remain, and the other items choose among them. -`(.q over .r)` says that the paper around `.q` lies over the paper around -`.r`, and `(toward .q)` picks one of the results that are still left. Both -need points that lie in one quarter of the sheet and on none of the -creases through the center. The corners and crossings named so far all lie -on such a crease. `free on --ab from .a at 1/4` -is a point a quarter of the way along the bottom edge from `.a`; `free` -records that any spot on that stretch would do, and the program uses this -one. - -`flatten` handles one vertex per statement. The reference describes the -rest under [Write statements](/language/writes/). - -## Points from creases - -A point does not have to be a corner. `*` gives the point where two creases -cross on the paper: - -::: {.figure #fig-guide-center caption="`.o`, the point where `--h` and `--v` cross: the center of the sheet, and the closed tip of the base." views="cp folded" highlight=".o" after="fig-guide-prelim"} -.o = --h * --v -::: - -`=` binds a name to something computed from the paper as it is, and changes -nothing. That is the difference between the two ways to name: `as` names -the crease a statement makes, `=` names a value the program reads off the -paper. `--mid = (through .c .o)` binds a line with no crease under it yet, -which a later fold can use as its fold line or its target. - -A point name belongs to the paper. `.o` is a spot on the sheet, and it -travels with the paper wherever later folds take it. A construction such as -`(map .b onto .c)` works with where its points lie on the table at that -step, since that is where the fold happens. A crossing `*` is found on the -unfolded sheet, where the creases are scored. - -On the unfolded sheet, one crease can be several lines. `--h` was folded -through both layers of the triangle at once and left a *scar* in each. -Unfolded, the scar in the upper layer runs from the center to the right -edge, and the scar in the lower layer, which lay folded over the diagonal, -runs from the center down to the bottom edge. A crease is all of its scars -together, and `*` looks for a crossing among all of them. The crease pattern -of the preliminary base shows this: `--h` and `--v` each bend at the -center. - -## Where to go from here - -[Reading the crane](/guide/reading-the-crane/) continues this program into a -traditional crane and introduces the rest of what it needs along the way. -The [playground](/playground/) runs any program in the browser. The -[language reference](/language/) defines every statement this page used. diff --git a/packages/www/src/content/docs/guide/first-folds.md b/packages/www/src/content/docs/guide/first-folds.md new file mode 120000 index 000000000..5cee0aa81 --- /dev/null +++ b/packages/www/src/content/docs/guide/first-folds.md @@ -0,0 +1 @@ +../../../../../../docs/guide/first-folds.md \ No newline at end of file diff --git a/packages/www/src/content/docs/guide/reading-the-crane.md b/packages/www/src/content/docs/guide/reading-the-crane.md deleted file mode 100644 index 4a290f848..000000000 --- a/packages/www/src/content/docs/guide/reading-the-crane.md +++ /dev/null @@ -1,171 +0,0 @@ ---- -title: Reading the crane -description: The traditional crane as a Beloch program, read section by section. Introduces perpendiculars, moving flaps, mountain folds, filters and free points where the crane first needs them. -tableOfContents: - minHeadingLevel: 2 - maxHeadingLevel: 2 ---- - -This page reads a whole model: the traditional crane, folded flat, by the -sequence Ida gives in her book [@ida2020, Fig. 7.19]. It reaches the bird -base with reverse folds and uses no petal fold, so it differs from the -diagrams most folders learned the crane from, and ends in the same bird base. -It assumes -[First folds](/guide/first-folds/), and it adds the rest of what the crane -needs where it first appears. The full program is -[`examples/crane.bel`](https://github.com/tophcodes/beloch/blob/main/examples/crane.bel) -in the repository; the figures below build it up section by section, and -each shows only the lines it adds. - -Beloch describes paper that lies flat. The crane ends where its last flat -step ends, with the wings still closed; spreading them makes the model -three-dimensional, which the language does not model. - -## The base and its center line - -The program starts where the first page ended: the preliminary base, with -the center of the paper named `.o`. - -::: {.figure #fig-crane-base caption="The preliminary base. `--mid` runs from the loose corners at `.c` to the closed tip `.o`." views="cp folded" highlight=".o --mid"} -paper square -fold (map .a onto .c) as --bd -reverse (map .b onto .c) as --h -reverse (map .d onto .c) as --v -.o = --h * --v ---mid = (through .c .o) -::: - -On the table the base is a small square. The four corners of the sheet lie -together at one of its corners, `.c`, the *loose corners*. The center of the -sheet is the opposite corner, `.o`, the *closed tip*, where no paper edge -reaches. `--mid` is the line between them, the *center line* of the base. -It is bound with `=`, so it has no crease under it. The next folds bring -paper onto it, and a line you only fold onto never needs to be scored. - -## The side corners - -The two remaining corners of the base square are its *side corners*. Each -is two layers thick, one on the front of the base and one on the back, so -there are four: `.sr` and `.sl` on the front, right and left, `.br` and -`.bl` on the back. Each is reverse-folded inside, so that its edge lies -along the center line. - -::: {.figure #fig-crane-sides caption="The four side corners reversed onto the center line. Each crease runs from the loose corners at `.c`." views="cp folded" highlight="--mid" after="fig-crane-base"} -.sr = --ab * --h -reverse (map .sr onto --mid through .c) as --rsr -.sl = --da * --v -reverse (map .sl onto --mid through .c) as --rsl -.br = --bc * --h -reverse (map .br onto --mid through .c) as --rbr -.bl = --cd * --v -reverse (map .bl onto --mid through .c) as --rbl -::: - -`.sr = --ab * --h` finds a side corner as a crossing on the unfolded sheet. -[First folds](/guide/first-folds/#points-from-creases) showed that `--h` -left two scars, one of them running from the center down to the bottom -edge. That scar meets the bottom edge `--ab` at $(1/2, 0)$, the middle of -the bottom edge, and on the base this spot is the right side corner of the -front layer. `.sl`, `.br` and `.bl` are the other three the same way, each -where an edge of the sheet meets a scar of `--h` or `--v`. - -`(map .sr onto --mid through .c)` is the axiom that folds a point onto a -line with a fold line through a second point. It has up to two solutions. -Here only one of them crosses the folded paper, so the program needs no -item to choose. - -## The bird base - -The front flap and the back flap are folded over along the same line, -square to the center line through the side corners. That leaves the two long -points, the future neck and tail, standing up in the middle: the bird base. - -::: {.figure #fig-crane-bird caption="The bird base. `--pf` folds the front flap, `--pb` the back flap along the same line." views="cp folded" highlight="--pf --pb" after="fig-crane-sides"} -fold (perp --mid through .sr) (moving .a) (up to #[.a .o]) as --pf -fold (perp --mid through .sr) (moving .c) (up to #[.c .o]) (mountain) as --pb -::: - -`(perp --mid through .sr)` is the axiom for the line through a point, -square to another line. - -The two folds follow the rule of -[Which layers move](/guide/first-folds/#which-layers-move). Without `up to` -each would take every layer below the line, front and back together. -`#[.a .o]` is the flap that holds both the corner `.a` and the paper center -`.o`: the center face of the front. `(up to #[.a .o])` makes the valley -fold take that face and the layers on top of it. The side corners reversed -beneath it are joined to it by creases away from the fold line, so they go -along, and the front flap moves whole. The second fold names the center -face of the back, and `(mountain)` makes it fold away from the viewer, -taking that face and the layers beneath it. Seen from the front, its crease -is a ridge. - -The two long points left standing are the *legs* of the bird base. Their -tips are the corners `.b` and `.d`. - -## Narrowing the legs - -Each of the two long points gets narrower by folding its outer edges onto -the center line, on the front and on the back. That is four folds, and each -has to move exactly one layer. - -::: {.figure #fig-crane-legs caption="The legs narrowed. The front edges fold as valleys (`--n1`, `--n2`), the back edges as mountains." views="cp folded" highlight="--n1 --n2" after="fig-crane-bird"} -.e1 = (--rsr & .b) * --pf -fold (map --rsr & .b onto --mid) (moving .e1) (up to #[.e1 .b .o]) as --n1 -.e2 = (--rsl & .d) * --pf -fold (map --rsl & .d onto --mid) (moving .e2) (up to #[.e2 .d .o]) as --n2 -.e3 = (--rbr & .b) * --pb -fold (map --rbr & .b onto --mid) (moving .e3) (up to #[.e3 .b .o]) (mountain) as --n3 -.e4 = (--rbl & .d) * --pb -fold (map --rbl & .d onto --mid) (moving .e4) (up to #[.e4 .d .o]) (mountain) as --n4 -::: - -`&` does the work here, as it picked the rays of the collapse on the first -page: it narrows a crease to one of its pieces. Once a crease has been -folded over, its scars point in different directions, and "the line of -`--rsr`" no longer names one line. -`--rsr & .b` is the piece of `--rsr` that touches `.b`: the outer edge of -the leg that ends in `.b`. That piece is straight, so it can be folded onto -`--mid`. - -Each fold names its side with `moving` on a point bound on the line before -it, `.e1` to `.e4`: the point where that edge meets the crease of the flap -it lies on. Its `up to` names the layer of the leg that holds that point, -the leg's tip and the paper center, so the valley fold takes the front -layer and nothing beneath it. Without `up to` the fold would take the back -layers too, because the edge runs through them as well. The two back folds -name the back layer and fold as mountains. - -## Neck and tail - -Each narrowed leg is inside reverse-folded, so that it turns up between the -layers of the body: one becomes the neck, the other the tail. - -::: {.figure #fig-crane-neck caption="The neck and the tail, each reversed about a line square to its narrowed edge." views="cp folded" highlight="--neck --tail" after="fig-crane-legs"} -reverse (perp --n1 through .sr) (moving .b) as --neck -reverse (perp --n2 through .sr) (moving .d) as --tail -::: - -A perpendicular moves nothing by itself, so unlike a `map`, it does not say -which side goes, and the reverse fold needs `(moving .b)`: the tip of the -leg that becomes the neck. - -## The head - -The last fold bends the tip of the neck into a head. Where exactly it bends -is a choice the folder makes by eye, and the program says so. - -::: {.figure #fig-crane-head caption="The finished crane. `.hp` is where the head bends, `.ht` sets its angle." views="cp folded" highlight=".hp .ht --head" after="fig-crane-neck"} -.hp = free on --bd & .b from .b at 1/4 -.ht = free on --rsl & .a from .a at 1/2 -reverse (through .hp .ht) (moving .b) as --head -::: - -`free on --bd & .b from .b at 1/4` names a spot a quarter of the way along -the piece of `--bd` that touches `.b`, counted from `.b`, measured on the -paper. As in the collapse on the first page, `free` records that the -position was a choice and follows from no construction; the program folds -with the point like with any other. Two such points pin down the line of -the head fold. - -## References diff --git a/packages/www/src/content/docs/guide/reading-the-crane.md b/packages/www/src/content/docs/guide/reading-the-crane.md new file mode 120000 index 000000000..9d8d68406 --- /dev/null +++ b/packages/www/src/content/docs/guide/reading-the-crane.md @@ -0,0 +1 @@ +../../../../../../docs/guide/reading-the-crane.md \ No newline at end of file diff --git a/packages/www/src/content/docs/kernel.md b/packages/www/src/content/docs/kernel.md index 5b57f5f14..2e5e433fd 120000 --- a/packages/www/src/content/docs/kernel.md +++ b/packages/www/src/content/docs/kernel.md @@ -1 +1 @@ -../../../../../spec/KERNEL.md \ No newline at end of file +../../../../../docs/reference/KERNEL.md \ No newline at end of file diff --git a/packages/www/src/content/docs/language.md b/packages/www/src/content/docs/language.md index a8dd2701f..8e54392a7 120000 --- a/packages/www/src/content/docs/language.md +++ b/packages/www/src/content/docs/language.md @@ -1 +1 @@ -../../../../../spec/BELOCH.md \ No newline at end of file +../../../../../docs/reference/BELOCH.md \ No newline at end of file diff --git a/packages/www/src/content/docs/language/annotations.md b/packages/www/src/content/docs/language/annotations.md index 9a07ec436..b20a05226 120000 --- a/packages/www/src/content/docs/language/annotations.md +++ b/packages/www/src/content/docs/language/annotations.md @@ -1 +1 @@ -../../../../../../spec/BELOCH-ANNOTATIONS.md \ No newline at end of file +../../../../../../docs/reference/BELOCH-ANNOTATIONS.md \ No newline at end of file diff --git a/packages/www/src/content/docs/language/constructions.md b/packages/www/src/content/docs/language/constructions.md index ca04eee3f..e035c94f1 120000 --- a/packages/www/src/content/docs/language/constructions.md +++ b/packages/www/src/content/docs/language/constructions.md @@ -1 +1 @@ -../../../../../../spec/BELOCH-CONSTRUCTIONS.md \ No newline at end of file +../../../../../../docs/reference/BELOCH-CONSTRUCTIONS.md \ No newline at end of file diff --git a/packages/www/src/content/docs/language/grammar.md b/packages/www/src/content/docs/language/grammar.md index f8f301add..7582dbe4a 120000 --- a/packages/www/src/content/docs/language/grammar.md +++ b/packages/www/src/content/docs/language/grammar.md @@ -1 +1 @@ -../../../../../../spec/BELOCH-GRAMMAR.md \ No newline at end of file +../../../../../../docs/reference/BELOCH-GRAMMAR.md \ No newline at end of file diff --git a/packages/www/src/content/docs/language/writes.md b/packages/www/src/content/docs/language/writes.md index 68c1e0df4..eb208cd20 120000 --- a/packages/www/src/content/docs/language/writes.md +++ b/packages/www/src/content/docs/language/writes.md @@ -1 +1 @@ -../../../../../../spec/BELOCH-WRITES.md \ No newline at end of file +../../../../../../docs/reference/BELOCH-WRITES.md \ No newline at end of file diff --git a/packages/www/src/content/docs/model.md b/packages/www/src/content/docs/model.md index c3449dee3..90ed8a757 120000 --- a/packages/www/src/content/docs/model.md +++ b/packages/www/src/content/docs/model.md @@ -1 +1 @@ -../../../../../spec/MODEL.md \ No newline at end of file +../../../../../docs/reference/MODEL.md \ No newline at end of file diff --git a/packages/www/src/content/docs/output.md b/packages/www/src/content/docs/output.md index 24e4537bc..db5f2701a 120000 --- a/packages/www/src/content/docs/output.md +++ b/packages/www/src/content/docs/output.md @@ -1 +1 @@ -../../../../../spec/FOLD.md \ No newline at end of file +../../../../../docs/reference/FOLD.md \ No newline at end of file diff --git a/packages/www/src/lib/eval-bel.ts b/packages/www/src/lib/eval-bel.ts index f79e0d683..ce6c2d336 100644 --- a/packages/www/src/lib/eval-bel.ts +++ b/packages/www/src/lib/eval-bel.ts @@ -29,7 +29,7 @@ export function evalBelToFold(source: string, opts: { trace?: boolean } = {}): u code?: string; stdout?: Buffer | string; stderr?: Buffer | string; message?: string; }; // Traced, a program that fails still writes its file, with the failure in - // `beloch:error` (spec/FOLD.md, "The trace"); a figure may draw that state. + // `beloch:error` (docs/reference/FOLD.md, "The trace"); a figure may draw that state. const partial = opts.trace ? e.stdout?.toString() : undefined; if (partial) return JSON.parse(partial); if (e.code === "ENOENT") { diff --git a/packages/www/src/lib/fixtures/remark-bel-blocks.json b/packages/www/src/lib/fixtures/remark-bel-blocks.json index c841e0738..79ed3eb1f 100644 --- a/packages/www/src/lib/fixtures/remark-bel-blocks.json +++ b/packages/www/src/lib/fixtures/remark-bel-blocks.json @@ -1,5 +1,5 @@ { - "spec/BELOCH.md": [ + "docs/reference/BELOCH.md": [ { "index": 0, "status": "ok", "expected": false, "asserts": [] }, { "index": 1, diff --git a/packages/www/src/lib/grammar-notation.ts b/packages/www/src/lib/grammar-notation.ts index 52edfc99c..fd088eca5 100644 --- a/packages/www/src/lib/grammar-notation.ts +++ b/packages/www/src/lib/grammar-notation.ts @@ -1,4 +1,4 @@ -// The grammar notation of spec/BELOCH.md: a lexer over one line at a time, the +// The grammar notation of docs/reference/BELOCH.md: a lexer over one line at a time, the // document checks, and the HTML renderers. // // A rule starts at column 0 and runs to the next line that starts at column 0 diff --git a/packages/www/src/lib/reference-corpus.test.ts b/packages/www/src/lib/reference-corpus.test.ts index 61aaa67ac..1116b8885 100644 --- a/packages/www/src/lib/reference-corpus.test.ts +++ b/packages/www/src/lib/reference-corpus.test.ts @@ -1,6 +1,6 @@ /** * The tree-sitter side of the reference corpus test (design doc "The three - * runners"): every tagged block of the language pages, spec/BELOCH*.md, extracted by the same + * runners"): every tagged block of the language pages, docs/reference/BELOCH*.md, extracted by the same * rule as packages/core/tests/test_reference_corpus.ml, parses with the * shipped wasm and produces no ERROR node. Unlike the kernel runner this * stays parse-only: a block is parsed on its own, without its prelude @@ -76,7 +76,7 @@ function parseTag(info: string): Tag | null { return null; } -// Every fence in spec/*.md opens and closes with a bare ``` line (no longer +// Every fence in docs/reference/*.md opens and closes with a bare ``` line (no longer // backtick run, no indentation); an unterminated fence is a malformed // document, not a block to silently drop. function extractBlocks(src: string): Block[] { @@ -102,7 +102,7 @@ function extractBlocks(src: string): Block[] { return blocks; } -// Block inventory of each language page, spec/BELOCH*.md, by tag (matches +// Block inventory of each language page, docs/reference/BELOCH*.md, by tag (matches // test_reference_corpus.ml's expected_inventories). Ceiling: this catches the // tree-sitter extractor drifting from the pages, not from the OCaml and // build-side copies of the same rule; update all three when a tagged block is @@ -115,13 +115,13 @@ const expectedInventories: Record> = { "BELOCH-GRAMMAR.md": { whole: 0, prelude: 0, frag: 0, construction: 0 }, }; -const languagePages = readdirSync(join(repoRoot, "spec")) +const languagePages = readdirSync(join(repoRoot, "docs", "reference")) .filter((f) => f.startsWith("BELOCH") && f.endsWith(".md")) .sort(); for (const page of languagePages) { test(`${page} reference corpus: every tagged block parses with no ERROR node`, async () => { - const src = readFileSync(join(repoRoot, "spec", page), "utf8"); + const src = readFileSync(join(repoRoot, "docs", "reference", page), "utf8"); const blocks = extractBlocks(src); const inventory: Record = { whole: 0, prelude: 0, frag: 0, construction: 0 }; diff --git a/packages/www/src/lib/remark-bel.test.ts b/packages/www/src/lib/remark-bel.test.ts index 8304b0934..d578b01d8 100644 --- a/packages/www/src/lib/remark-bel.test.ts +++ b/packages/www/src/lib/remark-bel.test.ts @@ -19,7 +19,7 @@ async function render(blocks: string): Promise { return String( await unified() .use(remarkParse) - .use(remarkBel, { blocks, doc: "spec/BELOCH.md" }) + .use(remarkBel, { blocks, doc: "docs/reference/BELOCH.md" }) .use(remarkRehype, { allowDangerousHtml: true }) .use(rehypeStringify, { allowDangerousHtml: true }) .process(readFileSync(doc, "utf8")), @@ -124,7 +124,7 @@ test("a missing blocks.json is not fatal", async () => { expect(withoutBuild).not.toContain("sentinel-prelude-marker"); }); -// Fix for a bug where the plugin always fell back to spec/BELOCH.md's +// Fix for a bug where the plugin always fell back to docs/reference/BELOCH.md's // entries regardless of which document was being processed: a document with // no entry in blocks.json must render nothing, even when blocks.json holds // entries (for a different document) at the same indices. @@ -132,7 +132,7 @@ test("a document with no blocks.json entry renders no outcomes at all", async () const rendered = String( await unified() .use(remarkParse) - .use(remarkBel, { blocks: blocksWithEntries, doc: "spec/OTHER.md" }) + .use(remarkBel, { blocks: blocksWithEntries, doc: "docs/reference/OTHER.md" }) .use(remarkRehype, { allowDangerousHtml: true }) .use(rehypeStringify, { allowDangerousHtml: true }) .process(readFileSync(doc, "utf8")), @@ -147,7 +147,7 @@ async function renderInline(markdown: string): Promise { return String( await unified() .use(remarkParse) - .use(remarkBel, { blocks: blocksWithEntries, doc: "spec/OTHER.md" }) + .use(remarkBel, { blocks: blocksWithEntries, doc: "docs/reference/OTHER.md" }) .use(remarkRehype, { allowDangerousHtml: true }) .use(rehypeStringify, { allowDangerousHtml: true }) .process(markdown), diff --git a/packages/www/src/lib/remark-bel.ts b/packages/www/src/lib/remark-bel.ts index 80ffa604b..18fe707cb 100644 --- a/packages/www/src/lib/remark-bel.ts +++ b/packages/www/src/lib/remark-bel.ts @@ -5,7 +5,7 @@ // highlighter covers completely gets the same colors; any other inline code, // a path or an identifier, is left to the page. // -// spec/BELOCH.md's example blocks carry pandoc's attribute form of the info +// docs/reference/BELOCH.md's example blocks carry pandoc's attribute form of the info // string, `{.bel .frag prelude=triangle}` (design doc "Marking the blocks"), // because pandoc's markdown reader takes only a single bare word or a bracketed // attribute list. remark-parse splits an info string at its first space, so a @@ -48,9 +48,9 @@ function repoRoot(): string { // The document a processed file corresponds to, relative to the repo root: // the same key packages/core/tools/blocks.ml writes into blocks.json. The // reference documents are reached through symlinks under -// src/content/docs/ (e.g. language.md -> ../../../../../spec/BELOCH.md). +// src/content/docs/ (e.g. language.md -> ../../../../../docs/reference/BELOCH.md). // Resolving the path before comparing keeps a symlinked page keyed off the -// spec/ path blocks.ml wrote entries under, instead of its own content +// docs/reference/ path blocks.ml wrote entries under, instead of its own content // path. `null` when the file carries no path at all (e.g. a `VFile` built // straight from a string), left to the caller. function docPathOf(file: any): string | null { @@ -89,7 +89,7 @@ function parseFenceTag( return { isPrelude: classes.includes(".prelude") }; } -// `_build/spec/blocks.json`[doc] once no `.exe` has run yet: `astro dev` still +// `_build/reference/blocks.json`[doc] once no `.exe` has run yet: `astro dev` still // has to work, so every block just falls through to the no-entry rendering. function loadEntries(path: string, doc: string): BlockEntry[] { try { @@ -146,7 +146,7 @@ function withoutAssertions(src: string): string { export default function remarkBel(options: { blocks?: string; doc?: string } = {}) { return async (tree: any, file: any) => { - const blocksPath = options.blocks ?? join(repoRoot(), "_build", "spec", "blocks.json"); + const blocksPath = options.blocks ?? join(repoRoot(), "_build", "reference", "blocks.json"); const doc = options.doc ?? docPathOf(file) ?? ""; const entries = loadEntries(blocksPath, doc); diff --git a/packages/www/src/lib/remark-grammar.ts b/packages/www/src/lib/remark-grammar.ts index 99f72707f..0bed11b66 100644 --- a/packages/www/src/lib/remark-grammar.ts +++ b/packages/www/src/lib/remark-grammar.ts @@ -1,4 +1,4 @@ -// Grammar fragments of spec/BELOCH-GRAMMAR.md. `grammar`, `grammar-external` +// Grammar fragments of docs/reference/BELOCH-GRAMMAR.md. `grammar`, `grammar-external` // and `grammar-planned` fenced blocks become raw HTML: every rule gets an id, // and every nonterminal on a right-hand side gets a link to its rule. // diff --git a/packages/www/src/lib/remark-model-blocks.ts b/packages/www/src/lib/remark-model-blocks.ts index eb5290998..b7ae755e0 100644 --- a/packages/www/src/lib/remark-model-blocks.ts +++ b/packages/www/src/lib/remark-model-blocks.ts @@ -1,4 +1,4 @@ -// Typed cross-references for spec/MODEL.md. Pandoc fenced divs +// Typed cross-references for docs/reference/MODEL.md. Pandoc fenced divs // // ::: {.definition #def-flat-state name="flat folded state" defines="term-table"} // body @@ -11,7 +11,7 @@ // // `::: {.figure #fig-point caption="…" views="cp folded" highlight=".p"}` is a // Beloch program with its crease pattern and its folded form beside it. The -// SVGs come pre-rendered from _build/spec/figures (scripts/render-figures.ts); +// SVGs come pre-rendered from _build/reference/figures (scripts/render-figures.ts); // a figure with no files there renders a placeholder and the build carries on. // Figures are numbered per section on a counter of their own, so adding one // renumbers no statement. @@ -96,7 +96,7 @@ function repoRoot(): string { // Whether the file being processed is the model document. The reference // documents are reached through symlinks under src/content/docs/ (model.md -> -// ../../../../../spec/MODEL.md), so both sides are resolved before comparing. +// ../../../../../docs/reference/MODEL.md), so both sides are resolved before comparing. function samePath(a: string | undefined, b: string): boolean { if (!a) return false; const real = (path: string) => { @@ -244,8 +244,8 @@ export default function remarkModelBlocks( const processor = this; return async (tree: any, file: any) => { const registerPath = options.register ?? join(repoRoot(), "_build", "api-register.json"); - const modelPath = options.model ?? join(repoRoot(), "spec", "MODEL.md"); - const figuresPath = options.figures ?? join(repoRoot(), "_build", "spec", "figures"); + const modelPath = options.model ?? join(repoRoot(), "docs", "reference", "MODEL.md"); + const figuresPath = options.figures ?? join(repoRoot(), "_build", "reference", "figures"); const source = String(file.value ?? ""); if (!source.includes(":::")) return; const raw = scanBlocks(source).filter( diff --git a/scripts/api-register.ts b/scripts/api-register.ts index eb75cbe31..16c5684f1 100644 --- a/scripts/api-register.ts +++ b/scripts/api-register.ts @@ -8,7 +8,7 @@ // the item is documented on (scripts/build-api-docs.sh publishes that HTML // under /api/). // -// The register is what `::: {.include api="Fold_state.t"}` blocks in spec/ are +// The register is what `::: {.include api="Fold_state.t"}` blocks in docs/reference/ are // replaced by, on both renderers (packages/www/src/lib/remark-model-blocks.ts, // scripts/model-blocks.lua), and what gives the model page its "Realized by" // lines. diff --git a/scripts/build-api-docs.sh b/scripts/build-api-docs.sh index 3587ec443..ad0dfc6e4 100755 --- a/scripts/build-api-docs.sh +++ b/scripts/build-api-docs.sh @@ -7,21 +7,21 @@ # and gitignored. # # scripts/api-register.ts reads the same .mli sources and records these paths -# in _build/api-register.json, which the `.include` blocks in spec/ read; it +# in _build/api-register.json, which the `.include` blocks in docs/reference/ read; it # runs here as well so one command produces both. # -# scripts/grammar-register.ts parses the grammar fragments of spec/ into +# scripts/grammar-register.ts parses the grammar fragments of docs/reference/ into # _build/grammar.json, which the pandoc filter renders the PDF's grammar pages # from and which the keyword cross-check reads; it runs here so one command # still produces every generated input the spec documents read. # -# scripts/render-figures.ts draws the `.figure` blocks of spec/ and the guide into -# _build/spec/figures, the other generated input both renderers of those +# scripts/render-figures.ts draws the `.figure` blocks of docs/reference/ and the guide into +# _build/reference/figures, the other generated input both renderers of those # documents read. It needs the `beloch` binary on PATH. # # packages/core/tools/blocks.exe evaluates the tagged `.bel` blocks of the -# language pages, spec/BELOCH*.md, and the guide and writes -# _build/spec/blocks.json, which packages/www/src/lib/remark-bel.ts reads to +# language pages, docs/reference/BELOCH*.md, and the guide and writes +# _build/reference/blocks.json, which packages/www/src/lib/remark-bel.ts reads to # render each block's outcome. It reads and writes paths relative to the repo # root, hence the `cd`. # @@ -36,7 +36,7 @@ dune build --root "$root" @doc bun "$root/scripts/api-register.ts" bun "$root/scripts/grammar-register.ts" bun "$root/scripts/render-figures.ts" -(cd "$root" && dune exec packages/core/tools/blocks.exe -- spec/BELOCH*.md packages/www/src/content/docs/guide/*.md) +(cd "$root" && dune exec packages/core/tools/blocks.exe -- docs/reference/BELOCH*.md packages/www/src/content/docs/guide/*.md) rm -rf "$dest" mkdir -p "$dest" diff --git a/scripts/check-commit-subjects.sh b/scripts/check-commit-subjects.sh index b4faa777c..fd4d6ea00 100755 --- a/scripts/check-commit-subjects.sh +++ b/scripts/check-commit-subjects.sh @@ -32,7 +32,7 @@ set -uo pipefail root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) -OTHER_SCOPES=(spec decisions notes paper examples brand ci nix) +OTHER_SCOPES=(reference decision notes paper examples brand ci nix) TYPES=(feat fix docs refactor test chore build ci perf style revert) package_scopes() { diff --git a/scripts/decisions.test.ts b/scripts/decisions.test.ts index 8f67939c3..927a61b7b 100644 --- a/scripts/decisions.test.ts +++ b/scripts/decisions.test.ts @@ -2,7 +2,7 @@ import { test, expect } from "bun:test"; import { readdirSync, readFileSync } from "node:fs"; import { join } from "node:path"; -const dir = join(import.meta.dir, "..", "decisions"); +const dir = join(import.meta.dir, "..", "docs", "decision"); const records = readdirSync(dir).filter((f) => /^\d{4}-.*\.md$/.test(f)); test("a record's issue names owner and repository", () => { diff --git a/scripts/grammar-blocks.lua b/scripts/grammar-blocks.lua index 2d09dd61a..7bd9ba707 100644 --- a/scripts/grammar-blocks.lua +++ b/scripts/grammar-blocks.lua @@ -1,4 +1,4 @@ --- Grammar fragments of spec/BELOCH-GRAMMAR.md, pandoc side. +-- Grammar fragments of docs/reference/BELOCH-GRAMMAR.md, pandoc side. -- -- The parse is shared with the docs site through _build/grammar.json -- (scripts/grammar-register.ts writes it; BELOCH_GRAMMAR_REGISTER overrides the diff --git a/scripts/grammar-register.test.ts b/scripts/grammar-register.test.ts index 7bb8f07b0..2bd3cace9 100644 --- a/scripts/grammar-register.test.ts +++ b/scripts/grammar-register.test.ts @@ -13,10 +13,10 @@ const root = join(import.meta.dir, ".."); const register = buildGrammarRegister(DOCUMENTS); const lexerSource = readFileSync(join(root, LEXER), "utf8"); -const beloch = register.documents.find((d) => d.path === "spec/BELOCH-GRAMMAR.md"); -if (!beloch) throw new Error("spec/BELOCH-GRAMMAR.md missing from the register"); +const beloch = register.documents.find((d) => d.path === "docs/reference/BELOCH-GRAMMAR.md"); +if (!beloch) throw new Error("docs/reference/BELOCH-GRAMMAR.md missing from the register"); -test("spec/BELOCH-GRAMMAR.md yields 31 rules and 7 external names", () => { +test("docs/reference/BELOCH-GRAMMAR.md yields 31 rules and 7 external names", () => { expect(beloch.fragments.flatMap((f) => f.rules).length).toBe(31); expect(beloch.external.length).toBe(7); expect(beloch.external.map((e) => e.name)).toEqual([ @@ -66,8 +66,8 @@ test("a rule's lines are the rendering contract both renderers consume", () => { ]); }); -test("spec/SPECIFICATION.md is in the register, read for its keywords", () => { - const spec = register.documents.find((d) => d.path === "spec/SPECIFICATION.md"); +test("docs/reference/SPECIFICATION.md is in the register, read for its keywords", () => { + const spec = register.documents.find((d) => d.path === "docs/reference/SPECIFICATION.md"); expect(spec?.fragments.flatMap((f) => f.rules).length).toBeGreaterThan(20); expect(spec?.external).toEqual([]); }); @@ -89,7 +89,7 @@ test("a documented keyword the lexer lacks fails, naming where it is stated", () const failures = crossCheck(register, unlexed, LEXER); expect(failures).toEqual([ expect.stringMatching( - /^keyword "align" is stated in spec\/BELOCH-GRAMMAR\.md:\d+ and packages\/core\/lib\/lexer\.ml does not lex it$/, + /^keyword "align" is stated in docs\/reference\/BELOCH-GRAMMAR\.md:\d+ and packages\/core\/lib\/lexer\.ml does not lex it$/, ), ]); }); @@ -104,14 +104,14 @@ test("a lexed keyword no documented rule states fails, naming the keyword", () = test("a planned keyword the lexer already has fails, naming its entry", () => { const stale = { documents: register.documents.map((d) => - d.path === "spec/BELOCH-GRAMMAR.md" + d.path === "docs/reference/BELOCH-GRAMMAR.md" ? { ...d, planned: [...d.planned, { keyword: "map", line: 275, note: "" }] } : d, ), }; const failures = crossCheck(stale, lexerSource, LEXER); expect(failures).toEqual([ - 'keyword "map" is declared planned in spec/BELOCH-GRAMMAR.md:275 and packages/core/lib/lexer.ml ' + + 'keyword "map" is declared planned in docs/reference/BELOCH-GRAMMAR.md:275 and packages/core/lib/lexer.ml ' + "lexes it; remove the entry", ]); }); diff --git a/scripts/grammar-register.ts b/scripts/grammar-register.ts index 06f3296f0..36a3e1223 100644 --- a/scripts/grammar-register.ts +++ b/scripts/grammar-register.ts @@ -1,8 +1,8 @@ #!/usr/bin/env bun -// The grammar register: the documented grammar of spec/, parsed. +// The grammar register: the documented grammar of docs/reference/, parsed. // -// Scans spec/BELOCH-GRAMMAR.md, the grammar of the language, and -// spec/SPECIFICATION.md, whose Appendix A block carries the `grammar` tag and +// Scans docs/reference/BELOCH-GRAMMAR.md, the grammar of the language, and +// docs/reference/SPECIFICATION.md, whose Appendix A block carries the `grammar` tag and // is read for its keywords alone: no ids, no links, and its rules satisfy no // external declaration of the grammar page. Parsing both means the documented // side of the keyword cross-check is the whole documented grammar while the @@ -34,8 +34,8 @@ export interface GrammarRegister { } export const DOCUMENTS: DocumentSpec[] = [ - { path: "spec/BELOCH-GRAMMAR.md", references: "check" }, - { path: "spec/SPECIFICATION.md", references: "ignore" }, + { path: "docs/reference/BELOCH-GRAMMAR.md", references: "check" }, + { path: "docs/reference/SPECIFICATION.md", references: "ignore" }, ]; /** The keyword table the cross-check reads. */ diff --git a/scripts/model-blocks.lua b/scripts/model-blocks.lua index b8de7d03d..76a71c1f3 100644 --- a/scripts/model-blocks.lua +++ b/scripts/model-blocks.lua @@ -1,4 +1,4 @@ --- Typed cross-references for spec/MODEL.md, pandoc side. +-- Typed cross-references for docs/reference/MODEL.md, pandoc side. -- -- Pandoc reads `::: {.definition #def-sheet name="sheet" uses="…"}` as a Div, -- so this filter only has to number the statements, render the head and links @@ -12,7 +12,7 @@ -- -- `::: {.figure #fig-point caption="…" views="cp folded"}` becomes the figure's -- pre-rendered views side by side, the caption, and the program as a code --- block. The SVGs come from _build/spec/figures (scripts/render-figures.ts +-- block. The SVGs come from _build/reference/figures (scripts/render-figures.ts -- writes them; BELOCH_FIGURES overrides the directory); a view with no file -- renders a placeholder. The program text is read from the source file rather -- than from the Div's content, because the markdown reader has already turned @@ -37,7 +37,7 @@ -- register an `.include` block renders a placeholder and no statement gets that -- line. -- --- Labels for links into the model come from spec/MODEL.md, which this filter +-- Labels for links into the model come from docs/reference/MODEL.md, which this filter -- scans line by line when the document it is rendering is not the model itself; -- an id it cannot number is written as the id. @@ -91,13 +91,13 @@ local function register() return api end --- spec/MODEL.md's numbering, read from the source. The same counting rule as +-- docs/reference/MODEL.md's numbering, read from the source. The same counting rule as -- `collect` below, over the fenced divs as they are written. local modelLabels = nil local function model_labels() if modelLabels then return modelLabels end modelLabels = {} - local file = io.open(root .. "/spec/MODEL.md", "r") + local file = io.open(root .. "/docs/reference/MODEL.md", "r") if not file then return modelLabels end local section, counters, figureCounters = 0, {}, {} for line in file:lines() do @@ -404,7 +404,7 @@ local function figure_div(id, f) -- typst resolves a leading slash against its project root, which is the -- directory pandoc runs in; scripts/render-model.sh makes that the repo root, -- so the directory is named relative to it. - local dir = os.getenv("BELOCH_FIGURES") or "_build/spec/figures" + local dir = os.getenv("BELOCH_FIGURES") or "_build/reference/figures" local width = #f.views > 1 and "48%" or "70%" local views, missing = {}, {} for _, view in ipairs(f.views) do diff --git a/scripts/prose.sh b/scripts/prose.sh index 9e3d99759..7ce219415 100755 --- a/scripts/prose.sh +++ b/scripts/prose.sh @@ -36,10 +36,10 @@ if [ $# -gt 0 ]; then else # Test fixtures and the license are not prose of the project. The brand # documents are left out until the lint has rules for German. - # spec/SPECIFICATION.md is being dissolved into the other documents (ADR + # docs/reference/SPECIFICATION.md is being dissolved into the other documents (ADR # 0032); its sections are linted where they move to. mapfile -t targets < <(tracked | grep -E '\.(md|mdx|ml|mli|ts|css|lua|astro|typ|sh)$' | - grep -vE '^(LICENSE\.md$|packages/www/src/lib/fixtures/|scripts/fixtures/|spec/SPECIFICATION\.md$)') + grep -vE '^(LICENSE\.md$|packages/www/src/lib/fixtures/|scripts/fixtures/|docs/reference/SPECIFICATION\.md$)') # A failed file listing leaves the list empty; stop there, or the run # reports no alerts for a tree it never read. [ ${#targets[@]} -gt 0 ] || { echo "prose: no files listed" >&2; exit 1; } diff --git a/scripts/render-figures.test.ts b/scripts/render-figures.test.ts index 8e58bf070..b3fa7c0ba 100644 --- a/scripts/render-figures.test.ts +++ b/scripts/render-figures.test.ts @@ -16,7 +16,7 @@ test("a highlight the program defines renders both views", () => { const entry = renderFigure( { id: "fig-ok", views: ["cp"], highlight: ["--ac", ".a"], program: SQUARE }, outDir, - "spec/TEST.md", + "docs/reference/TEST.md", ); expect(entry.error).toBeNull(); expect(entry.files.cp).toBe("fig-ok-cp.svg"); @@ -27,7 +27,7 @@ test("a highlight naming an entity the program does not define is an error", () const entry = renderFigure( { id: "fig-bad", views: ["cp"], highlight: ["--ac", "--nope"], program: SQUARE }, outDir, - "spec/TEST.md", + "docs/reference/TEST.md", ); expect(entry.error).toContain("fig-bad"); expect(entry.error).toContain("--nope"); @@ -38,7 +38,7 @@ test("an unknown point inside a flap selector is named too", () => { const entry = renderFigure( { id: "fig-flapless", views: ["cp"], highlight: ["#[.zz]"], program: SQUARE }, outDir, - "spec/TEST.md", + "docs/reference/TEST.md", ); expect(entry.error).toContain("fig-flapless"); expect(entry.error).toContain(".zz"); @@ -70,7 +70,7 @@ test("a candidates figure draws the choices of a program that stops at them", () const entry = renderFigure( { id: "fig-choice", views: ["candidates"], highlight: [], at: "choose", program: AMBIGUOUS }, outDir, - "spec/TEST.md", + "docs/reference/TEST.md", ); expect(entry.error).toBeNull(); expect(entry.files.candidates).toBe("fig-choice-candidates.svg"); @@ -85,7 +85,7 @@ test("an op figure draws the write of the labeled statement", () => { program: "paper square\nfold (map .a onto .c) as --bd\n@label rev\nreverse (map .b onto .c) as --h\n", }, outDir, - "spec/TEST.md", + "docs/reference/TEST.md", ); expect(entry.error).toBeNull(); const svg = readFileSync(join(outDir, "fig-rev-op.svg"), "utf8"); @@ -97,7 +97,7 @@ test("a figure that shows an unlabelled statement is an error", () => { const entry = renderFigure( { id: "fig-noat", views: ["candidates"], highlight: [], at: "nope", program: AMBIGUOUS }, outDir, - "spec/TEST.md", + "docs/reference/TEST.md", ); expect(entry.error).toContain("nope"); }); @@ -176,7 +176,7 @@ test("a highlight may name a crease that a later fold bends", () => { program: "paper square\nfold (map .a onto .c) as --bd\nreverse (map .b onto .c) as --h", }, outDir, - "spec/TEST.md", + "docs/reference/TEST.md", ); expect(entry.error).toBeNull(); expect(readFileSync(join(outDir, "fig-bent-cp.svg"), "utf8")).toContain('data-construction="bd"'); diff --git a/scripts/render-figures.ts b/scripts/render-figures.ts index 33c6c077e..f2dcd38b2 100644 --- a/scripts/render-figures.ts +++ b/scripts/render-figures.ts @@ -2,13 +2,13 @@ // The figures of the reference documents and the guide, drawn by Beloch's own // pipeline. // -// Scans spec/*.md and the guide's pages for `::: {.figure #fig-point +// Scans docs/reference/*.md and the guide's pages for `::: {.figure #fig-point // caption="…" views="cp folded" highlight=".p"}` blocks, whose body is a // Beloch program, evaluates each one // with the `beloch` binary and renders the requested views through // packages/render-2d, the same functions the docs site's card uses. // -// Output goes to _build/spec/figures: one `-.svg` per view (`cp`, +// Output goes to _build/reference/figures: one `-.svg` per view (`cp`, // `folded`, `candidates`, `op`, `stages`, `side`, `faces`), and // index.json (one entry per figure, with the files it produced and the reason // if it produced none). Both renderers of the documents read the SVG files and @@ -141,7 +141,7 @@ export function unknownHighlights( return unknown; } -// The statement a program labels with `@label WORD` (spec/BELOCH-ANNOTATIONS.md), as an index into its statements. +// The statement a program labels with `@label WORD` (docs/reference/BELOCH-ANNOTATIONS.md), as an index into its statements. export function labelledStatement(fold: Record, label: string): number | undefined { const annotations = (fold["beloch:annotations"] ?? []) as { key: string; @@ -210,7 +210,7 @@ export function renderFigure(block: FigureBlock, outDir: string, source: string) } // The directories whose Markdown files carry figures, relative to the repo root. -const DOCUMENT_DIRS = ["spec", "packages/www/src/content/docs/guide"]; +const DOCUMENT_DIRS = ["docs/reference", "packages/www/src/content/docs/guide"]; export function documentFiles(root: string): string[] { return DOCUMENT_DIRS.flatMap((dir) => @@ -259,7 +259,7 @@ export function renderDocuments(root: string, files: string[], outDir: string): function main() { const root = join(import.meta.dir, ".."); const flag = process.argv.indexOf("--out"); - const outDir = flag >= 0 ? process.argv[flag + 1]! : join(root, "_build", "spec", "figures"); + const outDir = flag >= 0 ? process.argv[flag + 1]! : join(root, "_build", "reference", "figures"); rmSync(outDir, { recursive: true, force: true }); mkdirSync(outDir, { recursive: true }); diff --git a/scripts/render-model.sh b/scripts/render-model.sh index 3c4b13be4..373226a8e 100755 --- a/scripts/render-model.sh +++ b/scripts/render-model.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Render the four spec/ documents (MODEL, KERNEL, the language, FOLD) to PDFs with resolved citations. +# Render the four docs/reference/ documents (MODEL, KERNEL, the language, FOLD) to PDFs with resolved citations. # # Statements and terms are pandoc fenced divs, `::: {.definition #id …}`; # scripts/model-blocks.lua numbers them and generates the cross-reference lines @@ -20,7 +20,7 @@ set -euo pipefail root="$(cd "$(dirname "$0")/.." && pwd)" -out="$root/_build/spec" +out="$root/_build/reference" mkdir -p "$out" # typst reads a figure's SVG through a path rooted at the directory pandoc runs @@ -32,7 +32,7 @@ cd "$root" bun "$root/scripts/grammar-register.ts" # The language is one PDF of its pages, in the order of the site's sidebar. -# The pages go to pandoc as copies under $out/language/spec/, where +# The pages go to pandoc as copies under $out/language/docs/reference/, where # grammar-blocks.lua still finds the grammar page's register entry by its # path. A page after the first loses its front matter, since pandoc keeps the # title of the last one, and opens with its title as a level-1 heading @@ -40,9 +40,9 @@ bun "$root/scripts/grammar-register.ts" # where citeproc puts the bibliography. lang="$out/language" rm -rf "$lang" -mkdir -p "$lang/spec" +mkdir -p "$lang/docs/reference" pages=() -for page in spec/BELOCH.md spec/BELOCH-WRITES.md spec/BELOCH-CONSTRUCTIONS.md spec/BELOCH-ANNOTATIONS.md spec/BELOCH-GRAMMAR.md; do +for page in docs/reference/BELOCH.md docs/reference/BELOCH-WRITES.md docs/reference/BELOCH-CONSTRUCTIONS.md docs/reference/BELOCH-ANNOTATIONS.md docs/reference/BELOCH-GRAMMAR.md; do copy="$lang/$page" if [ ${#pages[@]} -eq 0 ]; then grep -vx '## References' "$page" > "$copy" @@ -72,7 +72,7 @@ render() { echo "$out/$name.pdf" } -render model "$root/spec/MODEL.md" -render kernel "$root/spec/KERNEL.md" +render model "$root/docs/reference/MODEL.md" +render kernel "$root/docs/reference/KERNEL.md" render beloch "${pages[@]}" -render fold "$root/spec/FOLD.md" +render fold "$root/docs/reference/FOLD.md"