Files
ClawdDotNet/docs/Roadmap.md
T
RichardandClaude Opus 5 33d95a6c3f UI-Entwurf umgesetzt, Rocket.Chat-Tool, Deploymentcenter 2.4
Sicherungspunkt vor dem Aufraeumen. Buendelt die Arbeit, die seit dem
Abschluss der Avalonia-Portierung im Arbeitsverzeichnis lag.

Oberflaeche
- Entwurf aus Mockup/ umgesetzt: Theme.axaml (Farben je Thema, Barlow als
  mitgelieferte Schrift), Icons.axaml (Symbolgeometrien), Shell.axaml
  (eigene ControlThemes statt Fluent umzufaerben).
- Neue Steuerelemente StrokeIcon und BlueprintFrame, Seiten fuer
  Token-Verbrauch und Agenten-Chats, Werkzeug-Einstellungen als Seite
  statt eigenem Fenster, Texteditor-Fenster.
- ThemeManager mit hellem und dunklem Thema; die beiden Pinsel-Konverter
  entfallen, weil ein fester Farbwert den Themenwechsel nicht ueberlebt.

Rocket.Chat
- Neues Tool-Projekt (Client, Konfiguration, Workspace-Dateien) nach der
  Bauform des Telegram-Tools: rocketchat_poll als Tool-Job, geweckt wird
  nur, wenn wirklich etwas anliegt.
- send_file ist freigabepflichtig, send_message bewusst nicht: Der Raum
  ist Arbeitsraum, der Schutz sitzt an der Raum-Allowlist.
- Konzept-Doc um die Messung gegen die echte Instanz 8.7 ergaenzt; drei
  Annahmen waren falsch und sind korrigiert.

Deploymentcenter
- DC6 (Update anwenden) und DC7 (Erstinstallation ueber setup.json)
  erledigt, DC3 fuer win-x64/dev; deploy/publish.py als Release-Strecke.
- AppHost.DisposeAsync gegen doppeltes Herunterfahren gesperrt - sonst
  ueberschreibt eine zweite Abmeldung den Wartungszustand am Watchdog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:16:05 +02:00

309 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Roadmap
Zentrale Liste aller offenen Vorhaben. Sie löst die beiden „Vorgeschlagene
Reihenfolge"-Abschnitte in der [Bestandsaufnahme](Bestandsaufnahme-2026-07.md) und im
[Konzepte-Dokument](Konzepte-Backup-Finanz-Analyse.md) ab — die bleiben als Befund bzw.
Konzept bestehen, gepflegt wird nur noch hier.
Kürzel (S4, K2, T4, F-A1, …) verweisen auf die Bestandsaufnahme.
---
## A — Beschlossen (aus dem OpenAlice-Vergleich, Juli 2026)
Hintergrund: Konzeptvergleich mit [OpenAlice](https://github.com/TraderAlice/OpenAlice)
(AGPL-3.0 — Konzepte übernehmen ja, Code nein). Übernommen werden Taskboard,
Staging-Freigabe, Audit-Log und das Skill-Modell. Die Inbox-Idee entfällt zugunsten
der geplanten Matrix-Migration (A5).
### A1 — Taskboard
Aufgaben als Markdown-Dateien mit YAML-Frontmatter im `SharedWorkspace`:
`title`, `status` (`backlog | todo | in_progress | done | canceled`), `priority`,
`assignee`, optional `when` (`at` | `every` | `cron` **mit Zeitzone**).
- **Scanner statt Delay-Schleifen**: Ein Takt (~60 s) prüft, was fällig ist.
Persistiert werden nur Last-Fired-Marker — ein fehlgeschlagener Lauf bleibt der
einzige Versuch für diesen Termin, kein automatischer Retry-Sturm.
- **Assignee bestimmt die Ausführung**: `@new` = frischer Lauf ohne Historie,
`@<agent>` = bestehender Agent mit seinem Kontext, `@human` = wartet auf uns.
Das ersetzt das implizite `UseChatContext`-Flag (T7) durch eine explizite Angabe
am Auftrag.
- **Agenten-Tool**: `task_create`, `task_list`, `task_update`, `task_comment`.
Agent-zu-Agent-Delegation läuft künftig über Tasks statt über rekursives
`send_message`.
- **Migration**: Die improvisierten `coordination/*.md`-Dateien der Agenten
(task_*, status_*, broadcast) gehen im Taskboard auf.
**Detailbauplan** (aus dem Fünf-Repo-Vergleich, Juli 2026 beschlossen):
- Status zusätzlich mit **`in_review`**; im Frontmatter **`require_approval`**
(Task gilt erst nach Review als done) und **`acceptance`** (Abnahmekriterien,
gegen die das Ergebnis geprüft wird).
- **Task-Typen `approval` und `human_input`** — ein Mensch ist einfach ein
Assignee; seine Antwort ist das Task-Ergebnis und Input für Folgetasks.
- **Atomares Claiming**: Die DB verhindert, dass zwei Läufe denselben Task
ziehen. Der Scanner arbeitet mit **Claim-before-run** (at-most-once — ein
doppelter Tick findet den Claim bereits vergeben) und
**Startup-Reconciliation**: Beim Start wird Soll (Frontmatter) gegen Ist
(Marker/Claims) abgeglichen, verpasste Läufe werden erkannt statt still
übersprungen.
- **`blocked_by`-Abhängigkeiten** mit Auto-Dispatch: Wird der letzte Blocker
fertig, wird der wartende Task automatisch angestoßen. Meldet ein Agent einen
Blocker, fällt der Task und der Zuständige (Lead/Benutzer) wird benachrichtigt
(**Blocker-Eskalation**).
- **Reopen-/Feedback-Semantik**: Ergebnis + Kritik gehen per `task_comment` an
denselben Agenten zur Nachbesserung zurück, statt einen neuen Task von vorn
zu beginnen.
Damit erledigt oder aufgegangen:
| Punkt | Warum |
|---|---|
| F-A5 Task-Queue | das Taskboard **ist** die Queue |
| F-A4 Run-Historie | Läufe werden am Task verknüpft und persistiert |
| B8 Rekursion `send_message` | Delegation über Tasks ist strukturell zyklenfrei |
| B6 `Task.Delay`-Überlauf | Scanner-Modell kennt keine langen Delays |
| B7 Cron in Lokalzeit | Frontmatter-`when` ist zeitzonen-explizit |
| T7 `RunAsync` vs. `ChatAsync` | Assignee-Semantik beantwortet die Frage |
Verzahnung: Das Marktkalender-Flag (`onlyWhenMarketOpen`, siehe C1) gehört ins
Frontmatter, nicht in einen eigenen Mechanismus.
Konzept-Doc: [Taskboard-Konzept](Taskboard-Konzept.md) (Dateiformat,
Wahrheitsaufteilung Datei/DB, Scanner-Verhalten, Invarianten, Migration).
### A2 — Staging-Freigabe für irreversible Aktionen (F-A1 + S4)
Konzept-Doc: [Staging-Konzept](Staging-Konzept.md).
Irreversible Aktionen (Mail senden, X posten, DB-Schreibzugriff, Datei löschen,
perspektivisch Orders) werden **gestaged statt ausgeführt**: Vorschlag → Review im
Hauptfenster → Freigabe/Ablehnung. Pro Tool/Aktion konfigurierbar:
`auto | approve | deny`.
Das bisher wirkungslose `PermissionGate` (S4) wird dabei zum zentralen
Durchsetzungspunkt ausgebaut: Policy-Prüfung, Staging-Entscheidung und Audit-Hook
(A3) an einer Stelle statt ad-hoc in jedem Tool. S4 wird nicht separat bearbeitet,
sondern geht hier auf.
Ergänzungen (Juli 2026 beschlossen):
- **Plan-Freeze**: Freigegeben wird ein eingefrorener, konkreter Aufruf — Tool,
Aktion und exakte Argumente zum Zeitpunkt des Stagings. Ausgeführt wird genau
das Eingefrorene; jede nachträgliche Änderung ist eine neue Freigabe.
- **Approval-Records**: Jede Entscheidung (Freigabe wie Ablehnung) wird als
Datensatz im Audit-Log (A3) verankert — wer, wann, was, mit welchem Ergebnis.
Sicherheitswirkung: Eine Prompt-Injection (K2) kann dann nur noch einen Vorschlag
erzeugen, keine Ausführung.
### A3 — Audit-Log (F-A2)
Konzept-Doc: [Audit-Konzept](Audit-Konzept.md).
Jeder Tool-Aufruf wird protokolliert: Agent, Lauf/Session, Zeitstempel, Argumente,
Ergebnis-Status. Append-only (JSONL oder SQLite-Tabelle auf dem vorhandenen
`SqliteStorage`).
Designregeln (aus dem OpenAlice-Provenance-Konzept):
- Herkunft wird **von der Engine gestempelt**, nie vom Agenten behauptet.
- Einträge sind unveränderlich; Korrekturen sind neue Einträge.
- Unbekannte Herkunft wird als unbekannt markiert, nicht geraten.
- Worker-Typ (Modell/Engine) und verantwortliche Session sind getrennte Begriffe.
Ergänzung (Juli 2026 beschlossen) — **Receipts**: Jeder abgeschlossene Task/Lauf
erhält einen Abschluss-Beleg mit Ergebnis-Verweis, Schritten, Tokens und Kosten
(Verknüpfung `RunUsage` ↔ Task). Damit fällt C7 („Kosten pro Ergebnis")
weitgehend als Abfallprodukt ab.
Das Audit-Log ist zugleich das Fundament für das Ergebnisregister (C7) und die
Tool-Fehlerquote aus der Leistungsanalyse.
### A4 — Skill-/Toolset-Modell (ersetzt T6)
Dreischichtig statt „alles immer im System-Prompt":
1. **Dauerhafter Kern** — Identity, Soul, unveränderliche Regeln. Schlank, damit der
Prompt-Cache (T1) stabil bleibt.
2. **Nachladbare Skills/Toolsets** — fachliche Abläufe und selten genutzte Tools
werden erst auf Anforderung geladen (`list_toolsets``load_toolset`).
3. **Selbstkorrigierende Tool-Fehler** — Fehlermeldungen nennen die gültigen
Parameter/Aktionen, statt das Modell raten zu lassen.
Mechanik (Juli 2026 beschlossen, nach GoClaw-Vorbild): Skills liegen als
`SKILL.md` mit Frontmatter (`name`, `description`) im Instanz- bzw.
Agenten-Verzeichnis. Bei wenigen Skills werden die Kurzbeschreibungen inline in
den Prompt eingebettet, bei vielen gibt es stattdessen ein `skill_search`-Tool.
Änderungen an Skill-Dateien werden per Hot-Reload übernommen.
Dazu Hermes' Selbstverbesserungs-Idee: **Agenten dürfen Skills aus Erfahrung
selbst schreiben** (das AgentEditor-Tool ist die Vorstufe). Wichtig: Ein Skill
ist Prompt-Input — agentengeschriebene Skills werden erst nach Freigabe (A2)
aktiv, sonst wäre das ein Injection-Kanal in künftige Läufe.
### A5 — Matrix/Element-Migration
Beschlossene Richtung: Die Kommunikation (Benachrichtigungen, Berichte, Chat mit
Agenten) wird auf Element/Matrix umgestellt.
- Ersetzt die im OpenAlice-Vergleich erwogene Inbox — Berichte landen in
Matrix-Räumen.
- Der Tool-Kandidat **Notify** entfällt und geht hierin auf.
- Betroffen: Telegram-Tool (Rolle klären), WebView-Chat (bleibt er Haupt-UI?),
Streaming K4 (Matrix streamt nicht — nach dieser Entscheidung neu bewerten).
Scope ist noch unbestimmt — braucht ein eigenes Konzept-Doc, bevor es in die
Reihenfolge eingeordnet wird.
### A6 — MySQL-Replikations-Spiegel (optional)
Beschlossen Juli 2026. **SQLite bleibt die einzige Wahrheit** — gearbeitet wird
ausschließlich auf der Instanz-DB. MySQL ist ein reiner, nachgelagerter Spiegel:
Er empfängt nur INSERT/UPDATE/DELETE vom Replikator; die App liest im Betrieb
**nie** daraus. Einziger Lesezweck: Wiederherstellung, falls die SQLite korrupt
ist — daneben steht der Spiegel externen Auswertungen (Dashboards, Ad-hoc-SQL)
offen, ohne die Agenten-Maschine zu berühren.
Leitplanken:
- **Outbox-Muster** an der vorhandenen Schreib-Warteschlange von `SqliteStorage`:
Replikations-Einträge lokal puffern, idempotente Upserts nach MySQL.
Nie blockierend — ist MySQL nicht erreichbar, staut die Outbox und holt auf.
- Mehrere Instanzen replizieren in denselben Spiegel; Zeilen tragen `instance_id`.
- **Restore-Pfad (Spiegel → frische SQLite) muss existieren und getestet sein** —
gleiche Regel wie beim Backup: ein ungeprüftes Restore ist eine Vermutung.
- Kein Koordinationspunkt: Claiming, Locks, Taskboard-Zustand bleiben lokal.
Die Regel „nur der Replikator schreibt, niemand liest im Betrieb" gehört ins
Konzept-Doc.
- Sicherheit: TLS zur Datenbank, Zugangsdaten über `SecretProtector`;
Output-Scrubbing der Tool-Ergebnisse wird wichtiger, weil Kontext-Daten
künftig auch im Spiegel liegen.
- Ergänzt das ZIP-Backup, ersetzt es nicht — Identity/Soul, Settings, Workspace
und Telegram-Session bleiben Sache des Instanz-Backups.
**Voraussetzung — Historie-Umzug:** `ChatHistory.json` zieht in die Instanz-DB um
(aktive Tabelle + Archiv-Tabelle mit FTS5-Volltextindex und `history_search`-Tool,
siehe K6 in Abschnitt B). Das löst
nebenbei B10 (O(n²)-Schreiblast) und gibt K6 seine Form; erst danach schützt der
Spiegel auch die Historie. Zeitlich passt A6 zu dem Server, der ggf. mit A5
(Matrix) ohnehin dazukommt.
---
## B — Offen aus der Bestandsaufnahme
| Punkt | Was | Stand |
|---|---|---|
| T4 | Proaktiv statt reaktiv kompaktieren | offen, unverändert |
| K2-Rest | Untrusted Content als Daten rahmen (`<untrusted_content>`) | A2 nimmt die Schärfe; die Rahmung selbst bleibt nötig |
| K4 | Streaming | **zurückgestellt** bis A5 entschieden ist |
| K6 | Historie **archivieren + durchsuchbar machen** (FTS5-Index, `history_search`-Tool) statt nur rotieren | beschlossen; Teil des Historie-Umzugs (Voraussetzung von A6) |
| Memory-Flush vor Compaction | Bevor der ContextCompactor zusammenfasst, bekommt der Agent ein eng begrenztes Fenster, Dauerhaftes per `memory_store` zu sichern — sonst wirft die Compaction Wissen weg | beschlossen (GoClaw-Muster) |
| Memory-Auto-Injection | Relevante Memory-Abstracts werden automatisch eingeblendet (Relevanzschwelle, Deckel ~200 Tokens), **in die Nutzernachricht, nie in den System-Prompt** (Prompt-Cache T1) | beschlossen; löst den offenen Punkt „Automatische Einblendung" im [Memory-Konzept](Memory-Konzept.md) |
| Output-Scrubbing | Bekannte Secret-Werte (Register des `SecretProtector`) werden zentral aus **allen** Tool-Ergebnissen maskiert, bevor sie in Kontext, Historie oder Spiegel (A6) gelangen | beschlossen; schließt die Lücke, die S3 nur für URLs schloss |
| Hygiene-Paket | B9 (`index_Count`-Race), B11/T8 (`max_tokens` setzen), B13 (`instanceId`-Inkonsistenz), F-A6-Rest (UI zum Setzen/Rotieren der Secrets) | Kleinbugs, in einem Aufwasch. B10 geht im Historie-Umzug (A6) auf |
Erledigt seit der letzten Fortschreibung: B4 vollständig (Preise kommen live vom
`/models`-Endpunkt, unbekannte Modelle werden sichtbar gemeldet).
### B-DC — Deploymentcenter-Anbindung
WatchDog und LicenseLabrador sind durch das
[Deploymentcenter](Deploymentcenter-Integration.md) ersetzt: eine Adresse, ein Token,
und dazu Update-Prüfung, Fehler-Stream und Bugtracker. Watchdog läuft wieder pro
Instanz (ein Monitor je Instanz, mit Gesundheitsprüfungen und angekündigtem Ende).
Offen:
| Punkt | Was | Bemerkung |
|---|---|---|
| DC1 | Oberfläche „Fehler melden" | Client vorhanden, Schaltfläche fehlt |
| DC2 | Agenten-Tool für den Bugtracker | macht den Claim/Lease-Workflow des Deploymentcenters nutzbar |
| DC3 | Release-Strecke | **erledigt für win-x64/dev** ([`deploy/publish.py`](../deploy/publish.py), 0.1.1 veröffentlicht). Offen: `linux-x64` nach der Avalonia-Portierung, `prod` |
| DC4 | SDK als Git-Submodul unter `external/` statt Cross-Repo-Pfad | betrifft auch die CI |
| DC5 | Betreiber: Evaluator-Cron einrichten, Token ausstellen, `parent_source` pflegen | **ohne den Cron ist die Überwachung wertlos** |
| DC6 | Update anwenden statt nur melden | **erledigt.** Agent liegt im Paket (Prüfsumme geprüft), Rückfrage in der Oberfläche, geordnetes Herunterfahren vor dem Agentenstart, `maintenance` an den Watchdog |
| DC7 | Erstinstallation über `--action install` + `setup.json` | **erledigt.** Setup-Kette live durchgespielt (Login, Katalog, Token mit Rechteschranke), Round-Trip SDK-Writer → SettingsManager trägt. `fileWindows`/`fileLinux` gesetzt |
| DC8 | Signaturpflicht (`--require-signature`) | Schlüssel steht, ab 0.1.2 wird signiert, Prüfung beidseitig getestet. **Blockiert:** `LaunchUpdateAgent` reicht den Schalter nicht durch — aus der Anwendung heraus nicht erzwingbar (gemeldet) |
Details: [Deploymentcenter 2.22.4 Integrationsplan](Deploymentcenter-2.4-Integrationsplan.md).
Der Zugangsschutz aus 2.4 (Lizenzschlüssel als Basic-Auth-Zugang zur Release-Ablage) ist
bereits umgesetzt — er muss im **ersten** veröffentlichten Release enthalten sein.
---
## C — Offen aus dem Finanz-/Analyse-Konzept
Punkte 12 von dort (atomares Schreiben, Backup/Restore inkl. UI) sind umgesetzt.
| # | Was | Bemerkung |
|---|---|---|
| C1 | Marktkalender (`onlyWhenMarketOpen` + `MarketCalendar`-Tool) | Scheduler-Teil gehört ins Taskboard-Frontmatter (A1) |
| C2 | `Indicators`-Tool — deterministische Berechnung | Qualität hoch, Tokens runter |
| C3 | Datenaktualität erzwingen (`maxAgeSeconds`) | |
| C4 | Termine & Fundamentaldaten (Earnings, EDGAR, Wirtschaftskalender) | |
| C5 | Bestandsregister (Positionen) | Grundlage für C7/C8 |
| C6 | Nachrichten-Entdopplung (`SeenItems`) | |
| C7 | Ergebnisregister (Stufe 2, „Kosten pro Ergebnis") | fällt weitgehend aus den A3-Receipts ab |
| C8 | Falsifizierbare Aussagen + Auflösung, Brier-Score (Stufe 3) | braucht C5, C7 und einen Auflösungs-Task (A1) |
---
## D — Toolkandidaten (unbeschlossen)
WebSearch, Http (generisch mit Allowlist), Shell (sandboxed), Git, Vision.
Notify ist gestrichen — geht in A5 auf.
---
## Vorgeschlagene Reihenfolge
| # | Vorhaben | Begründung |
|---|---|---|
| 1 | A1 Taskboard | Fundament; löst sechs bestehende Punkte auf einmal |
| 2 | A3 Audit-Log | klein, sofort nützlich; muss vor A2 da sein, damit Freigaben protokolliert werden |
| 3 | A2 Staging-Freigabe | größter Sicherheitsgewinn; Voraussetzung für unbeaufsichtigten Betrieb |
| 4 | C1 Marktkalender | spart sofort Kosten; nutzt A1-Frontmatter |
| 5 | A4 Skills/Toolsets | Token-Hebel, Cache-stabil |
| 6 | C2 Indicators | Qualität + Kosten |
| 7 | C7 + C8 Ergebnisregister, Aussagen | das eigentliche Leistungsmaß; braucht A3 |
| — | Hygiene-Paket (B) | zwischendurch, unabhängig |
| — | Historie-Umzug in die Instanz-DB | löst B10 + K6; Voraussetzung für A6 |
| — | A6 MySQL-Spiegel | nach dem Historie-Umzug; natürliches Zuhause auf dem A5-Server |
| — | A5 Matrix | eigenes Konzept-Doc zuerst; Scope klären, dann einordnen |
Leitlinie der Reihung: erst Nachvollziehbarkeit und Kontrolle (Audit, Staging),
dann Fähigkeiten — ein Agent, der unbeaufsichtigt läuft, braucht zuerst Bremsen,
dann PS.
---
## Umsetzung mit Opus 4.6 — Einstufung
Die Entwicklung erfolgt mit Opus 4.6. Die meisten Vorhaben sind damit gut
machbar, sofern die hier notierten Vorgaben mitgegeben werden. Zwei Stellen
berühren Nebenläufigkeits-Invarianten bzw. Engine-Querschnitte — sie sind für
Opus 5 / Fable markiert oder durch eine Architektur-Vorgabe entschärft.
| Vorhaben | Einstufung | Vorgabe / Begründung |
|---|---|---|
| A1: Dateiformat, Frontmatter-Parsing, `task_*`-Tool, Migration | 4.6 | klar spezifizierbar, gut testbar |
| A1: **Scanner-Kern** (atomares Claiming, Auto-Dispatch, Reconciliation) | ⚠️ **Opus 5 / Fable** | At-most-once-Semantik, Claim-CAS und das Zusammenspiel mit den seit B2 serialisierten Chat-Läufen sind genau die Fehlerklasse, die hier schon einmal schiefging. Falls doch 4.6: erst Konzept-Doc, Umsetzung strikt dagegen, Property-Tests für die Invarianten („nie zwei Claims auf einen Task", „kein Dispatch bei offenem Blocker", „doppelter Tick = ein Lauf") |
| A2: Gate, Policy, Staging-Queue, Review-UI, Approval-Records | 4.6 | mit der folgenden Architektur-Vorgabe |
| A2: **Fortsetzung nach Freigabe** | 4.6 nur mit Vorgabe | **Kein pausierter, im Speicher gehaltener Lauf.** Vorgabe: Der Lauf endet beim Staging regulär — das Tool liefert „zur Freigabe vorgelegt" als Ergebnis, der Agent schließt ab. Die Freigabe erzeugt einen Folge-Task (A1), der den Agenten mit dem **eingefrorenen** Aufruf weckt. Echtes Suspend/Resume eines laufenden `ChatAsync` wäre Fable-Terrain — und ist mit dieser Vereinfachung unnötig |
| A3: Audit-Log + Receipts | 4.6 | append-only, klares Schema, keine Nebenläufigkeitsfallen |
| A4: Skills | 4.6 | `FileSystemWatcher` mit Debounce (~500 ms); agentengeschriebene Skills erst nach Freigabe aktiv (siehe A4) |
| Memory-Flush vor Compaction | 4.6 mit Anleitung | Harte Grenzen: max. 35 Schritte, einziges Tool `memory_store`, Timeout, günstiges Modell (wie T3), höchstens einmal je Compaction-Zyklus. Vorsicht: Der ContextCompactor hatte B1/B14 — die bestehenden Paarungs-Tests müssen unverändert grün bleiben |
| Memory-Auto-Injection | 4.6 | in die Nutzernachricht, nie in den System-Prompt (sonst verfällt der Prompt-Cache T1); Deckel ~200 Tokens |
| Output-Scrubbing | 4.6 | ein zentraler Filter an der Stelle, wo Tool-Ergebnisse in den Kontext gelangen (`ExecuteToolCallAsync`); Werte aus dem Secret-Register |
| Historie-Umzug + FTS5 + `history_search` | 4.6 | Migration nur nach frischem Backup; alte JSON-Dateien erst nach verifiziertem Import löschen |
| A6: MySQL-Spiegel | 4.6 mit Anleitung | Outbox mit Wasserzeichen, idempotente Upserts, nie blockieren; der getestete Restore-Pfad ist Teil der Definition of Done |
| C1 Marktkalender, C2 Indicators | 4.6 | reine Fachlogik, deterministisch testbar |
Generell: Neue Subsysteme (Scanner, Staging, Audit, Replikator) kommen mit Tests
nach der [Teststrategie](Teststrategie.md) — die Invarianten-Tests sind bei den
markierten Punkten kein Nice-to-have, sondern die Absicherung dafür, dass ein
schwächeres Modell sie umsetzen darf.