MH-4c ManagedStateService — Plan-Review

Projekt: Steve-TradingBot · Phase: RECON-MH-4c · Author: claude-opus-4-7[1m]
Generated: 2026-05-12 21:17 UTC · master HEAD: 93f4026 (MH-4b-3 closed)
Status: NO CODE Plan-Review only — Operator-GO erforderlich vor MH-4c Code-Phase


1 — Live-State Verification

CheckSollIstOK
master HEAD93f402693f4026 mh-4b-3: add proposal reject command service
git statuscleanempty output
Bot in-container PID29984unverändert
Worker Host PID(egal)2486135 (pre-existing Watchdog-Respawn, nicht MH-4c-blocking)
cmd 13cancelled13 | apply_baseline_holdings | cancelled
managed_proposals rows00
managed_assets_history rows00
BINANCE_TESTNETtrueBINANCE_TESTNET=true
runtime_config.jsonabsentnot present
baseline_holdings.jsonabsentnot present
managed_state.jsonabsentnot present
state/risk_proposals/absentnot present
Tracebacks last 200 lines00 matches

2 — Konsumierte Artefakte

KomponenteStatusKonsumiert in MH-4c
MH-1: pause_managed_asset / resume_managed_asset / release_managed_asset CommandTypes + Validatorsea11637Service ruft $registry->get(...) für jeden Type
MH-4a: managed_assets_history Table + Models + Enum83dafcanicht aktiv konsumiert (Service schreibt nicht in history; Worker MH-6 Job)
MH-4b-1/2/3: ProposalService-Pattern3fd7846 / be9cab7 / 93f4026Pattern-Vorlage: DB::transaction, writeAudit, validateAsset, validateUserId, Idempotency-Pre-Check
ManagedProposalState EnumMH-4anur peripher — Service prüft nicht state
Worker-Handler _handle_pause/_handle_resume/_handle_releaseMH-6nicht in MH-4c
Filament Wizard mit Pause/Resume/Release-UIMH-5nicht in MH-4c

Wichtig: ProposalService bleibt unverändert. MH-4c liefert eine eigene neue Klasse ManagedStateService (separate File).

3 — MH-4c Scope-Rekonstruktion

Roadmap-Definition (canonical aus 05_commandbus_worker §8)

class ManagedStateService
{
    public function createPauseCommand(string $asset, int $userId): Command { ... }
    public function createResumeCommand(string $asset, int $userId): Command { ... }
    public function createReleaseCommand(string $asset, int $userId, string $strategy): Command { ... }
}

3 Service-Methoden im Detail

a) createPauseCommand(string $asset, int $userId)

b) createResumeCommand(string $asset, int $userId)

c) createReleaseCommand(string $asset, int $userId, string $strategy, string $hardConfirm)

Strategy-Whitelist für Release

Vorschlag — 2 Werte:

Welche DB-Reads/Writes sind erlaubt?

READ (Phase 1, empfohlen):

MH-4c-Phase-1 macht KEINE State-Cache-Lookup. Service ist pure command-builder. Worker MH-6 ist final state-validator.

WRITE:

State-Transitions: nur vorbereitet, nicht ausgeführt

CommandVorbereitet von MH-4cAusgeführt von MH-6
pauseINSERT pendingmanaged_active → managed_paused
resumeINSERT pendingmanaged_paused → managed_active
release(to_frozen)INSERT pendingmanaged_* → managed_released → frozen (Two-File-Atomic)
release(mark_released_only)INSERT pendingmanaged_* → managed_released (single file)

4 — Konfliktcheck Sonder-Anforderungen

AnforderungMH-4c-TouchVerdict
Kein managed_state.json writeService touched keine state fileskonform
Kein baseline_holdings.json writeService touched keine state fileskonform
Kein ProposalWriter-Aufrufarchitekturell unmöglich + Source-Grep Pinkonform
Kein Worker-Handlercommand_worker.py bleibt unverändertkonform
Kein Bot-Wiringmain.py / paper_trade.py / live_trade.py / risk_manager.py bleiben unverändertkonform
Kein Filament WizardUI ist MH-5konform
Kein Mainnethardcoded environment='testnet'konform
Kein runtime_config-touchnicht im Service-Scopekonform

5 — Empfohlene Lieferung

Service-API

namespace App\Services\Managed;

class ManagedStateService
{
    public function __construct(private readonly CommandTypeRegistry $commandRegistry) {}

    public function createPauseCommand(string $asset, int $userId): Command;
    public function createResumeCommand(string $asset, int $userId): Command;
    public function createReleaseCommand(
        string $asset, int $userId, string $strategy, string $hardConfirm
    ): Command;

    // Public static helper (reusable in MH-5 Wizard)
    public static function buildReleaseHardConfirmString(
        string $asset, string $strategy
    ): string;  // returns "<asset>:release:<strategy>"

    // Constants
    public const REQUEST_ENVIRONMENT     = 'testnet';
    public const AUDIT_SUBJECT_TYPE      = 'ManagedAsset';
    public const PAUSE_TIMEOUT_SECONDS   = 120;
    public const RESUME_TIMEOUT_SECONDS  = 120;
    public const RELEASE_TIMEOUT_SECONDS = 120;
    public const ALLOWED_RELEASE_STRATEGIES = ['to_frozen', 'mark_released_only'];
}

Erlaubte Methoden

Verbotene Methoden

Exceptions

0 neue Exception-Klassen. Reuse aus MH-4b:

Payload-Schemas

pause / resume:

{
  "environment":  "testnet",
  "asset":        "<asset>",
  "requested_by": <userId>,
  "expires_at":   "<iso8601-z>"
}

release:

{
  "environment":  "testnet",
  "asset":        "<asset>",
  "strategy":     "to_frozen|mark_released_only",
  "hard_confirm": "<asset>:release:<strategy>",
  "requested_by": <userId>,
  "expires_at":   "<iso8601-z>"
}

Idempotency-Keys

CommandKey-PatternVerhalten
pausemh:pause:{asset}:{YmdHis}per-click distinct — same-second double-click returns existing
resumemh:resume:{asset}:{YmdHis}per-click distinct
releasemh:release:{asset}:{YmdHis}per-click distinct

NICHT shared wie decide. Operator kann legitim mehrfach pause/resume/release klicken — jeder Click = neuer Command + neuer Audit-Trail.

6 — Test-Plan

Test-KlasseAnzahlInhalt
ManagedStateServiceCreatePauseTest8happy path · payload env=testnet · payload alle keys · audit prefix managed.* · audit event_type=managed.asset_pause_requested · asset regex · userId positive · same-second idempotency
ManagedStateServiceCreateResumeTest6happy path · payload · audit · asset regex · userId · same-second idempotency
ManagedStateServiceCreateReleaseTest12happy path · payload · audit event_type=managed.asset_release_requested · strategy whitelist (to_frozen / mark_released_only) · strategy reject unknown · strategy reject empty · hardConfirm exact match · hardConfirm asset mismatch · hardConfirm strategy mismatch · hardConfirm case mismatch · hardConfirm empty · same-second idempotency
ManagedStateServiceBoundaryTests4no managed_proposals write · no managed_assets_history write · no file/subprocess tokens · no ProposalWriter/Engine refs
ManagedStateServiceIdempotencyTests4pause and resume have distinct keys (not shared) · multiple pause within same second returns existing · different-second different commands · per-asset isolation
ManagedStateServiceMainnetGuardTest3pause payload environment=testnet hardcoded · resume same · release same
ManagedStateServiceAtomicityTest1failed audit insert rolls back command (test against release)
BuildReleaseHardConfirmStringTest3builds <asset>:release:<strategy> · case preserved · 2 strategies
AuditPrefixTest3every audit prefix managed.* · per-type event_type pinned
ManagedStateServiceConstantsPinned2ALLOWED_RELEASE_STRATEGIES pinned · timeout-Konstanten pinned
Total~46 Tests(kleiner als approve weil keine confidence/state-cache lookup)

7 — Betroffene Dateien

Neue Files

DateiStatus
gui/app/Services/Managed/ManagedStateService.phpNEU
gui/tests/Feature/ManagedStateServiceCreatePauseTest.phpNEU
gui/tests/Feature/ManagedStateServiceCreateResumeTest.phpNEU
gui/tests/Feature/ManagedStateServiceCreateReleaseTest.phpNEU
gui/tests/Feature/ManagedStateServiceBoundaryTest.phpNEU

Unverändert

Erwartete LOC: ~450 Service + ~750 Tests = ~1200 LOC

8 — Stop-Regeln MH-4c

IDStop wenn…
MH-4c-SR-1Service UPDATE auf managed_proposals
MH-4c-SR-2Service INSERT in managed_assets_history
MH-4c-SR-3Service file IO / subprocess
MH-4c-SR-4Service akzeptiert environment != 'testnet'
MH-4c-SR-5Service ruft Worker / Engine / Writer / Reader
MH-4c-SR-6Service-Methode NICHT in DB::transaction
MH-4c-SR-7release strategy ist case-insensitive whitelist-check
MH-4c-SR-8release Hard-Confirm ist case-insensitive
MH-4c-SR-9Audit-Event-Prefix ist nicht managed.*
MH-4c-SR-10pause/resume idempotency key shared mit anderen (nur per-click distinct erlaubt)
MH-4c-SR-11release whitelist akzeptiert unbekannte strategy
MH-4c-SR-12pause/resume haben Hard-Confirm (architectural decision: nur release)

9 — Backup / Migration / Restart-Bedarf

AktionPflicht?
pg_dump GUI-DBNEIN
State-Files snapshotNEIN
DB MigrationNEIN
Bot-RestartNEIN
Worker-RestartNEIN
docker cpNEIN

MH-4c = Reine Code+Test+Commit Phase.

10 — Risiken-Übersicht

#RisikoSeverityMitigation
R1Service-Methode ohne state-validation lässt Operator pause auf frozen-asset → Worker MH-6 wird ablehnenLOWUX-Issue, kein Service-Bug. Filament-Wizard (MH-5) zeigt nur erlaubte Aktionen pro state. Worker wirft InvalidStateTransitionException zum Audit. Symmetric mit createRequestCommand Pattern.
R2Release Strategy-Drift Service↔WorkerLOWWhitelist als Service-Konstante + future Worker-side mirror. Parity-Test in MH-6.
R3Operator klickt pause+resume+pause schnell hintereinanderLOWPer-click distinct Idempotency-Keys mean alle 3 Commands persisted. Audit-Trail vollständig. Worker verarbeitet sequenziell.
R4Release Hard-Confirm-Format-Verwechslung mit approve <asset>:<variant>:<sha8>LOWDistinct Literal release in mitte verhindert; sha8 not used (asset hat kein proposal_sha256-Kontext).
R5strategy=Unknown silent-akzeptiertLOWWhitelist-check explicit; Test pinned.
R6DB::transaction-Rollback bei AuditEvent failureLOWPattern bewährt aus MH-4b-1/2/3
R7pause/resume ohne Hard-Confirm → Operator-Fehler kann mehrere assets versehentlich pause-stormLOWFilament-UI bietet Confirm-Dialog ohne Hard-Confirm-String; reversibel via resume
R8release ohne strategy-Pflicht durchgewunkenLOWService erfordert strategy als 3. Param; PHP-type-system erzwingt non-null
R9Strategy mark_released_only lässt Asset in undefiniertem state hängenMEDIUMUX-Doc-Issue für MH-5 Wizard; Service trägt strategy nur weiter; Worker MH-6 ist authoritative
R10ProposalService::buildHardConfirmString und ManagedStateService::buildReleaseHardConfirmString driftLOWBeide separate static methods; Test pinnt jeweils Format

11 — Kleinste sichere Code-Phase + GO/NO-GO

Subschnitt-Optionen

VarianteInhaltLOCTestsRisk
MH-4c-monolithic ← empfohlenManagedStateService mit allen 3 Methoden + buildReleaseHardConfirmString + Tests~1200~46LOW
MH-4c-aNUR createPauseCommand + happy path Tests~350~10LOW
MH-4c-b (folgt)createResumeCommand + Tests~250~10LOW
MH-4c-c (folgt)createReleaseCommand + buildReleaseHardConfirmString + Tests~500~20LOW

Empfehlung: MH-4c-monolithic

Begründung:

  1. Pattern voll etabliert durch MH-4b — keine Discovery
  2. 3 Methoden gehören semantisch zusammen als asset-lifecycle commands; sub-cuts würden Wizard-Build (MH-5) unvollständig deployen
  3. Service hat NICHTS Komplexes — pure command-builder ohne state-cache lookup
  4. Release ist die einzige nicht-triviale Methode (Hard-Confirm + Strategy); pause/resume sind trivial
  5. Rollback-Cost minimal: git revert + 0 DB-Rows

Pre-Implementation-Q an Operator

  1. MH-4c-monolithic oder Sub-Cut? ← Empfehlung monolithisch
  2. ManagedStateService als separate Klasse ODER Methoden in ProposalService einbauen? ← Empfehlung separate Klasse (saubere domain-separation)
  3. Release Strategy-Whitelist: ['to_frozen', 'mark_released_only'] — beide? andere Werte? ← Empfehlung beide, Operator kann später erweitern
  4. Release Hard-Confirm Format: <asset>:release:<strategy> (3-Teil mit strategy-binding) ODER <asset>:release (2-Teil simpel)? ← Empfehlung 3-Teil (bindet an strategy-Wahl)
  5. pause/resume Hard-Confirm: NEIN (low-risk, reversibel)? ← Empfehlung JA, NEIN bestätigen
  6. State-Cache-Lookup-Strategie: Phase 1 NO lookup (Worker = authoritative) ← Empfehlung Phase 1 NO lookup
  7. Code-Reuse aus ProposalService: Duplizieren ODER Trait extrahieren? ← Empfehlung Duplizieren (kein Premature-Abstraction)
  8. 0 neue Exception-Klassen bestätigen? ← Empfehlung JA (InvalidCommandPayloadException reicht)
  9. audit_event_types: managed.asset_pause_requested / managed.asset_resume_requested / managed.asset_release_requested bestätigen?

Scope-Größe + Risiko-Bewertung MH-4c-monolithic

AspektBewertung
LOC~450 Service + ~750 Tests = ~1200
Tests~46
KomplexitätLOW (massive Reuse aus MH-4b-Pattern)
Blast-RadiusNULL — INSERT-only auf commands + audit_events
Roll-Back-Costminimal: git revert + 0 neue DB-Rows
Dependencies-KlärungQ-3 (Strategy-Whitelist) + Q-4 (Hard-Confirm-Format)
Backup-PflichtNEIN
Migration-PflichtNEIN
Restart-PflichtNEIN
Mainnet-TouchNEIN
docker cpNEIN

STOP vor Implementierung. Erwarte Operator-GO mit Subschnitt-Wahl (monolithic empfohlen) + Q1-Q9-Approval, insbesondere Strategy-Whitelist + Hard-Confirm-Format + State-Cache-Lookup-Strategie.

© Steve-TradingBot · RECON-MH-4c · Plan-Review (no-code phase)