""" AUTH.4C3 — test_productive_incident_fixture.py ============================================== ISOLIERTE Fixture, die exakt den realen AUTH.4C2-Incident nachbildet. Real-Incident (AUTH.4C2, produktiv): JOB_ID: f18608df-0469-4760-8d84-d6bf1917e772 STATE: OUTCOME_UNKNOWN attempt_count: 1 Canary: PRESENT Path: tolaria/auth4c2-canary.md Object ID: object/cfeafffb-415e-4743-af44-e8c92efb9ac5 Hash: 798ae0315c14aa9d7e3a3f759c952f7c18cbce5154844f447e597b7fd1776515 Tolaria Markdown Count: 85 Erwartung (AUTH.4C3): Reconciliation bestätigt Erfolg (TARGET_EXACT) SAVE_CALL_COUNT = 0 attempt_count bleibt 1 Historie bleibt erhalten (OUTCOME_UNKNOWN sichtbar im Audit) KEINE produktive DB. KEIN produktiver Job. KEIN SAVE. Exit 0 = alle PASS. """ from __future__ import annotations import hashlib import os import shutil import sys import tempfile import unittest sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from job_schema import make_save_job from job_store import JobStore from job_state_machine import ( ST_OUTCOME_UNKNOWN, ST_SUCCEEDED, ST_CLAIMED, ST_EXECUTING, ) from save_reconciliation import ( SaveReconciliationCore, EV_RECONCILIATION_STARTED, EV_RECONCILIATION_TARGET_EXACT, EV_CONFIRMED_EXECUTED, ) # Exakte Werte aus dem realen Incident (ISOLIERTE Fixture, KEINE produktive DB) INCIDENT_JOB_ID = "f18608df-0469-4760-8d84-d6bf1917e772" INCIDENT_OBJECT_ID = "object/cfeafffb-415e-4743-af44-e8c92efb9ac5" INCIDENT_PATH = "tolaria/auth4c2-canary.md" INCIDENT_HASH = "798ae0315c14aa9d7e3a3f759c952f7c18cbce5154844f447e597b7fd1776515" INCIDENT_ATTEMPTS = 1 class ProductiveIncidentFixtureTests(unittest.TestCase): @classmethod def setUpClass(cls): # Canary-Content: der EXAKTE reale Inhalt aus dem produktiven Vault # (read-only verifiziert, Hash stimmt exakt mit dem Incident überein) cls.canary_content = ( "---\n" "id: object/cfeafffb-415e-4743-af44-e8c92efb9ac5\n" "type: Note\n" "title: AUTH.4C2 Canary\n" "tags: [auth4c2, canary, c5-save]\n" "created: 2026-08-27\n" "mission: AUTH.4C2\n" "---\n" "\n" "# AUTH.4C2 First Productive SAVE Canary\n" "\n" "Dieser Eintrag ist der kontrollierte produktive SAVE-Canary der Mission AUTH.4C2.\n" "\n" "- **Mission:** AUTH.4C2 — First Productive SAVE Canary\n" "- **Zweck:** Beweis exakt eines produktiven SAVEs über den isolierten c5-save-executor-Pfad\n" "- **Pfad:** tolaria/auth4c2-canary.md\n" "- **Quelle:** Forgejo Source of Truth (commit-bound)\n" "- **Fachlich:** neutral — kein Trading-Inhalt, keine Secrets\n" "\n" "Dieser Canary bleibt kontrolliert vorhanden für spätere AUTH.4E / Cleanup-Mission.\n" ) # Verifiziere: Hash des Canary-Contents == Incident-Hash computed = hashlib.sha256(cls.canary_content.encode("utf-8")).hexdigest() assert computed == INCIDENT_HASH, ( f"Fixture-Hash mismatch: computed={computed} expected={INCIDENT_HASH}" ) def setUp(self): # Jeder Test bekommt eine FRISCHE isolierte DB (create_job ist idempotent # per job_id — dieselbe INCIDENT_JOB_ID darf nicht über Tests kollidieren) self.tmp = tempfile.mkdtemp(prefix="c5-4c3-incident-") self.db = os.path.join(self.tmp, "incident.db") self.store = JobStore(self.db, "SAVE") def tearDown(self): self.store.close() shutil.rmtree(self.tmp, ignore_errors=True) def _create_incident_job(self): """Erzeugt den Job exakt wie im realen Incident (OUTCOME_UNKNOWN, attempts=1).""" job = make_save_job( job_id=INCIDENT_JOB_ID, mission_id="00000000-0000-0000-0000-000000000001", object_id=INCIDENT_OBJECT_ID, vault_path=INCIDENT_PATH, source_commit="a" * 40, provenance_hash=INCIDENT_HASH, expected_state="present", created_at="2026-08-27T00:00:00Z", idempotency_key="00000000-0000-0000-0000-000000000002", ) self.store.create_job(job) self.store.mark_ready(job["job_id"]) # Simuliere Execution -> OUTCOME_UNKNOWN (attempt_count=1 via Claim) self.store._transition(job["job_id"], ST_CLAIMED) self.store._transition(job["job_id"], ST_EXECUTING) self.store._transition(job["job_id"], ST_OUTCOME_UNKNOWN) # attempt_count auf 1 setzen (wie im Incident) self.store._conn.execute( "UPDATE jobs SET attempt_count = ? WHERE job_id = ?", (INCIDENT_ATTEMPTS, job["job_id"]), ) self.store._conn.commit() return self.store.get_job(job["job_id"]) def test_incident_reconciliation_confirms_success(self): """TARGET_EXACT: Reconciliation bestätigt Erfolg, Job -> SUCCEEDED.""" job = self._create_incident_job() self.assertEqual(job["state"], ST_OUTCOME_UNKNOWN) self.assertEqual(job["attempt_count"], INCIDENT_ATTEMPTS) # Read-Back liefert exakt den Canary-Content (Target PRESENT + exact) core = SaveReconciliationCore( self.store, lambda sc, oid, vp: self.canary_content, # source_loader lambda vp: self.canary_content, # read_back ) result = core.reconcile(job["job_id"], "worker-1") self.assertEqual(result["state"], ST_SUCCEEDED) def test_incident_zero_save_calls(self): """SAVE_CALL_COUNT = 0: Reconciliation ruft niemals write() auf.""" job = self._create_incident_job() save_calls = {"count": 0} def fake_save(*args, **kwargs): save_calls["count"] += 1 raise AssertionError("Reconciliation darf NIE write() aufrufen!") core = SaveReconciliationCore( self.store, lambda sc, oid, vp: self.canary_content, lambda vp: self.canary_content, ) # Reconciliation-Core hat KEIN write-Callable (technisch unmöglich) self.assertFalse(hasattr(core, "tolaria_save")) self.assertFalse(hasattr(core, "write")) result = core.reconcile(job["job_id"], "worker-1") self.assertEqual(result["state"], ST_SUCCEEDED) self.assertEqual(save_calls["count"], 0) def test_incident_attempt_count_unchanged(self): """attempt_count bleibt 1 (Reconciliation ist KEIN neuer Mutation Attempt).""" job = self._create_incident_job() core = SaveReconciliationCore( self.store, lambda sc, oid, vp: self.canary_content, lambda vp: self.canary_content, ) result = core.reconcile(job["job_id"], "worker-1") self.assertEqual(result["state"], ST_SUCCEEDED) self.assertEqual(result["attempt_count"], INCIDENT_ATTEMPTS) def test_incident_history_preserved(self): """Historie bleibt erhalten: OUTCOME_UNKNOWN sichtbar im Audit-Trail.""" job = self._create_incident_job() core = SaveReconciliationCore( self.store, lambda sc, oid, vp: self.canary_content, lambda vp: self.canary_content, ) core.reconcile(job["job_id"], "worker-1") trail = self.store.audit_trail(job["job_id"]) events = [e["event_type"] for e in trail if "event_type" in e] # Reconciliation-Evidence vorhanden self.assertIn(EV_RECONCILIATION_STARTED, events) self.assertIn(EV_RECONCILIATION_TARGET_EXACT, events) self.assertIn(EV_CONFIRMED_EXECUTED, events) # KEIN EXECUTED (Mutation wurde NICHT neu ausgeführt) self.assertNotIn("EXECUTED", events) # Der Job-Snapshot im Trail zeigt den finalen State SUCCEEDED, # aber die OUTCOME_UNKNOWN-Historie ist in den Events sichtbar # (der Job durchlief OUTCOME_UNKNOWN -> RECONCILED -> SUCCEEDED). def test_incident_no_production_db(self): """Fixture nutzt eine ISOLIERTE temporäre DB, keine produktive DB.""" self.assertNotEqual(self.db, "/opt/data/forgejo/trading-system-docs/tolaria/c5-sync-service/c5a_save.db") self.assertTrue(self.db.startswith(tempfile.gettempdir()) or "/tmp" in self.db or "c5-4c3-incident" in self.db) if __name__ == "__main__": unittest.main(verbosity=2)