feat(app): resume installed apps on stack up + persisted value overrides + sell linkage#704
Closed
OisinKyne wants to merge 1 commit into
Closed
feat(app): resume installed apps on stack up + persisted value overrides + sell linkage#704OisinKyne wants to merge 1 commit into
OisinKyne wants to merge 1 commit into
Conversation
Contributor
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.
Summary
obol appwas the only stateful subsystem not replayed after cluster recreation: RPC upstreams, Agent CRs, storefront branding, and sell offers all resume onobol stack up, but installed apps silently evaporated — deployment directories intact on disk, nothing in the cluster. This PR fixes that and closes two adjacent gaps.Resume on stack up
New
app.ResumeAll(cfg, u)re-runshelmfile syncfor every app deployment directory (applications/<app>/<id>/helmfile.yaml+values.yaml) — the on-disk pair is already the declarative record, so resume is a pure re-apply. Wired into both replay paths, in each case deliberately beforeresumeSellOffers, becauseobol sell httpoffers can gate an app's Service as their upstream and the controller's upstream health check needs it present:cmd/obol/main.gostack-up: afterstorefront.ReconcileRecorded, before offers.cmd/obol/sell.gosell resume(reboot-recovery path): afteragentcrd.ResumeAll, before offers.Best-effort like the other resumes: a broken app warns and never blocks stack-up. The source-level guard test (
stackup_resume_guard_test.go) now enforces presence and ordering in both files, same style as the existing agents-before-offers guards.Discovery uses the existing
ListInstanceIDsheuristic (directories containing a barevalues.yaml). The hermes/openclaw state dirs that shareapplications/usevalues-<component>.yamlnaming and are excluded —TestResumeAll_SkipsNonAppStateDirslocks this in against the real on-disk layout.--set/--valueson install and syncOverrides are persisted into the deployment's
values.yaml(deep-merge: files in order, then--seton top with YAML-typed scalars) rather than passed as ephemeral helmfile flags. Consequence: what you--setis exactly what resume replays, and the deployment directory never lies about what's deployed.Sell linkage
After a successful
obol app sync, the CLI discovers the app's Services (best-effort kubectl, capped at 3) and prints ready-to-run monetization commands:This turns
app installinto the on-ramp for selling non-LLM services (vLLM, ComfyUI, databases). The hint only prints from the interactiveapp syncaction, not during resume.Testing
TestResumeAll_NoApps(silent no-op),TestResumeAll_SkipsNonAppStateDirs(hermes-style dirs untouched).--setcreation, YAML typing (bool/int/string), file merge precedence (later wins, untouched keys survive), comment-only chart defaults, malformed expressions.app.ResumeAllpresence + ordering in bothmain.goandsell.go.go build ./... && go test ./...Review focus
cmd/obol/main.go/cmd/obol/sell.go: replay ordering — apps must sit afterstack.Up/cluster-wait and beforeresumeSellOffersin both paths.internal/app/values.go: merge semantics (maps merge recursively, scalars/lists replaced) and that overrides are written with 0600 like the original values.yaml.internal/app/resume.go: must never return an error into the stack-up path (warn-and-continue only).🤖 Generated with Claude Code