Das Dokumentquellformat .ttrs

Eine Dokumentquelle ist Fließtext mit {{ … }}-Direktiven darin. Der Text wird unverändert übernommen; jede Direktive benennt etwas in einem Transitrix-Modell und wird durch das ersetzt, wozu sie aufgelöst wird.

Auf dieser Seite

Was eine Quelldatei enthält

Eine Textdatei, zweiteilig: ein YAML-Kopf, danach der Dokumentkörper.

Der Körper ist gewöhnlicher Fließtext. Alles außerhalb von {{ … }} ist fester Text und wird wortgetreu übernommen; jedes {{ … }} ist eine Direktive, die etwas im Modell benennt und durch das ersetzt wird, wozu sie aufgelöst wird.

---
document: Market Requirements Document   # erforderlich — der Name, den seine Leser verwenden
kind: mrd                                # erforderlich — passt zur mittleren Komponente des Dateinamens
template_id: product.mrd                 # erforderlich — im Laufprotokoll benannt
template_version: "1.0"                  # erforderlich — im Laufprotokoll benannt
canon: ../canon                          # optional — das Modell-Repository
---

Vier Kopffelder sind erforderlich; canon: ist es nicht. Eine Quelle, die kein Modellobjekt und keine abgeleitete Abbildung benennt, löst eigenständig auf, ganz ohne konfiguriertes Repository — das ist eine legitime Eingabe für sich, und eine Implementierung, die eine solche Quelle liest, meldet den Zustand „kein Repository konfiguriert“, statt ihn als fehlgeschlagene Auflösung zu behandeln.

Wie der Dateiname gelesen wird

<basename>.<kind>.ttrs        z. B.  product.mrd.ttrs
                                     platform.srs.ttrs
                                     gateway.sdd.ttrs

Die mittlere Komponente ist die Dokumentart — niemals eine Notation. Eine Art ist ein Layout über dem Modell: welche Elemente ein Dokument dieser Art auswählt und wie sie angeordnet werden. Sie trägt keinen eigenen Inhalt, erhält keine eigene Direktivensprache, und eine neue Art bedeutet nie eine neue Sprache. Die heute spezifizierten Arten sind mrd, srs, sdd und sds; das Kopffeld kind: muss mit dem Dateinamen übereinstimmen.

Jede Notation hat genau eine kanonische Dateiendung, und zwar entweder *.<short-name>.transitrix.yaml oder *.<short-name>.ttrs. Welche davon eine bestimmte Notation trägt, ist eine Eigenschaft dieser Notation. Wo .ttrs gilt, ersetzt es die längere Endung vollständig — es wird ihr nie angehängt, und keine Notation trägt beide.

.trs liegt einen Tastendruck daneben und ist ein anderes, weit verbreitetes Format. Eine Datei mit der Endung .trs dort, wo eine Dokumentquelle erwartet wird, wird als eben diese Verwechslung benannt und nicht als unbekannte Datei gemeldet.

Die Direktivensprache

Die Begrenzer sind {{ und }}. Leerraum unmittelbar innerhalb der Begrenzer ist unerheblich, {{REQ-14}} und {{ REQ-14 }} sind also dieselbe Direktive. \{{ erzeugt ein wörtliches {{ und ist die einzige Maskierung der Sprache. Keine Direktive verschachtelt sich in eine andere, abgesehen davon, dass die beiden Blockformen unten einen Körper tragen.

Inline-Formen

Blockformen — es gibt genau zwei

{{# each <TYP> [where …] [order by <feld>] }} … {{/ each }} wiederholt seinen Körper einmal je ausgewähltem Element und bindet jedes davon der Reihe nach als aktuelle Zeile. Die where-Klausel ist bewusst klein gehalten: nur and, kein or und keine Klammern; nur = und !=; rechts steht ein Literal, nie ein weiteres Feld. order by nimmt ein einzelnes Feld und ist das, was ein gerendertes Dokument reproduzierbar macht.

{{# instruct <slot-id> }} … {{/ instruct }} deklariert einen Anweisungsslot — einen Abschnitt, den ein deterministischer Durchlauf nicht füllt, mit question: und sufficient: (beide erforderlich) und einem optionalen, kommagetrennten inputs:. Der Körper eines Slots ist opak: Ein Parser läuft vom öffnenden Tag direkt zum passenden schließenden und behält alles dazwischen als Rohtext, sodass ein innerhalb eines Slots geschriebenes {{ REQ-14 }} Anweisungstext ist und nie aufgelöst wird. Slot-Bezeichner bestehen aus Kleinbuchstaben, Ziffern und Bindestrichen und müssen innerhalb eines Dokuments eindeutig sein.

Bezeichner

Ein Bezeichner folgt der kanonischen Grammatik — REQ-14, CAP-1, BUSINESS_SERVICE-3. Ein Fähigkeitsbezeichner enthält eine Diagrammadresse, deren Punkte zum Bezeichner gehören; ein Parser trennt daher das Präfix CAPABILITY-V bzw. CAPABILITY-H ab, bevor er einen Feldpfad liest: {{ CAPABILITY-V1.2.3 }} ist ein Bezeichner ohne Feldpfad, {{ CAPABILITY-V1.2.3.name }} derselbe Bezeichner mit dem Feldpfad name.

Ein durchgearbeitetes Beispiel

Das eingecheckte Konformitätsbeispiel, vollständig — ein Kopf, fester Text, eine Referenz, ein Feldpfad, ein zweistufiger Pfad, eine abgeleitete Abbildung mit einem Verweis darauf und ein Anweisungsslot.

---
document: Market Requirements Document
kind: mrd
template_id: product.mrd
template_version: "1.0"
canon: canon
---
# {{ CAP-1.title }}

## Scope

This document covers {{ CAP-1.text }}

## Requirements

**{{ REQ-14 }}** — {{ REQ-14.text }}

Its parent capability is {{ REQ-14.parent.name }}.

{{ view diagrams/context.blocks.transitrix.yaml as = context fit = width }}

{{ figref context }} shows where the capability sits.

## Market

{{# instruct market-size }}
question: How large is the addressable market for this capability, and how fast is it growing?
inputs: CAP-1, REQ-14
sufficient: A market size with a currency and a year, a growth rate, and the method used to derive both.
{{/ instruct }}

Die Datei ist product.mrd.ttrs, und die Ausgabe, die sie erzeugen muss, liegt daneben eingefroren als product.mrd.expected.md.

Referenzzustände

Die Auflösung einer Referenz ergibt genau einen Zustand. Neben ok — aufgelöst, zugelassen und innerhalb seines Gültigkeitsintervalls — benennt die Sprache fünf weitere, und eine Implementierung muss jeden Zustand, den sie meldet, von jedem anderen unterscheidbar halten.

Die ersten drei werden in dieser Reihenfolge bestimmt: Existenz, dann Zulassung, dann Gültigkeit. Zwei Zustände zu einem zusammenzuziehen ist Nichtkonformität und keine Vereinfachung — Sie haben kein Repository und Ihr Repository kennt diesen Bezeichner nicht sind verschiedene Probleme mit verschiedenen Behebungen, und jeder Zustand benennt für seinen Leser etwas anderes zu tun.

Eine nicht-ok-Referenz wird nie als ihr blanker Wert dargestellt. Der Zustand, der sich wie korrekter Text liest, ist derjenige, den ein Leser nicht erkennen kann.

⚑S wird aus der Commit-Historie abgeleitet statt aus einer Datei gelesen und ist der eine Zustand, dessen Berechnung eine Implementierung ablehnen darf. Ablehnen ist zulässig; darüber zu schweigen nicht — drei Ergebnisse müssen unterscheidbar bleiben: fraglich, geprüft und sauber und nie geprüft. Ein Dokument, das ganz ohne ⚑S rendert, trifft eine Aussage; eine Implementierung, die die Prüfung nie ausgeführt hat, hat gar keine getroffen.

Render-Profile

Eine Implementierung bietet mindestens zwei Profile an, beide auswählbar, und benennt, welches ein bestimmter Lauf verwendet hat:

Zwei Regeln binden das Paar aneinander: Das tolerante Profil erkennt genau das, woran das strikte scheitert — keine Teilmenge davon — und keines der beiden stellt eine nicht-ok-Referenz als ihren blanken Wert dar. Die Namen oben bezeichnen die Rollen, nicht eine vorgeschriebene Schreibweise.

Eine Implementierung darf jedes Konstrukt der Sprache unimplementiert lassen; eine Teilmenge zu unterstützen ist der erwartete Fall. Was sie in ihrer eigenen Dokumentation angibt, sind beide Hälften: was sie unterstützt und was sie erkennt und ablehnt. Ein erkanntes, aber nicht implementiertes Konstrukt schlägt unter eben diesem Namen fehl, mit einem Code, der sich von dem für unbekannte oder fehlerhafte Syntax unterscheidet — die beiden Meldungen lauten das gehört nicht zur Sprache und das gehört zur Sprache und nicht zu diesem Werkzeug, und sie schicken einen Autor an verschiedene Stellen.

Was heute existiert

Weiterlesen — das Verzeichnis dieser Klasse ist notations/views/documents/README.md; die gemeinsamen Kopf- und Endungsregeln, denen jede Notation folgt, stehen in CONTRACT.md. Für die YAML-Notationen und ihre Dateistrukturen siehe die DSL-Beispiele.