feat(orchestrate): C5b — wire the real up-saga phases (spec 09) - #9
Merged
Conversation
Assemble the concrete up phases over the C5a engine (BuildUp → []Phase): preflight → network → generate → shared(health-gated) → compose-up(per project) → hooks(postUp, per project) - preflight: docker daemon reachable (full doctor matrix is X6). - network: idempotent EnsureNetwork(devstack_shared) under the flock — never auto-removed (no compensation). - generate: GenerateAll + writeIfChanged; runs BEFORE the compose phases (the files must exist to `up`) and re-arms on a config edit (fingerprint = the on-disk workspace/devstack yaml). - shared: RegisterUp ref rows + `compose up -d` only the shared services the requested projects `uses`, then health-gate each (Healthy if it declares a healthcheck, else Started) via internal/health. Compensation drops the refs. - compose-up (per project): `compose up -d` (+ optional --build); compensation `compose down` (never -v — a failed up never drops volumes). Re-armed by a devstack.yaml edit. - hooks (per project): postUp via internal/hooks (OSExecer + the DB ledger + flock). Engine refinement: a FAILED mutating phase now runs its OWN compensation too (it may have partially applied — e.g. compose-up created containers), while its saga_phase row is KEPT failed (so `status` can surface it); succeeded phases still unwind in reverse with their rows cleared. Deferred + flagged (slot in as more phases, no engine change): clone (gitx), provision (needs the shared-Postgres host-port coupling), secrets (M4/S6), trust (N5), firstRun hooks (need the provisioned-volume scope_key). Wiring is unit-tested with a mock docker client + a fake compose runner + a real temp ledger + a real temp workspace over the embedded templates: full happy path (network ensured, refs added, both stacks up'd, files written, postUp ran), near-instant re-run (all skips bar AlwaysRun preflight/hooks), and a project compose-up failure that compensates the shared refs to zero and downs the project. The real end-to-end daemon test lands with G1's isolation harness (parameterized devstack-it-<pid> network/prefix — the saga must not touch a real devstack_shared). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Chunk C5b (M2-remainder) — concrete up phases
Assembles the real
upphases over the C5a engine (BuildUp → []Phase), driven by the resumable/compensating Saga.Phases
EnsureNetwork(devstack_shared)under the flock; never auto-removed (no compensation).GenerateAll+writeIfChanged; runs before the compose phases (files must exist toup); re-armed by a config edit.RegisterUpref rows +compose up -donly the shared services the requested projectsuses, then health-gate each (Healthyif it declares a healthcheck, elseStarted) viainternal/health. Compensation drops the refs.compose up -d(+ optional--build); compensationcompose down(never-v— a failed up never drops volumes).postUpviainternal/hooks(OSExecer + DB ledger + flock).Engine refinement
A failed mutating phase now runs its own compensation too (it may have partially applied — e.g. compose-up created containers) while its
saga_phaserow is kept failed (sostatuscan surface it); succeeded phases still unwind in reverse with rows cleared.Deferred + flagged
Slot in as more phases with no engine change: clone (gitx), provision (needs the shared-Postgres host-port coupling — the flagged design item), secrets (M4/S6), trust (N5), firstRun hooks (need the provisioned-volume scope_key).
Tests
Mock docker client + fake compose runner + real temp ledger + real temp workspace over the embedded templates: full happy path (network ensured, refs added, both stacks up'd, files written, postUp ran), near-instant re-run (all skips bar AlwaysRun preflight/hooks), and a project compose-up failure → shared refs compensated to zero + project downed.
The real end-to-end daemon test lands with G1's isolation harness (the saga must not touch a real
devstack_shared; G1 parameterizes adevstack-it-<pid>network/prefix).Gate
make ci+make determinismgreen (race included).🤖 Generated with Claude Code