Emergente Architektur-Eigenschaften von Jade¶
Status: Entwurf, informativ
Version: 0.2.0
Abhängigkeiten: Design Constitution (§8, §9), Plugin System Revised, Blueprint Spec, Vision, 07-cast-effekte-refinements (v0.3)
Zielgruppe: Mitwirkende, Architekturentscheidende, interessierte Leser
Priorität. Dieses Dokument ist informativ und leitet ab. Bei Widerspruch mit
07-cast-effekte-refinementsgilt07. Bei Widerspruch mit der Design Constitution gilt die Constitution. Wo dieses Dokument eine Frage offenlässt, die anderswo entschieden ist, ist das ein Fehler dieses Dokuments und kein Designspielraum.
0. Zweck dieses Dokuments¶
Jade definiert eine kleine Menge von Grundprimitiven: Blueprints, Engines, Protocols, Handles, Arenas, Refinements, Effekte und ein Ring-basiertes Isolationsmodell. Dieses Dokument beschreibt die Eigenschaften, die sich aus dem Zusammenspiel dieser Primitive ergeben, ohne dass sie explizit als Features entworfen wurden.
Emergente Eigenschaften sind kein Zufall. Sie sind der Beweis, dass die Grundarchitektur konsistent ist — wenn sich aus wenigen Regeln komplexe Fähigkeiten ableiten lassen, ohne Sondermechanismen oder Ausnahmen einzuführen, dann tragen die Regeln.
Dieses Dokument identifiziert acht emergente Eigenschaften:
- Universelles UI-Toolkit — GUI, TUI und Web aus demselben Blueprint.
- Inhärente Fehlertoleranz — Arena-basierte Fehlergrenzen ohne explizite Programmierung.
- Universelle Format-Verarbeitung — Parsing, Transformation und Generierung beliebiger Formate über ein einheitliches Blueprint-Modell.
- Selbst-generierende Runtime-Infrastruktur — JDL erzeugt Teile seiner eigenen nativen Schicht.
- Reproduzierbare, typsichere Builds — Determinismus als Konsequenz des Typsystems, nicht als Sandbox-Mechanik.
- OS-Integration durch Architektur — JadeOS als System, in dem der Benutzer nie die Abstraktionsgrenze verlassen muss.
- Dezentrales Community-Repository — Vertrauenswürdige Paketverteilung durch unabhängige Build-Verifikation ohne zentrale Autorität.
- Deterministischer Systemzustand — User-seitiges Einfrieren beliebiger Systemkomponenten als Konsequenz der Content-Adressierung.
Jede dieser Eigenschaften wird mit ihrer architektonischen Herleitung, ihren Voraussetzungen und ihren normativen Konsequenzen beschrieben.
1. Universelles UI-Toolkit¶
1.1 Architektonische Herleitung¶
Die Blueprint-Engine-Trennung (Constitution §8) besagt: Ein Blueprint beschreibt was, eine Engine entscheidet wie. Ein Blueprint weiß nicht, welche Engine ihn konsumiert. Daraus folgt unmittelbar, dass ein UI-Widget als Blueprint definiert werden kann, der von verschiedenen RenderEngines konsumiert wird — einer grafischen, einer textbasierten und einer web-basierten.
Das Widget selbst sagt nie „male ein Pixel an Position X". Es sagt „ich bin ein Button mit diesem Label und diesem State." Die Darstellung ist Sache der Engine.
1.2 Schichtung des Rendering-Stacks¶
Der Rendering-Stack besteht aus fünf Schichten, von denen die unteren drei über FFI angebunden und die oberen zwei in JDL implementiert werden:
FFI-Schicht (extern, als Plugins gewrappt):
- Windowing und Input:
libwayland-clientfür das Wayland-Protokoll. C-Library, nachrichtenbasiert, stabile ABI. Passt natürlich auf Jade's Query/Command-Modell — Events werden als Queries empfangen, Aktionen als Commands gesendet. - 2D-Rendering: Skia (über
skia-cC-Wrapper) für GPU-beschleunigtes Zeichnen — Pfade, Text, Anti-Aliasing, Compositing. Alternativ Cairo oder wgpu. Die Wahl der Rendering-Library ist ein Implementierungsdetail hinter der Plugin-Grenze. - Text-Stack: HarfBuzz für Shaping, FreeType für Rasterisierung, Fontconfig für Font-Discovery. Alle drei sind C-Libraries mit stabilen ABIs und fokussierten APIs.
Diese Libraries sind Werkzeuge, keine Frameworks. Sie diktieren nicht die Architektur — sie machen, was man ihnen sagt. Die Plugin-Grenze hält die rohen C-Ressourcen (Wayland-Surfaces, Skia-Canvases, FreeType-Faces) als opake Handles, managed deren Lifecycle intern und exponiert nach außen nur Jade-Typen.
JDL-Schicht (nativ, als Protocols und Blueprints):
- Zeichenprimitiven: Protocols wie
RenderableundPaintable, die Operationen wiedrawRect,drawText,drawPath,clipRegiondefinieren. EinCanvas-Handle, das intern einen Skia-SkCanvas*hält, implementiert diese Protocols. - Layout-Engine: Ein
LayoutSpec-Blueprint beschreibt den gewünschten Layout-Baum — Größe, Position, Kinder, Constraints (min/max-Width, Flex-Grow, Padding, Alignment). EineLayoutEnginelöst die Constraints auf und produziert einen konkretenLayoutTreemit berechneten Positionen. Für den Anfang kann Yoga (Facebook/Meta) als FFI-basierter Flexbox-Solver dienen, bevor ein eigener Solver in JDL geschrieben wird. - Widget-Toolkit: Widgets sind Blueprints. Ihre Konfiguration sind Felder, ihre Erscheinung ein
provide Renderable, ihr Verhalten einprovide InputHandler, ihr Zustand ein Handle in einer Arena. Refinements wie:> Scrollableoder:> Resizablebeschreiben Layout-Policies.
1.3 Reaktivität über das Handle-System¶
Reaktivität entsteht aus dem bestehenden Handle-Modell, nicht aus einem separaten Framework. Ein State[T]-Handle ist ein reaktiver Wert in einer Arena. Wenn sich der Wert ändert, markiert die RenderEngine die abhängigen Widgets als dirty. Beim nächsten Frame werden nur die dirty Widgets neu gelayoutet und gerendert. Kein Virtual-DOM-Diffing, kein manuelles setState(), kein Reconciliation-Algorithmus. Die Engine sieht den Blueprint, kennt die Dependencies und updatet was nötig ist.
1.4 Widget-Orchestrierung¶
Einfache Widgets (Button, Label, Checkbox) sind passive Blueprints — reine Datenstrukturen mit provide Renderable und provide InputHandler. Sie brauchen keinen eigenen Execution-Context. Die RenderEngine walkt den Layout-Baum und rendert sie direkt.
Komplexe Widgets mit eigenem internem State — Text-Editoren, Terminal-Emulatoren, Live-Daten-Feeds — können sich über provide ActorWidget in den Actor-Modus opt-in. Sie bekommen eine eigene Coroutine mit Mailbox, verwalten ihren State selbst und kommunizieren über Signal/Slot nach außen.
Signal/Slot funktioniert für beide Fälle identisch: Ein Widget deklariert seine Signals als Protocol-Oberfläche, die Verbindung zwischen Signal und Slot ist zur Compile-Zeit prüfbar. Das Protocol-System erzwingt diese Entscheidung nicht vorab — ob ein Widget ein simpler Blueprint oder ein Actor ist, ist ein Implementierungsdetail hinter dem Protocol.
1.5 Automatische TUI-Fähigkeit¶
Die emergente Eigenschaft: Dasselbe Widget, das in der GUI als grafischer Button gerendert wird, kann in einem Terminal als TUI-Element erscheinen. Der Widget-Code ändert sich nicht — es gibt nur eine zweite Engine.
Eine GuiRenderEngine zeichnet den Blueprint mit Skia auf einen Wayland-Surface. Eine TuiRenderEngine zeichnet denselben Blueprint mit ANSI-Escape-Codes in ein Terminal. Der Widget-Blueprint beschreibt nur die Absicht — „ich bin ein Button mit diesem Label" — nicht die Darstellungsform.
Der Protocol-Schnitt: Renderable als Basis-Protocol. provide GuiRenderable für die grafische Darstellung. provide TuiRenderable für die Terminal-Darstellung. Die Basis-Widgets liefern beides mit. Für Custom-Widgets kann ein eigenes provide TuiRenderable eine sinnvolle vereinfachte Darstellung liefern — ein Chart wird zur ASCII-Tabelle, ein Color-Picker wird zur Hex-Eingabe.
Widgets ohne TUI-Äquivalent erhalten automatisch eine Fallback-Darstellung: Die TuiRenderEngine erkennt das fehlende provide TuiRenderable und rendert einen Platzhalter. Kein Crash, kein Fehler, nur saubere Degradierung.
1.6 Remote-Verwaltung als Konsequenz¶
Die unmittelbare Konsequenz der TUI-Fähigkeit: Ein SystemSpec-Settings-Panel, das in der GUI ein Fenster mit Tabs und Toggles ist, funktioniert automatisch über SSH. Ein Administrator verbindet sich remote auf einen JadeOS-Node, hat kein Wayland, und bekommt dasselbe Settings-Panel als TUI — dieselben Widgets, derselbe State, dieselbe Validierung, nur ein anderer Renderer.
Eine dritte Engine — eine WebRenderEngine, die den Blueprint als HTML/CSS rendert — erweitert das Muster auf Browser-basierte Verwaltung. Selber Blueprint, dritter Renderer, keine Duplikation.
2. Inhärente Fehlertoleranz¶
2.1 Architektonische Herleitung¶
Die Constitution definiert zwei Prinzipien: Kein undefiniertes Verhalten (§2) und Graceful Degradation by Default (§9). Zusammen ergeben sie: Jade-Programme haben definiertes Verhalten auf jeder Ebene — vor der Ausführung, während der Ausführung und im Fehlerfall.
Die Fehlertoleranz ist kein Feature das gebaut werden muss. Sie ist eine Konsequenz der Arena-Architektur (§6) in Kombination mit dem Result-Typsystem. Arenas begrenzen Speicher-Lebensdauern; sie begrenzen damit automatisch auch den Blast-Radius von Fehlern.
2.2 Arena-Scopes als Fehlergrenzen¶
Zuerst die Abgrenzung, ohne die der Rest dieses Abschnitts falsch wird. JDL kennt vier
Arten des Fehlschlagens (07 §4.3):
| Art | Fangbar | Ort |
|---|---|---|
Option-Abwesenheit |
n/a — kein Fehlschlag | Wert |
Throw[E] |
ja, über Handler | Sprachebene |
| Trap | nein | Engine; invalidiert den lokalen Scope |
| Abbruch | nein | Prozessende |
Regel E-3. Ein Trap ist auf Sprachebene nicht fangbar und lässt sich nicht in ein
Resultverwandeln. Trap-Behandlung ist Sache der Engine, nicht des Nutzercodes.
Wenn ein Trap innerhalb eines Arena-Scopes auftritt:
- Die Arena wird deterministisch aufgeräumt. Alle Handles innerhalb der Arena werden invalidiert. Ressourcen werden freigegeben.
- Die Engine, die den Scope betreibt, nimmt den Trap an der Scope-Grenze entgegen und entscheidet über das Fallback-Verhalten ihres eigenen Aufrufers.
- Der auslösende JDL-Code sieht davon nichts. Er ist beendet, nicht behandelt.
Der entscheidende Punkt gegenüber Version 0.1.0 dieses Dokuments: Die Eindämmung geschieht unterhalb der Sprachebene. Es gibt keinen JDL-Ausdruck, der einen Trap in einen Wert verwandelt, und es soll keinen geben — sonst wäre der Unterschied zwischen einem Fehler und einem Trap fließend, und die Aussage „hier ist der Zustand nachweislich intakt" verlöre ihren Boden.
Der Trap kann nicht nach oben durchschlagen, weil es keinen Mechanismus gibt, über den ein invalidiertes Handle aus einer zerstörten Arena noch von außen erreichbar wäre. Die JME garantiert das auf Ring-0-Ebene.
Fangbare Fehler laufen den anderen Weg: als Throw[E] in der Effect Row. Die Aufrufstelle
entscheidet über catching, ob daraus Kontrollfluss oder ein Result-Wert wird (Regel E-2).
Beide Wege existieren nebeneinander und werden nicht ineinander überführt.
2.3 Anwendung auf das Widget-System¶
Jedes Widget bekommt beim Rendern seinen eigenen Arena-Scope. Wenn das Widget trappt — Division durch Null, korrupter State, fehlerhafte Logik — wird die Arena aufgeräumt, und die RenderEngine stellt an dieser Stelle des Baums eine Fallback-Box dar. Der Rest des UI-Baums bleibt völlig unberührt.
Dass hier die Engine handelt und nicht der Parent-Widget-Code, ist keine Feinheit, sondern Regel E-3: Widget-Code ist gewöhnlicher JDL-Code und kann einen Trap nicht fangen. Die Engine ist ohnehin der richtige Ort — sie besitzt den Baum, den Scope und die Entscheidung, was ein Loch im Baum bedeutet. Ein Widget, das seine Kinder selbst absichern müsste, wäre genau die Sorte Boilerplate, die diese Architektur vermeiden soll.
Widget-Fehler, die vorhersehbar sind — fehlende Daten, ungültige Konfiguration —, gehören
dagegen nicht in einen Trap, sondern in die Row als Throw[WidgetError]. Die Trennung ist
dieselbe wie überall: Was das Widget kommen sieht, deklariert es; was es nicht kommen sieht,
fängt die Engine.
Für den Plugin-Entwickler bedeutet das: Ein fehlerhaftes Custom-Chart-Widget, das bei bestimmten Datensätzen durch Null dividiert, erzeugt in JadeOS eine graue Box mit Fehlermeldung. In Qt oder GTK crasht die Anwendung. In Electron crasht der Renderer-Prozess. In JadeOS läuft der Rest der Anwendung weiter.
Für die Desktop-Umgebung bedeutet das: Ein fehlerhaftes Panel-Applet oder eine fehlerhafte Extension nimmt nicht den ganzen Desktop mit. Im Gegensatz zu GNOME Shell, wo eine Extension mit Null-Referenz einen schwarzen Bildschirm verursachen kann, ist das fehlerhafte Widget in JadeOS eine isolierte graue Box, während der Rest des Desktops funktioniert.
2.4 Ring-basierte Eskalation¶
Die Fehlerbehandlung folgt dem Ring-Modell der Constitution (§12):
- Ring 2 (Plugins, Userland, Engines): Fehler werden lokal eingedämmt. Kein Prozessabbruch. Der Plugin Broker markiert fehlerhafte Plugins als FAILED, setzt Abhängige auf BLOCKED, aktive Plugins bleiben aktiv.
- Ring 1 (VM, Type Engine): Einzelfallbewertung. Wiederherstellbare Fehler werden degradiert, nicht-wiederherstellbare führen zum Prozessabbruch.
- Ring 0 (JME): Prozessabbruch. Korrupte Speicherzustände oder verletzte Verifier-Invarianten erlauben keine sichere Fortsetzung.
2.5 Allokationsversagen als austauschbare Politik¶
Mit Alloc[A] als Effekt (07 §5) bekommt die Fehlertoleranz einen Baustein, den Version
0.1.0 dieses Dokuments noch nicht kannte. Allokation verändert globalen Zustand und kann
fehlschlagen, steht also in der Row.
Regel M-1. Der Default-Handler für
Alloc[A]trappt bei Erschöpfung. Fallibilität ist eine Handler-Entscheidung, keine Eigenschaft der Operation.
Die emergente Folge: Derselbe Code, anderer Handler. Auf dem Desktop trappt eine
erschöpfte Arena und die Engine räumt den Scope ab — das ist die richtige Politik, weil ein
Anwendungsprogramm sinnvollerweise nicht jede Struktur-Konstruktion absichert. Im
JadeOS-Kernel oder auf einem eingebetteten Ziel installiert man einen Handler, der stattdessen
ein Result liefert, und derselbe unveränderte JDL-Code behandelt Speichermangel explizit.
Das ist keine Konfigurationsoption, die jemand einbauen musste. Es fällt daraus heraus, dass Allokation ein Service ist und Services über Handler aufgelöst werden.
2.6 Warum das emergent ist¶
Keine der beteiligten Komponenten — Arenas, Handles, Result, Protocols, Ringe — wurde für Fehlertoleranz entworfen. Arenas wurden für deterministische Speicherverwaltung entworfen. Result wurde für typsichere Fehlerbehandlung entworfen. Ringe wurden für Subsystem-Isolation entworfen. Aber zusammen ergeben sie ein System, in dem Fehler automatisch eingegrenzt werden, ohne dass der Entwickler explizite Fehlertoleranz-Mechanismen einbauen muss.
3. Universelle Format-Verarbeitung¶
3.1 Architektonische Herleitung¶
Die Blueprint-Engine-Trennung (Constitution §8) sagt: Ein Blueprint beschreibt Absicht, eine Engine interpretiert sie. Parsing ist ein Spezialfall von Interpretation — eine ParserEngine interpretiert einen ParserSpec-Blueprint und produziert getypte Daten. Die Engine ist universell; die Format-Kenntnis lebt ausschließlich im Blueprint und im Zieltyp.
3.2 Dreischichtiges Parser-Modell¶
Die Format-Verarbeitung besteht aus drei unabhängigen Komponenten:
Zieltyp: Eine getypte JDL-Datenstruktur, die ein valides Dokument des jeweiligen Formats repräsentiert. Der Zieltyp ist formatneutral — ein MarkdownDoc weiß nicht, dass er aus Markdown kam.
type MarkdownDoc: struct {
meta: Option[FrontMatter]
blocks: [Block]
}
type Block: enum =
| Heading { level: Int :> Range(1, 6), content: [Inline] }
| Paragraph { content: [Inline] }
| CodeBlock { language: Option[Str], code: Str }
| List { ordered: Bool, items: [[Block]] }
| Quote { content: [Block] }
| Break
type Inline: enum =
| Text { value: Str }
| Bold { content: [Inline] }
| Italic { content: [Inline] }
| Code { value: Str }
| Link { text: [Inline], url: Str :> Url() }
| Image { alt: Str, url: Str :> Url() }
Refinements wie :> Range(1, 6) und :> Url() sind Compile-Zeit-Constraints. Ein Heading { level: 9 } ist ein Typfehler, kein Laufzeitfehler.
GrammarSpec[T]: Ein Blueprint, der die Grammatik eines Formats als Kombinator-Baum beschreibt. Die Kombinatoren — alt, seq, between, many, map, lazy — sind deklarative Datenstrukturen, keine imperative Logik. Die ParserEngine inspiziert den Kombinator-Baum und kann intern optimieren: Prediction-Tables bauen, spezialisierte Scanner erzeugen, tote Branches eliminieren.
val md_grammar = GrammarSpec[MarkdownDoc] {
entry: many(block) |> map(bs => MarkdownDoc { blocks: bs })
rules: {
inline = alt([
between("**", "**", lazy(inline)) |> map(Inline.Bold),
between("*", "*", lazy(inline)) |> map(Inline.Italic),
between("`", "`", text_until("`")) |> map(Inline.Code),
seq([lit("["), lazy(inline), lit("]("), text_until(")"), lit(")")])
|> map(p => Inline.Link { text: p.1, url: p.3 }),
take_while(not(special_char)) |> map(Inline.Text),
])
block = alt([
seq([one_or_more(char('#')), ws, inline, newline])
|> map(p => Block.Heading {
level: p.0.len(), content: p.2
}),
seq([lit("```"), opt(word), newline, text_until("```"), lit("```")])
|> map(p => Block.CodeBlock {
language: p.1, code: p.3
}),
prefixed("> ", lazy(block)) |> map(Block.Quote),
seq([inline, blank_line]) |> map(Block.Paragraph),
])
}
}
ParserSpec[T]: Der formatagnostische Pipeline-Blueprint, der eine GrammarSpec[T] mit optionaler Validierung verbindet.
type ParserSpec[T]: blueprint {
grammar: GrammarSpec[T]
validation: Option[(T) -> Result[T, ValidationError]]
}
Offener Punkt (O-7). Die Fehlerkonvention hat sich mit
07v0.3 geändert:-> Result[T, E]als Autorenentscheidung ist dem Row-ElementThrow[E]gewichen, und die Aufrufstelle entscheidet übercatching, ob daraus ein Wert wird. Für Funktionen in Signaturposition ist die Umstellung mechanisch. Für Funktionen in Feldposition — wievalidationhier — ist sie es nicht: Rows würden damit in Datentypen wandern, und das ist in07§11.1 als offener Punkt O-7 verzeichnet. Hinzu kommt, dass Constitution §8.2 Blueprints als effektfrei festlegt; ein Blueprint-Feld mit nichtleerer Row braucht dafür eine Auslegung. Die Signaturen in diesem Kapitel stehen deshalb noch im alten Stil. Sie sind als noch nicht migriert zu lesen, nicht als Gegenentwurf.
Eine ParserEngine konsumiert jede ParserSpec[T], unabhängig vom Format:
val md = ParserSpec[MarkdownDoc] { grammar: md_grammar }
val yaml = ParserSpec[YamlValue[Cfg]] { grammar: yaml_grammar }
val html = ParserSpec[HtmlDocument] { grammar: html_grammar }
val css = ParserSpec[CssStylesheet] { grammar: css_grammar }
val jdl = ParserSpec[JdlModule] { grammar: jdl_grammar }
Fünf verschiedene Formate, eine Engine, ein Blueprint-Typ.
3.3 Doc-Blöcke als getyptes Markdown¶
JDL-Doc-Blöcke verwenden Markdown-Syntax. Mit einer ParserSpec[MarkdownDoc] werden Doc-Blöcke zur Compile-Zeit in getypte MarkdownDoc-Werte geparst — nicht als opake Strings durchgereicht.
Konsequenzen:
- Kaputtes Markdown in Doc-Blöcken ist ein Compiler-Fehler. Ein nicht geschlossenes
**, ein Link mit fehlender URL, ein Code-Block ohne schließendes Fence — das sind Typfehler, nicht stille Probleme die erst im generierten HTML auffallen. - Der LSP bekommt Markdown-Completion innerhalb von Doc-Blöcken, Link-Validierung gegen existierende Symbole und Live-Preview — weil er denselben Parser benutzt wie der Compiler.
- Der Dokumentationsgenerator muss nicht nochmal parsen. Er bekommt vom Compiler den getypten
MarkdownDocals Metadatum am Symbol und transformiert nur noch.
Der JDL-Compiler benutzt einen ParserSpec-Blueprint um seine eigene Dokumentationssprache zu verarbeiten. Die Bootstrap-Reihenfolge ist sauber: der Zig-basierte Bootstrap-Parser (Stage 1) behandelt Doc-Blöcke als rohe Strings, und sobald der JDL-Markdown-ParserSpec verfügbar ist, übernimmt er als Ring-1-Engine.
Der Übergang ist kein Sonderfall, sondern der reguläre Provider-Wechsel der CompilerDB: Für eine gegebene Query gibt es pro Stage-Profil genau einen aktiven Provider, und der Wechsel von einem Zig-Bootstrap-Provider zu einem Ring-1-EngineProvider darf die Query-Semantik nicht ändern. Das Dokumentationsmodell hängt damit an derselben Mechanik wie jede andere Compile-Zeit-Information.
3.4 Format-Konvertierung über das Cast-System¶
Konvertierung zwischen getypten Dokumenten nutzt das bestehende CastTo-Protocol mit CastMode(Try[E]):
provide CastTo[TomlDoc] for YamlDoc
:> CastMode(Try[ConvertError])
{
def castTo(self) -> Result[TomlDoc, ConvertError] =
yaml_to_toml(self)
}
Die Transformation ist eine Funktion zwischen getypten Bäumen. Der Compiler erzwingt exhaustives Pattern-Matching — vergisst du einen Variant im Quelltyp, ist das ein Compile-Fehler. Die Konvertierung wird über die Standard-JDL-Syntax aufgerufen:
Der Aufruf steht ohne Sonderoperator da. =? existiert seit 07 v0.3 nicht mehr
(Invariante 12). Ein fallibler Cast trägt seinen Fehler als Throw[ConvertError] in der Row
der aufrufenden Funktion; wer stattdessen einen Wert will, wandelt an der Aufrufstelle um
(catching, 07 §4.2 — dort ebenfalls als spekulativ geführt). Die Entscheidung liegt beim
Aufrufer, nicht beim Autor der Konvertierung (Regel E-2).
Nicht jede Konvertierung ist verlustfrei. CastMode unterscheidet Lossless (total, verlustfrei), Narrowing (total, verlustbehaftet) und Try[E] (fallibel). Refinements können die Verlustfreiheit granularer steuern: ein MarkdownDoc :> NoImages() konvertiert verlustfrei zu reinem Text, ein allgemeiner MarkdownDoc möglicherweise nicht.
3.5 Generator[In, Out] als Pipeline-Blueprint¶
Die gesamte Kette — Parsing, Transformation, Serialisierung — kann als Generator-Blueprint zusammengefasst werden:
type Generator[In, Out]: blueprint {
parser: ParserSpec[In]
transform: (In) -> Result[Out, TransformError]
serializer: SerializerSpec[Out]
}
val yaml2toml = Generator[YamlDoc, TomlDoc] {
parser: yaml_parser
transform: convert
serializer: toml_serializer
}
val output = GeneratorEngine.execute(yaml2toml, input_string)
Weil der Generator ein Blueprint ist, greifen alle Blueprint-Eigenschaften: DryRun-Engines können die Pipeline simulieren, Tooling kann den Datenfluss visualisieren, der Playground kann Zwischenschritte inspizieren.
3.6 Roundtrip-Validierung¶
Dieselbe ParserSpec, die Input parst, kann die Ausgabe eines Generators validieren. Wenn parse(serialize(doc)) == doc gilt, ist der Serializer korrekt.
Wenn der Generator direkt mit getypten Werten arbeitet statt Strings zu konkatenieren, ist die Roundtrip-Validierung in den meisten Fällen unnötig. Der Zieltyp verhindert invalide Konstruktion auf Typebene — ein Heading { level: 9 } kann nicht existieren, Inline-Text und Struktur sind auf Typebene getrennt (Injection-sicher by construction), und der Serializer ist eine einzige getestete Funktion die immer einen validen Zieltyp als Input bekommt.
Der Roundtrip-Check wird zum Test für den Serializer selbst, nicht für jeden Generator der ihn benutzt.
4. Selbst-generierende Runtime-Infrastruktur¶
4.1 Architektonische Herleitung¶
Die Format-Verarbeitung (§3) ist nicht auf externe Formate beschränkt. Wenn ein Generator[In, Out] beliebige getypte Dokumente erzeugen kann, dann kann er auch Zig-Quellcode erzeugen. Und wenn das Build-System (§5) den generierten Code kompilieren kann, entsteht ein Self-Hosting-Pfad: JDL generiert Teile seiner eigenen nativen Infrastruktur.
4.2 FFI-Trampoline aus JDL¶
Der Trusted Core der Jade VM ist in Zig implementiert. Die Brücke zwischen JDL-Code und nativen Zig-Funktionen benötigt FFI-Trampolines — Wrapper mit C-Aufrufkonvention, die JadeValues entgegennehmen, in native Typen konvertieren, die Zig-Funktion aufrufen und das Ergebnis zurückkonvertieren. Diese Trampolines sind repetitiver Glue-Code der einem festen Muster folgt und sich aus der Typsignatur ableiten lässt.
Ein TrampolineSpec-Blueprint beschreibt die JDL-seitige Signatur: welche Funktion gewrappt wird, welche JadeValue-Typen rein und rausgehen, welches Calling-Convention-Label gilt. Ein Generator[TrampolineSpec, ZigSourceFile] erzeugt daraus Zig-Quellcode:
val trampoline_gen = Generator[TrampolineSpec, ZigSourceFile] {
parser: trampoline_grammar
transform: spec_to_zig_source
serializer: zig_code_serializer
}
Der JDL-Compiler kennt sowohl den JDL-Typ als auch den generierten Zig-Code — beide stammen aus derselben Quelle. Die Konsistenz zwischen JDL-Seite und Zig-Seite der Bridge ist durch Konstruktion garantiert.
Das bleibt innerhalb der Rollenverteilung, die 07 Invariante 46 festhält: Zig stellt
Ring-0-Substrate, Host-Integration und den Bootstrap-/Recovery-Pfad bereit und ist kein
Bestandteil der JDL-Semantikschicht. Generierte Trampolines sind Host-Integration. Es wandert
keine Semantik nach Zig, nur die Brücke dorthin.
4.3 Build-Pipeline als Blueprint¶
Das Jade Build-System kompiliert den generierten Zig-Code automatisch:
// spekulativ — Schrittnamen und Flags sind Anschauung, keine normative BuildSpec-API
val bridge_build = BuildSpec {
steps: [
generate(trampoline_gen, trampoline_specs),
compile_zig(generated_sources, mode: .ReleaseSafe, target: host_target),
link(output: "jade_bridge.so"),
register_plugin(ring: Ring.One, manifest: bridge_manifest),
]
}
Kein Makefile, kein Shell-Skript, kein CMake. Der Compiler prüft die Build-Pipeline auf Typebene — wenn ein Schritt eine .zig-Datei erwartet und der vorherige Schritt einen anderen Dateityp produziert, ist das ein Compile-Fehler.
Ein ehrlicher Vermerk zur Voraussetzung: Dieser Pfad setzt eine Zig-Toolchain auf dem bauenden System voraus. Für einen Entwicklungs-Node ist das unkritisch; für einen minimalen Ziel-Node ist noch nicht entschieden, ob generierte Bridges dort gebaut oder als fertige Artefakte über den Content-Addressable Store bezogen werden. Die Frage berührt §7 und §8 und ist dort nicht beantwortet.
4.4 Anwendungsbereich und Grenzen¶
Der Mechanismus ist bewusst auf strukturellen Glue-Code beschränkt: Trampolines, JadeValue-Marshalling, C-Konventions-Wrapper für Intrinsics, Handle-Adapter für FFI-Libraries. Kein algorithmischer Zig-Code — nur Brücken die sich aus Typsignaturen ableiten lassen.
Eine zweite Grenze verläuft am unteren Ende und ist wichtiger als sie aussieht: Die Ring-0-Grundlagen — primitive Typen, Intrinsic-Kennungen, Operations-Zuordnungen — werden nicht generiert, sondern direkt in Zig geschrieben. Sie sind der Trust Anchor, gegen den alles andere geprüft wird; ein Generator davor würde eine Ebene einziehen, die selbst wieder vertrauenswürdig sein müsste. Selbstgenerierung ist ein Werkzeug für die Fläche, nicht für das Fundament.
5. Reproduzierbare, typsichere Builds¶
5.1 Architektonische Herleitung¶
Reproduzierbarkeit wurde nicht als Feature entworfen. Sie ist eine Konsequenz der Kombination von drei Architekturprinzipien:
-
Blueprints sind intrinsisch serialisierbar (Constitution §8.2). Jeder Build-Schritt ist ein Blueprint mit getypten, serialisierbaren Feldern. Es gibt keinen Ort für impliziten Zustand oder nicht-deterministische Inputs.
-
Der Content-Addressable Store identifiziert Artefakte über den Hash ihrer Inputs. Gleiche Inputs erzeugen denselben Hash, derselbe Hash garantiert denselben Output.
-
Das Typsystem erzwingt vollständige Deklaration. Jeder Input eines Build-Schritts muss als Feld im Blueprint deklariert werden. Es gibt keinen Mechanismus für undokumentierte Seitenkanäle — keine impliziten Umgebungsvariablen, keine versteckten Dateisystem-Zugriffe, keine Timestamps.
5.2 Abgrenzung zu Nix¶
NixOS erreicht Reproduzierbarkeit durch eine explizite Sandbox-Mechanik: keine Netzwerkzugriffe im Builder, keine Timestamps, kein /usr/lib, strikt kontrollierte Umgebung. Die Garantie kommt von der Sandbox-Grenze — innerhalb des Builders kann der Code theoretisch nicht-deterministisch sein, aber die Sandbox verhindert die häufigsten Quellen von Nicht-Determinismus.
In Jade kommt die Garantie tiefer: aus dem Typsystem. Ein BuildSpec-Blueprint kann keinen nicht-deterministischen Schritt enthalten, weil ein solcher Schritt keine gültige Blueprint-Semantik hätte. Ein Blueprint-Feld das eine Umgebungsvariable liest, müsste einen Effekt deklarieren. Ein Effekt in einem Blueprint ist ein Typfehler (Constitution §8.2: Blueprints sind effektfrei). Die Sandbox ist nicht nötig, weil das Typsystem die Invariante bereits auf einer tieferen Ebene erzwingt.
Was die Effect Row daran geändert hat. In Version 0.1.0 war „effektfrei" eine Behauptung
über Blueprints. Seit 07 v0.3 ist es ein Teilmengentest: Die Effektmenge steht zwischen
Parameterliste und Rückgabetyp, eine fehlende Menge bedeutet die leere Menge und nicht
eine unbestimmte (Regel R-3), und die Prüfung an jeder Aufrufstelle geht eine Ebene tief
gegen die Deklarationen der Aufgerufenen. Das Argument dieses Abschnitts ist damit von einer
Designabsicht zu einer prüfbaren Aussage geworden.
Und welches Label es trägt. Nicht Pure, sondern Deterministic. Seit Allokation ein
Effekt ist (§2.5), trägt fast jeder nicht-triviale Schritt Alloc[_] in der Row und ist damit
nicht mehr Pure. Reproduzierbarkeit verlangt aber nicht Allokationsfreiheit, sondern dass
gleiche Inputs gleiche Outputs erzeugen — und genau das ist Deterministic (Regel P-2:
Row ⊆ {Alloc[_]}, keine RefMut/Out-Parameter). Ein Build-Schritt, der eine Liste
aufbaut, ist reproduzierbar; er ist nur nicht rein.
Diese Unterscheidung ist keine Wortklauberei. Hinge die Reproduzierbarkeitsgarantie an
Pure, wäre sie für praktisch jeden realen Build-Schritt nicht erfüllbar — und eine Garantie,
die nie greift, ist keine.
5.3 Konsequenzen¶
- Cache-Invalidierung ist ein gelöstes Problem. Wenn der Hash der Inputs sich nicht ändert, ist das Artefakt identisch. Kein
make clean, kein „hat jemand vergessen den Cache zu invalidieren". - Verteilte Builds sind trivial. Ein Build-Blueprint kann an einen Remote-Node gesendet werden (Blueprints sind serialisierbar), dort ausgeführt werden, und das Ergebnis kommt als Hash-identifiziertes Artefakt zurück.
- Auditing ist eingebaut. Jedes Artefakt im Store hat einen vollständigen Stammbaum: welche Inputs, welche Build-Schritte, welche Compiler-Version. Nachvollziehbarkeit ist keine nachträgliche Metadaten-Schicht, sondern eine Konsequenz der Content-Adressierung.
6. OS-Integration durch Architektur¶
6.1 Das Problem¶
Die etablierten Linux-Desktop-Umgebungen leiden an einem strukturellen Defizit: Die GUI deckt die Oberfläche ab, aber tiefergehende Systemverwaltung fällt durch das Raster und zwingt den Benutzer in die Shell. Für Benutzer die von macOS oder Windows kommen, bedeutet das einen Bruch in der Erfahrung. Das Problem ist nicht die Shell an sich, sondern die Tatsache, dass ein unbedarftes Copy-Paste von Shell-Befehlen das System beschädigen kann — ein Risiko, das in GUI-basierten Betriebssystemen nicht existiert.
GNOME ist zu minimalistisch und lagert wesentliche Funktionalität auf Extensions aus, die bei jedem Release brechen können. KDE bietet zu viele Einstellungsmöglichkeiten ohne ausreichende System-Usability in der GUI. YaST2 von openSUSE hatte den richtigen Ansatz — eine durchgängige Systemverwaltung die sowohl grafisch als auch im Terminal funktioniert — aber die Pflege solcher Tools ist ressourcenintensiv und wurde weitgehend eingestellt.
6.2 Jades Architekturantwort¶
JadeOS existiert nicht neben dem Linux-Kernel, sondern mit ihm. Die GUI ist keine Fassade über einer Shell — sie ist die primäre Verwaltungsschnittstelle, hinter der die üblichen GNU/Linux-Tools über Lib-Plugins an Jade angebunden und durch Jade verwaltet werden.
Ein SystemPackageManager-Subsystem, das intern apt oder pacman aufruft, exponiert nur Queries (listInstalled(), getPackageInfo()) und Commands (installPackage(), removePackage()). Die Shell-Kommandos werden zu Implementierungsdetails hinter der Subsystem-API. Der Benutzer sieht nie den darunterliegenden Paketmanager — er sieht ein Jade-Interface.
6.3 SystemSpec als Single Source of Truth¶
Der SystemSpec-Blueprint beschreibt eine vollständige Node-Konfiguration: Pakete, Services, User, Netzwerk, Filesystem, Boot-Konfiguration. Dieser Blueprint ist die einzige Quelle der Wahrheit — die GUI rendert ihn als Settings-Panel, die TUI rendert ihn als Terminal-Interface, eine WebRenderEngine rendert ihn als Web-UI.
Ein Administrator der über SSH auf einen JadeOS-Node zugreift, bekommt dasselbe Settings-Panel als TUI. Er ändert eine Netzwerk-Konfiguration, der Blueprint wird atomar appliziert, fertig. Kein vim /etc/network/interfaces, kein sudo systemctl restart, kein Copy-Paste aus einem Forum.
6.4 Fehlertoleranz auf Desktop-Ebene¶
Die Arena-basierte Fehlerisolation (§2) gilt auch für Desktop-Komponenten. Ein fehlerhaftes Panel-Widget, ein fehlerhaftes Notification-Plugin, ein fehlerhafter Systemmonitor — keines davon kann den Desktop crashen. Das fehlerhafte Widget degradiert lokal zu einer Fallback-Darstellung, der Rest des Systems läuft weiter.
Das ist der dritte Unique Selling Point: Reproduzierbarkeit ist ein Admin-Feature, das universelle UI-Toolkit ist ein Developer-Feature, und Fehlertoleranz ohne Crash ist ein User-Feature — für die Zielgruppe die von macOS oder Windows kommt und erwartet, dass nichts explodiert.
7. Dezentrales Community-Repository¶
7.1 Architektonische Herleitung¶
Reproduzierbare Builds (§5), serialisierbare Blueprints (Constitution §8.2), das Plugin-System (Plugin System Revised) und typsichere Abhängigkeitsdeklarationen existieren bereits als Grundprimitive. Ein Community-Repository ist die Komposition dieser Primitive zu einem Verteilungssystem — eine RegistryEngine die PackageSpec-Blueprints konsumiert. Es braucht keinen separaten Paketmanager, keine externe Infrastruktur und kein eigenständiges CI-System.
7.2 Registrierung und Autorisierung¶
Der Ablauf folgt einem vierstufigen Trust-Modell:
-
Registrierung: Der Entwickler sendet einen
RegisterBlueprintan den Community-Jade-Node. Dieser Blueprint enthält Projektinformationen, den Quell-Endpunkt des Build-Servers und die gewünschten Namespace-Claims. -
Autorisierung: Bei Annahme der Registrierung erhält der Entwickler einen Hash-Token. Dieser Token bindet alle zukünftigen Builds kryptographisch an die Registrierung.
-
Build-Benachrichtigung: Nach jedem erfolgreichen lokalen Build sendet der Build-Server des Entwicklers den Hash des Artefakts zusammen mit dem Hash-Token an den Community-Node. Der Community-Node kennt damit den erwarteten Hash.
-
Unabhängiger Rebuild und Hash-Vergleich: Der Community-Node fetcht die Quellen und baut das Plugin selbst. Stimmt der Hash des unabhängigen Builds mit dem vom Entwickler gemeldeten Hash überein, wird das Artefakt versioniert, gecacht und deployed. Divergieren die Hashes, wird der Build abgelehnt.
7.3 Dezentrale Build-Verifikation¶
Der Community-Node muss nicht jeden Build selbst ausführen. Entwickler die über den Community Hub deployen, stellen automatisch ihren Build-Server für externe Build-Verifikation zur Verfügung — im Fair-Use-Modell: für jeden eigenen Build, den der Community Hub validiert, stellt der Entwickler 1:1 Build-Kapazität für die Verifikation anderer Projekte bereit.
Die Zuweisung erfolgt zufällig nach einem Fair-Schedule-Verfahren. Ein Entwickler weiß nicht im Voraus, wessen Build er verifiziert, und weiß nicht, wer seinen Build verifiziert. Das verhindert Absprachen.
Um Lügen über Build-Ergebnisse zu verhindern, verifiziert nicht ein einzelner Node, sondern ein Quorum von mindestens zwei bis drei unabhängigen Buildern. Nur wenn alle denselben Hash produzieren, gilt der Build als verifiziert. Ein einzelner divergierender Hash fällt sofort auf.
Der Community-Node selbst baut nur als Fallback-Validator — wenn nicht genügend Kapazität im Mesh vorhanden ist oder ein Quorum nicht zustande kommt.
7.4 Capability-basiertes Build-Matching¶
Build-Jobs haben unterschiedliche Ressourcenanforderungen. Der lokale Build-Server trackt automatisch den Ressourcenverbrauch (Peak-RAM, Disk, CPU-Zeit) beim erfolgreichen Build und erzeugt ein BuildProfile:
type BuildProfile: struct {
arch: Architecture
peak_memory: Bytes
disk_usage: Bytes
cpu_time: Duration
parallelism: Int
}
Dieses Profil reist als Metadatum mit dem Artefakt. Der Scheduler im Community-Mesh matcht Build-Jobs auf Verification-Nodes, die die Mindestanforderungen erfüllen. Jeder Build-Node advertised seine Ressourcen als Queryable-Tags im Node-Mesh (mem: 512MB, arch: x86_64, cores: 6).
Die Zielarchitektur ist ein harter Constraint — ein x86_64-Node kann keinen AARCH64-Build verifizieren. RAM und CPU-Kapazität sind weiche Constraints: sie bestimmen ob der Build durchkommt, nicht was er produziert. Wenn zwei Nodes mit unterschiedlicher Hardware denselben Build erfolgreich abschließen, müssen sie denselben Hash produzieren — andernfalls liegt ein Reproduzierbarkeitsbug vor.
7.5 Supply-Chain-Sicherheit¶
Der unabhängige Rebuild mit Hash-Vergleich schließt drei Angriffsvektoren gleichzeitig:
Kompromittierter Build-Server des Entwicklers: Der Community-Node (oder das Verification-Quorum) baut aus denselben Quellen ein anderes Artefakt als der kompromittierte Server. Die Hashes divergieren. Der Build wird abgelehnt.
Injizierter Code der nur im Binary existiert: Was nicht im Quellcode steht, kann der Verification-Node nicht reproduzieren. Der Hash-Vergleich schlägt fehl. Angriffe im Stil des xz-Backdoors werden automatisch erkannt, ohne dass ein Mensch etwas bemerken muss.
Kompromittierte Maintainer-Accounts: Ohne den Hash-Token der Registrierung nimmt der Community-Node keine Builds an. Selbst mit gestohlenem Token greift der unabhängige Rebuild — der Angreifer müsste sowohl die Quellen kompromittieren als auch den Verification-Prozess umgehen.
Der einzige verbleibende Angriffsvektor ist Schadcode der tatsächlich im Quellcode steht und durch Code-Review rutscht. Das ist kein Build-Problem, sondern ein Audit-Problem.
7.6 Der Community-Node als Jade-Anwendung¶
Der Community-Node selbst ist ein JadeOS-Node. Er empfängt RegisterBlueprint-Anfragen über das Node-Mesh, verifiziert Hash-Tokens, fetcht Quellen, baut mit seiner eigenen BuildEngine, vergleicht Hashes und deployed über sein eigenes Plugin-System. Kein separates CI-System, kein Jenkins, kein GitHub Actions — der Community-Server ist eine Jade-Anwendung die Jade-Blueprints baut und Jade-Plugins verteilt.
7.7 Stdlib als Plugin¶
Die JDL-Stdlib selbst kann als versioniertes Plugin über das Community-Repository verteilt werden. Eine Stdlib-Version ist ein Hash im Content-Addressable Store. Verschiedene Stdlib-Versionen können auf demselben Node koexistieren, weil das Plugin-System Isolation zwischen Versionen bietet. Der Jade Package Manager löst Versionsabhängigkeiten auf wie bei jedem anderen Plugin.
8. Deterministischer Systemzustand¶
8.1 Architektonische Herleitung¶
In jedem bestehenden Linux-System ist die Wahl zwischen LTS (Long Term Support) und Rolling Release eine Distributionsentscheidung. Ubuntu LTS oder Arch Linux — der Benutzer wählt einmal und lebt mit den Konsequenzen für das gesamte System.
In JadeOS ist diese Entscheidung eine Konsequenz der Content-Adressierung und fällt deshalb auf eine andere Ebene: Der Benutzer trifft sie pro Komponente, pro Service, pro Paket, jederzeit änderbar.
8.2 Freezing als Hash-Pinning¶
Ein SystemSpec-Blueprint enthält Referenzen auf Artefakte im Content-Addressable Store. Jede Referenz ist ein Hash. Den Systemzustand einzufrieren bedeutet: die Hashes pinnen.
Wenn ein Benutzer seinen SystemSpec mit konkreten Hashes festschreibt, ist sein System exakt dieser Zustand — reproduzierbar, verifizierbar, unveränderlich bis der Benutzer es anders entscheidet. Die Hashes referenzieren Artefakte deren Inhalt durch den Hash kryptographisch gebunden ist. Es gibt keine versteckte Drift, keine stillen Updates, keinen Unterschied zwischen "installiert am Montag" und "installiert am Freitag".
8.3 Granulares Versionsmanagement¶
Die Granularität der Versionskontrolle folgt der Granularität des SystemSpec. Der Benutzer kann mischen:
- Kernel eingefroren auf einer stabilen Version.
- Stdlib rolling auf dem neuesten Stand.
- GUI-Toolkit gepinnt auf eine getestete Version.
- Entwicklungstools auf bleeding edge.
Jede Kombination die der Dependency-Graph zulässt, ist gültig. Der Package Manager löst die Versionen auf und meldet Konflikte als Typfehler, nicht als Laufzeitprobleme.
8.4 Lokale Verifizierbarkeit¶
Der Benutzer muss weder dem Community-Node (§7) noch dem Entwickler blind vertrauen. Jedes Artefakt im Store kann lokal gebaut und der Hash verglichen werden. Stimmt der Hash überein, ist das Artefakt exakt das was der Quellcode beschreibt. Es gibt keine Möglichkeit für versteckte Modifikationen — das Vertrauen ist kryptographisch beweisbar, nicht sozial.
8.5 Warum das emergent ist¶
Deterministischer Systemzustand wurde nicht als Feature entworfen. Er ist eine Konsequenz der Content-Adressierung (jedes Artefakt ist sein Hash), der Blueprint-Serialisierbarkeit (der SystemSpec ist eine vollständige, portable Beschreibung) und der reproduzierbaren Builds (gleiche Inputs erzeugen gleiche Hashes). Zusammen ergeben diese drei Primitive ein System, in dem der Benutzer seinen Systemzustand mit derselben Präzision kontrollieren kann wie ein Entwickler seine Abhängigkeiten in einem Lock-File — nur dass das Lock-File hier das gesamte Betriebssystem umfasst.
9. Zusammenfassung: Warum das emergent ist¶
Keine der acht beschriebenen Eigenschaften erfordert einen Sondermechanismus. Jede ergibt sich aus der Kombination bestehender Primitive:
| Eigenschaft | Beteiligte Primitive |
|---|---|
| Universelles UI-Toolkit | Blueprint-Engine-Trennung, Protocols, Provides |
| Inhärente Fehlertoleranz | Arenas, Trap/Throw[E]-Trennung, Alloc-Handler, Ringe |
| Universelle Format-Verarbeitung | Blueprints, Engines, CastTo-Protocol, Kombinatoren |
| Selbst-generierende Runtime | Generator-Blueprints, BuildSpec, Plugin-System |
| Reproduzierbare Builds | Serialisierbare Blueprints, Content-Addressable Store, Effect Row und Deterministic |
| OS-Integration | Subsystem-APIs, SystemSpec-Blueprints, Multi-Engine-Rendering |
| Community-Repository | Reproduzierbare Builds, Plugin-System, Node-Mesh, Hash-Vergleich |
| Deterministischer Systemzustand | Content-Addressable Store, SystemSpec-Blueprints, Hash-Pinning |
Die Grundarchitektur — Blueprints beschreiben Absicht, Engines interpretieren, das Typsystem beweist Korrektheit, Arenas begrenzen Lebensdauern und Fehler, Protocols definieren Verhalten — trägt sich selbst. Neue Fähigkeiten entstehen durch neue Blueprints und neue Engines, nicht durch neue Sprachprimitive oder Compiler-Hooks.
Das ist der stärkste Test für eine Architektur: Wenn die Regeln ausreichen um Fähigkeiten zu erzeugen, die nicht vorhergesehen wurden, dann sind die Regeln richtig.
10. Offene Punkte und bekannte Lücken¶
Dieses Kapitel ist neu in v0.2.0. Es hält fest, wo dieses Dokument dem Stand der übrigen Specs nachläuft oder wo eine Entscheidung noch aussteht. Es ist ausdrücklich keine Vorschlagsliste — es benennt nur, was ungeklärt ist.
10.1 In den Specs noch nicht nachgezogen¶
| Thema | Stand |
|---|---|
| Fehlerstil in Feldposition (§3.2, §3.5) | -> Result[T, E] in Blueprint-Feldern ist nicht auf Throw[E] umgestellt. Hängt an O-7 (07 §11.1) und an der Auslegung von Constitution §8.2 für Felder mit nichtleerer Row. |
| Zig-Toolchain auf Ziel-Nodes (§4.3) | Ob generierte Bridges auf minimalen Nodes gebaut oder als Artefakte bezogen werden, ist offen. Berührt §7 und §8. |
Result in älteren Specs |
01-grundlagen §6 und 09-migration-checklist führen =? weiterhin als gültige Form. 07 Invariante 12 streicht es. Die älteren Dokumente sind nicht migriert; im Konfliktfall gilt 07. |
10.2 Aus Arbeitssitzungen, in keiner Spec abgebildet¶
Die folgenden Punkte wurden in Entwurfsgesprächen berührt, sind aber in keinem Spec-Dokument festgehalten. Dieses Dokument bildet sie deshalb nicht ab. Wer sie umsetzen will, muss sie zuerst dort normieren, wo sie hingehören.
- Enum-Schreibweise. Die Varianten-Schreibweise mit führendem
|steht unverändert in01-grundlagen,08-grammar-sketchundjdl-types-tags-phantoms. Die Beispiele in §3.2 folgen dieser Schreibweise. Eine Umstellung auf Blockform ist nicht spezifiziert. typefnals eigenes Konstrukt.08-grammar-sketch§6 führttypefnweiterhin als eigenständige Deklarationsform. Eine Auflösung in gewöhnliche Funktionen mit Compile-Zeit-Effekt ist nicht spezifiziert.- Terminierungsgarantie für Compile-Zeit-Code. Dass Compile-Zeit-Auswertung
nachweislich terminieren muss, ist eine getragene Absicht; ein Label oder eine Regel dafür
existiert in keiner Spec.
07§11.1 führt die Frage als offenen Punkt O-6. - Bootstrap-Seed-Umfang.
07Invariante 40 verlangt für den Seed eine Schema-Änderung mit Erhöhung derschemaVersion. Ob Seed-Format undschemaVersionin dieser Form bestehen bleiben, ist an anderer Stelle in Bewegung; solange07gilt, gilt Invariante 40.
10.3 Kandidat für eine neunte Eigenschaft¶
Erlernbarkeit als Nebenprodukt der Beweispflicht. Weil kein Label, das dem Compiler Rechte gibt, gesetzt werden kann, sondern jedes bewiesen werden muss, und weil der Proof-Trace für jedes abgeleitete Label Regel, Prämissen und Herkunft bis auf ein konkretes Feld festhält, kann der Compiler seine Ablehnungen begründen statt sie nur auszusprechen.
Das ist als emergente Eigenschaft plausibel, aber es fehlt ihr etwas, das die acht anderen haben: Sie ergibt sich nicht von allein. Sie entsteht erst, wenn Fehlermeldungen und LSP-Hover den Beweisbaum in lesbarer Sprache ausklappen. Die anderen acht folgen aus der Architektur; diese folgt aus der Architektur plus einer Tooling-Zusage.
Sie ist deshalb hier als Kandidat vermerkt und nicht als neunte Eigenschaft aufgenommen.
Änderungsprotokoll¶
Version 0.2.0 — Abgleich mit 07-cast-effekte-refinements v0.3 und dem Wechsel der
Host-Sprache:
- Korrektur (§2.2): Die Aussage, ein Trap werde als Result-Fehler an die umgebende
Schicht propagiert, widersprach Regel E-3 und ist entfernt. Eindämmung geschieht unterhalb
der Sprachebene durch die Engine. Die vier Fehlschlagsarten sind als Tabelle ergänzt.
- Korrektur (§2.3): Im Widget-Beispiel fängt die RenderEngine den Trap, nicht der
Parent-Widget-Code. Abgrenzung zu Throw[WidgetError] für vorhersehbare Fehler ergänzt.
- Neu (§2.5): Alloc[A] als Effekt und Regel M-1 — austauschbare Fehlerpolitik bei
Speichererschöpfung ohne Codeänderung. Vormaliger §2.5 ist jetzt §2.6.
- Korrektur (§3.4): =? entfernt (Invariante 12). Umwandlung liegt an der Aufrufstelle
(Regel E-2).
- Korrektur (§3.3): Bootstrap-Parser ist Zig-basiert, nicht D-basiert. Provider-Wechsel
über die CompilerDB ergänzt.
- Korrektur (§4): Host-Sprache durchgehend von D auf Zig umgestellt — Trampoline-Ziel,
Generator-Typ, Build-Schritt, Dateiendung. Rollenabgrenzung nach Invariante 46 und die
Ausnahme für Ring-0-Grundlagen ergänzt.
- Präzisierung (§5.2): Reproduzierbarkeit hängt am Label Deterministic, nicht an
Pure — seit Allokation ein Effekt ist, wäre Pure für reale Build-Schritte nicht
erfüllbar. „Effektfrei" ist durch Regel R-3 von einer Absicht zu einem Teilmengentest
geworden.
- Neu (§10): Offene Punkte, nicht nachgezogene Specs und ein Kandidat für eine neunte
Eigenschaft.
- Prioritätsvermerk im Kopf ergänzt.
Version 0.1.0 — Initiale Fassung: - Acht emergente Eigenschaften identifiziert und beschrieben. - Architektonische Herleitung aus bestehenden Primitiven für jede Eigenschaft. - Abgrenzung zu bestehenden Ansätzen (Nix, GNOME/KDE, Qt/GTK). - Dezentrales Community-Repository mit Trust-Modell, Fair-Use Build-Verifikation und Supply-Chain-Sicherheit. - Deterministischer Systemzustand als Konsequenz der Content-Adressierung.