What a language change costs
Adding syntax is rarely just a parser edit. If the feature changes behavior, its meaning must reach HIR, MIR, the runtime or backend, both execution tests, documentation, and sometimes an artifact version.
Change matrix
| Change | Required surfaces | Version consequence |
|---|---|---|
| syntax or keyword | token vocabulary, lexer, parser/AST, highlighting, positive/refusal specs, Guide/reference | none unless downstream wire meaning also changes |
| type or semantic rule | support types, resolver/checker, HIR, MIR/verifier as needed, both-path spec, diagnostics, docs | MIR bump if encoded types or instructions change |
| dynamic operation | runtime body/export, MIR instruction or intrinsic, interpreter dispatch, codegen lowering, effect metadata, specs | MIR bump; ABI only if host-facing table changes |
| MIR tag, trap/error code, layout field | defs, encoding/decoding, verifier, fingerprint, hostile-input tests, every consumer | bump MIR format |
| host table field or signature | ABI struct/slots, generated access, every host, oracle host, stale-artifact tests | bump host ABI |
| standard module/API | .luc source, embedded roster, specs, host fixture if needed, Library page and coverage audit | ABI only for a new/changed host primitive |
| public artifact behavior | CLI, loader/linker, product tests, Guide/Tools/Status, archive and installer smoke | tag/generator/ABI according to the changed seam |
Example: add one dynamic collection operation
- SurfaceDecide the signature, element constraints, mutation, result, bounds behavior, and public documentation.
- MeaningTeach semantic call selection and HIR recording the exact receiver/result ownership.
- ProtocolAdd or reuse a MIR intrinsic, verifier rule, print/encode/decode arm, and format fingerprint.
- One semantic bodyImplement the operation in
runtime/containers.zigwith rollback and trap behavior. - Two callersDispatch it from the interpreter and lower it to the checked runtime export in LLVM.
- EvidenceCompare success, boundaries, trap, element ownership, aliasing, and zero live objects on both paths.
Version the representation that changed
Put evidence where its claim lives
A Luce program's observable behavior belongs in src/luce/specs/ and runs on native and oracle paths. Tests of internal structures live beside their implementations. New spec files enter the spec import roster and one owner suite; new language packages enter the language re-export and test rosters.
Documentation is an executable surface
Repository documentation checks execute current luce snippets and validate expected diagnostics and traps. The public site stores separately generated source, MIR, LLVM, and assembly traces; its build validates the trace inventory, source links, internal links, and standard/compiler rosters. Planned syntax remains plain text. A feature is ready when its implementation, tests, examples, and public reference describe the same behavior.
Before calling the change complete
- Can one stage clearly own each new decision?
- Do both native and oracle paths reach the same runtime semantic?
- Do tests cover success, the relevant boundary, diagnostic or trap behavior, and cleanup?
- Do hostile serialized inputs remain reject-or-run-cleanly total?
- Did each changed protocol receive its corresponding version update?
- Do the Guide, Library, status boundary, examples, and editor vocabulary agree?
- Does the repository gate pass after the focused test lanes?