diff --git a/docs/DESIGN.md b/docs/DESIGN.md index b95826d..115d0d4 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -138,8 +138,38 @@ Decision 1 anticipated this: it says a textual form exists "as a bidirectional projection of the JSON form." The pretty-printer already emits S-expression-style text (see `crates/ailang-core/src/pretty.rs`). What is missing is the inverse direction — text → AST. Decision 6 -makes that inverse the canonical authoring surface, with JSON-AST -demoted to "storage and exchange" only. +adds that inverse as **one** authoring projection alongside the +existing pretty-printer; the JSON-AST remains the source of truth. + +### Architectural pin: data structure is the source of truth + +The textual surface is **not** a replacement for the JSON-AST. It is +one projection among potentially many. Concretely: + +- The JSON-AST keeps its role as the canonical, hashable, content- + addressed representation of a module. All hashing, content- + addressing, cross-module references, and typecheck/codegen input + flow through the JSON-AST. **No new hashable form is introduced.** +- The textual surface (form A, this Decision) is the **AI authoring + projection**: optimised for me producing programs token-efficiently + and for foreign LLMs producing programs from a spec. It is not + optimised for human authors and does not need to be human-pleasant. +- Future projections are explicitly anticipated: a visual / graphical + front-end is a plausible second projection for human review and + inspection (display being the one case where non-AI eyes matter). + The architecture leaves room: any producer of well-formed + `ailang-core::ast::Module` values is a valid front-end. +- **No human is expected to author AILang seriously.** Authoring is + AI work. Display and verification, by contrast, are concerns where + human-facing alternatives may be useful — and which can therefore + layer their own projections on top of the same AST without + touching the surface or the core. + +In code terms: `ailang-core` owns the AST. `ailang-surface` (new in +Iter 14c) is one producer/consumer pair: text-form-A → AST → text- +form-A. A hypothetical `ailang-visual` would be a different producer +of the same AST. `ailang-check` and `ailang-codegen` consume only +the AST and remain projection-agnostic. ### Constraints (hard, in priority order) @@ -328,17 +358,38 @@ on the shelf for a future iter only if both fail. ### Implementation outline (Iter 14c onwards, not done in 14b) -- `crates/ailang-surface` — new crate. PEG parser → existing - `ailang-core::ast` types. No new AST nodes. -- Round-trip test: every `examples/*.ail.json` → emit via - `pretty::module` → parse via new crate → re-canonicalise → - hash-equivalent to original. Hash equivalence is the truth check; - no surface form ships if a single fixture loses its hash. -- CLI: `ail parse -o `. Symmetric to the - existing `ail render`. -- Then: rewrite one existing fixture (probably `box.ail.json`) in - the surface, hash-compare, commit both forms. Stdlib starts in - the surface from day one. +- `crates/ailang-surface` — new crate. **Strictly additive.** PEG + parser produces existing `ailang-core::ast` types. No new AST + nodes, no schema changes, no new hashable form. Pretty-printer + for form (A) lives here too (the round-trip is the contract). +- `ailang-check`, `ailang-codegen` are **not modified**. They + continue to consume `ailang-core::ast::Module` values regardless + of which projection produced them. +- Round-trip test: for every `examples/*.ail.json`, parse the + corresponding hand-written `*.ailx`, canonicalise, and assert + hash-equivalence to the original. Hash equivalence is the truth + check; the surface ships only if every fixture round-trips + identically. +- CLI: `ail parse -o `. Symmetric to + existing `ail render`. **`.ail.json` remains a first-class input** + to every existing subcommand; the parser is a producer, not a + gatekeeper. +- Iter 14d: stdlib (`std_list`, `std_maybe`, ...) authored in + form (A) from day one **because that is the AI authoring + projection**, not because JSON authoring is forbidden. The + resulting `.ail.json` is what tests and downstream tools see. + +### What this Decision deliberately does not do + +- It does not promote form (A) to the source of truth. Form (A) is + one projection; the JSON-AST stays canonical. +- It does not foreclose visual or graphical front-ends. The crate + layout (`core` owns AST; `surface`/`visual`/... are siblings) + reserves that lane. +- It does not remove `.ail.json` as input. Every existing + CLI subcommand (`check`, `render`, `describe`, `emit-ir`, + `build`, `run`, `manifest`, `deps`, `diff`, `workspace`, + `builtins`) keeps its current `.ail.json` interface. ## Mangling scheme (Iter 5c)