# AUTH.3D — HUMAN DELETE APPROVAL AUTHENTICITY **Status:** SECURITY DESIGN + CODE + ISOLATED TESTS + REVIEW ONLY (KEIN produktives Deployment) **Datum:** 2026-08-27 **Mission Type:** SECURITY DESIGN + CODE + ISOLATED TESTS + REVIEW ONLY **Baseline:** AUTH.1 (40bbc40) + AUTH.2 (edcb4902) + AUTH.3A (a11c1bb) + AUTH.3B + AUTH.3C = COMPLETE > ⚠️ Dies ist ein **Design + Code + Test-Dokument**. Es wird KEIN produktives > Deployment ausgeführt, kein echter Signing Key erzeugt, kein Christians Private > Key erzeugt, kein echter Public Key deployed, keine ENV geändert, kein Container > erstellt, kein Executor deployed, keine produktive SAVE/DELETE-Probe. Bei Zweifel: > FAIL CLOSED + HARD STOP. --- ## 1. CURRENT APPROVAL FLOW (Phase 1) — rekonstruiert (READ-ONLY) ### 1a. Vollständiger Flow ``` Delete Request → State Machine → Approval Creation → Approval Persistence → DeleteExecutor → Approval Validation → Tolaria DELETE → Ledger/Consumption ``` 1. **Delete Request:** Ein Forgejo-Commit enthält einen DELETE-ObjectChange (`operation == OP_DELETE_REQUEST`). 2. **State Machine:** Commit wird in C5-State-Machine verarbeitet (C5AStore, c5a.db). 3. **Approval Creation:** `cmd_c5_delete_approve` (CLI, rq_c5_cli.py Z.355) → `store.create_delete_approval()`. 4. **Approval Persistence:** SQLite-Tabelle `delete_approvals` (c5a.db). 5. **DeleteExecutor:** `cmd_c5_delete_execute` (CLI, Z.424) → `DeleteExecutor.execute()`. 6. **Approval Validation:** `_validate_approval()` (rq_c5_delete.py Z.105) — Invarianten D/E/F/I. 7. **Tolaria DELETE:** `_do_delete()` → `client.delete()`. 8. **Ledger/Consumption:** `mark_delete_approval_used()` → `approval_status='USED'`, Commit → ST_UPDATING_SEARCH. ### 1b. Wer kann Approval heute erzeugen? - **NUR der CLI-Befehl `approve-delete`** (`cmd_c5_delete_approve`). Kein Code erzeugt Approval automatisch (Invariante B/C). - **Jeder, der die CLI im RQ-Container ausführen kann** (User `hermes`), kann eine Approval erzeugen. - **`approved_by` ist ein frei wählbares CLI-Argument** (Default `human:christian`). **KEINE kryptographische Bindung an Christian.** ### 1c. Exakte Felder (DB-Tabelle `delete_approvals`) | Feld | Typ | Bedeutung | |---|---|---| | `approval_id` | TEXT (uuid4) | Eindeutige ID | | `workflow_commit` | TEXT | Commit-Binding | | `object_change_id` | INT | ObjectChange-Binding | | `object_id` | TEXT | Objekt-Binding | | `path` | TEXT | Pfad-Binding | | `operation` | TEXT | 'DELETE' | | `approval_status` | TEXT | APPROVED/USED/REVOKED | | `approved_by` | TEXT | **frei wählbar** (Default human:christian) | | `approval_nonce` | TEXT (uuid4) | Nonce (kryptographisch zufällig, aber NICHT signiert) | | `approved_at` | INT (ms) | Zeitpunkt | | `used_at` | INT (ms) | Single-Use-Zeitpunkt | ### 1d. Bestehende Bindings (im Code verifiziert) - **Object-Binding:** `_validate_approval` Z.143 — `approval.object_id == oid` (Invariante E). - **Commit-Binding:** Z.136 — `approval.workflow_commit == commit_sha` (Invariante F). - **Path-Binding:** Z.150 — `approval.path == path` (Invariante I). - **Operation-Binding:** `create_delete_approval` setzt `operation='DELETE'` fest. - **Nonce:** `approval_nonce` = uuid4, aber **nicht signiert, nicht verifiziert**. - **Single-Use:** `mark_delete_approval_used` → `approval_status='USED'`; `_validate_approval` prüft `approval_status == 'APPROVED'`. - **Mission-Binding:** **FEHLT** — kein `mission_id`-Feld. - **Provenance-Binding:** **FEHLT** — kein `expected_provenance_hash`-Feld. - **Expiry:** **FEHLT** — kein `expires_at`-Feld. - **Actor-/Identity-Information:** `approved_by` (frei wählbar). - **Authentizitätsprüfung:** **KEINE** — es gibt keine kryptographische Prüfung, dass die Approval von Christian stammt. ### 1e. Kernbefund **HUMAN_APPROVAL_AUTHENTICITY_GAP = OPEN.** Die Approval ist eine reine DB-Zeile mit frei wählbarem `approved_by`. Jeder mit CLI-/DB-Zugriff (RQ/Hermes, User `hermes`) kann eine syntaktisch perfekte Approval erzeugen. Es gibt **keine kryptographische Bindung an Christian**. → DELETE_OPERATION_ACTIVATION bleibt BLOCKED. --- ## 2. THREAT MODEL (Phase 2) > ⚠️ NUR ANALYSE. FAIL CLOSED. | Threat | CURRENT_PROTECTION | CURRENT_GAP | TARGET_CONTROL | FAIL_CLOSED_BEHAVIOR | |---|---|---|---|---| | **T1 RQ erzeugt selbst Approval** | CLI-Zugriff (User hermes) | RQ kann `approve-delete` ausführen | RQ besitzt keinen Signing Key → kann keine gültige signierte Approval erzeugen | DELETE_DENIED | | **T2 Hermes erzeugt selbst Approval** | Gleiche Boundary wie RQ | Hermes kann CLI ausführen | Hermes besitzt keinen Signing Key | DELETE_DENIED | | **T3 Rain erzeugt Approval** | Separater Container | Rain hat keinen CLI-Zugriff auf c5a.db | Rain besitzt keinen Signing Key | DELETE_DENIED | | **T4 SAVE Executor erzeugt Approval** | Separater Container (AUTH.3C) | Kein CLI-Zugriff auf c5a.db | SAVE Executor besitzt keinen Signing Key | DELETE_DENIED | | **T5 DELETE Executor erzeugt Approval** | Separater Container (AUTH.3C) | Kein CLI-Zugriff auf c5a.db | DELETE Executor ist **verify-only**, besitzt keinen Signing Key | DELETE_DENIED | | **T6 Agent verändert gespeicherte Approval** | DB-Zugriff | DB-Zeile kann geändert werden | Signatur über Payload → Änderung invalidiert Signatur | DELETE_DENIED | | **T7 Agent verändert Object nach Approval** | Object-Binding (E) | Nur DB-Vergleich, nicht kryptographisch | Object im signierten Payload → Änderung invalidiert Signatur | DELETE_DENIED | | **T8 Agent verändert Commit nach Approval** | Commit-Binding (F) | Nur DB-Vergleich | Commit im signierten Payload | DELETE_DENIED | | **T9 Agent verändert Path nach Approval** | Path-Binding (I) | Nur DB-Vergleich | Path im signierten Payload | DELETE_DENIED | | **T10 Approval wird kopiert** | approval_id uuid4 | Kopie ist gültig (keine Signatur) | Signatur + Single-Use → Kopie hat gleiche Signatur, aber Nonce/consumed | DELETE_DENIED (Replay) | | **T11 Approval wird wiederverwendet** | Single-Use (USED) | Nur DB-Status | Signatur + consumed-check | DELETE_DENIED | | **T12 Approval wird zwischen Missions übertragen** | Kein mission_id | Kein Mission-Binding | mission_id im signierten Payload | DELETE_DENIED | | **T13 alte Approval nach State Change** | Commit-Status-Check (Gate 2) | Nur DB-Status | State-Check + Signatur | DELETE_DENIED | | **T14 Nonce wird wiederverwendet** | uuid4 | Nonce nicht signiert/verifiziert | Nonce im signierten Payload + consumed-check | DELETE_DENIED | | **T15 DB-Eintrag wird manipuliert** | — | DB-Zeile allein erzeugt gültige Approval | Signatur → DB-Forgery ohne Private Key unmöglich | DELETE_DENIED | | **T16 Approval aus Backup wiederhergestellt** | — | Backup enthält gültige Approval | Signatur + consumed-check + expires_at | DELETE_DENIED | | **T17 Approval nach Executor-Restart erneut verwendet** | Single-Use (USED) | Nur DB-Status | consumed-check + Signatur | DELETE_DENIED | | **T18 Race zwischen Verify und Delete** | — | TOCTOU-Fenster | Atomare Reservation (RESERVED) | DELETE_DENIED | | **T19 LLM erzeugt syntaktisch perfekte Fake-Approval** | — | Keine Signatur | Signatur → LLM ohne Private Key kann nicht signieren | DELETE_DENIED | | **T20 kompromittierter RQ-Prozess versucht Approval-Bypass** | — | RQ kann CLI ausführen | RQ besitzt keinen Signing Key | DELETE_DENIED | **Kern-Gap:** Alle Bindings (Object/Commit/Path) sind nur DB-Vergleiche, nicht kryptographisch. `approved_by` ist frei wählbar. **Es fehlt eine kryptographische Bindung an Christian.** --- ## 3. HUMAN IDENTITY ROOT (Phase 3) — Optionen > ⚠️ NUR BEWERTUNG. KEINE Keys erzeugen. | Option | HUMAN_AUTH | LLM_CAN_FORGE | RQ_CAN_FORGE | DELETE_EXEC_CAN_FORGE | PRIVATE_SECRET_EXPOSURE | REPLAY_RES | AUDIT | ROTATION | REVOCATION | BACKUP_RISK | OP_COMPLEXITY | STACK_COMPAT | OFFLINE_RECOVERY | |---|---|---|---|---|---|---|---|---|---|---|---|---|---| | **A: HMAC (geteiltes Secret)** | Mittel | Nein (ohne Secret) | Nein (ohne Secret) | Nein (verify-only) | **Hoch** (Secret muss bei Verifier liegen) | Mittel | Mittel | Ja | Ja | Mittel | Niedrig | Hoch | Ja | | **B: Asymmetrisch (Ed25519)** | **Hoch** | **Nein** | **Nein** | **Nein** (verify-only) | **Niedrig** (nur Public Key bei Verifier) | **Hoch** | **Hoch** | Ja | Ja | Niedrig | Mittel | **Hoch** (Python stdlib/cryptography) | Ja | | **C: Forgejo-signiertes Artefakt** | Mittel | Nein | Nein | Nein | Mittel (Key bei Forgejo) | Mittel | Hoch | Ja | Ja | Mittel | Hoch | Hoch | Mittel | | **D: Separater Approval-Service** | Hoch | Nein | Nein | Nein | Niedrig | Hoch | Hoch | Ja | Ja | Niedrig | **Hoch** (neue Infrastruktur) | **Niedrig** | Mittel | | **E: Telegram + kryptogr. Bindung** | Mittel | Nein | Nein | Nein | Mittel | Mittel | Mittel | Ja | Ja | Mittel | Mittel | Hoch | Ja | | **F: Andere minimal sichere** | — | — | — | — | — | — | — | — | — | — | — | — | — | **Bewertung:** - **OPTION B (Ed25519 asymmetrisch)** ist die **stärkste und stack-kompatible** Lösung: Christian besitzt den Private Key, der DELETE Executor kennt nur den Public Key. **LLM/RQ/SAVE/DELETE-Executor können ohne Private Key nicht signieren.** Python `cryptography`-Bibliothek (oder `pynacl`) unterstützt Ed25519 nativ. - **OPTION A (HMAC)** ist schwächer: das geteilte Secret müsste beim Verifier liegen, was die Exposure-Fläche vergrößert. Nicht bevorzugt. - **OPTION C (Forgejo-signiert)** ist möglich, aber komplexer und bindet an Forgejo. - **OPTION D (separater Service)** erfordert neue Infrastruktur → Scope-Creep. - **OPTION E (Telegram)** allein ist KEIN kryptographischer Proof (siehe §7). **Empfehlung: OPTION B (Ed25519 asymmetrisch).** --- ## 4. PREFERRED SECURITY PROPERTY (Phase 4) **Bevorzugte Eigenschaft (bestätigt):** - **Christian:** PRIVATE KEY (Ed25519) - **DELETE Executor:** PUBLIC KEY ONLY (verify-only) - **RQ/Hermes:** NO PRIVATE KEY - **SAVE Executor:** NO PRIVATE KEY - **Rain:** NO PRIVATE KEY - **Tolaria:** NO PRIVATE KEY **Gegen reale Architektur bewertet:** - Python `cryptography`/`pynacl` ist im Stack verfügbar (C5-Caller sind Python). - Keine neue Infrastruktur nötig. - Der DELETE Executor kann eine Approval **verifizieren**, aber **nicht erzeugen**. - **Bestätigt als bevorzugte Lösung.** --- ## 5. APPROVAL PAYLOAD (Phase 5) — kanonisch ### Kanonischer Payload ```json { "approval_version": 1, "approval_id": "", "mission_id": "", "delete_request_id": "", "operation": "DELETE", "object_id": "", "vault_path": "", "expected_commit": "", "expected_provenance_hash": "", "nonce": "", "issued_at": "", "expires_at": "" } ``` ### Canonicalization - **CANONICALIZATION:** Deterministische Serialisierung: Felder in fester Reihenfolge (wie oben), keine Duplikate, keine Whitespace-Varianz, UTF-8, keine Unicode-Normalisierung (exakte Bytes), Pfad-Normalisierung (kein `./`, kein `..`, keine doppelten Slashes). - **ENCODING:** UTF-8, JSON ohne optionale Felder (nur die 12 Pflichtfelder). - **HASH:** SHA-256 über den kanonisierten Payload-Bytes. - **SIGNATURE_INPUT:** Die kanonisierten Payload-Bytes selbst (nicht der Hash) werden signiert (Ed25519 signiert intern den Hash). Keine Signatur über frei formatierte Texte. --- ## 6. APPROVAL SIGNATURE (Phase 6) — Ed25519 - **SIGNATURE_ALGORITHM:** **Ed25519** (RFC 8032), via Python `cryptography` oder `pynacl`. - **PRIVATE_KEY_OWNER:** Christian (einziger Besitzer). - **PRIVATE_KEY_LOCATION:** Christians vertrauenswürdiges Gerät (NICHT im Stack). - **PUBLIC_KEY_LOCATION:** DELETE Executor-Konfiguration (read-only, injiziert via Secret/File). - **KEY_ID:** SHA-256-Hash des Public Keys (kurz, zur Key-Identifikation). - **SIGNATURE_FORMAT:** Ed25519-Signatur (64 Bytes), Base64-URL-encoded. - **VERIFICATION:** `verify(public_key, canonical_payload_bytes, signature)`. - **ROTATION:** Neuer Key → neue KEY_ID; alte Approvals mit altem Key bleiben bis Expiry gültig (Multi-Key-Transition). - **REVOCATION:** Key-Revocation-Liste (KEY_ID → revoked); verifier prüft. - **MULTI_KEY_TRANSITION:** Verifier akzeptiert mehrere Public Keys (aktuelle + vorherige), markiert ältere als "transitioning". **Private Key darf NICHT liegen in:** RQ ENV, Hermes ENV, Rain ENV, SAVE Executor, DELETE Executor, Forgejo Repo, C5 DB, Tolaria, Logs, Reports. --- ## 7. APPROVAL CREATION CHANNEL (Phase 7) > ⚠️ NUR DESIGN. KEINE Implementierung in AUTH.3D (nur Code + Tests). ### Modelle | Modell | UX | Sicherheit | Stack-Kompatibilität | |---|---|---|---| | **A: Lokales Signing Tool auf Christians Gerät** | Mittel (Christian signiert manuell) | **Hoch** (Private Key nie im Stack) | Hoch (Python-Skript) | | **B: Separater Approval-Container/Service** | Niedrig | Hoch | **Niedrig** (neue Infrastruktur) | | **C: Telegram Approval → separater Signer** | Hoch | Mittel (Signer muss getrennt sein) | Mittel | | **D: Forgejo Workflow** | Mittel | Mittel | Hoch | | **E: Anderer sicherer Kanal** | — | — | — | **Empfehlung: OPTION A (lokales Signing Tool auf Christians Gerät).** Christian erzeugt den kanonischen Payload (aus dem Delete-Request), signiert ihn mit seinem Private Key, und übergibt die signierte Approval (Payload + Signatur + KEY_ID) an den DELETE Executor (via CLI/Inbox). Der Executor verifiziert mit dem Public Key. **WICHTIG (strikte Unterscheidung):** - **HUMAN_INTENT:** Ein Telegram-Text "Ja"/"Approve"/"Delete" ist NUR Intent, KEIN kryptographischer Proof. - **CRYPTOGRAPHIC_APPROVAL_ARTIFACT:** Die signierte Approval (Payload + Signatur) ist der einzige gültige Proof. - RQ darf NICHT aus einem Telegram-Text den finalen Approval-Datensatz erzeugen können (ohne Christians Private Key). --- ## 8. APPROVAL VERIFICATION (Phase 8) **DeleteExecutor MUSS VOR DELETE prüfen (alle, sonst DELETE_DENIED):** 1. Schema gültig (kanonischer Payload) 2. Unterstützte Approval-Version 3. Signatur gültig (Ed25519, Public Key) 4. Key nicht revoked 5. Operation == DELETE 6. Mission stimmt 7. Delete Request stimmt 8. Object stimmt 9. Path stimmt 10. Commit stimmt 11. Provenance stimmt 12. Nonce stimmt 13. issued_at plausibel (nicht in der Zukunft) 14. expires_at nicht überschritten 15. Approval noch nicht consumed 16. State erlaubt Delete 17. kein Replay 18. kein Cross-Object-Reuse 19. kein Cross-Mission-Reuse **Jeder Fehler → DELETE_DENIED. KEIN Tolaria HTTP DELETE.** --- ## 9. TOCTOU / RACE SAFETY (Phase 9) - **VERIFY → STATE CHANGE → DELETE:** Zwischen Verification und Mutation gibt es ein Fenster. - **Lösung:** Atomare **Reservation** in der DB: Approval-Status `APPROVED → RESERVED` (mit `execution_attempt_id` + `idempotency_key`) in einer SQLite-Transaktion, BEVOR der Tolaria-DELETE ausgeführt wird. Nur eine Reservation pro Approval möglich. - **DB Transaction:** `UPDATE ... SET approval_status='RESERVED' WHERE approval_status='APPROVED'` — atomar, nur wenn noch APPROVED. - **Crash before delete:** Approval bleibt RESERVED → Recovery: prüfen, ob DELETE tatsächlich ausgeführt wurde (Read-Back). Wenn nicht → zurück zu APPROVED (oder neuer Attempt mit neuem idempotency_key). - **Crash after delete before ledger:** Read-Back zeigt Ziel absent → Ledger nachtragen, Approval → CONSUMED. - **Retry:** Idempotenz via `idempotency_key` — gleicher Attempt wird nicht doppelt ausgeführt. - **Uncertain network result:** **DELETE_OUTCOME_UNKNOWN** — der Executor darf bei Unsicherheit NICHT blind wiederholen. Er meldet OUTCOME_UNKNOWN und wartet auf manuelle Klärung (Read-Back). **Recovery State für DELETE_OUTCOME_UNKNOWN:** Approval bleibt RESERVED; ein manueller Read-Back entscheidet, ob CONSUMED (Ziel absent) oder zurück zu APPROVED (Ziel noch da). --- ## 10. SINGLE USE (Phase 10) **Approval Lifecycle:** ``` CREATED → VERIFIED → RESERVED → EXECUTED → CONSUMED ``` | Zustand | Verhalten | |---|---| | **INVALID** | DELETE_DENIED (Signatur/Binding-Fehler) | | **EXPIRED** | DELETE_DENIED (expires_at überschritten) | | **REVOKED** | DELETE_DENIED (Key oder Approval revoked) | | **FAILED** | DELETE_DENIED (Execution-Fehler) | | **OUTCOME_UNKNOWN** | Kein blinder Retry; manuelle Klärung | **Eine Approval darf nach CONSUMED niemals erneut ausführbar sein.** Der consumed-check ist Teil der Verification (§8, Punkt 15) und der Reservation (§9). --- ## 11. STORAGE (Phase 11) **Was wird gespeichert:** - Payload (kanonisch) - Signature (Ed25519, Base64-URL) - Public Key ID (KEY_ID) - Verification Result (PASS/DENIED + Reason) - consumed_at - execution_attempt (attempt_id, idempotency_key) - Result (DELETE_OK / DELETE_OUTCOME_UNKNOWN / DELETE_DENIED) **Was wird NICHT gespeichert:** - Private Key - Signing Secret **DB-Manipulationsrisiko:** Eine DB-Zeile allein darf keine gültige Approval erzeugen. Selbst vollständige Schreibkontrolle über die Approval-DB darf ohne Christians Private Key keine neue gültige Approval erzeugen können (Signatur fehlt → DENIED). --- ## 12. ISOLATED IMPLEMENTATION (Phase 12) > ⚠️ NUR Code + Tests. KEIN produktives Deployment. **Modular (keine Vermischung mit Tolaria HTTP):** - `approval_payload.py` — kanonischer Payload, Canonicalization, Encoding, Hash - `approval_signature.py` — Ed25519 sign/verify (synthetische Test-Keypairs) - `approval_verifier.py` — Verification-Logik (alle §8-Checks) - `approval_state.py` — Lifecycle (CREATED→VERIFIED→RESERVED→EXECUTED→CONSUMED), Single-Use, Reservation **Bestehende C5-Invarianten erhalten.** Keine Änderung an Tolaria-HTTP-Code. --- ## 13. TEST CONTRACT (Phase 13) > ⚠️ NUR synthetische Test-Keypairs. KEINE echten Keys. **T1–T30 (siehe Freigabe):** - T1 gültige Christian-Approval → PASS - T2 falsche Signatur → DENIED - T3 falscher Public Key → DENIED - T4 Payload nach Signatur verändert → DENIED - T5 Object verändert → DENIED - T6 Path verändert → DENIED - T7 Commit verändert → DENIED - T8 Provenance verändert → DENIED - T9 Mission verändert → DENIED - T10 Request-ID verändert → DENIED - T11 Nonce verändert → DENIED - T12 expired → DENIED - T13 future-issued invalid → DENIED - T14 falsche Operation → DENIED - T15 unbekannte Version → DENIED - T16 malformed payload → DENIED - T17 malformed signature → DENIED - T18 Replay → DENIED - T19 consumed Approval → DENIED - T20 cross-object reuse → DENIED - T21 cross-mission reuse → DENIED - T22 DB fake row ohne Signature → DENIED - T23 DB fake row mit erfundener Signature → DENIED - T24 DELETE Executor kann keine Approval erzeugen - T25 RQ besitzt keinen Signing Key - T26 SAVE Executor besitzt keinen Signing Key - T27 Logs enthalten keinen Private Key - T28 DB enthält keinen Private Key - T29 Retry nach confirmed delete führt nicht zu zweitem Delete - T30 OUTCOME_UNKNOWN führt nicht zu blindem Retry **Adversarial:** canonicalization ambiguity, duplicate JSON keys, Unicode normalization, path normalization, signature substitution, key-id substitution, oversized payload, malformed timestamps, nonce collision, stale state, concurrent execution. --- ## 14. TEST SENSITIVITY (Phase 14) **Mutationen (jede muss Tests ROT machen):** - A Signaturprüfung entfernen - B Object Binding entfernen - C Commit Binding entfernen - D Nonce Binding entfernen - E Expiry entfernen - F consumed-check entfernen - G Operation-check entfernen - H Mission Binding entfernen - I Provenance Binding entfernen - J Replay-Schutz entfernen --- ## 15. REGRESSION (Phase 15) Volle relevante C5-Test-Suite. Keine bestehenden Sicherheitsinvarianten abschwächen. Baseline-Fails separat beweisen. Keine unrelated Reparaturen. --- ## 16. SECURITY REVIEW (Phase 16) - NO_PRIVATE_KEY_IN_REPO / ENV / DB / LOGS - RQ_CANNOT_SIGN / HERMES_CANNOT_SIGN / RAIN_CANNOT_SIGN / SAVE_EXECUTOR_CANNOT_SIGN / DELETE_EXECUTOR_CANNOT_SIGN - DELETE_EXECUTOR_VERIFY_ONLY - SIGNATURE_FAIL_CLOSED / REPLAY_FAIL_CLOSED / EXPIRY_FAIL_CLOSED / STATE_FAIL_CLOSED --- ## 17. COMMIT / PUSH (Phase 17) Nur AUTH.3D-relevante Dateien. Vor Commit: git diff, git status, Secret-Scan, Private-Key-Pattern-Scan. Keine echten Keys. Tests nur mit synthetischen Test-Keypairs. FF-only Push. HEAD == origin/main verifizieren. --- ## 18. FRESH CHECKER (Phase 18) > ⚠️ Wird als unabhängiger Subagent ausgeführt. --- ## 19. FINAL REPORT (Phase 19) > ⚠️ Wird nach Fresh Checker ausgefüllt.