Files
AILang/docs/roadmap.md
T
Brummel daf9f4fdc9 roadmap: roundtrip-invariant milestone (P1) + cross-model authoring-form test (P2)
Surfaced while scoping an empirical test of Decision 6 (.ailx as the
AI authoring projection). The cross-model test depends on a structural
.ail.json <-> .ailx bijection being established and prominently anchored
in DESIGN.md first; otherwise measured form-preference is contaminated
by expressive-power gaps rather than authoring ergonomics. P2 entry
carries the smoke-test evidence and full IONOS-endpoint addressing
notes so the test can be picked up without redoing the connection work.
2026-05-12 08:53:47 +02:00

343 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AILang Roadmap
Priority-ordered list of upcoming work — milestones, features, todos,
and ideas. The orchestrator maintains this file. The user can request
additions; the orchestrator chooses what to remove or reprioritise as
work progresses.
## Conventions
- One checkbox per entry. `- [ ]` is open; `- [~]` is in progress
(work has started — a plan exists, a branch is open, or commits are
landing); `- [x]` is done. A finished entry may stay briefly for
context, then is removed (with a one-line mirror in
`docs/journals/`).
- Each entry is tagged by **kind** and lives under a **priority**
bucket:
- **\[milestone\]** — big chunk that will get a `docs/specs/<milestone>.md`.
- **\[feature\]** — smaller addition inside a milestone, no full
spec.
- **\[todo\]** — concrete task that can run without a brainstorm
(cleanup, doc fix, mechanical refactor, test backfill).
- **\[idea\]** — not yet decision-ready, no commitment.
- Optional `depends on:` line names another entry that has to land
first.
- Optional `context:` line points to the journal entry (per-iter
file under `docs/journals/` or, for pre-2026-05-11 entries, the
archived `docs/journal-archive.md`) where the rationale lives.
The roadmap is intentionally terse; rationale stays in the
journals.
- Priority buckets:
- **P0** — in flight. Spec or plan already exists.
- **P1** — next up. Decision made; not yet started.
- **P2** — medium-term. Decided in principle, scheduled later.
- **P3** — ideas. No commitment; may be cut.
## P0 — In flight
_(empty — canonical-type-names milestone closed 2026-05-11; Floats
closed 2026-05-10 and was removed once it stopped being load-bearing
context. Pick the next milestone from P1.)_
## P1 — Next
- [x] **\[milestone\]** Post-22 Prelude — Eq/Ord — shipped milestone
23 (2026-05-12). `Ordering` ADT, `Eq`/`Ord` classes, primitive
instances on Int / Bool / Str, polymorphic free fns
`ne`/`lt`/`le`/`gt`/`ge`, runtime `ail_str_eq` + `ail_str_compare`,
end-to-end coverage including user-ADT-instance integration. Float
has neither instance by design; polymorphic helpers at Float fire
Float-aware `NoInstance` per DESIGN.md §"Float semantics".
- [ ] **\[milestone\]** Round-trip completeness invariant — `.ail.json`
`.ailx` must be a structurally lossless bijection. For every
valid module: `ail parse` followed by `ail render` yields the
original `.ailx` (modulo formatting), and `ail render` followed by
`ail parse` yields the original `.ail.json` (canonical key order).
Decision 6 mentions round-trip-as-property in passing, and
`crates/ailang-surface/tests/round_trip.rs` checks the `.ailx`
direction over the fixture corpus, but the invariant is not
prominently anchored as a non-negotiable language property and
the symmetric direction (every `.ail.json` has a printable, re-
parseable `.ailx` form) is not workspace-wide enforced. This
milestone (a) audits the existing fixture corpus for structural
gaps in either direction, (b) closes any render / parse gaps
surfaced, (c) lifts the round-trip property to a named, prominent
invariant in DESIGN.md (likely as a dedicated subsection of
Decision 6, or as its own decision-level entry), (d) adds a
workspace-wide check (E2E or unit, in addition to the existing
surface-side fixture test) that the invariant holds over every
fixture on every build.
- context: brainstorm 2026-05-12 — surfaced while scoping the
cross-model authoring-form test (see P2 entry below). The test
requires both forms to be exactly equipotent in expressive
power; otherwise measured form-preference is contaminated by
expressive-power gaps rather than authoring ergonomics. The
invariant is also load-bearing on its own: if `.ailx` is the
"AI authoring projection" per Decision 6, programs expressible
in one form but not the other are a first-class bug class.
- [ ] **\[milestone\]** Post-22 Prelude — Show + print rewire — ship
`Show` typeclass with `Show Int/Bool/Str/Float` instances; rewire
`print` through `Show.show`. Gated on heap-`Str` ABI runtime work
(`int_to_str` needs to allocate). Originally queued as 22b.4 in
the typeclass milestone, kept on hold pending demand and the
heap-`Str` prerequisite.
- context: brainstorm 2026-05-12 (iter 23.5 wrap). Heap-`Str` ABI
is the load-bearing prerequisite; until it ships, `Show Int`
cannot allocate a `Str` to return.
## P2 — Medium-term
- [ ] **\[milestone\]** Cross-model authoring-form test — empirically
measure whether `.ail.json` or `.ailx` is the form a foreign LLM
author reaches for and succeeds with. Setup: three configurations
per task — (i) JSON-mandated, (ii) `.ailx`-mandated, (iii) free
choice (both corpora available, model picks). Multiple subjects to
check whether form-preference is model-robust. For each (model ×
form × task): system prompt includes DESIGN.md verbatim (~28k
tokens); user prompt is the task plus the form mandate; an error-
roundtrip loop feeds `ail check` / `ail parse` errors back to the
model until green or iter-limit. Measure: first-attempt success
(yes/no), iterations to green, total tokens spent, error classes
encountered (schema violation, type mismatch, hash mismatch, syntax
error in the chosen form); for free-choice runs, which form the
model picked unprompted. The output is a JOURNAL'd dataset +
interpretation + a concrete DESIGN.md edit on Decision 6 —
either ratify "ailx is the AI authoring projection" with empirical
backing across N subjects, or retire the form if JSON wins
consistently across all subjects.
- context: brainstorm 2026-05-12 (aborted in favour of two roadmap
entries). The Decision-6 prose currently asserts `.ailx` is the
AI authoring projection while §"Feature-acceptance criterion"
cites JSON-as-canonical-authoring-surface as a behavioural
counterexample to human-driven feature picks. The tension is
real; only empirical data over multiple downstream subjects
resolves it.
- depends on: Round-trip completeness invariant (P1 above) —
without it, measured preference is confounded by expressive-
power gaps. Strongly benefits from (but is not strictly
blocked by): `ail check`/`build`/`run` accept `.ailx`
extension (P2 todo below); workspace search beyond entry-
module's directory (P2 todo below). Both will be encountered
during the test if not closed first.
- smoke-test evidence (2026-05-12): Qwen3-Coder-Next reads
DESIGN.md and produces a structurally correct AILang program
that passes `ail check` in two turns; first turn missed the
module-name-matches-file-path rule, second turn fixed it after
`ail check` error was fed back. ~28k prompt tokens, ~150
completion tokens, ~2-5 s latency per turn.
- how to address the IONOS endpoint:
- URL: `https://openai.inference.de-txl.ionos.com/v1/chat/completions`
- protocol: OpenAI-compatible chat completions API.
`/v1/models` returns the catalogue.
- auth: HTTP header `Authorization: Bearer <token>`. Store the
token outside the repo (e.g. `~/.ionos_token`, `chmod 600`).
Tokens are JWTs; the one used in the 2026-05-12 smoke test
was IONOS-issued and time-bound — refresh when re-engaging.
- model IDs to try (subset of the IONOS catalogue as of
2026-05-12, sorted by relevance to this test):
- `Qwen/Qwen3-Coder-Next` — code-specialised, smoke-tested.
- `meta-llama/Meta-Llama-3.1-405B-Instruct-FP8` — large
general instruct, useful as a contrast subject.
- `meta-llama/Llama-3.3-70B-Instruct` — mid-size instruct.
- `openai/gpt-oss-120b` — OpenAI open-weight 120B.
- `mistralai/Mistral-Small-24B-Instruct` — smaller subject,
stresses spec comprehension.
- `meta-llama/CodeLlama-13b-Instruct-hf` — older code model,
useful as a low-capability floor.
- request shape: standard `messages: [{role: "system", ...},
{role: "user", ...}, ...]`, with DESIGN.md (107 KB / ~28k
tokens) in the system message and the task + form mandate in
the first user message. Subsequent turns alternate
`assistant` / `user` with the `ail check` error verbatim in
the user message.
- response shape: `choices[0].message.content` carries the
generated program (request "no markdown fences, no
explanation" in the prompt to skip post-processing).
`usage.prompt_tokens` + `usage.completion_tokens` give per-
turn token spend.
- cost estimate: ~56k tokens per task per (model × form)
configuration including a few correction roundtrips; a
full matrix (4 tasks × 3 forms × 4 models × 1 run each) is
~2.7M tokens total. Multiply by repetition count if a
median-of-3 design is chosen.
- [ ] **\[feature\]** Operator routing through `Eq` / `Ord` — `==`,
`<` etc. resolved via the typeclass instead of the built-in
primitive comparators. No commitment; gated on bench re-baselining
to make sure the indirection doesn't tank latency.
- context: JOURNAL 2026-05-09
- depends on: Post-22 Prelude — Eq/Ord (shipped 23.5)
- [ ] **\[todo\]** `types` / `ctor_index` overlay shape question —
decide whether the env's two parallel ctor maps should collapse
into one overlay, or stay split. Surfaced during the
env-construction unify audit.
- context: JOURNAL 2026-05-10 ("Audit close: env-construction unify")
- [ ] **\[todo\]** CLI human-mode diagnostic surface for `WorkspaceLoadError` —
non-JSON `ail check` routes ct.1 errors via `anyhow`/`thiserror`
Display (`Error: <message>`) instead of going through
`workspace_error_to_diagnostic`, so the bracketed `[code]` prefix
the JSON path carries is missing. Plausibly applies to every CLI
subcommand that calls `load_workspace(&path)?` directly.
- context: JOURNAL 2026-05-11 ("Iteration ct.1") — surfaced by ct.1.8 tester.
- [ ] **\[todo\]** Retire dead `KindMismatch` arm — `validate_classdefs`'s
`walk_kind_mismatch` path is structurally unreachable through
well-formed schema post-ct.1 (the canonical-form validator catches
the malformed `Type::Con { name: param }` shape earlier). The
enum variant + `walk_kind_mismatch` helper stay as dead-but-defensive
code; a future tidy can delete both.
- context: JOURNAL 2026-05-11 ("Iteration ct.1").
- [ ] **\[todo\]** Re-key `Registry.type_def_module` to handle
bare-name-collision-across-modules — `BTreeMap<String, String>` keyed
by bare type name silently overwrites when two modules each define
`type Foo`; `normalize_type_for_registry` would then collapse `M.Foo`
and `N.Foo` to whichever insert won. Acceptable for current corpus
(distinct bare type names across modules), but the proper fix is to
key by `(owning_module, bare_name) → defining_module`.
- context: JOURNAL 2026-05-11 ("Iteration ct.1") — flagged by ct.1.5a quality reviewer.
- [ ] **\[feature\]** 22c — typeclass corpus expansion. User-defined
classes beyond the prelude four; multi-parameter classes; superclass
chains; richer instance bodies. Deferred from milestone 22.
- context: JOURNAL 2026-05-09
- [ ] **\[milestone\]** Module-qualified class names + type-driven
method dispatch — retire the `MethodNameCollision` workaround
(`crates/ailang-core/src/workspace.rs:472`) that today keeps bare
class names viable by enforcing workspace-global method-name
uniqueness. Replaces name-driven method resolution
(`ModuleGlobals::class_methods: IndexMap<String, ClassMethodEntry>`,
`crates/ailang-check/src/lib.rs:983`; consumed by
`mono::rewrite_class_method_calls`, `crates/ailang-check/src/mono.rs:657`)
with type-driven dispatch — look up `eq` candidates by argument
type, pick the unique class instance, fail closed on ambiguity.
Once shipped, two libraries can each declare `class Eq` with their
own `eq`. Carries its own DESIGN spec: inference rules, ambiguity
diagnostics, and the canonical-form extension for class-reference
fields (`InstanceDef.class`, `SuperclassRef.class`, `Constraint.class`)
that the canonical-type-names milestone explicitly out-of-scoped.
- context: `docs/specs/2026-05-10-canonical-type-names.md` "Out of
scope: Class names" — the workaround is named there so it stays
visible until this milestone retires it.
- [ ] **\[todo\]** Boehm full retirement — remove the transitional
Boehm GC path now that RC + uniqueness is the canonical memory
story.
- context: JOURNAL pre-22, "Boehm transitional"
- [ ] **\[feature\]** Closure-pair slab / pool — codegen tweak to
pool the env+code closure pairs instead of one-shot heap allocs.
Bench-gated.
- [ ] **\[todo\]** `FnDef::synthetic` flag — formalise the
monomorphiser-emitted FnDefs so downstream passes can tell
user-authored from synthesised at a glance. Currently inferred from
symbol naming.
- [ ] **\[todo\]** 21'h iteration — final 21' carry-over (latency
methodology pass). Numbering kept for continuity with the 21' arc.
- [ ] **\[todo\]** `io/print_float` always-emit-`.0` — surface
printer always emits `.` or `e/E` so re-lex routes to Float;
the runtime printer (`printf("%g\n", v)`) doesn't, so `2.0`
prints as `2` (Int-shaped). Asymmetric. Either switch the
runtime path to a `.0`-fallback printer (matching surface) or
document the `%g` contract in DESIGN.md §"Float semantics" so
the LLM-author knows `io/print_float`'s output is for-humans
not round-trip.
- context: `docs/specs/2026-05-10-fieldtest-floats.md` finding F1.
- [ ] **\[todo\]** Rustdoc warning sweep — `cargo doc --no-deps`
reports 16 pre-existing warnings (15 in `ailang-check`, 1 in
`ailang-core`: private-item links from public doc, unresolved
intra-crate links). All predate the design-md-consolidation
milestone; treat as a one-off sweep.
- context: JOURNAL 2026-05-10 ("Audit close: design-md-consolidation").
- [ ] **\[todo\]** `design_schema_drift.rs` fidelity widening —
current test checks anchor *presence* anywhere in DESIGN.md;
the audit found that `[high]` schema gaps in §"Data model"
are invisible because anchors live in Decision 11 instead.
Constrain the test to scan only §"Data model" + ParamMode
block, or extract JSON-schema blocks into a machine-readable
file the test consumes.
- context: JOURNAL 2026-05-10 ("Audit close").
- [ ] **\[todo\]** Split `BadCrossModuleTypeRef` into two diagnostics —
the current single shape collapses unknown-owner and
known-owner / unknown-type-in-owner into one message. The two
cases suggest different fixes (add `(import <owner>)` vs. fix the
type name). In the known-owner branch, list the owner's available
type defs as candidates the way `bare-cross-module-type-ref`
lists candidates from imports.
- context: fieldtest 2026-05-11 — `examples/ct_3*.ailx` exhibits both branches with identical-shape diagnostics.
- [ ] **\[todo\]** Workspace search beyond entry-module's directory —
`load_workspace` only finds sibling `.ail.json` files in the same
directory as the entry module, so any consumer of prelude/std in a
subdirectory has no way to resolve cross-module imports. Add either
a `--workspace-root` flag on `ail check` / `ail build` / `ail run`,
or upward-search from the entry module's directory. Alternatively
ratify the flat-workspace assumption in DESIGN.md if intentional.
- context: fieldtest 2026-05-11 — fieldtest fixtures could not be
placed under `examples/fieldtest/` because of this; predates the
canonical-type-names milestone but surfaces every time.
- [ ] **\[todo\]** `ail check`/`build`/`run` accept `.ailx` extension —
today `ail check foo.ailx` produces a misleading JSON-parse error
(`json: expected value at line 1 column 1`) because the loader only
accepts `.ail.json`. Either teach the CLI subcommands to auto-parse
`.ailx` internally, or detect the extension and emit a
"did you mean `ail parse foo.ailx`?" hint. The LLM-author's natural
first command should not be the one that produces a misleading
diagnostic.
- context: fieldtest 2026-05-11 — orthogonal to canonical-type-names
but every fieldtest invocation hits this on its first command.
- [ ] **\[todo\]** `check_in_workspace` per-module overlay narrowing —
`crates/ailang-check/src/lib.rs:1234` still clears+rebuilds
`env.ctor_index` per-module; ct.3.2 narrowed the analogous mono
overlay to types-only. The typecheck-side overlay's `env.ctor_index`
half serves the duplicate-detection diagnostic at workspace-build
time, not the runtime ctor lookup (which is type-driven post-ct.2.2).
Narrowing is mechanical but needs a careful read to confirm no
other consumer survives.
- context: JOURNAL 2026-05-11 ("Iteration ct.4") — milestone close
follow-up.
## P3 — Ideas
- [ ] **\[todo\]** `compare_primitives_smoke.ailx` counterpart —
the canonical happy-path exhibit for canonical-type-names ships
only as JSON. Per Decision 6, Surface is the LLM-author surface;
the milestone should have a `.ailx` counterpart. Two paths: author
`examples/compare_primitives_smoke.ailx` to round-trip into the
existing JSON, OR retire the JSON fixture in favour of
`examples/ct_1_ordering_signum.{ailx,ail.json}` as the new canonical
happy-path exhibit.
- context: fieldtest 2026-05-11 (spec_gap).
- [ ] **\[todo\]** Codegen `lookup_ctor_in_pattern` type-anchoring —
`crates/ailang-codegen/src/lib.rs:1790` still walks every module's
ctor_index by bare ctor name. Plumbing the scrutinee's
qualified `Type::Con` through pattern lowering would type-anchor
it symmetric to the ct.2.2 typecheck-side fix. Not load-bearing
(uniqueness is enforced at typecheck), but cleaner.
- context: JOURNAL 2026-05-11 ("Iteration ct.3" + ct.4 close).
- [ ] **\[todo\]** `compare_primitives_smoke` IR-shape assertion —
observe `compare__Int` / `compare__Bool` / `compare__Str` symbols
in the emitted IR. Blocked on `emit-ir` CLI not running mono;
resolution paths include extending the CLI to run mono, using
library APIs directly in e2e.rs, or adding `--dump-ir` to `ail
build`. The E2E stdout assertion already covers correctness; the
IR-shape test would catch refactor regressions that rename
mono symbols.
- context: JOURNAL 2026-05-11 ("Iteration ct.4") — dropped from
ct.4.4 when the BLOCKED condition surfaced.
- [ ] **\[idea\]** Latency methodology rework — switch from per-run
timing to a histogram-based approach so tail-latency regressions
are visible without re-running. Queued from 21'g.
- [ ] **\[idea\]** Parser-test backfill for 22b.4a-era duplicate-clause
sites (class × 3, class method × 2, instance × 3, instance method
× 1). No regression pin today; only worth it if a 22b.4a-era
diagnostic needs to change.
- context: JOURNAL 2026-05-10 ("Iteration 22-tidy.7")
- [ ] **\[idea\]** `write_type` `Type::Forall` arm in
`crates/ailang-prose/src/lib.rs` silently drops constraints in
inline-type rendering. Dormant — surface forms today only carry
forall at fn-signature top level. Fix only if a future feature
carries forall + constraints inline.
- context: JOURNAL 2026-05-10 ("Iteration 22-tidy.6")
- [ ] **\[idea\]** Richer integration paths between RC and
uniqueness — deferred from the 21' arc; revisit once the
uniqueness inference covers more program shapes.