Repository navigation
Pause migrate for a release approval and let rollback run without one (S-008-13, S-008-14) - #182
Conversation
… (S-008-13, S-008-14) migrate's deploy:<component> step called lifecycle.deploy directly, so a manual application was gated through cloudfall deploy but not through cloudfall migrate. The step now runs the same approval check deploy --yes runs: without an approval that counts the run pauses there with deployment_approval_missing, the built release and the release approve command, and a resumed migrate --yes deploys the release the completed build step recorded, pinned to the approved archive digest, without building again or needing --build again. A broken approvals file stops the step with RECORD_INVALID, and migrate gains --approvals, bound by mcp serve. rollback needs no approval; its plan says so with approval.required false and a reason. The README, the SDK README and the Render migration guide show the release approve step, and spec 008 is built with its verification. Fixes #165 Fixes #106 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@romamo Decided without waiting: a resumed Why: S-008-14 says plain Reply with a comment starting with |
Summary
migrate'sdeploy:<component>step calledlifecycle.deploydirectly, so after #178 amanualapplication was gated throughcloudfall deploybut not throughcloudfall migrate. Now the step runs the same approval checkdeploy --yesruns (deployment_approvalinrelease_approval.py, shared by both):deploy:<component>(deployment_approval_missingjoins_PAUSE_CODES).migrate --yesexits 3PARTIAL_FAILUREwithcontext.code: deployment_approval_missing, the builtreleaseand the exactcloudfall release approvecommand, and the message names bothrelease approve,migrate --yesresumes at that step with the release the completedbuild:<component>step recorded. It does not build again, the deploy is pinned to the approved archive digest (approved_sha256), and the step's detail gainsapproval(the record it went on). The resumed run no longer needs--buildfor a component whose build step the saved plan already completedmigrateexitsRECORD_INVALID, asdeploydoes.migrategains--approvals(defaultdecisions/releases), whichcloudfall mcp servealready binds by name, so themigratetool can't name its own folderrollbackneeds no approval: its plan gainsapproval,{"policy": "manual", "required": false, "reason": ...}for amanualapplication and{"policy": "automatic"}otherwiseDocs:
README.md,sdk/README.mdanddocs/render-migration-guide.mdshow therelease approvestep for themanualapplication in theirmigrate --yesanddeploy --yesexamples. This is the last build issue of S-008, so the spec is set tostatus: built, with one Verification line per criterion.Plan
sdk/src/cloudfall/migrate.py,sdk/src/cloudfall/release_approval.py,sdk/src/cloudfall/agent_tools.py,sdk/src/cloudfall/app.py,sdk/src/cloudfall/commands.py,sdk/tests/test_migrate_approval.py,sdk/tests/test_agent_server.py,README.md,sdk/README.md,docs/render-migration-guide.md,docs/specs/008-enforce-manual-approval.md,changelog.d/165-migrate-approval-pause.mdmigrate,rollbackandrestart": gatemigrate'sdeploy:<component>runner with the same approval checkdeployuses and pause ondeployment_approval_missing; resume deploys the release the completedbuild:step recorded, pinned to the approved digest;rollback's plan gainsapproval(required: falseand a reason formanual); then the docs, and the spec's Verificationsdk/tests/test_migrate_approval.py;specs.py checkandspecs.py coverage --spec 008Test notes
sdk/tests/test_migrate_approval.py, run through the CLI against a copy of the example project without its domains. The engine is a stand-in whose playbooks runansible-playbookon localhost and only leave markers and a receipt. The artifact is built for real bycloudfall-engine artifact buildfrom a local git repositorytest_s008_14_migrate_pauses_for_an_approval_and_resumes_without_a_rebuild: exit 3PARTIAL_FAILUREatdeploy:crm-backendwith the built release and command, and no deploy playbook. Afterrelease approvethe source repository is deleted, so a second build couldn't succeed;migrate --yescompletesdeploy:crm-backendwith the recorded release and the record, and the artifacts folder is unchangedtest_s008_14_a_broken_approval_record_stops_the_deploy_step(exit 86) andtest_s008_14_an_automatic_application_migrates_without_a_recordtest_s008_13_rollback_needs_no_approval(manualandautomatic): the plan'sapproval, thenrollback --yesruns with no approvals folder at alltest_s008_5_the_deploy_tool_refuses_an_unapproved_manual_releasealso checks that themigrateMCP tool takes noapprovalsargumentuv run ruff check .,uv run mypy,uv run pytest sdk/tests/test_migrate_approval.py sdk/tests/test_migrate.py sdk/tests/test_deploy_approval.py sdk/tests/test_release_approval.py sdk/tests/test_agent_server.py sdk/tests/test_commands.py sdk/tests/test_app.py sdk/tests/test_lifecycle.py sdk/tests/test_data_migration.py sdk/tests/test_data_copy_preflight.py sdk/tests/test_owned_postgresql_converge.py, anduv run pytest engine/tests.specs.py checkandspecs.py coverage --spec 008pass. The full suite is left to CIaudit, which crashes withHANDLER_CRASHED(ConfigValidationError) whentmp/observedholds no observations. The tests read the saved plan for that reason. This predates this changeStacked on #178
Fixes #165
Fixes #106
🤖 Generated with Claude Code