Skip to content

feat(app): resume installed apps on stack up + persisted value overrides + sell linkage#704

Closed
OisinKyne wants to merge 1 commit into
oisin/fable-1from
oisin/permanent-apps
Closed

feat(app): resume installed apps on stack up + persisted value overrides + sell linkage#704
OisinKyne wants to merge 1 commit into
oisin/fable-1from
oisin/permanent-apps

Conversation

@OisinKyne

Copy link
Copy Markdown
Contributor

Summary

obol app was the only stateful subsystem not replayed after cluster recreation: RPC upstreams, Agent CRs, storefront branding, and sell offers all resume on obol 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-runs helmfile sync for 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 before resumeSellOffers, because obol sell http offers can gate an app's Service as their upstream and the controller's upstream health check needs it present:

  • cmd/obol/main.go stack-up: after storefront.ReconcileRecorded, before offers.
  • cmd/obol/sell.go sell resume (reboot-recovery path): after agentcrd.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 ListInstanceIDs heuristic (directories containing a bare values.yaml). The hermes/openclaw state dirs that share applications/ use values-<component>.yaml naming and are excluded — TestResumeAll_SkipsNonAppStateDirs locks this in against the real on-disk layout.

--set / --values on install and sync

Overrides are persisted into the deployment's values.yaml (deep-merge: files in order, then --set on top with YAML-typed scalars) rather than passed as ephemeral helmfile flags. Consequence: what you --set is exactly what resume replays, and the deployment directory never lies about what's deployed.

obol app install bitnami/redis --set architecture=standalone --set auth.enabled=false
obol app sync redis --values ./my-overrides.yaml --set image.tag=7.2

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:

To put this app on sale behind x402 payments:
  obol sell http redis --upstream redis --port 6379 --namespace redis-eager-fox --per-request 0.001 --pay-to 0x<wallet>

This turns app install into the on-ramp for selling non-LLM services (vLLM, ComfyUI, databases). The hint only prints from the interactive app sync action, not during resume.

Testing

  • TestResumeAll_NoApps (silent no-op), TestResumeAll_SkipsNonAppStateDirs (hermes-style dirs untouched).
  • Five values tests: nested --set creation, YAML typing (bool/int/string), file merge precedence (later wins, untouched keys survive), comment-only chart defaults, malformed expressions.
  • Guard test extended for app.ResumeAll presence + ordering in both main.go and sell.go.
  • Full suite green: go build ./... && go test ./...

Review focus

  • cmd/obol/main.go / cmd/obol/sell.go: replay ordering — apps must sit after stack.Up/cluster-wait and before resumeSellOffers in 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

@bussyjd

bussyjd commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Closing as superseded by integration/v0.13.0-rc0 @ a29c826 (rolled up in #716 / release v0.13.0-rc0). All commits of this PR are contained in the RC tip (verified by ancestry/patch-id audit).

@bussyjd bussyjd closed this Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants