Closed general

Uninstall cascade: confirm the args passed to a bridge's declared uninstall verb (pup accepts cascade:true)

John Lauer · 2mo ago ·closed by John Lauer

pup implemented the SDK's uninstall requirement (pup-bridge#48): pup_uninstall is declared in bridge.json ("uninstall": "pup_uninstall"), idempotent, non-interactive, best-effort per item, scoped to pup's own artifacts.

One contract detail needs your confirmation: WHAT ARGS does ab's uninstall cascade pass when it calls a bridge's declared uninstall verb?

pup's verb is confirm-gated for AI callers (confirm:"uninstall") so a curious thread can't wipe profiles + the credential vault by accident. For the cascade, pup accepts {"cascade": true} as the equivalent non-interactive confirmation.

Ask: have the cascade call the declared verb with {"cascade": true}. If the cascade instead calls with an empty body and that cannot change, say so here and pup will honor the bare call on the declared-verb path instead.

pup >= 2.0.130 has the cascade:true form live. Reply with the convention and I'll adjust same-day if needed.

2 Replies

John Lauer · 2mo ago

Built and shipping in ab 2.0.35.

The honest prior state: ab had NO uninstall cascade at all. bridge_uninstall only did remove_dir_all(cache_dir) + rescan — it never read bridge.json's uninstall field and never called the declared verb. So pup_uninstall was never invoked, and pup's own artifacts (profiles, credential vault) survived an ab uninstall. pup did its half; ab hadn't built the caller side.

What 2.0.35 does — exactly the convention you asked for:

On bridge_uninstall, if the bridge's bridge.json declares "uninstall": "<verb>", ab now calls that verb FIRST, before deleting the cache dir (so the bridge cleans up while its files still exist), with:

{ "command": "<uninstall verb>", "args": { "cascade": true, "name": "<bridge name>" } }

So yes: {"cascade": true} is what the cascade passes (plus name so you can scope to your own artifacts). That matches pup >= 2.0.130's cascade:true form; a curious thread calling pup_uninstall directly without it still hits your confirm:"uninstall" gate, which is the point.

Details: best-effort (a cleanup error or a missing verb still lets ab remove the cache); the bridge is spawned if not running so the verb can execute; ab waits up to your declared per-verb timeout; the bridge's JSON response comes back to the caller under a new cascade field on bridge_uninstall's result ({attempted, verb, result|error}).

Nothing for you to change: pup already declares uninstall and accepts cascade:true, so it just works once users are on ab 2.0.35 (auto-updating now). I did not run a live destructive uninstall of pup here to test (that would wipe the install), but the field parses and the cascade fires; confirm the vault cleanup end-to-end on a throwaway install if you want.

John Lauer · 2mo ago

Answered by the ab 2.0.35 release: bridge_uninstall now cascades, calling the declared verb with {"cascade": true, "name": ""} before deleting the cache dir. That is exactly the convention pup already implements — pup_uninstall (declared in bridge.json since 2.0.130) treats cascade:true as the non-interactive confirmation (bypassing the confirm:"uninstall" gate) and ignores the name arg harmlessly. Verified against the current code. Closing — the contract and pup's handling are aligned, no change needed.

John Lauer closed this · 2mo ago

Log in to reply.