402 Commits
Author SHA1 Message Date
mhoennig db7b8004ee docs: Werkbaum-Plan — 1 Knoten in Produktion
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #col.git.timer: A timer on the backend host mirrors a list of documents into a branch (S)  %% tools/mirror-docs, systemd timer — see D88-Nachtrag 3
2026-09-04 12:40:55 +02:00
mhoennigandClaude Fable 5.1 28ff6844b0 fix(live): Wiederverbindung sendet nie von selbst — Server-Stand oder Rückfrage (D89-Nachtrag 2)
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
Ein Fenster, das mit altem Text aufwachte, schickte ihn beim Wiederverbinden
als Diff und überschrieb den aktuellen Plan (v660, v679). Jetzt entscheidet,
ob seit dem letzten Abgleich hier gearbeitet wurde: nein → Server-Stand
übernehmen (lokaler Text in die Sicherungen), ja → Konflikt-Band fragt.
Regel headless in live.js (reconnectAction), Bandtext in neun Sprachen.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 12:34:01 +02:00
mhoennigandClaude Fable 5.1 2e408d956c feat(tools): mirror-docs — Liste geteilter Dokumente per Timer nach git spiegeln (D88-Nachtrag 3)
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-04 09:52:02 +02:00
mhoennigandClaude Opus 5 c87cf6212d docs(prs): PR-doc auf Nummer 3 — 1 und 2 gehören der GitHub-Historie
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
Gitea begann nach dem Umzug wieder bei 1, Werkbaums Historie kennt aber
schon GitHub-PR #1 und #2. Beide Nummern sind in Gitea abgebrannt; die
Zählung setzt bei 3 auf, damit eine Nummer in docs/prs/ eindeutig bleibt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 19:26:31 +02:00
mhoennig 5ec5118cee docs: Werkbaum-Plan — 2 Knoten in Produktion
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #bld.werkator: Also built by Werkator, the project's own CI (S)  %% .werkator.yml, backend + frontend
- #bld.gitea: The repository lives on Gitea, GitHub stays a clone
2026-09-03 19:24:14 +02:00
mhoennigandClaude Opus 5 063d2c947b docs(scripts): push-github.sh nennt nicht mehr CORS als Grund für den Klon (D96)
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
Der Kopfkommentar behauptete noch, Gitea sende kein
Access-Control-Allow-Origin. Seit D96 tut es das; übrig bleibt GitHub Pages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 19:23:04 +02:00
mhoennigandClaude Opus 5 3cafc92d49 docs: Beispiel-Links laden aus dem eigenen Gitea (D96)
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
git.javagil.de sendete auf raw-Dateien kein Access-Control-Allow-Origin,
weshalb die ?sourceUrl=-Beispiel-Links nach dem Umzug (D95) auf dem
GitHub-Klon bleiben mussten. Der Header ist jetzt auf mih09 gesetzt:
Giteas [cors]-Abschnitt deckt nur /api/v1 ab, die Web-raw-Route bekommt
ihn im Apache davor. Die Links zeigen nun auf origin.

Nebenbei: "Werkbaum selbst" war schon vorher tot (example-werkbaum.werkbaum
existiert nicht, die Datei heisst werkbaum.werkbaum) und ist mit korrigiert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 18:31:37 +02:00
mhoennigandClaude Opus 5 29a217f892 chore(repo): Umzug nach Gitea — GitHub bleibt Klon, main von Hand gespiegelt (D95)
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s
Zuhause ist künftig git.javagil.de/mi/werkbaum (origin); GitHub bleibt unter
dem Remote `github` ein Klon, den scripts/push-github.sh mit `main` versorgt —
nur vorwärts, nie erzwungen.

Der Klon bleibt aus zwei gemessenen Gründen: Gitea sendet auf raw-Dateien kein
Access-Control-Allow-Origin (nachgemessen an mi/werkdock), die
?sourceUrl=-Beispiellinks der READMEs müssen also auf raw.githubusercontent.com
zeigen; und der Pages-Workflow lässt sich nicht mitnehmen.

Footer, llms.txt und llms.md zeigen jetzt auf Gitea (Repo-Seite ohne Anmeldung
lesbar, HTTP 200 geprüft); beide COMMIT_URL-Stellen (deploy-prod.sh und der
Pages-Workflow) ziehen mit. deploy-prod.sh prüft origin und github getrennt und
erinnert an das Spiegeln, statt selbst zu pushen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 17:26:15 +02:00
mhoennigandClaude Fable 5.1 736e9c1d88 docs(rfc): RFC 003 — Knoten im Text verschieben, als Bauanleitung für einen Coding-Agenten
Zwei Knöpfe in der Editor-Titelzeile und Alt+↑/↓ verschieben den Block des
Knotens der Cursor-Zeile (Zeile, \-Fortsetzungen, "-Beschreibungen,
Teilbaum) vor den vorherigen bzw. hinter den nächsten Geschwisterknoten —
als reine Text→Text-Regel neben setFoldMark/expandShortIds, ein Undo-Schritt
über writeAt, ohne neue Editor-Komponente. Das RFC legt Blockgrenzen,
Nachbarsuche, Zusammensetzen, Verdrahtung, i18n, 15 Testfälle samt
Mutations-Gegenproben, Browser-Nachmessung und die nachzuziehenden Dokumente
(SPEC §9, CHANGELOG, D95, Plan-Knoten #ed.move) fest. Nichts gebaut.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 16:12:31 +02:00
mhoennigandClaude Opus 5 5e72cd873f build(ci): Gradle-Wrapper ins Repo — ohne ihn baut kein frischer Klon das Backend
`.gitignore` schloss `backend/gradlew`, `gradlew.bat` und `gradle/wrapper/`
aus (40db415). Lokal fiel das nie auf, weil die Dateien unversioniert im
Arbeitsverzeichnis liegen — auf der Werkator-Instanz scheiterte der erste
Build sofort mit `/bin/sh: 1: ./gradlew: not found`.

Der Wrapper ist der vereinbarte Weg, eine Gradle-Version festzuschreiben
(9.1.0); die Sandbox hat kein eigenes Gradle, und `!gradle-wrapper.jar`
stand in derselben Datei bereits als Ausnahme zur `*.jar`-Regel — die drei
Ignore-Zeilen widersprachen ihr.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 14:12:54 +02:00
Michael Hönnig 828d961a8b Merge pull request #2 from mhoennig/werkator-ci
Werkator CI
2026-09-03 13:02:51 +02:00
mhoennig ac4a06bd18 Merge remote-tracking branch 'origin/main' into werkator-ci 2026-09-03 12:56:45 +02:00
mhoennigandClaude Opus 5 3ccff12cfd ci(werkator): .werkator.yml — Werkbaum wird zusätzlich von Werkator gebaut
Werkator ist ein deklaratives CI (https://werkator.javagil.de): Die Datei im
Repo-Root beschreibt die Builds, der Watcher der Instanz baut jeden Push auf
jedem Branch. Zwei Builds, wie die beiden Teile des Monorepos: `backend`
(Gradle-Tests, Artefakt sind die Berichte unter backend/build/reports) und
`frontend` (npm ci, Vitest, Vite-Bundle als frontend/dist). Das `default`
trägt bewusst keinen Trigger — es ist nur die Einstellungsbasis, damit nichts
doppelt läuft.

Beide Befehle laufen wörtlich so, wie sie in der Datei stehen, lokal durch:
Backend BUILD SUCCESSFUL in 1m35s mit 180 Testfällen (jacoco- und
Test-Berichte liegen im deklarierten Artefakt-Verzeichnis), Frontend npm ci +
628 Tests + Vite-Bundle nach frontend/dist/index.html (761 kB).

Die Sandbox hat Node 20.19, lokal läuft 22.17 — deshalb zusätzlich die
`engines`-Angaben aller installierten Pakete geprüft: Keines schließt 20.19
aus; die schärfsten Schranken sind vite 8.1.5 (^20.19.0 || >=22.12.0) und
jsdom 29.1.1 (^20.19.0 || ^22.13.0 || >=24). 20.19.0 ist damit exakt die
Untergrenze — wer eine Abhängigkeit aufnimmt, die darüber liegt, bricht den
CI-Build (Anleitung).

Werkator baut und testet nur; deployt wird weiterhin über scripts/deploy-*.sh
bzw. tools/remote (D77), und der GitHub-Pages-Workflow bleibt unberührt —
beide CI laufen parallel, bis das Repo nach Gitea umzieht. Die Footer-Version
setzt nur der Pages-Workflow (D16), das Werkator-Artefakt trägt sie nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 11:54:18 +02:00
Michael Hönnig 04cc154567 Merge pull request #1 from mhoennig/rfc-002-mehrfenster
RFC-002 verbesserte Mehrfenster Absicherung
2026-09-03 11:49:07 +02:00
mhoennigandClaude Opus 5 2d78baf407 fix(editor): „nur ansehen" gilt jetzt dem Dokument, nicht nur dem Textfeld — auch das Diagramm faltet dort nicht mehr
Nutzer-Einwand, folgerichtig aus dem Vorgänger-Commit: Wenn Falten eine
Änderung ist, muss der Nur-Ansehen-Modus auch das Diagramm stillstellen —
im haltenden Fenster natürlich weiter nicht.

Es war schlimmer als eine fehlende Sperre: `readonly` hielt gar nichts auf.
`replaceTextUndoable` fällt auf `src.value = neu` zurück, wenn `execCommand`
scheitert, und eine Zuweisung an `value` schreibt auch in ein
schreibgeschütztes Feld. Nachgemessen: Ein Klick auf das Falt-Zeichen im
Nur-Ansehen-Fenster setzte `- > Ast A (M)` in Textfeld UND Speicher — der
Modus war nur eine Beschriftung.

Gesperrt wird jetzt an der Schreibstelle: eine Zeile in
`replaceTextUndoable` weist jeden programmatischen Schreibzugriff ab
(Falten, Durchschalter, „aus Taiga übernehmen", früherer Stand,
ID-Kurzform). Dazu ruhen die Gesten selbst, damit nichts still ins Leere
geht — toggleFold und der Durchschalter kehren früh um, Falt-Zeichen und
Knopf treten zurück und nehmen keinen Klick an (body.viewonly), und im
Knoten-Fenster entfallen die Aktionen, die in die Zeile schreiben.
„Nach Taiga schreiben" bleibt: Es fasst den Plan nicht an. Ansicht bleibt
Ansicht — Zoom, Modus, Pfad, Export, Sprünge unverändert bedienbar.

Nachgemessen mit zwei Fenstern: Chip, Tastatur und Durchschalter lassen im
Nur-Ansehen-Fenster Text und Speicher unangetastet; im haltenden Fenster
faltet dieselbe Geste weiter; verlässt es das Dokument, wird das andere von
selbst wieder beschreibbar und faltbar. SPEC §9, D94-Nachtrag 3 und
CHANGELOG nachgezogen; 666 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:28:20 +02:00
mhoennigandClaude Opus 5 2a58951138 fix(i18n): die Zwei-Fenster-Warnung nennt die zuletzt gespeicherte Änderung, nicht den letzten Tastendruck
Nutzer-Rückfrage: „Was für ein letzter Tastendruck?" — die Formulierung
liest sich, als zähle nur Tippen. Tut es nicht: Umklappen im Diagramm
schreibt die Faltmarke in den Text (D38-Nachtrag 2) und damit in den
Speicher, nimmt also am selben Wettlauf teil. Nachgemessen mit zwei
Fenstern: A klappt zu, im Speicher steht `- > Ast A (M)`, B's Editor und
Diagramm bleiben unverändert — und B's nächster Tastendruck überschreibt
den Speicher, A's Faltung ist weg.

Beide Texte in allen neun Sprachen umformuliert (tabConflictWarn,
docLockText); der Dialogtext nennt das Falten ausdrücklich. SPEC §9 sagt
jetzt dazu, dass das andere Fenster nichts nachzieht und dass ein
Dokumentwechsel dort nicht mitwandert — `werkbaum-active` entscheidet erst
wieder, was ein Neustart öffnet (auch das eine Nutzer-Rückfrage,
nachgemessen). D94-Nachtrag 2 und CHANGELOG nachgezogen.

Benannt, nicht behoben: Wer „trotzdem hier bearbeiten" gewählt hat, behält
die Warnung, auch wenn das andere Fenster das Dokument längst verlassen
hat — dieser Ausweg fordert die Sperre bewusst nicht mehr an.

666 Tests grün; die neuen Texte im laufenden Editor nachgesehen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:21:29 +02:00
mhoennigandClaude Opus 5 7f4c2a3e6a fix(editor): der Sperr-Dialog wählt das andere Dokument im Aufklapp-Feld — die Knopfliste quetschte ihre Beschriftungen ineinander
Gemeldet aus der produktiven Instanz: „die Buttons mit den anderen
Dokumenten überlappen sich und sind unleserlich". Ursache ist eine
Flexbox-Falle, nicht die Zahl der Dokumente: Die Liste war ein
flex-Spaltenkasten mit max-height 9rem, und ihre Knöpfe tragen serienmäßig
flex-shrink 1 — statt zu scrollen, schrumpfte der Kasten sie unter ihre
eigene Textzeile. Nachgemessen bei acht Dokumenten: 14,5 px Kastenhöhe
gegen 32 px Inhalt, 17,5 px Überstand je Knopf bei 4 px Abstand.

Statt der naheliegenden Reparatur (flex-shrink 0, dann scrollt die Liste)
das vom Nutzer gewählte Aufklapp-Feld: eine Zeile hoch, unabhängig von der
Anzahl — der Dialog steckt im Editor-Panel und ist dort ohnehin knapp. Die
Kopfzeile ist jetzt ein echtes <label for>, der Platzhalter ein Strich,
die Auswahl schaltet sofort um (dieselbe Ein-Klick-Geste wie der Knopf).
Kein neuer i18n-Schlüssel.

Nachgemessen: Feld 36 px, kein Überstand, Karte 364 -> 256 px; Auswahl
schaltet um, Dialog schließt, Textfeld wird beschreibbar. D94-Nachtrag und
CHANGELOG nachgezogen; 666 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:16:58 +02:00
mhoennig 4bb9b768b0 docs: Werkbaum-Plan — 5 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #ed.docs.windows: Two windows on one storage: app and tab side by side (M)  %% docs/rfc/002-mehrfenster.md, D94
- #ed.docs.windows.keys: Every document owns its keys — text, meta, states; the index never deletes
- #ed.docs.windows.sync: The storage event keeps the list, names and tombstones current in every window
- #ed.docs.windows.lock: A per-document lock via the Web Locks API finds the one real loss case (S) :#ed.docs.windows.keys
- #ed.docs.windows.dialog: Three exits instead of continue anyway: open another, view only, edit anyway (XS) :#ed.docs.windows.lock
2026-09-02 20:10:20 +02:00
mhoennigandClaude Opus 5 e411927695 VERSION 1.2 — die Dokument-Ablage hat ein neues Format
Bewusster Bump-Commit nach D16. Anlass ist nicht die Zahl der Commits,
sondern dass sich das Format geändert hat, in dem der Editor Dokumente im
Browser hält (Schema v3, RFC 002 / D94): Text, Name und frühere Stände
liegen je Dokument unter eigenen Schlüsseln, der Index ist nur noch
Reihenfolge-Hinweis und löscht nie, Löschungen hinterlassen einen
Tombstone. Die Migration läuft einmalig beim Laden und ist idempotent;
ein Rückbau auf einen älteren Build findet die Dokumente über den Index.

Sichtbar wird das als Mehr-Fenster-Betrieb: installierte App und
Browser-Tab arbeiten nebeneinander, ohne sich gegenseitig Dokumente zu
löschen, und der modale Zwei-Fenster-Dialog (D89) ist einer Sperre je
Dokument gewichen.

Die Micro-Stelle beginnt damit wieder bei 0 (D16).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:09:51 +02:00
mhoennigandClaude Opus 5 94ee0f20e5 docs(spec): §9 — der Zeilenumbruch trennte live: von seinem Bindestrich
Der Absatz zum Mehr-Fenster-Betrieb brach nach dem Code-Span um, sodass
"`live:`\n-Dokumente" gerendert als „live: -Dokumente" dastand — der
Bindestrich sah aus wie ein Gedankenstrich am Zeilenanfang. Nur neu
umbrochen, kein Wort geändert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:08:17 +02:00
mhoennigandClaude Opus 5 da872f795c docs(changelog): die Planungszeile zum Mehr-Fenster-Betrieb entfällt — sie stand neben dem gebauten Ergebnis
Der 2026-09-02 trug beide Aussagen zur selben Sache: die vier Zeilen „geht
jetzt" und darunter noch „recorded as planned … before it is built" aus dem
RFC-Commit desselben Tages. Im Neuigkeiten-Popup (D58) liest sich das
widersprüchlich — der Leser sieht ein Feature, das zugleich fertig und
geplant ist. Die Planungszeile geht, weil das Gebaute mehr sagt; die
MCP-Planungszeile daneben bleibt stehen, die ist wirklich noch ungebaut.

Ein Test liest die ausgelieferte Datei (news.test.js), 666 Tests grün.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:07:42 +02:00
mhoennigandClaude Opus 5 caaf7c15e1 feat(editor): Mehr-Fenster-Betrieb gebaut — Ablageschema v3, Tombstones, docsync, Sperre je Dokument (RFC 002, D94)
Kein Fenster schreibt mehr den Schlüssel eines anderen: Text, Meta und
frühere Stände liegen je Dokument unter eigenen Schlüsseln, der Index ist
nur noch Reihenfolge-Hinweis und löscht nie, Löschungen hinterlassen einen
Tombstone (7 Tage). Der Voll-Flush weicht dem Dirty-Flush. Damit sind
Befund 2 und 3 des RFC weg — verschiedene Dokumente in zwei Fenstern
kollidieren gar nicht mehr. docsync.js zieht Liste, Namen, Tombstones und
den Stände-Cache aus dem storage-Ereignis nach; am aktiven Dokument die
drei Fälle umbenannt / anderswo gelöscht (behalten, bis getippt wird) /
fremd geschrieben. Der modale D89-Dialog samt Präsenz-Kanal ist ersatzlos
raus; den einen Verlustfall — dasselbe nicht-`live:`-Dokument in beiden
Fenstern vorn — findet eine Sperre per Web Locks, und das zweite Fenster
bekommt drei Auswege statt „trotzdem fortfahren".

Im Browser mit zwei echten Tabs nachgemessen (RFC §10): Fälle 1–8 grün,
Fall 1 im Vor-v3-Build gegengeprüft und dort nachweislich rot. Fall 9
deckte auf, dass reviveGoneDoc() den Index-Hinweis nicht mitschrieb — ein
durch Tippen wiederbelebtes Dokument hing bis zum nächsten Flush allein an
seinen eigenen Schlüsseln und wäre bei einem Rückbau auf einen Build vor
v3 still verlorengegangen; behoben, Gegenprobe per Mutation gezogen.
Headless 666 Tests grün. Offen bleibt die Handarbeit: PWA neben Tab,
Firefox, Safari, ein Browser ohne Locks-API.

SPEC §9, D94, D89-Nachtrag, RFC (Status, §10, Revisionsgeschichte),
CHANGELOG und Plan-Knoten #ed.docs.windows nachgezogen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 20:07:20 +02:00
mhoennigandClaude Fable 5.1 112ada4e58 docs(rfc): Mehr-Fenster-Betrieb (PWA + Tab) — RFC 002, Plan-Knoten #ed.docs.windows, D94 (revidiert D89)
Der modale Zwei-Fenster-Dialog (D89) verbietet den Fall, der funktioniert
(dasselbe geteilte Dokument in App und Tab), und schützt nicht vor dem,
wovor er warnt: Der Voll-Flush löscht Dokumente und Stände des anderen
Fensters. Entschieden: je Dokument eigene Schlüssel, Tombstones, Sperre je
Dokument per Web Locks, Dialog mit drei Auswegen. Nichts gebaut.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 12:57:22 +02:00
mhoennigandClaude Fable 5 1f186eddce docs(rfc): MCP-Server nur im Backend, kein Node als Laufzeit — dritte Runde; Hausregel: neue Technologie braucht ausdrückliche Zustimmung
Nutzer-FYI: Node.js einzuführen ist eine Dimension schwerer als eine
Backend-Abhängigkeit und muss dem Entwickler deutlich gemacht werden —
als Regel in CLAUDE.md. Aus den nachgefragten Beweggründen folgt: kein
lokaler Prozess. Der MCP-Server lebt im Backend (Streamable HTTP,
Bearer-Token), führt die Frontend-Module per GraalJS aus, jedes Werkzeug
hat eine text- und eine document-Form; das Node-Paket ist verworfen,
seine Tool-Schicht lebt als frontend/src/inspect.js, guard.js, edit.js.
Backend-Abhängigkeiten GraalJS + Spring-AI-Starter zugestimmt; der
GraalJS-Spike steht vor allem anderen. RFC neu geschrieben (§12 hält die
drei Runden fest), Plan-Teilbaum #ai.mcp neu, D93-Nachtrag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 10:04:11 +02:00
mhoennigandClaude Fable 5 62807b91a1 docs(rfc): MCP-Server — zweite Runde: Urheber im Spiegel-Commit, Streamable HTTP im Backend per GraalJS (Spike vorbehalten), Bearer-Token, nur Dokumente
Der erste Entwurf nahm an, MCP erzwinge Node; tatsächlich erzwang es nur
der Parser. Das Backend darf den HTTP-Transport tragen, wenn es die
JS-Module per GraalJS ausführt (dieselbe Technik wie #idea.drift.js) —
Kotlin ist Transport und Zugang, die Logik bleibt einmal vorhanden;
Rückfall ist der Node-Dienst hinter Apache. Urheber im Git-Spiegel:
Historie im Rumpf plus Trailer statt git --author, damit blame nicht lügt.
Entscheidungen in RFC §11 und D93 (zweite Runde).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 09:39:06 +02:00
mhoennigandClaude Fable 5 1e9cc93cb9 docs(rfc): MCP-Server für KI-Agenten — RFC 001, Plan-Knoten #ai.mcp, D93 (festgelegt, nichts gebaut)
Ein Node-Paket, das die headless-Module des Frontends unverändert
importiert (kein zweiter Parser, D14), den Plan als Ressource und Tools
anbietet (Baum, Warnungen, günstigster Pfad, Knoten-Verben) und
Änderungen als Zeilen-Diff mit Basisversion schreibt (D76); Leitplanken:
keine beschädigte Notation, kein [^] von einem Agenten. Geteiltes Dokument
und Git zugleich: nach jedem Agenten-Zug committet der Server über
pull-doc --git-commit (D88). Entscheidungen der Multiple-Choice-Runde in
RFC §11 und D93.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 09:25:02 +02:00
mhoennigandClaude Fable 5 aa6ca85bdf fix(diagram): umgeklappter Knoten behält seine Position im Bild — Scrollstand zieht nach (D38-Nachtrag 5)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 20:21:03 +02:00
mhoennigandClaude Fable 5 0fe4c07851 feat(diagram): Knoten-Fenster öffnet nur noch auf Klick, nicht mehr bei Hover (D92, SPEC §6/§9)
Der einfache Klick toggelt das Fenster überall — wie der Tipp auf Touch
(D52); der Link eines Knotens ist damit auch am Zeiger der ↗-Knopf im
Fenster, Enter und Strg+Klick öffnen die URL weiterhin direkt. Tastatur-
fokus öffnet nur noch echten (:focus-visible), focusout schließt nicht in
das Fenster hinein, und die Fokus-Rückgabe nach dem Falten ruft das
Fenster ausdrücklich nie.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 16:43:01 +02:00
mhoennigandClaude Opus 5 a223e6af57 fix(taiga): Knoten-Fenster-Knöpfe in einer Zeile — tipwide, Öffnen-Knopf in der Aktions-Zeile (D91-Nachtrag 12)
Eine gemeinsame flex-wrap-Aktions-Zeile für Schreiben/Übernehmen/Öffnen in
der Ticket-Box; mit Taiga-Knöpfen wird das Fenster auf 31rem breiter
(gemessen an den deutschen Labels), umgebrochen wird nur bei echtem
Platzmangel. Der Öffnen-Knopf heißt nur noch «{ref} öffnen» — «in Taiga»
sagen die Nachbarknöpfe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 13:01:25 +02:00
mhoennig 3984e91106 docs: Werkbaum-Plan — 1 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.link: Link an existing ticket to a node (S) :#trk.resolve.read
2026-08-28 12:48:41 +02:00
mhoennigandClaude Opus 5 1a33ebdac8 feat(taiga): Ticket verknüpfen — URL/Ref-Feld mit Betreff-Bestätigung (D91-Nachtrag 11)
Ein Knopf im Knoten-Fenster bindet ein bestehendes Taiga-Ticket an den
Knoten: Die eingefügte Ticket-URL trägt Slug, Typ und Nummer selbst; eine
nackte Nummer wird per Probe Story-dann-Task aufgelöst. Verknüpft wird erst
nach Anzeige des Betreffs; geschrieben werden Ref-Token und ggf.
&taiga.<slug> in einem Undo-Schritt, der geholte Stand füllt den
Ticket-Cache. Eine URL einer fremden Instanz wird benannt statt verknüpft.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 12:48:32 +02:00
mhoennig ce657e74c1 docs: Werkbaum-Plan — 3 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.bulk: Diverging tickets show up in the diagram (M) :#trk.resolve.read
- #trk.bulk.proxy: One request fans out into by_ref queries server-side
- #trk.bulk.mark: A diverging ref turns amber on its node
2026-08-28 11:44:42 +02:00
mhoennigandClaude Opus 5 a1e4a3bbab feat(taiga): Bulk-Abfrage und Abweichungs-Marke — das Diagramm zeigt, wo Ticket und Plan auseinanderlaufen (D91-Nachtrag 10, SPEC §9)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 11:44:33 +02:00
mhoennig e77a4d1ce4 docs: Werkbaum-Plan — 1 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.create.task: A dialog-free "create task" under a story ancestor (S) :#trk.create.tasks,#trk.resolve.read
2026-08-28 11:08:26 +02:00
mhoennigandClaude Opus 5 0ed30e9eae feat(taiga): Anlage-Knöpfe neu geschnitten — ein Story-Knopf mit Dialog, dialogfreie Task unter einem Story-Vorfahren (D91-Nachtrag 9)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 11:08:13 +02:00
mhoennig 4f6d45045a docs: Werkbaum-Plan — 1 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.write: Write the status back (M) :#trk.resolve
2026-08-27 22:20:45 +02:00
mhoennigandClaude Fable 5 323e8fe0ba feat(taiga): Status zurückschreiben — zwei Knöpfe, niemand gewinnt von selbst (D91-Nachtrag 8, SPEC §9)
Weicht der Ticket-Status von der Statusbox ab, markiert das Knoten-Fenster
die Abweichung und bietet beide Richtungen ausdrücklich an.

- „nach Taiga schreiben": Spalte des Projekts suchen (Taiga schreibt nach Id,
  die Namen sind je Projekt frei) und mit der zuletzt GELESENEN `version`
  patchen — hat jemand dazwischen geändert, lehnt Taiga ab und der Text steht
  im Fenster, statt dass etwas überschrieben wird.
- „aus Taiga übernehmen": `setStatusBox()` schreibt die Box in die Textzeile,
  undo-fähig wie jede andere Änderung.
- Schreibbar sind nur die fünf abgebildeten Zustände; `[?]`, `[!]`, `[-]` und
  der neutrale Knoten lassen das Ticket unangetastet — mit Begründung im
  Fenster.
- Proxy: zwei Spaltenlisten (`/taiga/{userstory,task}-statuses?slug=`) und
  zwei Schreib-Endpunkte (`PATCH …/{ref}/status?slug=`); die Zielspalte wählt
  der Editor, das Backend parst die Notation nicht (D14).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 22:18:52 +02:00
mhoennigandClaude Fable 5 4e6f98bbee docs: Status-Rückschreiben festgelegt — zwei Knöpfe statt einer Richtung, nur die fünf abgebildeten Zustände (D91-Nachtrag 7, SPEC §11)
Die offene Frage von #trk.write ist entschieden, gebaut ist nichts: Weicht
der Ticket-Status von der Statusbox ab, wird die Abweichung markiert und mit
zwei ausdrücklichen Aktionen angeboten — nichts geschieht von selbst.
Verworfen sind „der Text gewinnt" (schreibt selbsttätig in ein fremdes,
geteiltes System) und „Taiga gewinnt" (schriebe fortlaufend im Notationstext,
gegen D14); „Zeitstempel entscheidet" ist ohne erfundene Metadaten gar nicht
baubar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 22:00:20 +02:00
mhoennig 990632ddcf docs: Werkbaum-Plan — 1 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.resolve.read: Read title, link and status
2026-08-27 20:43:09 +02:00
mhoennigandClaude Fable 5 842e89795a feat(taiga): Ticket-Stand im Knoten-Fenster — gelesen, nie geschrieben (D91-Nachtrag 6, SPEC §9)
Wo eine Ref steht und ein `&taiga.<slug>` gilt, zeigt das Knoten-Fenster
Betreff, Status und Zuständigen des Tickets; Taigas Statusname steht neben
der Statusbox der Notation (`In progress → [~]`).

- Proxy: zwei benannte Lese-Endpunkte (`GET /taiga/userstories/{ref}` und
  `…/tasks/{ref}`, je `?slug=`) — das Präfix der Ref trägt den Typ, Taiga
  hat getrennte `by_ref`-Endpunkte. Erst `/projects/by_slug`, dann `by_ref`
  (eine Ref ist nur je Projekt eindeutig); der Slug wird kodiert angehängt.
- Die Abbildung Status → Statusbox liegt im Editor (`mapTaigaStatus`,
  headless): Statuscodes sind Notation, das Backend parst sie nicht (D14).
  Unbekannte Namen bleiben unabgebildet — Raten hieße, dem Knoten eine
  Aussage zu geben, die niemand gemacht hat.
- Geholt wird erst nach 400 ms Verweilen und je Ticket einmal je Sitzung
  (↻ holt neu); ohne Anmeldung gar nicht — der Knopf meldet erst an.
- Nichts wird geschrieben: kein Text, keine Statusbox (das bleibt
  `#trk.write`).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 20:41:21 +02:00
mhoennig e58f71bf90 docs: Werkbaum-Plan — 2 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #trk.create: Create tickets from nodes
- #trk.open: Open a ticket ref in Taiga (S) :#trk.create.ref,#not.tag.project
2026-08-27 17:30:33 +02:00
mhoennigandClaude Fable 5 eae2ff1ef0 docs: D91-Nachtrag 5 — Ref-Umbruch und Strg+Klick-Öffnen festgehalten; #trk.create bestanden, #trk.open im Plan
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 17:28:36 +02:00
mhoennigandClaude Fable 5 a22c320909 feat(editor): Strg+Klick öffnet eine Ticket-Ref in Taiga (D91, SPEC §9)
Im Text (freistehendes #US-123/#T-1234, D67-Ausschlüsse) wie auf dem
Knoten; das Knoten-Fenster trägt an Refs einen Öffnen-Knopf — der Weg
auf Touch. Adresse aus taigaWeb (/info) + &taiga.slug-Vererbung; in
einem :#…-Token gewinnt weiter der Abhängigkeits-Sprung.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 17:24:20 +02:00
mhoennigandClaude Fable 5 55cade1a65 feat(backend): /info meldet die Taiga-Web-Basis für Ticket-Links (D91)
WERKBAUM_TAIGA_WEB_URL (das Taiga-Frontend, nicht aus der API-URL
ableitbar) kommt als taigaWeb in GET /api/v1/info — ohne Schrägstrich am
Ende, fehlt unkonfiguriert. deploy-backend.sh zieht die Zeile aus der
lokalen .env idempotent in die Server-Umgebung nach.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 17:19:02 +02:00
mhoennigandClaude Fable 5 83eb6ff77f fix(diagram): Ticket-Refs im Label brechen nicht mehr am Bindestrich um (SPEC §9)
Der Browser bricht eine zu breit geratene Zeile an jedem Bindestrich —
aus #US-123 wurde #US-/123 über zwei Zeilen. Eine tref-Spanne mit
white-space:nowrap hält das Token zusammen; labelLines() (Export) misst
ihre Textknoten unverändert mit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 17:14:27 +02:00
mhoennig 3f336db680 docs: Werkbaum-Plan — 7 Knoten in Produktion
Beim Deploy der stabilen Instanz gehen diese Knoten live; SPEC §4
unterscheidet [x] fertig von [^] in Produktion (D30):

- #not.tag.project: (&taiga.slug) assigns the Taiga project, inherited
- #trk.create.proxy: Backend proxy with named endpoints
- #trk.create.login: Log in to Taiga, token stays in the browser (S) :#trk.create.proxy
- #trk.create.project: The project comes from the inherited tag (S) :#not.tag.project
- #trk.create.story: A "create story" action in the node window (S) :#trk.create.login
- #trk.create.tasks: Sub-packages become tasks, picked in a dialog (M) :#trk.create.story
- #trk.create.ref: The ref lands in the line beside the id (S) :#trk.create.story
2026-08-27 16:54:26 +02:00
mhoennigandClaude Fable 5 3ab931d50e docs: D91-Nachtrag 4 — Bau-Entscheidungen der Taiga-Anlage festgehalten
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:51:55 +02:00
mhoennigandClaude Fable 5 d1de8758b1 feat(editor): Taiga-Story und -Tasks aus dem Knoten-Fenster anlegen (D91, #trk.create)
Zwei Aktionen im Knoten-Fenster, nur wo GET /info das Feature meldet
(Lebendprobe-Muster, je Basis einmal gecacht) und nur an Knoten ohne
Ticket-Referenz — die Ref an der Zeile ist der Idempotenz-Marker.
Login-Dialog (type=password, kein window.prompt; nur das Token landet
im Browser, 401 fragt neu), Projekt-Dialog vorbelegt aus dem geerbten
&taiga.<slug>, Häkchen-Dialog nach der D91-Vorbelegung; Refs und ggf.
das Projekt-Schlagwort gehen undo-fähig als Tokens an die Zeilen
(appendToken: vor %% und vor der Fortsetzungsmarke). Regeln headless in
taiga.js (15 neue Tests); Deploy zieht TAIGA_API_URL aus der .env als
WERKBAUM_TAIGA_API_URL in die Server-Umgebung nach (Nutzerwunsch).

E2E im Browser gegen Backend + Taiga-Stub gemessen: Buttons nur ohne
Ref, Vorbelegung Kundenprojekt aus geerbtem Tag, Refs #US-/#T- an den
richtigen Zeilen, Erledigtes uebersprungen, abweichende Projektwahl
schreibt &taiga.mi-intern zurueck, Undo/Redo je Schreibzug, falsches
Passwort bleibt als Taiga-Fehlertext im Dialog.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:51:10 +02:00
mhoennigandClaude Fable 5 fd0e730656 feat(backend): Taiga-Proxy — vier schmale Endpunkte, Ziel-URL aus der Server-Konfiguration (D91, #trk.create.proxy)
API First: /taiga/auth, /taiga/projects, /taiga/userstories, /taiga/tasks
in der OpenAPI-Spec; TaigaClient/TaigaProperties in
de.werkbaum.integration.taiga. Die API-URL kommt aus
WERKBAUM_TAIGA_API_URL (nie Request-Parameter — SSRF), das Token je
Aufruf im Header X-Taiga-Token (Authorization muessen OpenAPI-Werkzeuge
als Header-Parameter ignorieren) und geht als Bearer hinaus; der Server
speichert nichts und loggt keine Request-Bodies. Taiga-4xx werden samt
_error_message durchgereicht, 5xx/Netz sind 502, unkonfiguriert 503 —
und GET /info meldet das Feature (taiga). Tests gegen aufgezeichnete
Antwortformen auf einem JDK-HttpServer-Stub (statt WireMock: keine neue
Test-Abhaengigkeit, dieselbe Zusicherung); Gegenprobe: ohne den
type-Durchreich faellt genau der benannte Test. check gruen, 93 %
Coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:33:35 +02:00
mhoennigandClaude Fable 5 5a18505571 feat(notation): Schlagworte &tag gebaut — taiga.<slug> benennt das Projekt je Teilbaum, vererbt (SPEC §1, D91)
SPEC zuerst: §1 Schritt 5b samt Block und Referenz-Regex, §11 auf
'umgesetzt' umgestellt; llms.md nachgezogen. Parser extrahiert
alleinstehende &-Token als node.marks (Zitier-Konvention gilt),
taigaSlugs() in model.js vererbt das taiga.*-Schlagwort wie die
@-Tags beim Engpass. Sichtbar im Tooltip und aria-label (a11yMarks,
9 Sprachen). Plan-Labels mit &-Erwähnungen eingeklammert; 12 neue
Tests, Gegenprobe: ohne Alleinstehend-Anker fallen genau die zwei
Zitier-Tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:20:03 +02:00