a project registry — the list of what exists (#25) #30
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#30
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/project-registry"
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?
Closes #25.
environments.yamlcould say where things deploy to, and — since #21 — how a project you have already named is placed once it is there. It could not say which projects exist. "Every project" was a thing the operator remembered, so fleet operations (#26) had nothing to iterate and rebuild-from-state (#27) was an assumption: you cannot restore what you cannot enumerate.A new optional top-level block, keyed by the full
<org>/<repo>slug:The key is the repo — no
repo:field, because a second place to write the same string is a second place for it to be wrong. And no bare-<repo>fallback, unlikegithub_appsandenvironments.<env>.projects: those carry one because state files in the wild are keyed that way, and this block has none to support. A bare<repo>is unique only within an org, which is exactly why it is not a key (#12, learned twice).Validated, because a registry only earns its keep if it is true
Both checks defend one failure — a silently skipped project reads exactly like a clean one. They run in
loadBindings, so every verb refuses a registry that lies, rather than one command warning about it:environments:block defines is an error (the project would be registered into an environment no command can visit);environments.<env>.projects.<slug>binding must be registered for that env, or the two blocks describe two different fleets: adestination_uuidorsmoke_targetreal enough for a directapply, invisible to every fleet run. Only enforced whenprojects:is present, so pre-registry state files keep loading unchanged.projectsIn(bindings, env)returns an environment's slugs, sorted. The--allflag that consumes it is #26's, not this PR's — this ships the schema, the validation, the accessor, tests and docs, and nothing else.Note for the reviewer
loadBindingsnow renders zod's issues rather thanresult.error.message. Zod's default.messageis the whole issue array as JSON, which flattened these multi-line refusals into a single line of\nescapes — throwing away the part worth writing.Merge order
This is the base of the stack. #26 (
--all) and #27 (--emit-draft) both build on it. #29 is independent.Gates:
npm run check,npm run build,npm test(213 passing) all green.🤖 Generated with Claude Code