• v2.1.0 18ae28f918

    v2.1.0
    CI / verify (push) Failing after 32s
    Release / release (push) Successful in 38s
    Stable

    torben released this 2026-09-01 14:30:30 +00:00 | 108 commits to main since this release

    2.1.0 - 2026-09-01 - Dual-Lizenz AGPL-3.0/CC-BY-4.0, und ein Leak-Canary fuer dist export

    Author: Torben Nehmer

    Das Repo hatte keine Lizenz. Für ein Repo, das privat auf der eigenen Gitea liegt, ist das
    folgenlos; für eines, das veröffentlicht werden soll, hebt es den Zweck der Veröffentlichung
    auf — ohne Lizenz gilt „alle Rechte vorbehalten", und niemand darf eine Instanz aufsetzen.

    Zwei Hälften, zwei Lizenzen. LICENSE trägt die AGPL-3.0 und gilt für den Stack
    (tools/, types/); LICENSE-CONTENT trägt CC-BY-4.0 und gilt für die Inhalte (kb/,
    raw/, instructions/, die CONTRACT.md-Ebene, die Prosa im Wurzelverzeichnis). Die
    Aufteilung folgt dem Vorbild der vendorten Commonplace-Basis, kehrt aber deren Dateinamen um:
    Die Copyleft-Hälfte heißt LICENSE, weil das die Lizenz ist, die eine Forge für das Repository
    meldet — und wer eine Copyleft-Pflicht übersieht, wird dadurch geschädigt, wer eine zu viel
    sieht, nicht.

    Die Affero-Variante statt der einfachen GPL, weil Issue #19 den Stack als MCP-Frontend
    erreichbar machen will. Bei der GPL schuldet nichts, wer nur einen Dienst betreibt statt
    Software zu verteilen; genau dieser Weg ist der, den dieses Projekt einschlägt.

    Die Grenze wird nicht aufgeschrieben. Welche Datei zu welcher Hälfte gehört, ist der
    Dateiplan, den dist export ohnehin berechnet. NOTICE verweist darauf, statt eine zweite
    Pfadliste anzulegen, die drifted (Invariante 8). NOTICE trägt außerdem die Attribution für
    commonplace (zby, CC-BY-4.0 Inhalte + MIT Code), die CC-BY verlangt.

    dist export liefert die Lizenzen mit — und weigert sich sonst. Die drei Dateien stehen
    jetzt in ROOT_FILES, aber nicht nur dort: REQUIRED_ROOT_FILES macht sie zur Bedingung.
    Jeder andere ROOT_FILES-Eintrag wird if source.is_file() kopiert und sonst stillschweigend
    übersprungen — richtig für INSTALL.md, das es lange nicht gab, und falsch für eine Lizenz:
    Ein Export, der sie weglässt, übergibt einen AGPL-tools/-Baum ohne Lizenztext, und das ist
    eine Verletzung, sobald die empfangende Instanz irgendwo öffentlich landet.

    Der Leak-Canary. find_leaks() prüft den fertigen Plan gegen das, was er nie enthalten
    darf: eine ausgefüllte USER.md/SOUL.md/ENVIRONMENT.md, etwas unter instructions/dev/,
    eine kb/-Seite oder eine raw/-Quelle. Drei getrennte Allowlists entscheiden bisher, was
    build_plan kopiert, und jede hält nur, solange sich beim Editieren jemand an die Regel
    erinnert hat — nichts prüfte das Ergebnis nach. export bricht jetzt ab, wenn der Plan etwas
    davon trägt, mit dem Hinweis, die Allowlist zu reparieren statt Dateien aus dem Ziel zu löschen.

    Die Prüfung ist bewusst strukturell und nicht textbasiert. Ein Muster-Scan auf Hostnamen
    oder IP-Literale wurde erwogen und verworfen: Der eigene Host steht legitim in INSTALL.md und
    version.py, ein solcher Scan müsste also genau die Zeichenkette ausnehmen, nach der er sucht —
    oder bei jedem Export Fehlalarm geben.

    Beispiele neutralisiert. Hilfetexte, Docstrings und Contract-Beispiele nannten reale
    Seiten und Pfade der Ursprungsinstanz (Quellenseiten und Pfade
    aus dem privaten Korpus). In einer
    Distribution ist das nicht nur unpassend, sondern verrät den Inhalt der Instanz, die sie gebaut
    hat. Ersetzt durch Beispiele aus dem verbleibenden öffentlichen Korpus.

    Dateien: LICENSE, LICENSE-CONTENT, NOTICE (neu), config.LICENSE_FILES,
    dist_cmd.REQUIRED_ROOT_FILES, dist_cmd.find_leaks(), Lizenzabschnitt in README.md,
    sechs neue Tests in test_dist_cmd.py; Beispiel-Neutralisierung in cite_cmd.py,
    page_ops.py, work_cmd.py, provenance.py, search/ripgrep.py, work/CONTRACT.md,
    instructions/session-setup.md und zwei Testdateien.

    Downloads