Strike two NEXT sections the day overtook

This commit is contained in:
Joseph Ferano 2026-09-13 15:03:19 +07:00
parent 8472c50d57
commit 75a430dce2

99
NEXT.md
View File

@ -77,45 +77,21 @@ Odin's `where N >= 0` is a predicate over a **value**, not a type. The `where` m
type predicates (`ordered?`, `copyable?`). Whether it also takes value predicates over a length parameter is a
separate question and should be answered deliberately rather than falling out of the implementation.
## To discuss: two decisions parked during the ownership discussion
## ~~To discuss: two decisions parked during the ownership discussion~~ — **both answered and built**
Both came out of the lane that closed the enum-layout and constant-checking gaps. Its work is sound and committed;
these are questions it raised rather than defects in it.
1. **The header is tracked now.** `vendor/raylib/raylib-5.5.h` is committed beside the package and
`vendor/raylib/headers` names it directly. **`FLAN_RAYLIB_H` is gone** — there is no variable to export and no
way for the check to silently not run, which is what `vendor/raylib/web/` being gitignored had been doing to
every worktree. The old argument for opt-in was that requiring a header makes a build need raylib-devel; that
dissolved once the header shipped with the repository. Measured before committing to it: a warm build of
`raylib-font.flan` is 0.10-0.11s against a 0.10s baseline, because the header read is cached and keyed like the
object cache. Verified it fires by putting `f64` where raylib says `int`.
### 1. The header check cannot run in a worktree, and nothing says so
`.gitignore:60` ignores `vendor/raylib/web/`, so the vendored `raylib.h` exists in the main tree and **never appears
in a worktree checkout**. Every parallel lane that touches bindings is therefore checking against nothing, or
against whatever it can find. The lane that hit this found a copy in `~/.local/share/Trash` and validated it the
right way — `generate-c` rewrote `generated.flan` byte-identically before it changed anything, and the two headers
are md5-identical — but a header in the Trash is not a corpus, and the next lane may be less careful or less lucky.
The options:
- **Vendor `raylib.h` as a tracked file.** It is one header. `BUILT.md` records that requiring a header was
rejected so that "a build needs libraylib linkable and not raylib-devel installed" stays true — but tracking the
header in this repository is not the same as requiring one on the machine, since `headers` is still
`?${FLAN_RAYLIB_H}` and still opt-in. This looks like the answer and the old argument may not actually apply.
- **Fail loudly when `FLAN_RAYLIB_H` names a path that is not there.** Already the behaviour for a set-and-wrong
path; what is missing is any signal when the *default* corpus has vanished, which is the worktree case.
- Leave it, and put the warning in the agent briefs instead. Weakest — it depends on whoever writes the brief
remembering.
### 2. A missing `bindings` line does not stop a build — a judgment call, flagged for review
The lane split its findings by severity:
- A **value mismatch or a missing C name** stops an ordinary build, the way `check_structs` does.
- A **coverage or typo finding about the `bindings` file itself** gates `generate-c` only.
The consequence is the part to decide: a lane that adds a `defenum` to `raylib.flan` and forgets its `bindings`
line gets **no warning from a plain build**, only from `generate-c`. Its reasoning was that failing somebody's
build over a config file, in a message shaped like "your layout is wrong", is the wrong place to stop them.
Arguable in both directions, and the argument against it is the one this whole feature exists for: an unchecked
enum member is exactly the silent wrongness the header read was built to catch, and "you have to remember to run
`generate-c`" is the same shape as "you have to remember to check the header by eye". Overruled by dropping the
`cmapping` guard in `lib/load.ml`.
2. **A `bindings` gap stops a build, and says which file to edit.** The findings stayed split by kind but both are
now fatal. The objection had really been to the *wording* — a coverage gap arrived wrapped in "the package
disagrees with the header", which describes a layout bug and sends the reader to the wrong file. Gating it to
`generate-c` instead meant an unchecked enum member went unreported on every ordinary build, and "remember to
run generate-c" is the same shape as "remember to check the header by eye", which is what this replaced.
## Decided 2026-09-13: generics by monomorphisation, checked abstractly, with `where` predicates
@ -260,45 +236,18 @@ which is an absence rule, and absence is a bad thing to give meaning to.
length rather than only element type. Not in the spike unless it falls out for free; the spike is to report what it
would cost.
## To discuss: five gaps the raylib examples hit and could not close
## ~~To discuss: five gaps the raylib examples hit and could not close~~ — **three closed, two live elsewhere**
Found by the lane that ported `core-2d-camera`, `core-scissor-test`, `core-window-flags`,
`core-world-screen` and `core-window-should-close`. None blocked those five. All five blocked
something else, and each is a language or checker question rather than a missing binding, which is
why they are here and not in a binding list.
1. **A `(Ptr T)` returned from C cannot be indexed.** `indexed` in `lib/check.ml` accepts `Array`
and `Slice` only, so a C function answering `int*` is readable at element 0 through `deref` and
nowhere else. `LoadRandomSequence` is the case that hit it and `core_random_sequence` is
unportable until it moves. The question is what the answer should be: a length has to come from
somewhere before a pointer can become a slice, and C does not supply one. Possibly a
`(slice-from-ptr p n)` where the caller states the length and owns being right about it.
2. ~~**An enum-typed `defstruct` field is refused by the layout check.**~~ **Closed.** The layout
check now accepts an enum where the header says `int`, symmetrically, and still refuses
anything that is not four bytes. `Camera3D.projection` is a `CameraProjection` again and the
`rl/camera-projection` helper is gone; `.projection :perspective` resolves at the construction
site, so the keyword half of the problem went away with it. See BUILT.md.
3. ~~**The header check does not reach `defconst` or `defenum`.**~~ **Closed.** It reaches both.
`bindings` gained `enum`, `const` and `constant` lines that say what a Flan constant is called in
C; every mapped name is compared by value, and a name the mapping cannot find, a rule that
reaches nothing, and a `defenum` with no line at all are each reported rather than skipped. All
eight raylib enums and all 16 `ConfigFlags` bits check out against 5.5. See BUILT.md.
4. **raymath is `static inline`, so there is no symbol to bind.** `Clamp`, `Vector2Add`, `Remap` and
the rest exist only in the header. `declare-c` has nothing to name. rlgl's matrix stack is
unbound for a different reason. Together they make `core_2d_camera_mouse_zoom` unfaithful rather
than merely awkward, so it was skipped. The options are writing the arithmetic in Flan, which is
what the prelude would do anyway, or compiling a small C file that re-exports them as real
symbols.
5. **Four families are still refused by the importer for want of a `defstruct`.** `FilePathList`
(a `char**`, blocks `core_drop_files`), `Model`/`Mesh`/`Ray`/`BoundingBox` (the model and
3D-collision families), and **function-pointer parameters** (`SetTraceLogCallback`, which blocks
`core_custom_logging`, and the audio stream processors). The first three are ordinary widening —
write the `defstruct` and they import. The function-pointer one is not, and is the interesting
one: it is the callback direction of the FFI, which nothing has needed yet.
- **Closed:** an enum-typed `defstruct` field is no longer refused by the layout check (an enum *is* an `i32`, and
the predicate is symmetric now, so the enum may be on either side); the header check reaches `defconst` and
`defenum` through name-mapping directives in `vendor/raylib/bindings`, so a wrong flag bit is no longer silent;
and the `Ptr`-indexing gap has its own queue entry at the top of this file, because it now blocks three
examples rather than being a note.
- **Still open, and both are here rather than in a queue entry because neither has a customer pressing:**
**raymath is `static inline`**, so `Clamp`, `Vector2Add` and `Remap` have no symbol to `declare-c` at all — a lane
measured the alternative and found writing the arithmetic in Flan cost nothing, which is what makes this a
non-problem rather than a gap; and **function-pointer parameters** are refused (`SetTraceLogCallback`, the audio
stream processors), which is the callback direction of the FFI and nothing has needed it yet.
## Queued, 2026-09-13 (second session) — everything four lanes left behind