Part of LeanerCloud/cloud-commitments-go#27 (commitment laddering automation). Phase 3 of 4: persistence, scheduled task, approval/auto modes, UI, Terraform. All flag-gated default-off.
PRs:
- Migrations 000078-000080 + stores:
ladder_configs (per cloud_account x provider), ladder_runs (immutable audit: inputs snapshot, plan jsonb with rationales, run-level approval token, status CAS), ladder_tranches; purchase_executions.ladder_run_id + ri_exchange_history.ladder_run_id link columns; global_config.laddering_enabled kill-switch; PurchaseSourceLadder = "cudly-ladder"; store methods in internal/config/store_postgres_ladder.go.
- Scheduled task, plan-only:
ladder_run task type + dispatch in internal/server/handler.go; handler_ladder.go with cadence self-gate (daily <20h / weekly <6d20h slack); persists planned runs + tranches, applies guardrails; no execution or email yet (safe dry-run milestone).
- Email-approval mode: pending purchase_executions + pending reshapes linked to the run; run-level token fan-out approve/cancel endpoints (3-mode auth dispatch, fail-closed);
SendLadderRunSummary (SES targeted only, ErrTokenInBroadcast guard); frontend/src/ladder-deeplink.ts.
- Auto-approve mode:
status=scheduled purchases with fire_at = now + PurchaseDelayHours riding the existing FireScheduledDelayedPurchases sweep (minimally extended for ladder-linked reshapes); pre-notification + SendLadderRunCompleted confirmation.
- Settings UI + config API: per-account laddering config editor in
settings.ts + /api/ladder/configs CRUD.
- Run history/detail UI + Terraform:
/api/ladder/runs list/detail (tokens stripped), run detail view with planned-vs-executed actions and rationales; EventBridge rule/target/permission behind enable_ladder_run_schedule (default false), vars threaded through environments/profiles.
Part of LeanerCloud/cloud-commitments-go#27 (commitment laddering automation). Phase 3 of 4: persistence, scheduled task, approval/auto modes, UI, Terraform. All flag-gated default-off.
PRs:
ladder_configs(per cloud_account x provider),ladder_runs(immutable audit: inputs snapshot, plan jsonb with rationales, run-level approval token, status CAS),ladder_tranches;purchase_executions.ladder_run_id+ri_exchange_history.ladder_run_idlink columns;global_config.laddering_enabledkill-switch;PurchaseSourceLadder = "cudly-ladder"; store methods ininternal/config/store_postgres_ladder.go.ladder_runtask type + dispatch ininternal/server/handler.go;handler_ladder.gowith cadence self-gate (daily <20h / weekly <6d20h slack); persists planned runs + tranches, applies guardrails; no execution or email yet (safe dry-run milestone).SendLadderRunSummary(SES targeted only,ErrTokenInBroadcastguard);frontend/src/ladder-deeplink.ts.status=scheduledpurchases withfire_at = now + PurchaseDelayHoursriding the existingFireScheduledDelayedPurchasessweep (minimally extended for ladder-linked reshapes); pre-notification +SendLadderRunCompletedconfirmation.settings.ts+/api/ladder/configsCRUD./api/ladder/runslist/detail (tokens stripped), run detail view with planned-vs-executed actions and rationales; EventBridge rule/target/permission behindenable_ladder_run_schedule(default false), vars threaded through environments/profiles.