# C5A — CONTRACT & STATE MACHINE v1 **Phase:** C5A (erste Phase des C5 Sync Service) **Status:** DONE (Contract & State Machine) — **INAKTIV, NO-WRITE** **Architektur:** FORGEJO MASTER → C5 SYNC SERVICE → TOLARIA DERIVED → SEARCH FULL REBUILD C5A implementiert **ausschließlich** den Contract + die Sync State Machine + die persistente Progress-State-Struktur. Es ist eine **deterministische, inaktive Python-Library + CLI + Testsuite** — es führt **keine** externen Writes aus. --- ## NO-WRITE GUARANTEE (verbindlich) C5A kann **NOCH NICHT**: - Tolaria schreiben - Search rebuilden - Forgejo schreiben - produktiv pollen - Netzwerk-Mutationen ausführen Es gibt **keine** Netzwerk-/HTTP-/Socket-/Subprocess-Mutationsfunktionen in C5A. Die No-Write-Guarantee wird statisch per `assert_no_write_guarantee()` bewiesen (keine `requests`/`urllib`/`http`/`socket`/`subprocess`-Imports) und durch den Test `test_no_write_guarantee` abgesichert. --- ## State Machine ### Normalzustände `DISCOVERED → VALIDATING → READY → PROPAGATING_TOLARIA → VERIFYING_TOLARIA → UPDATING_SEARCH → VERIFYING_SEARCH → APPLIED` ### Fehlerzustände `RETRY_PENDING`, `FAILED`, `DEAD`, `HUMAN_REVIEW_REQUIRED` ### Ordering `WAITING_FOR_PREDECESSOR` — Commits werden nur in korrekter Reihenfolge verarbeitet (`parent_sha` / `last_applied_commit`). Lücken werden **nicht** übersprungen. ### Kerninvariante **`last_applied_commit` wird NUR nach vollständigem Tolaria+Search PASS fortgeschrieben** (`mark_applied` wird nur nach `VERIFYING_SEARCH → APPLIED` aufgerufen). --- ## Commit Contract Eine Verarbeitungseinheit = **ein Forgejo Commit**: | Feld | Beschreibung | |---|---| | `commit_sha` | Primärschlüssel | | `parent_sha` | Vorgänger (Ordering) | | `discovered_at` | Zeitstempel | | `sequence` | Reihenfolge | | `status` | Sync-Zustand | | `retry_count` | Retry-Zähler | | `last_error` / `last_error_code` | Fehler + Reason Code | | `created_at` / `updated_at` | Zeitstempel | ### Pro Changed Object `object_id`, `path_before`, `path_after`, `operation`, `content_hash_before`, `content_hash_after`, `metadata_hash_before`, `metadata_hash_after`, `representation`, `state` --- ## Operation Model `CREATE`, `CONTENT_UPDATE`, `METADATA_UPDATE`, `STATE_UPDATE`, `RENAME`, `MOVE`, `SOURCE_CANONICAL_RELATION_UPDATE`, `TAGS_UPDATE`, `SUPERSEDE`, `DELETE_REQUEST` **`DELETE_REQUEST` bleibt Human-Gate** — kein automatisches Hard Delete. --- ## Idempotenz Basis: **`commit_sha + object_id + operation`** + Hash-Checks. | Ergebnis | Bedeutung | |---|---| | `ALREADY_APPLIED` | Commit bereits vollständig angewendet | | `ALREADY_AT_TARGET` | Ziel-Hash bereits erreicht | | `RETRY_SAFE` | Noch nicht angewendet, sicher zu verarbeiten | | `CONFLICT` | Existiert, aber Hash weicht ab | Doppelte Commit-Erkennung ist **deterministisch**. --- ## Ordering Commits nur in korrekter Reihenfolge. Fehlender Vorgänger → `WAITING_FOR_PREDECESSOR` (Reason Code `OUT_OF_ORDER_COMMIT`). Nach Anwendung des Vorgängers wird der Commit erneut validiert. --- ## Failure / Retry State - `max_retries = 5` (konfigurierbar) - Backoff: `1 / 2 / 4 / 8 / 16` Sekunden (gekappt) - Nach Max → `DEAD` oder `HUMAN_REVIEW_REQUIRED` - **Kein Endlos-Retry** --- ## Persistence SQLite (`c5a.db`), isoliert, restart-fest. Anforderungen erfüllt: - **atomic** (SQLite-Transaktionen, WAL) - **restart-safe** (neuer Store auf gleicher DB behält State) - **inspectable** (CLI `health`, `list-commits`, `commit-status`) - **backupbar** (einzelne Datei) - **keine externe DB** nötig - **kein Trading-/Forgejo-DB-Coupling** (eigene DB) --- ## Bootstrap State `UNINITIALIZED → RECONCILING → BASELINE_READY → ACTIVE` Baseline darf **nur** aus `BASELINE_READY` gesetzt werden (Master↔Tolaria- Reconciliation muss sauber sein). In C5A wird **keine produktive Baseline** gesetzt. --- ## Reason Codes (geschlossene Menge) `UNEXPECTED_TOLARIA_DRIFT`, `ID_COLLISION`, `UNKNOWN_OBJECT_ID`, `INVALID_SCHEMA`, `DANGLING_DERIVED_FROM`, `AMBIGUOUS_DELETE`, `UNKNOWN_LEGACY_OBJECT`, `AUTH_FAILURE`, `SEARCH_REBUILD_FAILURE`, `TOLARIA_UNAVAILABLE`, `FORGEJO_UNAVAILABLE`, `OUT_OF_ORDER_COMMIT`, `SECRET_DETECTED` Kein freier String-Wildwuchs als einziges Fehlerformat — unbekannte Reason Codes werden abgelehnt (`InvalidReasonCodeError`). --- ## Security Boundary (dokumentiert, NICHT implementiert) - **Forgejo credential:** READ ONLY (C5A hält keinen Forgejo-Write) - **Tolaria write:** nur später C5 Service - **Search rebuild:** nur C5 Service Token - **Agents:** keine direkten Tolaria-/Search-Admin-Writes - **Netzwerk-Härtung** wird später beim Deployment umgesetzt, NICHT jetzt --- ## Health Contract `status`, `bootstrap_state`, `last_seen_commit`, `last_applied_commit`, `pending_commits`, `failed_commits`, `dead_commits`, `human_review_required`, `forgejo_status`, `tolaria_status`, `search_status`, `drift_count`, `last_success_at`, `last_error_code` C5A führt **keine echten externen Health-Probes** aus (rein State-Machine) — `forgejo_status`/`tolaria_status`/`search_status` sind `UNKNOWN`. --- ## CLI ```bash export C5A_DB=/path/to/c5a.db # default: ./c5a.db python3 rq_c5a_cli.py health python3 rq_c5a_cli.py bootstrap-state python3 rq_c5a_cli.py bootstrap-transition --to RECONCILING python3 rq_c5a_cli.py set-baseline --commit python3 rq_c5a_cli.py ingest-commit --json python3 rq_c5a_cli.py process-commit --json python3 rq_c5a_cli.py list-commits [--status ] python3 rq_c5a_cli.py commit-status --sha python3 rq_c5a_cli.py no-write-check ``` --- ## Tests ```bash python3 test_c5a.py # 25 PASS / 0 FAIL ``` Abgedeckte Fälle: normal commit lifecycle, multi-object commit, duplicate commit, already-applied, out-of-order commit, missing predecessor, retry progression, max retry → DEAD, human gate transition, restart/reload persistence, state corruption handling, idempotency, delete request → human gate, dangling relation → human gate, unexpected drift → human gate, no-write guarantee, bootstrap lifecycle, baseline-only-from-BASELINE_READY, reason codes closed set, operations closed set, health contract fields, last_applied-only-after-full-pass, retry available bound, backoff sequence, invalid reason code rejected. --- ## Dateien - `rq_c5a.py` — Kern-Library (Store + State Machine + No-Write-Check) - `rq_c5a_cli.py` — CLI - `test_c5a.py` — Testsuite (25 Tests) - `README.md` — diese Datei