Zum Inhalt

Dependency Locks

Stand: 2026-05-26

Ziel

Dependency Locks verhindern parallele oder widerspruechliche Execution Chains auf denselben Objekten. Sie schuetzen vor Race Conditions zwischen Execution, Cleanup und Reconciliation.

Lock-Modell

Pflichtfelder:

Feld Zweck
lock_id eindeutige Lock-ID
object_id Zielobjekt, z. B. pve/lxc/124
object_type Objekttyp
source_system Quellsystem
lock_type Zweck des Locks
lock_owner Besitzer
chain_id Chain-Kontext
approval_id Approval-Kontext
created_at Erstellzeitpunkt
expires_at Ablaufzeitpunkt
status Lifecycle-Status
reason Begruendung
scope Geltungsbereich
blocking_level Blockierstufe
release_condition Freigabebedingung

Lock Types

  • execution
  • cleanup_prepare
  • cleanup_execute
  • reconciliation
  • manual_hold
  • emergency_hold

Status

  • active
  • released
  • expired
  • failed_release
  • orphaned

Blocking Levels

  • read_warning
  • write_block
  • destructive_block
  • global_block

Storage

Operationaler Store ist SQLite:

  • DB: /var/lib/lanstyle-agent/controlled-execution/locks/locks.db
  • Tabelle: active_locks
  • Tabelle: lock_events
  • WAL Mode: aktiv
  • busy_timeout: aktiv

JSONL bleibt als Audit-Trail erhalten:

  • Legacy JSONL: /var/lib/lanstyle-agent/controlled-execution/locks/locks.jsonl
  • Audit: /var/log/lanstyle-agent/dependency-locks.jsonl

Dateirechte sind 0600. Es werden keine Secrets gespeichert.

Falls SQLite nicht verfuegbar ist, arbeitet die Lock-Schicht fail-closed. Es gibt keinen automatischen Fallback auf ungesicherten JSONL-Write.

API

  • GET /dependency-locks/policy
  • GET /dependency-locks
  • GET /dependency-locks/lxc-124-template
  • POST /dependency-locks/acquire
  • POST /dependency-locks/validate
  • POST /dependency-locks/release
  • POST /dependency-locks/expire
  • POST /dependency-locks/orphan

Diese API veraendert nur Lock-Records, keine Infrastruktur.

Enforcement

Vor Execution muss geprueft werden:

  • aktiver Lock auf Zielobjekt
  • aktiver destruktiver Lock
  • globaler Lock auf source_system
  • abgelaufene aktive Locks
  • orphaned Locks
  • Chain-/Approval-Ownership

Rueckgabe:

  • execution_allowed
  • blocked_reason
  • blocking_locks
  • stale_locks
  • lock_recommendation

Chain Lifecycle Enforcement

Dependency Locks sind jetzt direkt in den Chain-Lifecycle eingebunden.

Preflight:

  • ermittelt Zielobjekte
  • berechnet Lock-Kandidaten
  • meldet Konflikte
  • setzt keinen dauerhaften Lock, ausser preflight_lock_requested=true und dry_run=false

Execute:

  • erwirbt vor dem ersten Step automatisch einen Lock
  • prueft chain_id, approval_id und Zielobjekt
  • bricht vor Step 1 ab, wenn ein fremder Lock blockiert
  • released den Lock erst nach erfolgreicher Verification und Audit
  • markiert den Lock bei Chain-Failure als orphaned
  • markiert Release-Probleme als failed_release
  • behandelt abgelaufene aktive Locks als blockierend, nicht als sichere Freigabe

Ein eigener Lock darf nur weiterverwendet werden, wenn chain_id und approval_id exakt passen.

Atomic Acquire/Release

acquire_lock nutzt eine SQLite-Transaktion mit BEGIN IMMEDIATE. Dadurch koennen parallele Acquires auf dasselbe Objekt nicht gleichzeitig gewinnen.

Validierter Concurrency-Test:

  • 10 parallele Acquire-Versuche auf pve/lxc/124
  • genau 1 Lock gewinnt
  • 9 Versuche werden blockiert
  • nach Release gewinnt ein neuer Acquire

SQLite verhindert Race Conditions operational. JSONL dient nur noch als Audit-/Historienquelle.

Recovery

Orphaned, failed-release, stale, expired und emergency-hold Locks duerfen nicht blind released oder geloescht werden. Recovery laeuft ueber einen eigenen Approval-Flow:

  1. Recovery Preflight
  2. Recovery Approval Request
  3. Verification
  4. Recovery Execute
  5. Audit

Details: Lock Recovery.

Timeout bedeutet nicht automatisch sicher. Ein stale Lock blockiert weitere Chains auf demselben Objekt, bis ein Operator mindestens inspect_lock, inspect_chain_status, state_drift_check und recovery_preflight ausgefuehrt hat. Erst danach darf mit eigener Recovery-Approval release_after_verification oder expire_after_verification ausgefuehrt werden.

Operator UX

Lock-Informationen werden in unified_operator_response.lock_summary gespiegelt. OpenCode soll anzeigen:

  • aktive Locks
  • Lock-Kandidaten
  • Blocker
  • lock_owner
  • expires_at
  • release_required
  • stale/orphan/failed-release Warnungen

Bei blockierendem Lock ist der Workflow-State blocked oder recovery_required. OpenCode darf dann keinen Execute anbieten, sondern muss Recovery oder manuelle Pruefung empfehlen.

Kompakte Operator Summary bei Lock-Konflikt:

  • Gesamtentscheidung: blocked_by_lock
  • Warum blockiert: aktiver, stale, orphaned oder failed-release Lock
  • Sicher als naechstes: Lock inspizieren, Chain-Status pruefen, State/Drift pruefen, Recovery-Preflight starten
  • Nicht tun: kein automatisches Release, keine automatische Folge-Chain, keine Fortsetzung nur wegen Timeout

LXC 124

Fuer pve/lxc/124 wurde ein Lock-Testpfad vorbereitet:

  • Acquire Lock
  • zweite konkurrierende Chain blockiert
  • Release Lock
  • danach wieder allowed
  • Expired Lock Simulation
  • Chain B bleibt bei Konflikt blockiert und wird nicht automatisch nach Lock-Freigabe fortgesetzt
  • Orphaned Lock Simulation

Es findet keine Proxmox-Aenderung statt.