b1dbafc6f2
JOURNAL bekommt fehlenden Iter-5d-Eintrag und Iter-5-Architektur- Review-Notiz mit Iter-6-Plan (Aufräumarbeiten). DESIGN.md korrigiert zwei Drifts vom Architekt-Befund: @main ist i32 (C-/LLVM-ABI), nicht i64; String-Globals tragen Hint @.str_<modul>_<hint>_<idx>.
352 lines
17 KiB
Markdown
352 lines
17 KiB
Markdown
# JOURNAL
|
|
|
|
Chronologische Notizen für mich. Nicht jede Änderung; nur Entscheidungen,
|
|
Hindernisse, Beobachtungen, die zukünftige Iterationen brauchen.
|
|
|
|
## 2026-05-07 — Tag 0
|
|
|
|
- Repo initialisiert. Auftrag in `CLAUDE.md`: LLM-native Sprache, LLVM-Backend.
|
|
- Designentscheidungen festgehalten in `docs/DESIGN.md`.
|
|
- Toolchain: `rustc 1.94`, `llvm-config 22.1.3`, `clang` vorhanden.
|
|
- Entschieden gegen `inkwell` zugunsten LLVM-IR-Text-Emit. Begründung im DESIGN.md.
|
|
- Workspace-Layout:
|
|
- `crates/ailang-core` — AST, Type, Hash, JSON-Schema
|
|
- `crates/ailang-check` — Typchecker (kommt später)
|
|
- `crates/ailang-codegen` — Lowering + LLVM IR Emit
|
|
- `crates/ail` — CLI
|
|
- MVP-Ziel: `examples/sum.ail.json` → Binary, das 55 druckt. **Erreicht.**
|
|
|
|
## 2026-05-07 — Architektur-Review nach MVP
|
|
|
|
Wieder am Pfad? Im Großen ja. Konkrete Beobachtungen:
|
|
|
|
**Was hält:**
|
|
|
|
- JSON-AST + canonical form + content-hash sind alle Lego-Steine, auf denen
|
|
spätere Tools ohne Refactor aufsetzen können (`ail deps`, `ail diff`).
|
|
- LLVM-IR-Text-Pipeline arbeitet wie geplant. Keine libllvm-Versionsschmerzen.
|
|
- Effekt-Set ist im Typsystem von Anfang an verbaut. Erweiterbar zu row-poly,
|
|
ohne den Kern zu ändern.
|
|
|
|
**Schulden, die Zinsen tragen:**
|
|
|
|
1. **`current_block_label_for_phi` ist eine Heuristik** (siehe codegen). Bei
|
|
verschachtelten `if`-Termen wird sie das falsche Block-Label zurückgeben,
|
|
weil sie rückwärts den Body scannt. Tickend, weil keine Test-Fälle das
|
|
bisher triggern. Muss als nächstes fixiert werden, bevor neue Sprachfeatures
|
|
dazu kommen.
|
|
2. **Kein typed-AST.** Codegen liest direkt das Quell-AST und verlässt sich
|
|
darauf, dass der Typchecker vorher lief. Für MVP OK; sobald ADTs oder
|
|
Closures dazukommen, brauche ich eine getrennte typisierte IR-Stufe (TIR).
|
|
3. **`hash`-Feld ist nicht im AST.** Aktuell hashen wir das Def-Objekt direkt.
|
|
Wenn ich Hashes später als Felder mitserialisiere (Caching), muss der Hash
|
|
das Feld vor der Berechnung ausschließen.
|
|
|
|
**Plan Iteration 2 (jetzt):**
|
|
|
|
1. Block-Label-Tracking sauber machen, verschachteltes-if-Test.
|
|
2. Strings als Literal + `io/print_str`.
|
|
3. Hello-world-Beispiel als zweiten E2E-Test.
|
|
4. CLI: `--json`-Output für maschinelle Konsumenten überall, wo es passt.
|
|
|
|
**Plan Iteration 3:**
|
|
|
|
ADTs + Pattern Matching. Das ist der nächste große Sprung. Erfordert
|
|
typisierte IR-Stufe (TIR), weil Pattern Matching zu Decision-Trees lowered
|
|
wird, was eine andere Form ist als der AST.
|
|
|
|
## 2026-05-07 — Iteration 2 fertig
|
|
|
|
- Block-Label-Tracking robust (verschachtelte `if`s funktionieren). Test
|
|
`max3_picks_largest` schützt das.
|
|
- Strings als `Lit::Str { value }`, Type `Str` -> LLVM `ptr`, mit
|
|
`io/print_str` Effekt-Op. `examples/hello.ail.json` druckt einen String.
|
|
- CLI: `manifest --json`, `builtins --json` für Tool-Konsumenten.
|
|
- `ail deps [--of NAME] [--json]` listet Aufruf-Edges. Effekt-Ops sind als
|
|
`effect:NAME` markiert, damit ein Konsument sie filtern kann.
|
|
|
|
**Architektur-Check:** Keine strukturellen Abweichungen. Codegen liest noch
|
|
direkt das Quell-AST (TIR-Stufe wird mit ADTs in Iteration 3 nötig).
|
|
|
|
## 2026-05-07 — Iteration 3 fertig: ADTs
|
|
|
|
- TypeDef im AST mit Ctors. Ein Ctor hat `name` und `fields: [Type...]`.
|
|
- Term::Ctor (Konstruktion) und Term::Match (Pattern Matching).
|
|
- Patterns: `Wild`, `Var`, `Lit`, `Ctor { ctor, fields }`. Im MVP sind nested
|
|
Ctor-Patterns NICHT erlaubt — Sub-Patterns müssen `Var` oder `Wild` sein.
|
|
- Typchecker mit Type-Registry und `ctor_index` (ctor-name → ADT). Im Match
|
|
wird Exhaustiveness gegen die volle Konstruktormenge geprüft. Negativ-Test
|
|
schützt das.
|
|
- Codegen: Boxed-Heap-Layout. Pro Ctor-Anwendung `malloc(8 + 8*n)` Bytes;
|
|
Tag in offset 0, Felder ab offset 8 (8-Byte-Slots, native typed
|
|
load/store). Match: load tag + switch + arm-blocks + phi am Join.
|
|
- `examples/list.ail.json` (Cons/Nil-Liste, sum_list über match) liefert 42.
|
|
|
|
**Erstaunlich problemlos.** Die Architekturentscheidungen aus Tag 0 haben
|
|
sich ausgezahlt: opaque ptr in LLVM 22 macht Boxed-Layout fast ohne
|
|
Glue-Code möglich; das Effekt-Tracking blieb von ADTs unberührt; der
|
|
JSON-AST nimmt neue Knoten-Typen sauber auf.
|
|
|
|
**Gewachsene Schulden:**
|
|
|
|
1. **Codegen liest immer noch direkt den Quell-AST.** Die Versuchung war
|
|
stark, ohne TIR weiterzumachen — und hat funktioniert, weil meine
|
|
Match-Restriktionen flach sind (keine nested Patterns). Sobald nested
|
|
Patterns kommen, braucht es ein Decision-Tree-Lowering, das ohne TIR
|
|
nicht sauber wird. Schulden anerkannt; nicht jetzt fällig.
|
|
2. **Kein GC.** Heap leakt. Akzeptabel für Demo-Programme; muss vor jedem
|
|
längerläufigen Programm angegangen werden. Optionen für Phase 4:
|
|
Refcount, Boehm-GC-Linkage, Region-Inference.
|
|
3. **Pretty-Printer für ADT-Werte zur Laufzeit fehlt.** `io/print_int`
|
|
reicht für Demos, aber ein generisches `show :: a -> Str` für ADTs
|
|
wäre wertvoll. Erfordert dispatch über tag — machbar, aber nicht jetzt.
|
|
|
|
**Plan Iteration 4:**
|
|
|
|
Die nächsten Schritte sind weniger eindeutig. Drei Kandidaten in
|
|
Prioritätsreihenfolge:
|
|
|
|
1. **Modulsystem (Imports).** Aktuell ist alles in einem Modul. Mit
|
|
mehreren Modulen + Cross-Module-Hashing wird die Sprache erst
|
|
praktikabel für mehrere Defs.
|
|
2. **Strukturierte Fehlerausgabe (`ail check --json`).** Damit Tools auf
|
|
Typfehler reagieren können, ohne Text zu parsen.
|
|
3. **Closures / höherwertige Funktionen.** Erfordert Closure-Konvertierung
|
|
und ist ein größerer Schritt.
|
|
|
|
Iteration 4 wird (1) + (2) — beides macht das LLM-Tooling stärker und
|
|
hat moderates Risiko.
|
|
|
|
## 2026-05-07 — Workflow-Wechsel: Orchestrator + Agent-Repo
|
|
|
|
Auf Anregung des Auftraggebers Wechsel auf **Orchestrator-Modus**: ich
|
|
delegiere abgrenzte Implementierungs-Brocken an Sub-Agenten und behalte
|
|
nur Architektur-Entscheidungen, Reviews und Commit-Disziplin. Vier
|
|
spezialisierte Agenten formuliert: implementer, architect, tester,
|
|
debugger.
|
|
|
|
**Wichtige Korrektur:** Auftraggeber hat verlangt, dass die Agenten nicht
|
|
in `.claude/agents/` versteckt liegen, sondern als sichtbarer Bestandteil
|
|
des Projekts unter `agents/` versioniert werden. DESIGN.md hat einen neuen
|
|
Abschnitt "Projekt-Ökosystem" bekommen, der das festhält: AILang ist nicht
|
|
nur eine Sprache, sondern Sprachkern + CLI + Examples + Agents + Doku +
|
|
Tests, alle gleichwertig.
|
|
|
|
Aufruf-Schema: System-Prompt-Body aus `agents/<name>.md` als Präfix vor
|
|
die konkrete Aufgabe + an `general-purpose`-Agent. Funktional identisch
|
|
zum Subagent-Loading aus `.claude/agents/`, aber sichtbar im Repo.
|
|
|
|
**Plan Iteration 4 (überarbeitet):**
|
|
|
|
Modulsystem ist aufwändiger als erwartet (Cross-Module-Hashing,
|
|
Import-Resolution). Erst die kleineren Tooling-Wins ziehen, dann das
|
|
Modulsystem als Iteration 5:
|
|
|
|
1. **Strukturierte Fehlerausgabe** (`ail check --json` mit Diagnostic-
|
|
Struct, stabile Codes wie `unbound-var`, `type-mismatch`).
|
|
2. **`ail diff <a> <b>`** — semantischer Modul-Diff via Hash-Vergleich
|
|
pro Def.
|
|
3. **IR-Snapshot-Tests** — Regressions-Schutz für die Codegen-Pipeline.
|
|
|
|
## 2026-05-07 — Iteration 4 fertig: LLM-Tooling-Konsolidierung
|
|
|
|
Drei Sub-Commits, jeder von einem `ailang-implementer`-Aufruf erzeugt
|
|
und stichprobenartig vom Orchestrator verifiziert:
|
|
|
|
- `93fe723` Iter 4a: `ail check --json` mit `Diagnostic`-Struct
|
|
(`severity`, `code`, `message`, `def`, `ctx`). Stabile Codes:
|
|
`unbound-var`, `type-mismatch`, `arity-mismatch`,
|
|
`non-exhaustive-match`, `unknown-ctor`, `unknown-ctor-in-pattern`,
|
|
`nested-ctor-pattern-not-allowed`, `duplicate-def`,
|
|
`unknown-effect-op`, `unknown-type`, `schema-mismatch`. API:
|
|
`check_module(&Module) -> Vec<Diagnostic>`.
|
|
- `c652b12` Iter 4b: `ail diff <a> <b> [--json]` als struktureller Top-
|
|
Level-Def-Diff via BLAKE3-Hash. Vier Kategorien (added/removed/
|
|
changed/unchanged), alphabetisch sortiert, Exit-Code 1 bei Diff.
|
|
- `74a2005` Iter 4c: IR-Snapshot-Tests in
|
|
`crates/ail/tests/snapshots/{sum,max3,hello,list}.ll`.
|
|
Normalisierung von `target triple`. Update via `UPDATE_SNAPSHOTS=1
|
|
cargo test ir_snapshot_`. Mismatch erzeugt `.actual`-Datei.
|
|
|
|
Test-Stand: 28 (vorher 19). 7 E2E + 4 IR-Snapshot + 9 ailang-check + 1
|
|
ailang-codegen + 7 ailang-core.
|
|
|
|
**Erledigt aus dem Schulden-Register:**
|
|
|
|
- Block-Tracking im Codegen ist seit Iter 2 kein Heuristik-Risiko mehr;
|
|
die explizite `current_block: String`-Spur wurde durch Iter 4c jetzt
|
|
zusätzlich von Snapshot-Tests gegen Regression geschützt. Schuld
|
|
geschlossen.
|
|
|
|
**Neue / präzisierte Schulden:**
|
|
|
|
1. `check_module` ist **single-shot** — der erste Fehler bricht ab, kein
|
|
Multi-Diagnose-Sammeln. Spec war so, aber das Format suggeriert
|
|
Vec-Semantik. Echter Multi-Diagnose-Refactor wird billiger, sobald
|
|
TIR existiert (zentraler Fehler-Akku durch separate Stufe). Nicht
|
|
jetzt fällig.
|
|
2. `source_filename` im IR ist hartkodiert auf `"<module>.ail"`. Solange
|
|
es nur ein Top-Level-Modul gibt, plattform-stabil. Mit Iter 5
|
|
(Modulsystem + Imports) wird der Pfad relevant — dort gleich beim
|
|
Bau pfad-unabhängig halten, sonst kippen die Snapshots.
|
|
|
|
**Plan Iteration 5:** Modulsystem mit Imports. Cross-Module-Hashing,
|
|
Import-Auflösung, mehrere `.ail.json`-Files in einem Build. Multi-
|
|
Diagnose-Refactor erst danach.
|
|
|
|
Sub-Schritte:
|
|
|
|
- **5a — Workspace-Loader.** `ailang_core::Workspace { modules:
|
|
BTreeMap<String, Module> }` plus `load_workspace(entry: &Path)`, das
|
|
`imports` rekursiv vom Eintrittsmodul folgt. Konvention: `import {
|
|
module: "foo" }` löst auf `<dir>/foo.ail.json` neben dem Entry. Zyklus-
|
|
Erkennung. CLI: bestehende Subkommandos arbeiten weiter auf einzelnem
|
|
Modul; ein neues `ail workspace <entry>` listet alle erreichbaren
|
|
Module mit Hash. Tests: zwei kleine Beispielmodule mit
|
|
Import-Beziehung; Zyklus-Test.
|
|
- **5b — Cross-Module-Typcheck.** Typchecker bekommt `&Workspace`
|
|
statt `&Module`. Imports werden im Env als Namespace eingehängt
|
|
(`alias.def` oder bei fehlendem Alias `module.def`). Neue Diagnostic-
|
|
Codes: `unknown-module`, `unknown-import`, `import-cycle`,
|
|
`ambiguous-name`. Tests pro Code.
|
|
- **5c — Cross-Module-Codegen.** Emitter erzeugt IR für alle Module im
|
|
Workspace, prefix-mangelt mit `@ail_<module>_<def>`. E2E-Test:
|
|
Programm, das eine Funktion aus Modul B in Modul A nutzt, liefert
|
|
korrektes Ergebnis im Binary.
|
|
- **5d — Tooling-Anpassungen.** `manifest`, `describe`, `deps`, `diff`
|
|
bekommen einen `--workspace`-Modus (rekursiv). Single-Modus bleibt
|
|
Default für Rückwärtskompatibilität.
|
|
|
|
Während Iter 5 gleich beim Bau **`source_filename` pfad-unabhängig
|
|
halten** (nur Modulname, kein Verzeichnis-Prefix), sonst kippen die
|
|
IR-Snapshots.
|
|
|
|
## 2026-05-07 — Iter 5b fertig: Cross-Module-Typcheck
|
|
|
|
- `check_workspace(&Workspace) -> Vec<Diagnostic>` als Top-Level-API.
|
|
`check_module` bleibt erhalten und hebt das Modul intern in einen
|
|
Trivial-Workspace.
|
|
- Konvention für qualifizierte Verweise (in DESIGN.md festgehalten):
|
|
`Term::Var { name }` mit genau einem Punkt = `<prefix>.<def>`. Prefix
|
|
ist Import-Alias oder Modulname. Kein neuer AST-Knoten, keine
|
|
umbenannten Felder ⇒ Hashes bleiben stabil; alle `ir_snapshot_*`
|
|
weiterhin grün.
|
|
- Drei neue Diagnostic-Codes: `unknown-module`,
|
|
`unknown-import`, `invalid-def-name` (mit `ctx.reason: "contains-dot"`).
|
|
- CLI: `ail check <entry>` lädt jetzt **immer** über `load_workspace`.
|
|
Workspace-Lade-Fehler werden im JSON-Modus zu strukturierten
|
|
Diagnostics mit Codes `module-not-found`, `module-cycle`,
|
|
`module-name-mismatch`, `module-hash-mismatch`, `schema-mismatch`.
|
|
`ail build` und `ail emit-ir` bleiben pro Einzelmodul (Codegen
|
|
cross-module ist 5c).
|
|
- Beispiele: `ws_main.ail.json` ruft jetzt `ws_lib.add` auf
|
|
(beobachtbar). Neu: `ws_broken.ail.json` (`unknown-import`),
|
|
`ws_unknown_module.ail.json` (`unknown-module`).
|
|
- Tests: 37 grün (vorher 32). 4 neue Workspace-Integrationstests in
|
|
`crates/ailang-check/tests/workspace.rs`, ein neuer e2e-Test
|
|
`check_workspace_resolves_import`.
|
|
- Schulden: Single-Shot-Diagnostics weiterhin (Multi-Diagnose nach 5c).
|
|
Punkt-Konvention deckt nur einen Punkt ab — verschachtelte Modulpfade
|
|
(`a.b.c`) gibt es nicht; das wäre erst mit Hierarchie-Modulen ein
|
|
Thema und fällt aktuell als `unbound-var` durch.
|
|
|
|
## 2026-05-07 — Iter 5c fertig: Cross-Module-Codegen
|
|
|
|
- **Mangling-Bruch (mit Bedacht).** Alle AILang-Funktionen heißen jetzt
|
|
`@ail_<modul>_<def>`, auch in Single-Modul-Programmen. Die alte Form
|
|
`@ail_<def>` ist weg. Strings/Const-Globals analog
|
|
(`@.str_<modul>_<hint>_<idx>`, `@ail_<modul>_<const>`). Eintrittspunkt
|
|
bleibt `main` als C-ABI: ein `define i32 @main()`-Trampoline ruft
|
|
`@ail_<entry-modul>_main()`. Fehlt im Eintrittsmodul ein
|
|
`main : () -> Unit !IO`, fällt der Build mit `MissingEntryMain`.
|
|
- **Workspace-Lowering.** Neue Top-Level-API
|
|
`ailang_codegen::lower_workspace(ws: &Workspace) -> Result<String>`
|
|
produziert eine einzelne `.ll` für den ganzen Workspace. Module
|
|
alphabetisch (BTreeMap-Order); Defs in AST-Reihenfolge. Cross-Module-
|
|
Calls werden im Codegen über die Import-Map des aufrufenden Moduls
|
|
aufgelöst — gleiche Logik wie im Typchecker, lokal dupliziert mit
|
|
Verweis (kein gemeinsames Helper-Modul, weil die Typ-Welten
|
|
unterschiedlich sind: Typchecker hantiert mit `Type`, Codegen mit
|
|
`FnSig` aus llvm-Typen).
|
|
- **CLI.** `ail build` und `ail emit-ir` laden jetzt immer den Workspace
|
|
und checken/lowern ihn vollständig. Single-Modul-Programme funktionieren
|
|
weiter (Trivial-Workspace mit einem Modul). `emit_ir(m)` bleibt im
|
|
Codegen-Crate als Bequemlichkeits-API erhalten und wrapt intern in
|
|
einen Trivial-Workspace.
|
|
- **Snapshots regeneriert.** `sum.ll`, `max3.ll`, `hello.ll`, `list.ll`
|
|
zeigen das neue Mangling. Neuer `ws_main.ll`-Snapshot dokumentiert den
|
|
Cross-Module-Build: `@ail_ws_main_main` ruft `@ail_ws_lib_add` auf.
|
|
- **Tests.** 40 grün (vorher 37). Neu: `workspace_build_runs_imported_fn`
|
|
(e2e: druckt 5), `ir_snapshot_ws_main`, `missing_entry_main_is_error`
|
|
(codegen-unit). Bestehende Verhaltens-Tests
|
|
(`sum_1_to_10_is_55`, `max3_picks_largest`, `hello_world_str_lit`,
|
|
`list_sum_via_match`) bleiben grün — Verhalten unverändert, nur das
|
|
Mangling ist neu.
|
|
|
|
**Schulden geschlossen:**
|
|
|
|
- **#19 (`source_filename` härten).** In der Workspace-Welt ist
|
|
`source_filename` jetzt einheitlich `<entry-modul>.ail`, einmal pro
|
|
Workspace. Der bisherige hartkodierte Pfad-Punkt entfällt damit.
|
|
|
|
**Stand:** Modulsystem ist Ende-zu-Ende geschlossen — Loader + Typcheck
|
|
+ Codegen + Build sehen den Workspace als kohärente Einheit. Multi-
|
|
Diagnose-Refactor und ggf. ADT-Cross-Module bleiben für später.
|
|
|
|
## 2026-05-07 — Iter 5d fertig: Tooling auf Workspace ausgedehnt
|
|
|
|
- `ail manifest|describe|deps|diff <entry> --workspace` arbeiten jetzt
|
|
über alle Module des Workspaces. Default ohne Flag bleibt single-modul
|
|
für Rückwärtskompatibilität. Manifest sortiert nach `(modul, name)`,
|
|
describe akzeptiert Punktnotation `ws_lib.add`, deps emittiert
|
|
`{from_module, from_def, to_module, to_def}`-Edges, diff vergleicht
|
|
workspace-übergreifend mit added/removed/changed/unchanged_modules
|
|
und nested Sub-Diff pro changed_module.
|
|
- Refactor: `diff_def_lists` ist die einzige Quelle der 4-Kategorie-
|
|
Logik; Single- und Workspace-Diff teilen sie.
|
|
- Tests: 44 grün (vorher 40). Neu: `manifest_workspace_lists_all_defs`,
|
|
`describe_workspace_resolves_qualified_name`,
|
|
`deps_workspace_includes_cross_module`, `diff_workspace_added_module`.
|
|
|
|
**Beobachtung (Schuld):** `deps` filtert Builtins/Locals/Funktions-
|
|
parameter nicht. Im Workspace-Modus wird das deutlicher als im Single-
|
|
Modus — `ws_lib.add` listet Edges auf `ws_lib.+` (Builtin) und
|
|
`ws_lib.a`/`ws_lib.b` (Funktionsparameter). Bekanntes Vorbestand-
|
|
Problem aus Iter 2; Task #22 im Backlog.
|
|
|
|
## 2026-05-07 — Architektur-Review nach Iter 5
|
|
|
|
Architekt-Agent gerufen. Befunde:
|
|
|
|
1. **Mangling-Konsistenz hält.** `@ail_<modul>_<def>` durchgängig in
|
|
Funktionen, Konstanten, String-Globals, Cross-Module-Calls.
|
|
Trampoline korrekt. ADT-Konstruktoren sind absichtlich symbol-frei
|
|
(inline malloc).
|
|
2. **Modul-Hashes bitidentisch seit Iter 4.** Iter-5c-Snapshot-
|
|
Regenerierung war Codegen-Output-Änderung, nicht Hash-Bruch.
|
|
3. **Drift, sofort fällig:**
|
|
- DESIGN.md sagt `define i64 @main()`, der Codegen emittiert
|
|
`define i32 @main()` (siehe `sum.ll:35`).
|
|
- Stringschema-Notation in DESIGN.md verkürzt
|
|
(`@.str_<modul>_<idx>` statt `@.str_<modul>_<hint>_<idx>`).
|
|
4. **Schulden, die Zinsen tragen:** `deps`-Builtin-Leck (Task #22) ist
|
|
im Workspace-Modus zu einer Falschaussage geworden — vor dem
|
|
nächsten großen Sprung schließen.
|
|
|
|
**Plan Iteration 6 — Aufräumarbeiten:**
|
|
|
|
1. **DESIGN.md-Drift fixen.** Mangling-Schema-Block aktualisieren,
|
|
`@main`-Signatur korrigieren, String-Globals präzise notieren.
|
|
2. **`deps`-Härtung (#22).** Pro Workspace eine Top-Level-Def-Tabelle
|
|
bauen; Edges, deren Ziel kein Top-Level-Symbol ist, filtern oder
|
|
als separate `builtin:`/`local:`-Kategorie ausgeben.
|
|
Funktionsparameter via Lexikalisches Scope-Tracking aus walk_term.
|
|
3. **Multi-Diagnose-Refactor (#20).** `check_workspace` akkumuliert
|
|
`Vec<Diagnostic>` über alle Defs, statt beim ersten Error zu
|
|
shortcuten. Intra-Def darf weiter shortcuten — der Wert ist
|
|
"alle defektiven Defs auf einmal sehen", nicht "alle defektiven
|
|
Subterme einer Def sehen".
|
|
|
|
Reihenfolge: 1 zuerst (Doku-Trivialität), dann 2 vor 3 (deps ist eine
|
|
Tooling-Wahrheit-Reparatur, Multi-Diag eine Strukturerweiterung).
|