<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://rehsack.de/feed.xml" rel="self" type="application/atom+xml" /><link href="https://rehsack.de/" rel="alternate" type="text/html" /><updated>2026-04-22T19:59:17+00:00</updated><id>https://rehsack.de/feed.xml</id><title type="html">Jens Rehsack</title><subtitle>Persönlicher Blog von Jens Rehsack — Technik, Meinung, Leben</subtitle><author><name>Jens Rehsack</name></author><entry><title type="html">PARIS statt RACI: Verantwortlichkeiten für req42 und arc42</title><link href="https://rehsack.de/2026/04/22/paris-statt-raci/" rel="alternate" type="text/html" title="PARIS statt RACI: Verantwortlichkeiten für req42 und arc42" /><published>2026-04-22T00:00:00+00:00</published><updated>2026-04-22T00:00:00+00:00</updated><id>https://rehsack.de/2026/04/22/paris-statt-raci</id><content type="html" xml:base="https://rehsack.de/2026/04/22/paris-statt-raci/"><![CDATA[<div class="paragraph">
<p>„In den letzten 30 Jahren hat das immer der Erwin gemacht."</p>
</div>
<div class="paragraph">
<p>So beginnen viele Gespräche, wenn ein Mittelständler feststellt, dass
Verantwortlichkeiten unklar sind. Erwin wusste, wo seine Werkzeuge liegen.
Erwins Chef sagte: „Mach das mal" — und dann lief das. Tradiertes Wissen,
impliziter Regelkatalog, gewachsene Strukturen.</p>
</div>
<div class="paragraph">
<p>Dann geht Erwin in Rente. Und plötzlich wird klar: Die Verantwortlichkeiten
waren nie dokumentiert. Sie waren in Erwins Kopf.</p>
</div>
<div class="sect1">
<h2 id="die-erste-antwort-raci">Die erste Antwort: RACI</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Jemand sagt: „Wir brauchen eine RACI-Matrix." Das klingt professionell.
RACI (Responsible, Accountable, Consulted, Informed) ist ein etabliertes
Werkzeug. Es soll klären, wer für was zuständig ist, wer abnimmt, wer
gefragt wird.</p>
</div>
<div class="paragraph">
<p>Das Problem ist nicht, dass RACI falsch wäre. Das Problem ist, dass RACI
in bestimmten Kontexten zu grob ist.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="wo-raci-an-seine-grenzen-stößt">Wo RACI an seine Grenzen stößt</h2>
<div class="sectionbody">
<div class="paragraph">
<p>RACI funktioniert gut, wenn Aufgaben klar abgrenzbar sind, die Rollen
dahinter homogen, und wenn die Trennung zwischen Ausführung, Beratung
und Abnahme nicht besonders fein sein muss. In operativen Bereichen —
Produktion, Logistik, Support — ist das oft der Fall.</p>
</div>
<div class="paragraph">
<p>In Forschung und Entwicklung sieht es anders aus. Nicht weil F&amp;E keine
Prozesse hätte — Reviews, Freigaben, Tests, Architekturentscheidungen,
Budgetsteuerung sind durchaus wiederkehrende Teilprozesse. Aber der
Gesamtprozess ist nicht vollständig stabil oder vorhersagbar.</p>
</div>
<div class="paragraph">
<p>Und hier zeigt sich die Schwäche von RACI: Wenn „Responsible" mehrere
fachlich unterschiedliche Beiträge gleichzeitig umfasst, wird die Matrix
unlesbar.</p>
</div>
<div class="paragraph">
<p>Der Architekt ist „R" für die arc42-Dokumentation. Aber was heißt das?
Schreibt er selbst? Reviewt er nur? Gibt er fachlich ab? Trainiert er
das Team? Diese Fragen beantwortet ein einzelner Buchstabe nicht.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="was-in-fe-oft-fehlt">Was in F&amp;E oft fehlt</h2>
<div class="sectionbody">
<div class="paragraph">
<p>RACI fragt im Kern: Wer arbeitet? Wer ist verantwortlich? Wer wird gefragt?
Wer wird informiert?</p>
</div>
<div class="paragraph">
<p>In F&amp;E braucht man oft mehr:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Wer <strong>berät die fachliche Richtung</strong>?</p>
</li>
<li>
<p>Wer <strong>prüft</strong> das Ergebnis?</p>
</li>
<li>
<p>Wer <strong>zeichnet fachlich verantwortlich ab</strong>?</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>„Consulted" ist dafür zu breit. Beratung ist nicht dasselbe wie fachliche
Vorprüfung. Und „Accountable" vermischt oft zwei verschiedene Dinge:
organisatorische Verantwortung (Budget, Zeit) und fachliche Abnahme.</p>
</div>
<div class="paragraph">
<p>Gerade in Architektur- und Entwicklungszusammenhängen ist diese Trennung
wichtig. Nicht jede Person, die Budget oder Zeit verantwortet, kann auch
fachlich entscheiden, ob eine Lösung tragfähig ist.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="paris-feinere-semantische-auflösung">PARIS: Feinere semantische Auflösung</h2>
<div class="sectionbody">
<div class="paragraph">
<p>PARIS stammt aus dem PMBOK <sup class="footnote">[<a id="_footnoteref_1" class="footnote" href="#_footnotedef_1" title="View footnote.">1</a>]</sup>.
Es ist kein Ersatz für saubere Governance, sondern eine feinere
Rollenbeschreibung dort, wo RACI zu viel in einer Spalte bündelt:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">P — Participant</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Arbeitet aktiv mit</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">A — Accountable</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Trägt organisatorische Verantwortung (Budget, Zeit)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">R — Review required</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Prüft fachlich</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">I — Input required</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Liefert fachlichen Input, berät die Richtung</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">S — Sign-off required</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Zeichnet fachlich verantwortlich ab</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Der Unterschied zu RACI ist nicht, dass PARIS „besser" wäre. Der Unterschied
ist die Auflösung. PARIS trennt Verantwortungsdimensionen, die in F&amp;E oft
auseinanderfallen.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="warum-a-und-s-trennen">Warum A und S trennen?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In vielen Organisationen fallen Budget-Verantwortung und fachliche Abnahme
bewusst zusammen. Das funktioniert, solange dieselbe Person beides kann.</p>
</div>
<div class="paragraph">
<p>Ein konkretes Szenario, wo es nicht funktioniert:</p>
</div>
<div class="paragraph">
<p>Der Product Owner (A) trägt die Budgetverantwortung für ein neues Feature.
Wenn es länger dauert, muss er das erklären. Aber kann er auch fachlich
beurteilen, ob die Architekturentscheidung tragfähig ist? Ob die
Qualitätsszenarien erfüllt sind? Ob die Sicherheitsanforderungen stimmen?</p>
</div>
<div class="paragraph">
<p>In diesem Fall braucht es jemanden, der fachlich abzeichnet (S) — einen
Architekten, einen QM-Beauftragten, einen Security-Experten. Die
organisatorische Verantwortung bleibt beim PO. Die fachliche Abnahme
liegt woanders.</p>
</div>
<div class="paragraph">
<p>PARIS macht diese Trennung explizit. RACI vermischt sie in „Accountable".</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="warum-r-und-i-trennen">Warum R und I trennen?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>RACI kennt „Consulted" — wird gefragt, gibt Input. Aber in F&amp;E gibt es
einen Unterschied zwischen:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Input</strong> (I): Der Fachbereich beschreibt Anforderungen. Der Kunde
erklärt seinen Anwendungsfall. Ein Stakeholder liefert Randbedingungen.
Das ist Beratung der fachlichen Richtung.</p>
</li>
<li>
<p><strong>Review</strong> &#174;: Der QM-Beauftragte prüft, ob die Qualitätsanforderungen
erfüllt sind. Der Security-Experte prüft das Bedrohungsmodell. Das ist
fachliche Vorprüfung mit Ergebnis.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>„Consulted" ist dafür zu breit und zu unverbindlich. PARIS unterscheidet.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="ergänzung-konsent-als-governance-muster">Ergänzung: Konsent als Governance-Muster</h2>
<div class="sectionbody">
<div class="paragraph">
<p>PARIS selbst sagt nicht, was mit dem Ergebnis eines Reviews passiert.
Hier kann Soziokratie 3.0 (S3) ergänzen:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Reviewer können einen <strong>begründeten Einwand</strong> erheben</p>
</li>
<li>
<p>Kein Einwand = Vorschlag gilt</p>
</li>
<li>
<p>Ein Einwand ist kein Veto, sondern ein Verbesserungsimpuls</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Das ist ein <strong>zusätzliches</strong> Governance-Muster — nicht Teil von PARIS selbst.
Es beantwortet die Frage: Was passiert, wenn der Reviewer Bedenken hat?</p>
</div>
<div class="paragraph">
<p>In der Praxis hängt viel davon ab, wer Einwände definiert, wann sie als
schwerwiegend gelten, und wie Konflikte aufgelöst werden. Das muss jede
Organisation für sich klären. S3 bietet einen Rahmen dafür.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="paris-in-req42-und-arc42">PARIS in req42 und arc42</h2>
<div class="sectionbody">
<div class="paragraph">
<p>req42 und arc42 haben explizite Stakeholder-Kapitel. Sie fragen für jede
Rolle: Warum diese Rolle? Was ist ihre Verantwortung? Welche Kompetenzen
braucht sie?</p>
</div>
<div class="paragraph">
<p>PARIS liefert die Begrifflichkeit, um diese Fragen zu beantworten:</p>
</div>
<div class="paragraph">
<p>Für <strong>req42 Kapitel 2</strong> lässt sich fragen:
* Wer arbeitet mit (P)?
* Wer trägt organisatorische Verantwortung (A)?
* Wer prüft fachlich (R)?
* Wer liefert Input (I)?
* Wer zeichnet ab (S)?</p>
</div>
<div class="paragraph">
<p>Für <strong>req42 Kapitel 9</strong> geht es dann um Rollen, Responsibilities und
Skills.  Genau hier wird aus einer abstrakten Matrix eine dokumentierbare
Verantwortungsstruktur.</p>
</div>
<div class="paragraph">
<p>Auch <strong>arc42</strong> profitiert davon, weil Architekturentscheidungen, Reviews
und Freigaben klarer zugeordnet werden können. Wer reviewed ADRs? Wer
gibt fachlichen Sign-off? Wer liefert die Anforderungen? PARIS macht diese
Fragen sichtbarer als RACI.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="zusammenfassung">Zusammenfassung</h2>
<div class="sectionbody">
<div class="paragraph">
<p>RACI ist nicht falsch. Es ist ein solides Werkzeug für Aufgaben- und
Zuständigkeitsklärung. Aber wenn „Responsible" mehrere fachlich verschiedene
Rollen zusammenzieht, wird die Matrix unlesbar.</p>
</div>
<div class="paragraph">
<p>PARIS bietet eine feinere Auflösung:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Trennung von organisatorischer (A) und fachlicher (S) Verantwortung</p>
</li>
<li>
<p>Trennung von Input (I) und Prüfung (R)</p>
</li>
<li>
<p>Explizite Benennung derer, die arbeiten (P)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Für F&amp;E und Architekturarbeit — wo nicht nur gefragt wird, wer arbeitet,
sondern auch wer fachlich berät, wer prüft und wer am Ende signiert —
ist diese Auflösung oft notwendig.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="nächste-schritte">Nächste Schritte</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In einem Folgepost zeige ich, wie man eine bestehende RACI-Matrix nach
PARIS übersetzt — und wo die typischen Stolpersteine liegen.</p>
</div>
</div>
</div>
<div id="footnotes">
<hr>
<div class="footnote" id="_footnotedef_1">
<a href="#_footnoteref_1">1</a>. A Guide to the Project Management Body of Knowledge. Project Management Institute. 2000. p. 111. ISBN 1-880410-22-2.
</div>
</div>]]></content><author><name>Jens Rehsack</name></author><category term="architektur" /><category term="req42" /><category term="arc42" /><category term="tpo42" /><category term="stakeholder" /><category term="verantwortung" /><summary type="html"><![CDATA[„In den letzten 30 Jahren hat das immer der Erwin gemacht."]]></summary></entry><entry><title type="html">Responsible Engineering Credo: Meine Antwort auf die KI-Debatte</title><link href="https://rehsack.de/2026/04/21/responsible-engineering-credo/" rel="alternate" type="text/html" title="Responsible Engineering Credo: Meine Antwort auf die KI-Debatte" /><published>2026-04-21T00:00:00+00:00</published><updated>2026-04-21T00:00:00+00:00</updated><id>https://rehsack.de/2026/04/21/responsible-engineering-credo</id><content type="html" xml:base="https://rehsack.de/2026/04/21/responsible-engineering-credo/"><![CDATA[<div class="paragraph">
<p>Seit Wochen geistert mir eine Frage durch den Kopf: Wie reden wir eigentlich
über Verantwortung in der KI-gestützten Softwareentwicklung?</p>
</div>
<div class="sect1">
<h2 id="manifeste-und-ihre-grenzen">Manifeste und ihre Grenzen</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Es entstehen gerade viele Manifeste zur KI-gestützten Entwicklung. Das
<a href="https://aicraftspeopleguild.github.io/aicraftspeopleguild-manifesto.html">AI Craftspeople Guild Manifesto</a>
ist eines davon. Gut gemeint, wichtige Themen. Aber beim Lesen habe ich
gemerkt: Meine Situation kommt darin nicht vor. Mein berufliches Umfeld,
meine Werkzeuge, mein Kontext — das Manifest spricht <strong>für</strong> alle
Softwareprofis, aber nicht <strong>mit</strong> mir.</p>
</div>
<div class="paragraph">
<p>Das ist das Grundproblem vieler Manifeste: Sie setzen Standards, ohne die
Vielfalt der Kontexte zu kennen. Semantic Anchors, Skills, Guardrails —
wer täglich mit diesen Werkzeugen arbeitet, erkennt sich in pauschalen
Forderungen oft nicht wieder.</p>
</div>
<div class="paragraph">
<p>Das <a href="https://agilemanifesto.org/">Agile Manifesto</a> hat das anders gemacht.
„Individuals and interactions over processes and tools" ist keine Deklaration
einer Gruppe, die für die Branche spricht. Es ist eine Einladung. Eine Haltung,
die <strong>ich</strong> annehmen kann — oder nicht. <strong>Ich</strong> priorisiere Menschen über Prozesse.
<strong>Ich</strong> entscheide mich dafür. Niemand spricht für mich.</p>
</div>
<div class="paragraph">
<p>Uncle Bob wird oft als Moralapostel missverstanden. Aber wenn man genau
liest, sagt er nicht: „Ihr müsst alle Clean Code schreiben." Er sagt:
„Hier sind Prinzipien, die — wenn du dich daran hältst — dir und deinem
Team helfen, daran zu wachsen." Selbstwirksamkeit, nicht Fremdbestimmung.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="left-over-right-für-mich-selbst">Left over Right — für mich selbst</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Also habe ich aufgeschrieben, woran <strong>ich</strong> mich halte. Kein Manifest, das
anderen vorschreibt. Ein Credo — eine persönliche Verpflichtung.</p>
</div>
<div class="paragraph">
<p>Das Fundament ist einfach:</p>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>Wir übernehmen die volle Verantwortung für jede Zeile Code, die wir
committen — unabhängig von ihrer Herkunft.</p>
</div>
</blockquote>
</div>
<div class="paragraph">
<p>Die Werte folgen dem „X über Y"-Muster:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Verantwortbare Urheberschaft über anonyme Erzeugung</p>
</li>
<li>
<p>Durchgesetzte über versprochene Qualität</p>
</li>
<li>
<p>Vorhersagbares über angenommenes Verhalten</p>
</li>
<li>
<p>Gewährleistete über versprochene Datenintegrität</p>
</li>
<li>
<p>Persönliche Haftung über diffuse Verantwortung</p>
</li>
<li>
<p>Informierte Zustimmung über stillschweigende Annahme</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Das vollständige Credo mit Erläuterungen gibt es auf GitHub:
<a href="https://github.com/rehsack/Responsible-Engineering-Credo" class="bare">https://github.com/rehsack/Responsible-Engineering-Credo</a></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="warum-jetzt">Warum jetzt?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>KI kann Code generieren. Aber <strong>Verantwortung</strong> kann nicht generiert werden —
sie muss übernommen werden. Jede Zeile Code, die in Produktion geht, braucht
jemanden, der sagt: „Ich stehe dahinter."</p>
</div>
<div class="paragraph">
<p>Das ist keine neue Idee. Signierte Commits gibt es seit Jahren. Code Reviews
auch. Aber in einer Welt, in der ein Wochenend-Projekt plötzlich SaaS-Startup
heißt und Kundendaten verarbeitet, wird die Frage drängender: Wer trägt die
Verantwortung, wenn es schiefgeht?</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="werkzeuge-statt-vorschriften">Werkzeuge statt Vorschriften</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Ein Credo ist schön. Aber wie setzt man es um? Nicht durch Regeln, die von
oben kommen — sondern durch Werkzeuge, die jedes Team befähigen, seine eigenen
Entscheidungen zu treffen.</p>
</div>
<div class="paragraph">
<p>Der <a href="https://llm-coding.github.io/vibe-coding-risk-radar/">Vibe Coding Risk Radar</a>
ist so ein Werkzeug. Fünf Dimensionen, vier Risikostufen, konkrete Mitigationen.
Kein „ihr müsst diese Risiken beachten" — sondern ein interaktives Tool, mit
dem <strong>du</strong> deine eigene Entscheidungsmatrix baust. Für dein Projekt, mit deinem
Kontext, nach deiner Einschätzung.</p>
</div>
<div class="paragraph">
<p>Das ist der Unterschied zwischen einem Manifest, das für alle spricht, und
einem Werkzeugkasten, der jeden einzelnen ermächtigt.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="die-unbeantwortete-frage">Die unbeantwortete Frage</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Was die meisten Manifeste nicht adressieren: Wo endet meine Verantwortung
in einer Welt voller Abhängigkeiten?</p>
</div>
<div class="paragraph">
<p>Ich nutze eine Government-API — die wurde mit KI entwickelt. Ich nutze
npm-Pakete — irgendwer hat mit Copilot contributed. Mein Auftraggeber zahlt,
dass ich keine KI nutze — muss ich dann die API der Bundesdruckerei ablehnen?</p>
</div>
<div class="paragraph">
<p>Das Credo zieht die Grenze klar: <strong>Ich übernehme Verantwortung für den Code,
den ich committe.</strong> Nicht für die gesamte Lieferkette. Nicht für Government-APIs.
Für meinen Beitrag.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="einladung">Einladung</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Das Credo ist ein Diskussionsentwurf. Ich erhebe keinen Anspruch auf
Vollständigkeit oder Weisheit. Wenn es bei dir resoniert — nimm es, fork es,
pass es an. Wenn du anderer Meinung bist — lass uns reden.</p>
</div>
<div class="paragraph">
<p>GitHub: <a href="https://github.com/rehsack/Responsible-Engineering-Credo" class="bare">https://github.com/rehsack/Responsible-Engineering-Credo</a></p>
</div>
<div class="paragraph">
<p>Die Zukunft der Softwareentwicklung wird nicht durch Tools entschieden,
sondern durch die Menschen, die sie einsetzen. Und durch die Haltung, mit
der sie das tun.</p>
</div>
</div>
</div>]]></content><author><name>Jens Rehsack</name></author><category term="ki" /><category term="software-engineering" /><category term="verantwortung" /><category term="credo" /><summary type="html"><![CDATA[Seit Wochen geistert mir eine Frage durch den Kopf: Wie reden wir eigentlich über Verantwortung in der KI-gestützten Softwareentwicklung?]]></summary></entry><entry><title type="html">Validate-First: AsciiDoc-Projekte mit Devcontainer und docker-compose</title><link href="https://rehsack.de/2026/04/12/validate-first-docker-compose-devcontainer/" rel="alternate" type="text/html" title="Validate-First: AsciiDoc-Projekte mit Devcontainer und docker-compose" /><published>2026-04-12T00:00:00+00:00</published><updated>2026-04-12T00:00:00+00:00</updated><id>https://rehsack.de/2026/04/12/validate-first-docker-compose-devcontainer</id><content type="html" xml:base="https://rehsack.de/2026/04/12/validate-first-docker-compose-devcontainer/"><![CDATA[<div class="paragraph">
<p>Im <a href="/2026/04/05/devcontainer-asciidoc-jekyll/">letzten Post</a> ging es
um einen einzelnen Container für Jekyll + AsciiDoc.  Diesmal wird es
spannender: zwei Container, die zusammenarbeiten&#8201;&#8212;&#8201;einer validiert,
der andere baut.</p>
</div>
<div class="sect1">
<h2 id="das-problem-doctoolchain-schluckt-fehler">Das Problem: doctoolchain schluckt Fehler</h2>
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://doctoolchain.org/">docToolchain</a> ist das Referenz-Werkzeug für
arc42/req42-Dokumentation.  Es baut HTML und PDF aus AsciiDoc-Quellen&#8201;&#8212;&#8201;zuverlässig, erprobt, gut integriert.</p>
</div>
<div class="paragraph">
<p>Was es nicht tut: bei kaputtem AsciiDoc abbrechen.  Fehlende Includes,
aufgelöste Cross-Referenzen, Syntaxfehler&#8201;&#8212;&#8201;docToolchain meldet sie als
Warnung und baut trotzdem weiter.  Am Ende hat man ein PDF mit
Platzhaltern, wo eigentlich Inhalte stehen sollten.</p>
</div>
<div class="paragraph">
<p>In einer CI-Pipeline ist das fatal.  Der Build ist „grün", das Artefakt
ist kaputt.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="die-lösung-validierung-als-gate">Die Lösung: Validierung als Gate</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Der <code>ghcr.io/tpo42/adoc</code>-Container (der aus dem
<a href="/2026/04/05/devcontainer-asciidoc-jekyll/">Jekyll-Post</a> bekannte)
enthält nicht nur die AsciiDoc-Toolchain, sondern auch ein
<code>validate</code>-Kommando.  Dahinter steckt ein <code>asciidoctor</code>-Aufruf im
Strict-Modus: fehlende Dateien, kaputte Referenzen, Syntaxfehler&#8201;&#8212;&#8201;alles wird zum Fehler, nicht zur Warnung.</p>
</div>
<div class="paragraph">
<p>Die Idee: Validierung <em>vor</em> dem Build.  Erst wenn die Quellen sauber
sind, darf docToolchain bauen.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="zwei-container-ein-workflow">Zwei Container, ein Workflow</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Statt alles in einen Container zu packen, trennen wir die Concerns:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 20%;">
<col style="width: 40%;">
<col style="width: 40%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Container</th>
<th class="tableblock halign-left valign-top">Aufgabe</th>
<th class="tableblock halign-left valign-top">Image</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>adoc</strong></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">AsciiDoc-Validierung, Toolchain für Entwicklung</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ghcr.io/tpo42/adoc:latest</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>doctoolchain</strong></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">PDF- und HTML-Build</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>doctoolchain/doctoolchain:v3.4.2</code></p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Das Bindeglied ist eine <code>docker-compose.yml</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="yaml"><span class="na">services</span><span class="pi">:</span>
  <span class="na">adoc</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">ghcr.io/tpo42/adoc:latest</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">.:/workspace</span>
    <span class="na">command</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">sleep"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">infinity"</span><span class="pi">]</span>

  <span class="na">doctoolchain</span><span class="pi">:</span>
    <span class="na">image</span><span class="pi">:</span> <span class="s">doctoolchain/doctoolchain:v3.4.2</span>
    <span class="na">platform</span><span class="pi">:</span> <span class="s">linux/amd64</span>
    <span class="na">volumes</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s">.:/project</span>
      <span class="pi">-</span> <span class="s">dtc-gradle-cache:/home/dtcuser/.gradle</span>
    <span class="na">entrypoint</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">sleep"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">infinity"</span><span class="pi">]</span>
    <span class="na">environment</span><span class="pi">:</span>
      <span class="na">DTC_HEADLESS</span><span class="pi">:</span> <span class="s2">"</span><span class="s">true"</span>
      <span class="na">DTC_OPTS</span><span class="pi">:</span> <span class="pi">&gt;-</span>
        <span class="s">-PmainConfigFile=docToolchainConfig.groovy</span>
        <span class="s">--warning-mode=none -Dfile.encoding=UTF-8</span>

<span class="na">volumes</span><span class="pi">:</span>
  <span class="na">dtc-gradle-cache</span><span class="pi">:</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Beide Container laufen dauerhaft (<code>sleep infinity</code>).  Befehle gehen per
<code>docker compose exec</code> rein&#8201;&#8212;&#8201;kein Container-Start-Overhead pro Aufruf.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="der-devcontainer">Der Devcontainer</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Die <code>.devcontainer/devcontainer.json</code> referenziert dieselbe Compose-Datei:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="json"><span class="p">{</span><span class="w">
  </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"mein-doku-projekt"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"dockerComposeFile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"../docker-compose.yml"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"service"</span><span class="p">:</span><span class="w"> </span><span class="s2">"adoc"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"workspaceFolder"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/workspace"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"shutdownAction"</span><span class="p">:</span><span class="w"> </span><span class="s2">"stopCompose"</span><span class="w">
</span><span class="p">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p><code>devcontainer up</code> startet <em>beide</em> Container.  Der adoc-Container ist
der Primary&#8201;&#8212;&#8201;dort editiert und validiert man.  Der
doctoolchain-Container läuft als Sidecar für Builds.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="der-workflow">Der Workflow</h2>
<div class="sectionbody">
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash"><span class="c"># Container starten</span>
docker compose up <span class="nt">-d</span>

<span class="c"># Validieren</span>
docker compose <span class="nb">exec </span>adoc validate <span class="se">\</span>
    <span class="nt">-i</span> Docs/req42-container-toolchain.adoc <span class="se">\</span>
    <span class="nt">-i</span> Docs/arc42-container-toolchain.adoc <span class="se">\</span>
    <span class="nt">--strict</span> <span class="nt">--verbose</span>

<span class="c"># Bauen</span>
docker compose <span class="nb">exec </span>doctoolchain <span class="se">\</span>
    bash <span class="nt">-c</span> <span class="s1">'doctoolchain . generatePDF $DTC_OPTS'</span>
docker compose <span class="nb">exec </span>doctoolchain <span class="se">\</span>
    bash <span class="nt">-c</span> <span class="s1">'doctoolchain . generateHTML $DTC_OPTS'</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Oder mit der devcontainer-CLI&#8201;&#8212;&#8201;zumindest für den adoc-Container:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">devcontainer <span class="nb">exec</span> <span class="nt">--workspace-folder</span> <span class="nb">.</span> validate <span class="nt">-i</span> Docs/<span class="k">*</span>.adoc <span class="nt">--strict</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Für den doctoolchain-Container geht das (noch) nicht:
<code>devcontainer exec</code> kennt nur den Primary-Service, kein <code>--service</code>-Flag.
Für den Build bleibt <code>docker compose exec</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="der-nebeneffekt-40-sekunden-2-sekunden">Der Nebeneffekt: 40 Sekunden → 2 Sekunden</h2>
<div class="sectionbody">
<div class="paragraph">
<p>docToolchain basiert auf Gradle.  Jeder <code>docker run</code> startet eine neue
JVM, initialisiert den Gradle-Daemon, lädt Plugins&#8201;&#8212;&#8201;rund 40 Sekunden,
bevor überhaupt etwas gebaut wird.</p>
</div>
<div class="paragraph">
<p>Der <code>dtcw</code>-Wrapper setzt bewusst <code>--no-daemon</code>, weil der Daemon bei
Einmal-Containern sowieso stirbt.  Wenn der Container aber <em>lebt</em>
(<code>sleep infinity</code> + <code>docker compose exec</code>), bleibt der Daemon warm:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 25%;">
<col style="width: 25%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top"></th>
<th class="tableblock halign-left valign-top">Erster Aufruf</th>
<th class="tableblock halign-left valign-top">Folgeaufrufe</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>docker run --no-daemon</code> (klassisch)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">~40s</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">~40s</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>docker compose exec</code> (persistent)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">~15s</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><strong>~2s</strong></p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Der Gradle-Cache liegt in einem Named Volume (<code>dtc-gradle-cache</code>) und
überlebt <code>docker compose down</code> / <code>up</code>-Zyklen.  Nur <code>docker compose down -v</code>
räumt ihn ab.</p>
</div>
<div class="paragraph">
<p>Das ist kein Trick&#8201;&#8212;&#8201;es ist schlicht die Arbeitsweise, für die Gradle
entworfen wurde.  <code>docker run</code> erzwingt den Cold-Start, den Gradle
eigentlich vermeiden will.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="ci-dieselben-images-anderer-ablauf">CI: Dieselben Images, anderer Ablauf</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In der CI-Pipeline (Jenkins, GitLab CI, &#8230;&#8203;) laufen die Container als
Einmal-Aufrufe.  Der warme Daemon bringt dort nichts&#8201;&#8212;&#8201;dafür ist die
Validierung als Gate entscheidend:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code>Stage: Validate    →  Stage: Build PDF  →  Stage: Build HTML  →  Archive
(ghcr.io/tpo42/adoc) (doctoolchain)       (doctoolchain)</code></pre>
</div>
</div>
<div class="paragraph">
<p>Wenn Validate fehlschlägt, laufen die Build-Stages nicht.  Kein
kaputtes PDF in den Artefakten.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="was-ich-dabei-gelernt-habe">Was ich dabei gelernt habe</h2>
<div class="sectionbody">
<div class="dlist">
<dl>
<dt class="hdlist1"><code>sleep infinity</code> ist keine Krücke</dt>
<dd>
<p>Bei Task-Runner-Containern (validate, build) klingt ein dauerhaft
laufender Container nach Verschwendung.  Aber wenn der Container
zustandsbehaftet ist (Gradle-Daemon, Gem-Cache), ist das persistente
Setup die performante Variante.</p>
</dd>
<dt class="hdlist1"><code>DTC_OPTS</code> als Environment-Variable</dt>
<dd>
<p>docToolchain erwartet diverse Flags (<code>-PmainConfigFile=&#8230;&#8203;</code>,
<code>--warning-mode=none</code>, &#8230;&#8203;).  In der <code>docker-compose.yml</code> als
<code>DTC_OPTS</code> hinterlegt, spart man sich die Flags bei jedem Aufruf:
<code>bash -c 'doctoolchain . generatePDF $DTC_OPTS'</code>.</p>
</dd>
<dt class="hdlist1"><code>devcontainer exec</code> hat Grenzen</dt>
<dd>
<p>Die devcontainer-CLI kann nur in den Primary-Service execen.  Für
Sidecar-Container bleibt <code>docker compose exec</code>.  Ein <code>--service</code>-Flag
wäre ein sinnvolles Feature-Request an die
<a href="https://github.com/devcontainers/cli">devcontainers/cli</a>.</p>
</dd>
</dl>
</div>
</div>
</div>
<div class="sect1">
<h2 id="ausblick">Ausblick</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Dieses Setup dokumentiert <em>nur</em> Anforderungen und Architektur&#8201;&#8212;&#8201;es gibt
keinen Quellcode zu kompilieren.  In einem Firmware-Projekt kommt
mindestens ein dritter Container dazu: der Cross-Compiler.  Und bei
Projekten mit herstellerspezifischer Code-Generierung (STM32CubeMX)
ein vierter, der Artefakte über ein Shared Volume an den
Compile-Container weitergibt.</p>
</div>
<div class="paragraph">
<p>Die <code>docker-compose.yml</code> skaliert dafür linear&#8201;&#8212;&#8201;ein Service pro
Concern, dieselbe Compose-Datei für Devcontainer und CI.</p>
</div>
<div class="paragraph">
<p>Aber dazu mehr, wenn es soweit ist.</p>
</div>
</div>
</div>]]></content><author><name>Jens Rehsack</name></author><category term="devcontainer" /><category term="docker-compose" /><category term="asciidoc" /><category term="doctoolchain" /><category term="ci" /><category term="tpo42" /><summary type="html"><![CDATA[Im letzten Post ging es um einen einzelnen Container für Jekyll + AsciiDoc. Diesmal wird es spannender: zwei Container, die zusammenarbeiten&#8201;&#8212;&#8201;einer validiert, der andere baut.]]></summary></entry><entry><title type="html">Yocto für Bare-Metal: Cross-Compiler und CI-Toolchain aus einem Guss</title><link href="https://rehsack.de/2026/04/09/yocto-bare-metal-sdk-aus-einem-guss/" rel="alternate" type="text/html" title="Yocto für Bare-Metal: Cross-Compiler und CI-Toolchain aus einem Guss" /><published>2026-04-09T00:00:00+00:00</published><updated>2026-04-09T00:00:00+00:00</updated><id>https://rehsack.de/2026/04/09/yocto-bare-metal-sdk-aus-einem-guss</id><content type="html" xml:base="https://rehsack.de/2026/04/09/yocto-bare-metal-sdk-aus-einem-guss/"><![CDATA[<div class="paragraph">
<p>Wer Firmware für Mikrocontroller baut, braucht einen Cross-Compiler.
Den bekommt man mit <a href="https://crosstool-ng.github.io/">crosstool-ng</a>,
als ARM-Download oder aus dem Paketmanager der Distribution.
Das funktioniert&#8201;&#8212;&#8201;und wenn man dann noch Unit-Tests in der CI
haben will, wird es richtig spannend.</p>
</div>
<div class="paragraph">
<p>Denn dann braucht man <em>zwei</em> Toolchains: eine für das Target
(<code>arm-none-eabi-gcc</code> mit newlib) und eine für den Host (<code>x86_64</code>
oder <code>aarch64</code>), mit der man denselben Code gegen ein Test-Framework
kompiliert.  Auf dem Host läuft natürlich eine andere libc&#8201;&#8212;&#8201;aber
GCC-Generation, Google-Test-Version, gcov und die
Analyse-Werkzeuge müssen auf Punkt und Komma zusammenpassen.</p>
</div>
<div class="paragraph">
<p>Bare-Metal klingt dabei nach wenig Aufwand: Wenn newlib schon das
Maß der Dinge ist, ist der Horizont quasi anfassbar.  Die
Herausforderung steckt nicht in der Menge der Abhängigkeiten,
sondern darin, dass die Werkzeuge drumherum für Target und Host
aus einem Guss sein müssen.  Genau das lässt sich elegant lösen.</p>
</div>
<div class="sect1">
<h2 id="das-problem-zwei-toolchains-eine-wahrheit">Das Problem: Zwei Toolchains, eine Wahrheit</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Nehmen wir an, der Cross-Compiler ist ein GCC 15 mit newlib.
Die Unit-Tests laufen auf dem CI-Host, also brauchen wir dort
ebenfalls einen GCC 15&#8201;&#8212;&#8201;nicht den GCC 14, den Fedora 43 mitbringt,
und schon gar nicht den GCC 13 aus dem Ubuntu-LTS der CI-Runner.</p>
</div>
<div class="paragraph">
<p>Dazu kommen ABI-gekoppelte Werkzeuge:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><strong>Google Test / GMock</strong>&#8201;&#8212;&#8201;kompiliert gegen die jeweilige Toolchain</p>
</li>
<li>
<p><strong>gcov / lcov</strong>&#8201;&#8212;&#8201;müssen zur GCC-Version passen, sonst stimmt die Coverage nicht</p>
</li>
<li>
<p><strong>valgrind</strong>&#8201;&#8212;&#8201;muss die ABI der getesteten Binaries verstehen</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Wenn man das manuell pflegt, landen Target- und Host-Toolchain
schnell in getrennten Beschaffungsketten.  Das muss nicht sein.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="warum-ich-da-heute-anders-rangehe">Warum ich da heute anders rangehe</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Vor einigen Jahren bei einem Telekommunikationsausrüster: Ein SoM mit
Netzwerk-Beschleunigern, dazu ein Binary-SDK vom Chip-Hersteller.
32-Bit, eine uralte GCC-Version, gelinkt gegen eine
Linux-Distribution, die es nur noch auf dem Schwarzmarkt gegen Kamele
gab.  Lange bevor LLVM/Clang als ernstzunehmende GCC-Konkurrenz die
Stagnation aufmischte.</p>
</div>
<div class="paragraph">
<p>Die IT betrieb dafür einen Multiprozessor-Knoten mit rund 64 VMs&#8201;&#8212;&#8201;je 2&#160;VCPUs, 2&#160;GB RAM, komplett überbucht, kaum wartbar.
Das SDK ließ sich nicht reproduzieren, nicht aktualisieren und nicht
auf eine andere Host-Plattform portieren.  Dabei war der Chip sogar
Linux-fähig&#8201;&#8212;&#8201;da wäre deutlich mehr gegangen.</p>
</div>
<div class="paragraph">
<p>Das Muster habe ich seitdem mehrfach gesehen:
Chip-Hersteller wollen Chips verkaufen, keine Entwicklungsumgebungen.
Das SDK ist Beiwerk&#8201;&#8212;&#8201;es erleichtert den Einstieg, soll aber nicht
langfristig tragen.  Ein Hersteller-BSP auf LTS-Basis, jahrelang gut
genug&#8201;&#8212;&#8201;und wenn der LTS-Zyklus ausläuft, heißt es: Updaten, in
sechs Wochen liefern, nichts darf kosten.</p>
</div>
<div class="paragraph">
<p>Das hat mich motiviert, einen anderen Weg zu gehen.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="die-yocto-lösung-machine-abstraktion-als-ssot">Die Yocto-Lösung: MACHINE-Abstraktion als SSOT</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Das <a href="https://www.yoctoproject.org/">Yocto Project</a> ist primär als
Build-System für Embedded-Linux-Distributionen bekannt.  Aber sein
Rezept-System kann mehr: Es baut <em>beliebige</em> Toolchains aus den
Quellen&#8201;&#8212;&#8201;und zwar für verschiedene Zielarchitekturen aus denselben
Rezepten.</p>
</div>
<div class="paragraph">
<p>Der Schlüssel ist die <code>MACHINE</code>-Variable.  Dieselben Rezepte für GCC,
newlib, Google Test und gcov erzeugen je nach Target:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 20%;">
<col style="width: 40%;">
<col style="width: 40%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">MACHINE</th>
<th class="tableblock halign-left valign-top">Ergebnis</th>
<th class="tableblock halign-left valign-top">Beispiel</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>aducm360</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>arm-none-eabi-gcc</code> (Cortex-M3, soft-float)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Mess-MCU, ADC-Frontend</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>stm32h7a3</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>arm-none-eabi-gcc</code> (Cortex-M7, hard-float, FPv5-D16)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Kommunikations-MCU, DCP-Stack</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>samd21</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>arm-none-eabi-gcc</code> (Cortex-M0+, soft-float)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Kamera-Steuerung</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>esp32c6</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>riscv32-none-elf-gcc</code> (RV32IMAC)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">RISC-V IoT, Wi-Fi/BLE</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>gd32vf103</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>riscv32-none-elf-gcc</code> (RV32IMAC)</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">RISC-V mit DSP-Erweiterungen, atomthreads</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>x86-64</code> / <code>aarch64</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Host-nativer GCC derselben Generation</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">CI: Unit-Tests, valgrind, Coverage</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Die Liste ließe sich fortsetzen.  Der Punkt ist: Ob ARM Cortex-M, RISC-V oder Host-nativ&#8201;&#8212;&#8201;die Rezepte sind dieselben.  Nur <code>MACHINE</code> und die zugehörige
Tune-Konfiguration unterscheiden sich.</p>
</div>
<div class="paragraph">
<p><strong>Eine</strong> Quelle, <strong>eine</strong> GCC-Version, <strong>eine</strong> ABI-Kopplung&#8201;&#8212;&#8201;DRY und
SSOT statt n&#160;getrennt gepflegte Toolchains.</p>
</div>
<div class="paragraph">
<p>Yocto baut dabei nicht nur den Compiler: Auch ein <strong>QEMU</strong> für das
jeweilige Target lässt sich aus denselben Rezepten erzeugen.  Damit
kann man Firmware-Binaries auf dem CI-Host emulieren&#8201;&#8212;&#8201;ohne echte
Hardware, aber mit der richtigen CPU-Emulation.  Für
Integrationstests auf einem Cortex-M oder RISC-V ist das Gold wert.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="was-gehört-ins-sdkund-was-nicht">Was gehört ins SDK&#8201;&#8212;&#8201;und was nicht?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Die erste Intuition ist: Nur der Compiler und seine unmittelbaren
Abhängigkeiten.  In der Praxis zieht man die Grenze weiter.</p>
</div>
<div class="paragraph">
<p><strong>Aus Yocto&#8201;&#8212;&#8201;eingefroren und versioniert:</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>GCC + binutils + newlib (der Compiler-Kern)</p>
</li>
<li>
<p>Google Test / GMock (Test-Framework, gegen die Toolchain kompiliert)</p>
</li>
<li>
<p>gcov / lcov (Coverage&#8201;&#8212;&#8201;muss zur GCC-Version passen)</p>
</li>
<li>
<p>valgrind (Speicheranalyse&#8201;&#8212;&#8201;muss die ABI verstehen)</p>
</li>
<li>
<p><strong>clang-tidy</strong> (statische Analyse&#8201;&#8212;&#8201;braucht die <em>richtigen</em> Header
und Bibliotheken des Targets, nicht die des Host-Systems)</p>
</li>
<li>
<p><strong>clang-format</strong> (eine eingefrorene Version verhindert
Whitespace-Kriege zwischen Entwicklern)</p>
</li>
<li>
<p><strong>CMake, Ninja</strong> (wenn das CMake der Host-Distribution plötzlich
ein Major-Update bekommt, spuckt es unter Umständen in den Build)</p>
</li>
<li>
<p>QEMU (Target-Emulation für Integrationstests)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Der gemeinsame Nenner: Alles, was das Build-Ergebnis oder die
Analyse des Build-Ergebnisses beeinflusst, muss einfrierbar und
reproduzierbar sein.  clang-tidy klingt zunächst orthogonal&#8201;&#8212;&#8201;bis
man merkt, dass es die Target-Header parsen muss, nicht die des
Host-Systems.</p>
</div>
<div class="paragraph">
<p><strong>Aus der Distribution&#8201;&#8212;&#8201;unabhängig aktualisierbar:</strong></p>
</div>
<div class="ulist">
<ul>
<li>
<p>Doxygen (API-Dokumentation)</p>
</li>
<li>
<p>srecord (ELF → HEX-Konvertierung)</p>
</li>
<li>
<p>doctoolchain, asciidoctor (Projektdokumentation)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Diese Werkzeuge beeinflussen weder das Binary noch die Analyse und
können unabhängig aktualisiert werden&#8201;&#8212;&#8201;ohne
Firmware-Requalifizierung.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="bare-metal-hardening-was-geht-ohne-os">Bare-Metal-Hardening: Was geht ohne OS?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Ein Nebeneffekt der Yocto-basierten Toolchain: Man hat volle
Kontrolle über die Compiler-Flags, und zwar in sauberen Schichten.</p>
</div>
<div class="paragraph">
<p>Auf Bare-Metal fehlen die üblichen OS-Schutzmechanismen
(<code><em>_stack_chk_fail</code> ohne libc, kein ASLR ohne Loader, kein PIE ohne
MMU).  Aber GCC 13+ bietet Hardening-Flags, die _ohne</em> OS
funktionieren:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash"><span class="nt">-fharden-compares</span>
<span class="nt">-fharden-conditional-branches</span>
<span class="nt">-fharden-control-flow-redundancy</span>
<span class="nt">-ftrivial-auto-var-init</span><span class="o">=</span>zero</code></pre>
</div>
</div>
<div class="paragraph">
<p>Diese Flags landen nicht in der Toolchain selbst (sonst würde newlib
nicht mehr bauen), sondern in einem SDK-Environment-Hook&#8201;&#8212;&#8201;einer
dünnen Shell-Datei, die beim Aktivieren der Toolchain die
<code>CFLAGS</code>/<code>CXXFLAGS</code> setzt.  Drei Schichten:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><strong>Distro-Config</strong> (Yocto): Flags, die auch newlib braucht (<code>-ffunction-sections</code>, <code>-fdata-sections</code>)</p>
</li>
<li>
<p><strong>SDK-Hook</strong>: Hardening und Warnungen für die Firmware-Entwicklung</p>
</li>
<li>
<p><strong>Firmware-Projekt</strong> (CMakeLists.txt): Projektspezifisches (<code>-std=gnu23</code>, Target-Defines)</p>
</li>
</ol>
</div>
</div>
</div>
<div class="sect1">
<h2 id="langzeitwirkung-10-jahre-firmware-support">Langzeitwirkung: 10 Jahre Firmware-Support</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In regulierten Branchen liefert man Firmware-Fixes für Produkte,
die vor 10 oder 15 Jahren ausgeliefert wurden.  Mit einer
Yocto-basierten Toolchain ist das ein <code>git checkout</code> auf den
Release-Stand und ein <code>bitbake meta-toolchain</code>&#8201;&#8212;&#8201;fertig.</p>
</div>
<div class="paragraph">
<p>Yocto liefert dafür zwei Mechanismen, die oft als Implementierungs-
detail abgetan werden, aber für das Release-Management essentiell sind:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>DL_DIR</code></dt>
<dd>
<p>Das Verzeichnis, in das Yocto alle heruntergeladenen
Quellen ablegt&#8201;&#8212;&#8201;Tarballs, Git-Snapshots, Patches.  Das ist kein
Nebenprodukt, das ist ein <strong>Quellenarchiv</strong>.  Wer <code>DL_DIR</code> archiviert,
kann die Toolchain auch dann noch bauen, wenn die Upstream-Server
längst offline sind.</p>
</dd>
<dt class="hdlist1"><code>SSTATE_DIR</code></dt>
<dd>
<p>Der Shared-State-Cache.  Yocto speichert hier die
Zwischenergebnisse jedes Build-Schritts.  Bei einem Release-Fix
Jahre später muss nicht alles von Grund auf neu gebaut werden&#8201;&#8212;&#8201;der Cache beschleunigt den Rebuild auf die tatsächlich geänderten
Komponenten.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Beide Verzeichnisse zusammen bilden das Rückgrat für langfristige
Nachlieferbarkeit: Quellen gesichert, Build-Ergebnisse
nachvollziehbar, Rebuild-Zeiten beherrschbar.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="cra-und-sbom-vom-nice-to-have-zur-pflicht">CRA und SBOM: Vom Nice-to-have zur Pflicht</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Mit dem <a href="https://digital-strategy.ec.europa.eu/en/policies/cyber-resilience-act">Cyber Resilience Act</a>
wird die Frage „Was steckt in meiner Toolchain?" regulatorisch
relevant.  Ein SBOM (Software Bill of Materials) mit voller Provenance
ist keine Kür mehr&#8201;&#8212;&#8201;es wird Pflicht für Produkte mit digitalen
Elementen.</p>
</div>
<div class="paragraph">
<p>Yocto erzeugt SPDX-SBOMs als Nebenprodukt des Builds&#8201;&#8212;&#8201;für jede
Komponente, die aus den Quellen gebaut wurde.  <code>DL_DIR</code> liefert die
Quellenarchivierung, die Rezepte liefern die Abhängigkeitskette,
und <code>INHERIT += "create-spdx"</code> bindet beides zu einem maschinenlesbaren
SBOM zusammen.</p>
</div>
<div class="paragraph">
<p>Aus Yocto gebaut heißt: Die Provenance stimmt per Konstruktion,
nicht per Vertrauen.  Das ist ein echtes Pfund, wenn der Auditor
vor der Tür steht.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="fazit">Fazit</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Cross-Compiler für Bare-Metal gibt es an jeder Ecke.  Der Mehrwert
von Yocto liegt nicht im Cross-Compiler selbst, sondern darin, dass
Target-Toolchain, Host-CI-Toolchain und alle Werkzeuge drumherum
<em>aus derselben Quelle</em> kommen&#8201;&#8212;&#8201;reproduzierbar, einfrierbar,
CRA-ready.</p>
</div>
<div class="paragraph">
<p>Die Einstiegshürde ist real: Yocto hat eine steile Lernkurve.  Aber
wer den Schritt wagt, bekommt eine Toolchain-Infrastruktur, die
mit jedem neuen Target und jedem neuen Projekt mitträgt&#8201;&#8212;&#8201;statt
jedes Mal bei null anzufangen.</p>
</div>
</div>
</div>]]></content><author><name>Jens Rehsack</name></author><category term="yocto" /><category term="embedded" /><category term="bare-metal" /><category term="ci" /><category term="toolchain" /><category term="cross-compilation" /><summary type="html"><![CDATA[Wer Firmware für Mikrocontroller baut, braucht einen Cross-Compiler. Den bekommt man mit crosstool-ng, als ARM-Download oder aus dem Paketmanager der Distribution. Das funktioniert&#8201;&#8212;&#8201;und wenn man dann noch Unit-Tests in der CI haben will, wird es richtig spannend.]]></summary></entry><entry><title type="html">Jekyll + AsciiDoc im Devcontainer — null lokales Setup</title><link href="https://rehsack.de/2026/04/05/devcontainer-asciidoc-jekyll/" rel="alternate" type="text/html" title="Jekyll + AsciiDoc im Devcontainer — null lokales Setup" /><published>2026-04-05T00:00:00+00:00</published><updated>2026-04-05T00:00:00+00:00</updated><id>https://rehsack.de/2026/04/05/devcontainer-asciidoc-jekyll</id><content type="html" xml:base="https://rehsack.de/2026/04/05/devcontainer-asciidoc-jekyll/"><![CDATA[<div class="paragraph">
<p>Eine Jekyll-Site mit AsciiDoc-Unterstützung aufzusetzen bedeutet normalerweise:
Ruby installieren, Bundler, eine Handvoll Gems.  Mit dem
<a href="https://github.com/tpo42/tpo42-asciidoc-container">tpo42/adoc</a>-Container und der
<a href="https://containers.dev/">Dev-Containers</a>-Spezifikation kann man sich das alles
sparen.</p>
</div>
<div class="sect1">
<h2 id="die-idee">Die Idee</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Der Container <code>ghcr.io/tpo42/adoc</code> bringt Ruby 3.x, Bundler 4.x und die
komplette Asciidoctor-Toolchain mit (asciidoctor, asciidoctor-pdf,
asciidoctor-diagram, …).  Jekyll und seine Plugins sind nur ein
<code>bundle install</code> entfernt&#8201;&#8212;&#8201;kein Grund, das Host-System zuzumüllen.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="setup">Setup</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="1-gemfile">1. Gemfile</h3>
<div class="paragraph">
<p>Ein Standard-Jekyll-Gemfile&#8201;&#8212;&#8201;der Container liefert Ruby und Bundler, auf
dem Host wird nichts weiter benötigt:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="ruby"><span class="n">source</span> <span class="s2">"https://rubygems.org"</span>

<span class="n">gem</span> <span class="s2">"jekyll"</span><span class="p">,</span> <span class="s2">"~&gt; 4.4"</span>
<span class="n">gem</span> <span class="s2">"jekyll-remote-theme"</span>
<span class="n">gem</span> <span class="s2">"jekyll-asciidoc"</span>
<span class="n">gem</span> <span class="s2">"asciidoctor"</span>
<span class="n">gem</span> <span class="s2">"jekyll-sitemap"</span>
<span class="n">gem</span> <span class="s2">"jekyll-feed"</span>
<span class="n">gem</span> <span class="s2">"jekyll-include-cache"</span>
<span class="n">gem</span> <span class="s2">"webrick"</span></code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="2-devcontainerdevcontainer-json">2. <code>.devcontainer/devcontainer.json</code></h3>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="json"><span class="p">{</span><span class="w">
  </span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"meine-site"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"image"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ghcr.io/tpo42/adoc:latest"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"workspaceFolder"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/workspace"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"workspaceMount"</span><span class="p">:</span><span class="w"> </span><span class="s2">"source=${localWorkspaceFolder},target=/workspace,type=bind"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"postCreateCommand"</span><span class="p">:</span><span class="w"> </span><span class="s2">"bundle config set --local path vendor/bundle &amp;&amp; bundle install"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"appPort"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="mi">4000</span><span class="p">,</span><span class="w"> </span><span class="mi">35729</span><span class="p">],</span><span class="w">
  </span><span class="nl">"forwardPorts"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="mi">4000</span><span class="p">,</span><span class="w"> </span><span class="mi">35729</span><span class="p">],</span><span class="w">
  </span><span class="nl">"portsAttributes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nl">"4000"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jekyll"</span><span class="p">,</span><span class="w"> </span><span class="nl">"onAutoForward"</span><span class="p">:</span><span class="w"> </span><span class="s2">"notify"</span><span class="w"> </span><span class="p">},</span><span class="w">
    </span><span class="nl">"35729"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"LiveReload"</span><span class="p">,</span><span class="w"> </span><span class="nl">"onAutoForward"</span><span class="p">:</span><span class="w"> </span><span class="s2">"silent"</span><span class="w"> </span><span class="p">}</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span><span class="p">}</span></code></pre>
</div>
</div>
<div class="paragraph">
<p>Die wichtigsten Punkte:</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1"><code>image</code></dt>
<dd>
<p>Nutzt direkt <code>ghcr.io/tpo42/adoc:latest</code> (der "einfache Fall" aus
ADR-005).  Kein eigenes Dockerfile nötig.</p>
</dd>
<dt class="hdlist1"><code>postCreateCommand</code></dt>
<dd>
<p>Installiert Gems nach <code>vendor/bundle</code> (schreibbar für
den Container-User, von <code>.gitignore</code> ignoriert).</p>
</dd>
<dt class="hdlist1"><code>appPort</code></dt>
<dd>
<p>Mappt Ports auf Docker-Ebene, damit <code>jekyll serve</code> auch ohne
VS Code vom Host aus erreichbar ist.</p>
</dd>
<dt class="hdlist1"><code>forwardPorts</code></dt>
<dd>
<p>Dasselbe für VS Codes eingebautes Port-Forwarding.</p>
</dd>
</dl>
</div>
</div>
<div class="sect2">
<h3 id="3-container-starten">3. Container starten</h3>
<div class="paragraph">
<p>Mit der <a href="https://github.com/devcontainers/cli">devcontainer-CLI</a>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">devcontainer up <span class="nt">--workspace-folder</span> .</code></pre>
</div>
</div>
<div class="paragraph">
<p>Dann die Site starten:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">devcontainer <span class="nb">exec</span> <span class="nt">--workspace-folder</span> <span class="nb">.</span> <span class="se">\</span>
  bundle <span class="nb">exec </span>jekyll serve <span class="nt">--host</span> 0.0.0.0 <span class="nt">--livereload</span></code></pre>
</div>
</div>
<div class="paragraph">
<p><a href="http://localhost:4000" class="bare">http://localhost:4000</a> öffnen&#8201;&#8212;&#8201;fertig.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="warum-kein-eigenes-jekyll-image">Warum kein eigenes Jekyll-Image?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Images wie <code>bretfisher/jekyll-serve</code> funktionieren, bringen aber ihr eigenes
Ruby und Gem-Set mit.  Wenn der Content AsciiDoc ist, braucht man die
Asciidoctor-Toolchain <em>und</em> Jekyll&#8201;&#8212;&#8201;zwei getrennte Container oder ein
aufgeblähtes Custom-Image.</p>
</div>
<div class="paragraph">
<p>Mit <code>ghcr.io/tpo42/adoc</code> als Basis bekommt man Asciidoctor für die
Dokumentenverarbeitung (flatten, validate, Diagramme extrahieren via <code>adcw</code>)
<em>und</em> Jekyll zum Servieren&#8201;&#8212;&#8201;aus einem einzigen Image, gesteuert über das
Gemfile des Projekts.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="asciidoc-validierunggeht-auch-ohne-devcontainer">AsciiDoc-Validierung&#8201;&#8212;&#8201;geht auch ohne Devcontainer</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Der <code>adcw</code>-Wrapper braucht keinen Devcontainer.  <code>.adoc</code>-Dateien lassen sich
jederzeit validieren:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="rouge highlight"><code data-lang="bash">adcw validate <span class="nt">-i</span> _pages/about.adoc</code></pre>
</div>
</div>
<div class="paragraph">
<p>Das startet einen kurzen <code>docker run --rm</code>&#8201;&#8212;&#8201;kein langlebiger Container nötig.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="was-ich-dabei-gelernt-habe">Was ich dabei gelernt habe</h2>
<div class="sectionbody">
<div class="dlist">
<dl>
<dt class="hdlist1"><code>appPort</code> vs <code>forwardPorts</code></dt>
<dd>
<p>Die devcontainer-CLI leitet Ports nicht selbst weiter.  <code>forwardPorts</code> ist ein
VS-Code-Feature.  Für reine CLI-Workflows braucht man <code>appPort</code>.</p>
</dd>
<dt class="hdlist1">Gem-Berechtigungen</dt>
<dd>
<p>Der <code>ghcr.io/tpo42/adoc</code>-Container läuft als unprivilegierter User.
<code>bundle install</code> ohne <code>--path</code> versucht in System-Gem-Verzeichnisse zu
schreiben und scheitert.  <code>bundle config set --local path vendor/bundle</code> löst
das sauber.</p>
</dd>
<dt class="hdlist1">Container-Wiederverwendung</dt>
<dd>
<p><code>devcontainer up</code> nutzt bestehende Container wieder.  Nach Änderungen an
<code>devcontainer.json</code> muss der alte Container erst entfernt werden
(<code>docker rm -f &lt;id&gt;</code>), bevor <code>devcontainer up</code> erneut funktioniert.</p>
</dd>
</dl>
</div>
</div>
</div>]]></content><author><name>Jens Rehsack</name></author><category term="devcontainer" /><category term="jekyll" /><category term="asciidoc" /><category term="docker" /><category term="tpo42" /><summary type="html"><![CDATA[Eine Jekyll-Site mit AsciiDoc-Unterstützung aufzusetzen bedeutet normalerweise: Ruby installieren, Bundler, eine Handvoll Gems. Mit dem tpo42/adoc-Container und der Dev-Containers-Spezifikation kann man sich das alles sparen.]]></summary></entry><entry><title type="html">Vermögens- und Erbschaftssteuer nach Art. 14 GG — ein Zwei-Säulen-Modell</title><link href="https://rehsack.de/2026/03/12/vermoegens-erbschaftssteuer-grundgesetz/" rel="alternate" type="text/html" title="Vermögens- und Erbschaftssteuer nach Art. 14 GG — ein Zwei-Säulen-Modell" /><published>2026-03-12T00:00:00+00:00</published><updated>2026-03-12T00:00:00+00:00</updated><id>https://rehsack.de/2026/03/12/vermoegens-erbschaftssteuer-grundgesetz</id><content type="html" xml:base="https://rehsack.de/2026/03/12/vermoegens-erbschaftssteuer-grundgesetz/"><![CDATA[<div class="paragraph">
<p>Die Macher von <a href="https://www.vergnuegt.info" target="_blank" rel="noopener">vergnügt</a> (<em>Vermögens- und
Erbschaftsteuer retten Gemeinden in Not über gerechte Talerabgabe!</em>) haben mich
inspiriert, einen Gedanken, der mich über Jahre nicht losließ, im Gespräch
herausfordern zu lassen und schließlich aufzuschreiben.  Ich hoffe, es
bereichert die Diskussion&#8201;&#8212;&#8201;und nun viel Vergnügen.</p>
</div>
<hr>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>Eigentum verpflichtet.  Sein Gebrauch soll zugleich dem Wohle der Allgemeinheit
dienen.</p>
</div>
</blockquote>
<div class="attribution">
&#8212; Art. 14 Abs. 2 GG
</div>
</div>
<div class="paragraph">
<p>Dieses Modell nimmt diese Norm beim Wort und leitet daraus ein operatives
Steuerprinzip ab: Vermögen, das dem Allgemeinwohl dient, ist steuerlich bedient.
Vermögen, das dies nicht tut, wird besteuert.</p>
</div>
<div class="sect1">
<h2 id="grundprinzip">Grundprinzip</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Die zentrale Unterscheidung ist nicht die <em>Höhe</em> des Vermögens, sondern seine
<em>Funktion</em>.  Die Frage lautet nicht &#8220;Wie viel besitzt jemand?&#8221;, sondern
&#8220;Trägt dieses Vermögen zum Allgemeinwohl bei&#8201;&#8212;&#8201;oder nicht?&#8221;</p>
</div>
<div class="paragraph">
<p>Vermögen gilt als gemeinwohldienlich, wenn es mindestens eines der folgenden
Kriterien erfüllt:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Es erzeugt Arbeitsplätze durch direkte, persönlich verantwortete Inhaberschaft
(Beispiel: inhabergeführter Mittelständler wie Trigema).</p>
</li>
<li>
<p>Es generiert versteuerte Erträge&#8201;&#8212;&#8201;Dividenden, Mieteinnahmen,
Betriebsgewinne&#8201;&#8212;&#8201;und wird damit bereits durch bestehende Steuern erfasst.</p>
</li>
<li>
<p>Es ist gemeinnützig gewidmet oder der Allgemeinheit zugänglich (Beispiel:
Naturschutzgebiet, öffentlich zugängliches Kulturgut).</p>
</li>
<li>
<p>Es zeigt messbares Wachstum über einen Mehrjahreszeitraum (3–5 Jahre), was auf
produktive Kapitalverwendung hindeutet.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="säule-1-vermögenssteuer-als-auffangnetz">Säule 1: Vermögenssteuer als Auffangnetz</h2>
<div class="sectionbody">
<div class="paragraph">
<p><strong>Was besteuert wird:</strong> Ausschließlich Vermögen, das durch keine bestehende
Steuer erfasst wird <em>und</em> keinen messbaren gesellschaftlichen Nutzen erzeugt.</p>
</div>
<div class="paragraph">
<p><strong>Was nicht besteuert wird:</strong> Jedes Vermögen, das bereits über
Kapitalertragsteuer, Einkommensteuer, Gewerbesteuer oder andere Abgaben zum
Gemeinwohl beiträgt.  Ebenso Vermögen, das gemeinnützig gewidmet ist oder durch
aktive Inhaberführung Arbeitsplätze schafft.</p>
</div>
<div class="paragraph">
<p><strong>Steuersatz:</strong> 1–2&#160;% jährlich auf das nicht-gemeinwohldienliche Vermögen.</p>
</div>
<div class="paragraph">
<p><strong>Freibetrag:</strong> Eine großzügig bemessene Lebensbedarfsgrenze, die Wohnen,
Bildung, Vorsorge und einen substanziellen Sicherheitspuffer abdeckt.  Alles
darunter ist grundsätzlich von der Vermögenssteuer befreit.</p>
</div>
<div class="paragraph">
<p><strong>Bewertungszeitraum:</strong> Die Gemeinwohldienlichkeit wird über einen rollierenden
3- bis 5-Jahreszeitraum bewertet, um konjunkturelle Schwankungen und
Wirtschaftskrisen nicht sinnlos zu verschärfen.</p>
</div>
<div class="paragraph">
<p><strong>Kernmerkmal:</strong> Es gibt per Design keine Doppelbesteuerung, da die
Vermögenssteuer nur in der Lücke greift, die bestehende Steuern nicht abdecken.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="säule-2-erbschaftssteuer-nach-gleichem-prinzip">Säule 2: Erbschaftssteuer nach gleichem Prinzip</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Die Erbschaftssteuer folgt derselben Logik: Wer beiträgt, trägt bei.  Wer noch
nicht beiträgt, hat jetzt die Chance.</p>
</div>
<div class="paragraph">
<p><strong>Vererbung eines operativen Unternehmens:</strong> Wer ein Unternehmen erbt und es
mindestens 10 Jahre in direkter Inhaberschaft fortführt, zahlt keine
Erbschaftssteuer.  Der gesellschaftliche Beitrag wird durch den Betrieb
erbracht.  Bei Verkauf nach Ablauf der Frist wird der Verkaufserlös als
reguläres Einkommen versteuert.</p>
</div>
<div class="paragraph">
<p><strong>Vererbung von passivem Vermögen:</strong> Wer ein Aktiendepot, Sachwerte oder andere
passive Vermögenswerte erbt, versteuert diese bei Veräußerung als Einkommen.  Es
gibt keinen Anspruch auf steuerfreie Weitergabe von Vermögen, das keinen aktiven
Beitrag zum Allgemeinwohl leistet.</p>
</div>
<div class="paragraph">
<p><strong>Entscheidende Unterscheidung:</strong> Direkte, persönlich verantwortete Inhaberschaft
wird privilegiert.  Anonyme Anteilseignerschaft&#8201;&#8212;&#8201;also die bloße Vererbung von
Kapitalbeteiligungen ohne operative Verantwortung&#8201;&#8212;&#8201;wird behandelt wie jedes
andere passive Vermögen.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="was-dieses-modell-nicht-ist">Was dieses Modell nicht ist</h2>
<div class="sectionbody">
<div class="paragraph">
<p><strong>Keine Neidsteuer.</strong> Das Modell richtet sich nicht gegen Reichtum, sondern
gegen brachliegendes Vermögen.  Wer mit seinem Vermögen wirtschaftet,
Arbeitsplätze schafft oder Erträge versteuert, wird nicht zusätzlich belastet.</p>
</div>
<div class="paragraph">
<p><strong>Keine Leistungsfeindlichkeit.</strong> Im Gegenteil: Das Modell privilegiert aktives,
produktives Eigentum gegenüber passivem Besitz.  Es belohnt den Unternehmer und
besteuert den Rentier.</p>
</div>
<div class="paragraph">
<p><strong>Keine Umverteilungsideologie.</strong> Der Ausgangspunkt ist das Grundgesetz, nicht
ein politisches Programm.  Art. 14 Abs. 2 GG formuliert eine Pflicht&#8201;&#8212;&#8201;dieses
Modell operationalisiert sie.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="offene-fragen-bewusst-transparent-gehalten">Offene Fragen (bewusst transparent gehalten)</h2>
<div class="sectionbody">
<div class="paragraph">
<p><strong>Administrierbarkeit:</strong> Die Bewertung von &#8220;Gemeinwohldienlichkeit&#8221; erfordert
klare, einfache Kriterien.  Je komplexer das System, desto mehr profitieren
diejenigen mit den besten Steuerberatern.  Die Kriterien müssen so formuliert
sein, dass sie regelbasiert und nicht ermessensbasiert angewendet werden können.</p>
</div>
<div class="paragraph">
<p><strong>Konkrete Lebensbedarfsgrenze:</strong> Die genaue Höhe des Freibetrags muss politisch
verhandelt werden.  Ob 25 oder 40 Millionen Euro&#8201;&#8212;&#8201;die Zielgruppe beginnt
mindestens bei Faktor 10 darüber.</p>
</div>
<div class="paragraph">
<p><strong>Deklarationspflicht:</strong> Um Umgehung zu verhindern (das
&#8220;Rembrandt-auf-dem-Dachboden&#8221;-Problem), braucht es eine jährliche
Deklarationspflicht für Vermögen oberhalb der Lebensbedarfsgrenze, inklusive
Sachwerte.  Nichtdeklaration wird sanktioniert.</p>
</div>
<div class="paragraph">
<p><strong>Rechtsstaatliche Ausgestaltung:</strong> Die konkrete juristische Umsetzung&#8201;&#8212;&#8201;insbesondere Fragen der Rückwirkung und der Vereinbarkeit mit europäischem
Recht&#8201;&#8212;&#8201;erfordert fachliche Expertise und ist in diesem Konzeptpapier bewusst
nicht abschließend behandelt.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="zusammenfassung-in-einem-satz">Zusammenfassung in einem Satz</h2>
<div class="sectionbody">
<div class="paragraph">
<p><em>"`Eigentum verpflichtet`"&#8201;&#8212;&#8201;wer dieser Verpflichtung nachkommt, ist steuerlich
bedient; wer nicht, zahlt Vermögenssteuer.</em></p>
</div>
<hr>
<div class="paragraph">
<p><em>Dieses Konzept entstand aus einer strukturierten Debatte, in der die Annahmen
bewusst und systematisch stressgetestet wurden.  Es erhebt keinen Anspruch auf
juristische Vollständigkeit, sondern versteht sich als Denkrahmen für die
politische Diskussion.</em></p>
</div>
</div>
</div>]]></content><author><name>Jens Rehsack</name></author><category term="politik" /><category term="grundgesetz" /><category term="vermögenssteuer" /><category term="erbschaftssteuer" /><category term="gemeinwohl" /><summary type="html"><![CDATA[Die Macher von vergnügt (Vermögens- und Erbschaftsteuer retten Gemeinden in Not über gerechte Talerabgabe!) haben mich inspiriert, einen Gedanken, der mich über Jahre nicht losließ, im Gespräch herausfordern zu lassen und schließlich aufzuschreiben. Ich hoffe, es bereichert die Diskussion&#8201;&#8212;&#8201;und nun viel Vergnügen.]]></summary></entry><entry><title type="html">Offener Brief an Dr. Katrin Vernau — 7 Monate WDR-Intendantin, Zeit für Open Source?</title><link href="https://rehsack.de/2025/08/18/offener-brief-wdr-open-source/" rel="alternate" type="text/html" title="Offener Brief an Dr. Katrin Vernau — 7 Monate WDR-Intendantin, Zeit für Open Source?" /><published>2025-08-18T00:00:00+00:00</published><updated>2025-08-18T00:00:00+00:00</updated><id>https://rehsack.de/2025/08/18/offener-brief-wdr-open-source</id><content type="html" xml:base="https://rehsack.de/2025/08/18/offener-brief-wdr-open-source/"><![CDATA[<div class="paragraph">
<p>Liebe Frau Dr. Vernau,</p>
</div>
<div class="paragraph">
<p>Sie sind seit Januar 2025 WDR-Intendantin&#8201;&#8212;&#8201;7 Monate, um neue Akzente zu setzen.
Haben Sie schon bemerkt, was Ihre Redaktionen seit Jahren übersehen?</p>
</div>
<div class="paragraph">
<p>Lassen Sie mich Ihnen eine Geschichte erzählen, die zeigt, warum dieser Neuanfang
nötig ist:</p>
</div>
<div class="sect1">
<h2 id="2018-deutscher-perl-workshop-in-köln">2018: Deutscher Perl-Workshop in Köln</h2>
<div class="sectionbody">
<div class="paragraph">
<p>2018 schrieb ich WDR-Redaktionen anlässlich des 20. Deutschen Perl-Workshops in
Köln.  Internationale Konferenz, 200+ Teilnehmer, direkt vor der WDR-Haustür.
Die Antwort der Lokalzeit-Redaktion:</p>
</div>
<div class="quoteblock">
<blockquote>
<div class="paragraph">
<p>Das Thema erscheint uns zu spezialisiert.  Unsere Zuschauer sind nicht
herausragend technisch interessiert.</p>
</div>
</blockquote>
</div>
<div class="paragraph">
<p>Aktuelle Stunde?  Keine Antwort.  Wissenschaftsredaktion?  Schweigen.
Weitere Redaktionen?  Totenstille.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="2025-die-ignoranz-bleibt-aber-die-probleme-werden-dramatischer">2025: Die Ignoranz bleibt, aber die Probleme werden dramatischer</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Gerade diese Woche: External Secrets Operator für Kubernetes vor dem Aus&#8201;&#8212;&#8201;nur
noch ein Maintainer, völlig überarbeitet.  Gernot Starke (arc42, 20 Jahre!)
berichtet: &#8220;Eine Million Downloads jährlich, hunderte Unternehmen nutzen es
täglich&#8201;&#8212;&#8201;aber Contributions?  Nahe Null.&#8221;</p>
</div>
<div class="paragraph">
<p><strong>Das ist die Realität unsichtbarer Communities: Genutzt von allen, unterstützt
von wenigen, berichtet von niemandem.</strong></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="deutsche-entwickler-sichern-globale-standards-ab">Deutsche Entwickler sichern globale Standards ab</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Während Millionen für Fußball-Übertragungen fließen, kostet ein Bericht über
deutsche Tech-Communities offenbar zu viel Aufwand für eine Antwort.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Chris Badura aus Köln portiert jährlich ~4 ARM-Architekturen für NetBSD&#8201;&#8212;&#8201;weltweit genutzt</p>
</li>
<li>
<p>Gernot Starke feiert mit arc42 das 20-jährige Jubiläum&#8201;&#8212;&#8201;<em>der</em>
Architektur-Standard in DACH</p>
</li>
<li>
<p>unByte GmbH entwickelt Self-Bootstrapping K8s&#8201;&#8212;&#8201;Kubernetes-Innovation aus NRW</p>
</li>
<li>
<p>Yocto Linux mit Contributoren aus Köln, NRW und ganz Deutschland steckt in
Milliarden von Geräten</p>
</li>
<li>
<p><a href="https://coocook.org">Coocook.org</a> hilft tausenden Ferienlagern bei der
Essensplanung</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Und das sind nur die, die mir in 30 Sekunden einfallen.  Was würde echte
Recherche zutage fördern?</p>
</div>
<div class="paragraph">
<p><strong>Aber Sie zeigen lieber die nächste Influencer-Doku.</strong></p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="der-wdr-hat-einen-bildungsauftrag">Der WDR hat einen Bildungsauftrag</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Dazu gehört zu zeigen, <em>wer</em> unsere digitale Zukunft gestaltet.  Das sind nicht
nur die üblichen Verdächtigen aus dem Silicon Valley&#8201;&#8212;&#8201;das sind auch Menschen
aus Köln, Düsseldorf, Essen.</p>
</div>
<div class="paragraph">
<p><strong>Und diese Menschen gehören in die Prime-Formate, nicht nur in
Bildungs-Nischen.</strong></p>
</div>
<div class="paragraph">
<p>Stellen Sie sich vor: &#8220;Austausch in der TH Köln: Coocook-Begründer auf
Konferenz&#8221;&#8201;&#8212;&#8201;das wäre in der Lokalzeit eingeschlagen wie eine Bombe.  Echter
lokaler Bezug, echte Innovation, echte Menschen.  Hintergrund-Recherchen gern in
Bildungsformaten&#8201;&#8212;&#8201;aber die Stories müssen raus aus der Nische!</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="mein-vorschlag-für-ihre-verbleibende-amtszeit">Mein Vorschlag für Ihre verbleibende Amtszeit</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Beauftragen Sie eine Redaktion mit einer Serie über deutsche Tech-Communities.
Zeigen Sie die FrOSCon, die Chemnitzer Linux-Tage, den German Perl Workshop.
Zeigen Sie die Menschen dahinter.</p>
</div>
<div class="paragraph">
<p>Nicht als &#8220;Nerd-Spektakel&#8221;, sondern als das, was es ist: Die Arbeit an unserer
gemeinsamen digitalen Zukunft.</p>
</div>
<div class="paragraph">
<p><strong>Werden Sie die Intendantin, die den Unterschied macht?</strong></p>
</div>
<div class="paragraph">
<p>Mit freundlichen Grüßen und konkreten Erwartungen,<br>
Jens Rehsack</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>Falls Sie Inspiration brauchen&#8201;&#8212;&#8201;die New York Perl Mongers schauten 2018 nach
Köln und sagten: &#8220;I had no idea how to celebrate our anniversary.  Now I know.&#8221;
Vielleicht sollte der WDR auch mal nach Köln schauen.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>]]></content><author><name>Jens Rehsack</name></author><category term="medien" /><category term="open-source" /><category term="wdr" /><category term="digitale-souveränität" /><category term="software-resilienz" /><summary type="html"><![CDATA[Liebe Frau Dr. Vernau,]]></summary></entry></feed>