Skip to content

feat(extensions): preview and confirm lifecycle change plans - #2903

Closed
tang-vu wants to merge 2 commits into
Osmantic:mainfrom
tang-vu:feat/extension-change-plan
Closed

tang-vu wants to merge 2 commits into
Osmantic:mainfrom
tang-vu:feat/extension-change-plan

Conversation

@tang-vu

@tang-vu tang-vu commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

Ready for independent review (2026-09-15). Candidate 829dd48f53619f881b037ee93bf647ca2838eedb has a successful GitHub check rollup and no base-branch conflict at this review snapshot. This supersedes earlier draft-status wording only. All validation gaps, migration requirements, live gates and independent human review requirements below remain in force; this is not a merge-ready approval.

Why this matters

Extension lifecycle actions previously jumped from a static sentence in the dashboard to filesystem and container mutations. Operators could not see affected Compose services, dependency activation, dependent breakage, data retention, or failed preconditions before confirming the action.

This PR now carries the contract end to end: an authenticated backend plan remains side-effect free, and the dashboard fetches and renders that authoritative plan before install, enable, disable, or uninstall. A blocked plan cannot reach the mutation endpoint.

Overlap check

Searched open and closed upstream PRs for extension change plan, preview extension, lifecycle confirmation, and the changed production files. PR #2626 previews ODS mode switches, not extension lifecycle operations. PR #2716 hardens service-id validation in another router region. PR #3065 touches the same dashboard page only to serialize progress polling; this PR owns pre-mutation planning/confirmation and has no logical dependency on it. Both heads were merged in that order on the inspectable synthetic branch tang-vu:validation/batch-20260824-architecture; the combined dashboard and API suites pass at integration SHA 2c82aaec.

Production contract and state machine

  1. A card action requests GET /api/extensions/{id}/plan?action=... through the existing authenticated dashboard proxy.
  2. The backend derives current/target state, affected Compose services, ordered operations, dependencies/dependents, preserved data, and blockers without writing files or calling the host agent.
  3. The dashboard renders that receipt in the confirmation dialog. Enable previews explicitly select dependency activation and the confirmed mutation carries the same auto_enable_deps=true choice.
  4. A synchronous in-flight guard prevents duplicate preview and mutation requests even before React state rerenders; buttons also expose the busy state.
  5. Blocked plans disable confirmation. Preview/network failures terminate as an error toast without mutating.
  6. Successful mutations retain the existing catalog refresh and install-progress reconciliation. The mutation endpoint revalidates current state, so a plan becoming stale does not bypass backend preconditions.

Regression coverage

  • API boundary tests prove install, enable/dependency choice, disable/dependent impact, uninstall blockers, side-effect freedom, and typed action rejection.
  • Dashboard boundary tests prove the plan is fetched before mutation, exact services/dependencies/steps/data are shown, duplicate clicks issue one request, blocked plans remain read-only, and existing update/rollback surfaces remain intact.

Concrete pre-change evidence: clicking Install opened only a static message and never requested /plan; the new dashboard regression failed because Deployment plan and the plan request were absent.

Validation

  • python -m pytest -q tests/test_extensions.py tests/test_extension_change_plan.py — 259 passed, 5 skipped.

pm test -- --run src/pages/Extensions.test.jsx` — 12 passed.

pm test -- --run` — 28 files, 260 tests passed.

pm run lint` — passed.

pm run build` — passed; only the pre-existing stale Browserslist notice was emitted.

Tradeoffs, limitations, and rollback

Install, enable, disable, and uninstall use the authoritative plan. Update, rollback, and destructive data purge keep their existing dedicated confirmations because the backend plan contract does not yet model those different transactions; the UI does not pretend otherwise. Plans are previews, not reservation tokens: backend mutation validation remains the final authority if state changes between preview and confirmation.

No live host-agent lifecycle mutation was performed locally. Synthetic compatibility with #3065 is complete. This PR is Ready for review but still requires a live host-agent lifecycle gate and independent human review of the user-visible mutation state machine before merge. A normal revert restores static confirmations without changing persisted extension state or formats.

@tang-vu tang-vu changed the title feat(extensions): preview lifecycle change plans feat(extensions): preview and confirm lifecycle change plans Aug 23, 2026
@tang-vu
tang-vu marked this pull request as draft August 23, 2026 17:11
@tang-vu

tang-vu commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

Batch compatibility receipt (2026-08-24)

Built the inspectable synthetic branch tang-vu:validation/batch-20260824-architecture from upstream main (6ff9b4fc) and merged exact candidate heads in this order:

  1. fix(dashboard): keep extension progress polls single-flight #3065 bad25e7f
  2. feat(extensions): preview and confirm lifecycle change plans #2903 829dd48f
  3. feat(observability): stream scoped service health transitions #2911 d8aed4c6
  4. feat(extensions): inspect and gate dependency graphs #2909 6e9bd227
  5. feat(release): publish commit-bound deterministic runtime SBOM #2894 9115d147
  6. refactor(cli): extract read-only formatting primitives #3071 bff5cbfc

No manual merge resolution was required, including the shared Extensions.jsx / Extensions.test.jsx surface in #3065 and #2903. Synthetic head: 2c82aaec.

Combined validation:

  • Dashboard: 28 files / 262 tests passed; ESLint passed; production Vite build passed
  • Dashboard API: 350 passed, 5 skipped across service events, main routing, extension plans, lifecycle, and dependency suites
  • dependency graph + manifest gates: 4 pytest cases, 8 shell cases, full canonical/library schema contract passed
  • runtime SBOM: 5 tests passed; shipped dependency-pin validation passed
  • CLI: JSON public boundary, Phase C smoke, Bash syntax, ShellCheck, 4/4 BATS formatting contract, and enable/reconciliation fixture passed

The stale Browserslist notice and authentication-dependent Phase C skips are unchanged environmental disclosures. #2903 remains draft because synthetic compatibility does not replace its declared live host-agent lifecycle gate and independent human review.

@Lightheartdevs

Copy link
Copy Markdown
Collaborator

Thanks for this contribution. We're closing outside-contributor pull requests that have had no activity for 14 days or more, so the queue reflects work that can still land. This isn't a judgment on the change itself. If it's still needed, please rebase onto main and reopen it or open a focused PR. See #7253 for details and the contribution policy.

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