fix: apply creates the environment its resources name (#38) #39
No reviewers
Labels
No labels
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-triage
ready
release
scope:apply
scope:capture
scope:coolify-api
scope:fleet
scope:manifest
scope:secrets
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/cast#39
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/ensure-environment"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #38.
The bug
POST /projectshands a newly created project Coolify's own default environment,production— never ours. cast then created every resource withenvironment_name: <our --env>, so the firstapplyagainst a project that did not exist yet 404'd on its first resource and left the project behind, created and empty:The route to create an environment exists in the vendored 4.1.2 spec (
POST /projects/{uuid}/environments); cast simply never called it. Two comments in the source (cli.ts:716,:808) and the README already asserted the behaviour as though it were implemented — this makes them true.It went unseen because every environment cast had touched until now was hand-built in a UI and then adopted, so it always already existed under whatever name someone typed (which is why
--environmentexists at all). The genuinely-from-nothing apply is the one path that had never been run.The fix
applyreconciles project + environment once per run, lazily, before the first create — memoized, so five creates reconcile once rather than five times.Read-before-write, which is the property that matters for blast radius: an environment that already exists takes the read and stops, and the create route is never called at all. Every environment cast has ever touched is in that case, so adoption is untouched and this cannot regress an apply that works today. A
409is read as "present" — the race between our read and our write.The decision the issue left open
The issue asked whether to delete the empty
productionCoolify leaves behind. Left alone, and reported instead:Deleting it would be the first delete cast ever performs, against a guarantee the tool states in
docs/semantics.mdand enforces everywhere else — an orphan is reported and not repaired, "removal is a manual runbook act". An empty environment beside the one everything lives in is the mildest possible case of exactly that rule, so it gets the same courtesy an orphan gets: named, and left to the operator.Tests
The regression test drives the real failure, not a call count — the fake Coolify 404s a create whose
environment_nameit does not carry, exactly as a live box does. Against the old executor it reproduces the reported error verbatim:Covered: from-nothing create · already-exists (never writes) · 409-as-present · non-409 surfaces · reconciles-once across several creates. Suite is 284 passing (279 before);
npm run check,build,testall green.Three existing
wire.test.tsmocks gained the environments route — they modelled an existing project but did not serve the route a real Coolify serves for one.Not verified against a live Coolify
Per D-208 an agent does not run
cast, so this is verified against the vendored 4.1.2 spec and a fake that enforces Coolify's rule. The operator's first apply is the real test — and it is the exact path (prod-migration Task 8 step 4) that the workaround in the issue currently unblocks.🤖 Generated with Claude Code