Files
AILang/design/contracts/0001-authoring-surface.md
Brummel eaa52ff64f docs(contracts): honesty-prose cleanup + ratifier integrity
Second tranche of the contracts-against-code audit. Two threads, both
applied conservatively under the over-correction guards in
docs_honesty_pin.rs (the self-labelled tiebreaker in 0008 and the
Diverge-reserved anchor in 0010 are deliberate honest content and were
left untouched; design rationale that explains a present-state design
principle — semantic-locality, the reuse-as-wrapper reasons — was also
preserved).

Honesty-rule (0007): demote clear change/deletion narration to
present tense.

- 0008: drop "they were promoted from ... to ... Recorded here so";
  strip the "Iter A"/"Iter B" iteration labels (the descriptive titles
  carry the meaning); drop "(no longer a carve-out)".
- 0001: "were rewired to use ... was deleted at the same time" ->
  present tense. (The substance was already correct: `pretty.rs` holds
  only the diagnostic helpers; an audit agent had misread the line as
  "pretty.rs was deleted" — the file exists, the printer code does not.)
- 0012: drop "Per the tail-call survey of existing fixtures" and
  "Migration of existing fixtures is partial" -> present-state
  description of which corpus fixtures carry the tail marker.

Ratifier integrity: a contract that names a test which does not
ratify it is itself a form of the dishonesty this ledger forbids.

- 0014 named `bench/architect_sweeps.sh`, which sweeps honesty-anchors
  and ratifies none of the six verification mechanisms; and claim 5
  cited `tests/expected/`, which never existed (git log empty). Point
  claim 5 at the real golden mechanism (`crates/ail/tests/snapshots/`
  via `ir_snapshot.rs`) and the footer at each mechanism's actual test.
- 0015's four constraints are guaranteed by absence (no thunk/`ref`/
  `IORef` node, non-recursive `let`); the named uniqueness in-source
  tests only count RC consumes, never the constraints. State the
  by-construction guarantee and point the ratifier at `ast.rs` (the
  single source of truth for which nodes exist).
- INDEX ratifying-test column updated for both to match.

All ledger pins green (docs_honesty_pin, design_index_pin incl.
every_contract_names_a_resolvable_ratifying_test, effect_doc_honesty_pin,
carve_out_inventory); architect honesty sweep clean.

Deferred, recommend-only: 0016-method-dispatch carries no invariant
absent from 0013 (merge candidate), but a contract-file merge touches
INDEX, the retired-counter convention, and cross-refs — a structural
call left for explicit direction. Minor history phrasing in 0008's
Type::Con.name hash-shift paragraph (§"FnDef.suppress") also left.
2026-06-02 11:27:53 +02:00

4.1 KiB

Authoring surface

Authoring surface

Form (A) is implemented as the ailang-surface crate (parser + printer). Form-A is gated against drift by ailang-surface/tests/round_trip.rs, which parses every .ail fixture, prints it back, re-parses, and demands canonical-byte equality. ail render and both branches of ail describe project through ailang_surface::print, so form (A) is the sole text projection of a module. pretty.rs carries no round-tripping printer — only the diagnostic helpers (type_to_string, pattern_to_string, manifest) are public there.

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 contract) 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 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)

  1. Formalizable for a foreign LLM. The grammar must fit in an EBNF/PEG spec of ≤ 30 productions. A model that has never seen AILang must be able to read the spec and produce conforming source zero-shot. Rules out: precedence between binary operators, semantic indentation, maximal-munch lexing, context-sensitive reductions.
  2. AST-isomorphic. Every surface form maps to exactly one AST shape. The full bijection between .ail.json and .ail (both directions, BLAKE3-stable hashing, Float-bits-hex encoding, workspace-CI enforcement points) is anchored as the top-level Roundtrip Invariant — this constraint records that the surface-design choice must satisfy that invariant; the invariant itself lives at top level because the property is load-bearing on the language identity, not on this file's surface-design rationale.
  3. No external symbols. ASCII only. No Greek (), no arrows (), no subscripts. Reasoning: I substitute mojibake for non-ASCII characters under context pressure; foreign LLMs vary in how they tokenize Unicode.
  4. No precedence. Either everything is parenthesized, or there are no infix operators. Prefer the latter — add(x, 1) over x + 1. Removes a fail mode for both me and foreign LLMs.
  5. No semantic indentation. Block structure expressed by paired delimiters or terminator tokens. Indentation is informational only; the parser ignores it.
  6. One construct per token-list. Every AST node corresponds to exactly one parenthesized form (or atom). No "sometimes you can omit the parens" rules.
  7. AST surface stays frozen. The surface adapts to the AST, not the other way around. We do not change the JSON schema or invalidate hashes to make the surface prettier.

Ratified by: crates/ailang-surface/tests/round_trip.rs.