DESIGN.md: tighten Decision 6 framing per user redirect

User clarified the architectural intent: the data structure is
the source of truth. The textual surface is one projection
among potentially many — visual / graphical front-ends are an
explicitly anticipated future lane.

The previous draft of Decision 6 said "JSON-AST demoted to
storage and exchange only", which was the wrong framing. The
JSON-AST stays canonical; form (A) is the AI authoring
projection but does not displace the AST.

Changes:
- New "Architectural pin: data structure is the source of truth"
  subsection.
- Implementation outline reworded: parser is "strictly additive",
  no schema changes, .ail.json remains a first-class input to
  every existing subcommand.
- New "What this Decision deliberately does not do" subsection
  to lock in the architectural commitments.

No code change. Pure documentation correction to the 14b
design pass before 14c starts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-07 16:07:31 +02:00
parent 2bce825b69
commit 5e8342df02
+64 -13
View File
@@ -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 <surface-file> -o <json-file>`. 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 <file.ailx> -o <file.ail.json>`. 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)