Repository navigation
fix(ui): restore per-node installed backend removal - #12785
Merged
Merged
Conversation
The coverage script ran ginkgo per test root with `|| fail=1`, which swallowed the exit code. Combined with `make --output-sync=target`, which buffers all output and flushes at the end, the actual ginkgo error was invisible in interleaved CI logs. Every test suite passed but the script still exited 1, and the error message was buried in 22 000 lines of buffered output. Each ginkgo invocation now captures combined stdout+stderr to a per-root log file. On failure the last 80 lines are printed to stderr so the error is visible in the CI log. On success the log is replayed to stdout so test output remains visible. The build flags (--tags, --coverpkg) are quoted correctly so values containing spaces (e.g. --tags="debug auth") are preserved through eval. Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
The previous commit added per-root log files but forgot to create the output directory before the first ginkgo invocation. On CI the coverage/ dir did not exist yet, so the shell redirect to cover-pkg.out.log failed with "No such file or directory" before ginkgo even ran. Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Commit 9ad7838 added GET /api/canvas/preview/:id as a public route (no auth — the random id is the capability, an iframe cannot send API key headers) but did not add it to expectedPublicRoutes in the route auth coverage test. The test flagged the route as an anonymous-access leak, failing the entire ./core ginkgo suite on every CI run since. The POST /api/canvas/preview endpoint is auth-gated (returns 401 to anonymous requests) and is intentionally absent from the allowlist. Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Verify exact node inventory and protection before offering and confirming removal. Capture the node/backend target, guard duplicate requests, and preserve installed data when refresh fails. Reuse the flow for catalog target removal and document scoped retry behavior. Assisted-by: nib:gpt-6.1-sol Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Distinguish ordinary refresh failures from successful deletion with stale data. Lock target installs synchronously and block conflicting install/removal actions through completion-driven refresh. Cover retry wording, deferred mutation races, obsolete inventory responses, and final installation selection cleanup. Assisted-by: nib:gpt-6.1-sol Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Keep generic deletion blocked during scoped removal and targeted installs. Recheck conflicts after dependency lookup and before confirmation so navigation cannot expose a conflicting delete action. Assisted-by: nib:gpt-6.1-sol Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
mudler
approved these changes
Oct 19, 2026
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.
Description
Restore confirmed per-node removal of concrete backend builds from Backends → Installed.
Expanded rows load actual node inventory. Removal requires a healthy backend node, an exact concrete name, and explicitly false system/meta protection flags. The confirmation captures the node and build, then rechecks status and inventory before sending one node-scoped request. This does not fan out deletion across nodes.
Keep successful Installed data visible when refresh fails. Distinguish ordinary refresh failures from successful deletion followed by stale data. Refresh retries do not repeat deletion. Block conflicting targeted installs, scoped removals, and generic deletions through pending requests and post-delete refresh, including when navigation clears the target.
Update backend documentation and English strings. This branch is independent of the development-backend preference change in #12782.
Notes for Reviewers
Verification against the final rebuilt UI and re-embedded Go test server:
npx playwright test e2e/backends-installed-node-removal.spec.js \ e2e/backends-management.spec.js e2e/backends-lifecycle.spec.js \ e2e/nodes-per-node-backend-actions.spec.js --workers=1tests/e2e-uiserver first; configure the mock backend and Chromium as documented by the UI test harness.Backends.jsx,useDistributedMode.js, and the new spec.Limitations: full UI/coverage suites were not run. Full ESLint retains two existing errors in unchanged
e2e/coverage-fixtures.js:44,53and existing warnings. An intermediate combined run had 61 passes and one invalid recovery assertion expecting a Remove button after its backend disappeared; the assertion now checks disappearance. No coverage baseline or tolerance changed. Browser tests use synthetic mocked inventory and mutation responses, not real backend deletion. No rollout or live model acceptance test is claimed.Signed commits
Assisted-by).docs/content/features/backends.md).