Repository navigation
Conversation
Port the launch-settings service contract from NVIDIA/Personal-AI-Router@0df32b0. Validate literal engine arguments and environment assignments in Go, preserve private per-platform overrides, and coordinate revisioned persistence, engine lifecycle and proxy rebind through the broker. Keep the fork's three proxy workers and their existing set-port protocol. Reject managed bind, port and proxy-wiring controls in launch text. Gate remote settings on verified peer inventory and pinned cluster mTLS. Extend the existing permission-read correlation path with method demultiplexing, retain live LAN-bind permission checks, and keep oMLX's app launch unchanged with only its proxy port editable. Redact settings frames and exclude custom vendor output from logged startup failures. Add the typed Electron relay and regenerate service contracts without changing the settings panel. Go suites, native/Linux/Windows vet, targeted race tests, desktop gates and SPDX checks pass. Relay, authoritative-validation and diagnostic regressions were observed failing without their fixes. Retain the existing unreleased minor versions for engine-manager and broker, already bumped appropriately from v0.8.0. Co-authored-by: Noah (Terve) Tervalon <ntervalon@nvidia.com> Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Adapt the settings panel and snapshot store from NVIDIA/Personal-AI-Router@0df32b0 to the fork's node-owned settings contract. Let local and verified paired devices preview ports and literal launch options before applying, confirm only required engine restarts, and render operation progress and one failure message. Reload revision conflicts instead of overwriting another editor's choices. Keep oMLX's server settings read-only and expose only its proxy port. Replace the superseded port editor without a fallback, keep launch values inside their editor, and cover panel states, remote eligibility, snapshot ordering and delayed-response races with isolated desktop tests. Document the workflow and typed renderer API. Co-authored-by: Noah (Terve) Tervalon <ntervalon@nvidia.com> Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Verify that a failed apply renders the owning node's restoration outcome once while retaining the revisioned desired settings for a retry. Match failed snapshot fixtures with failed receipts so the tests exercise the authoritative operation contract. Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
A delayed refresh could overwrite input entered after the refresh began. Correlate the draft reset with its editor generation so newer edits survive, while the snapshot store still records the authority's latest revision. Add a regression observed failing before the guard and passing afterward. Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Failed launch settings applies stopped the previous engine but retained the new configuration after persistence, proxy rebind, startup or readiness errors. Compensate under the same operation lock: restore the exact atomic override, previous proxy port and running state, preserving the effective listening address and a cancellation-independent recovery deadline. Keep failures in the existing receipt and snapshot fields, report failed restoration safely, and reconcile previous component settings before automatic startup without rewriting failed receipts. Replace failure-retention expectations with restoration regressions for every failure stage, rollback failure, cancellation and bind scope. The failure-stage tests were also run against cb6452e and failed as expected. Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
JaredP94
marked this pull request as ready for review
November 4, 2026 19:11
Startup ignored failed reconciliation and interrupted operations discarded their recovery errors. Pass per-engine exclusions to enabled-engine restoration, withdraw unsafe advertisements and proxy destinations, and report value-free recovery errors through the existing errors channel. Keep saved ON/OFF intent intact and let successfully reconciled engines restore independently. Retry reconciliation on startup, manager respawn and explicit engine start or restart, including requests arriving before startup recovery. Block all three settings-managed engines when their journal cannot be read. Preserve failed receipts and document the internal restoration gate and retry policy. The startup-caller regression fails for both failed and interrupted operations on c322a84. Cover independent engine recovery, explicit retries, unavailable managers, unreadable journals, result-save failures and saved enabled intent. Broker and manager race suites, fresh Go tests, cross-platform vet, all desktop checks, gofmt and SPDX checks pass. Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Apply Prettier to the engine settings state tests to remove the branch's 19 formatting warnings without changing assertions. Desktop lint now reports zero warnings; typecheck, all 892 unit tests, dead-code and service-contract checks pass. Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
A paired device could bypass the broker-only start check and launch an engine whose settings had not reconciled. Require broker authorization at Executor.doStart, the common launch and adoption chokepoint, rather than patching only the remote handler. Missing authority, failed reconciliation and revoked or wrong-engine grants fail closed with the existing value-free recovery error. Keep the journal and proxy transaction authoritative in the broker, not a second recovery implementation in engine-manager. Ordinary operations retry recovery through prepare-start before taking the engine operation lock; authorize-start checks the engine-scoped reconciliation generation at doStart. Configure acceptance and failed recovery revoke ordinary grants. The active broker configure token authorizes both its candidate and rollback restart using only the relay-state mutex, so neither can recursively recover or deadlock against settingsApplyMu, engineConfigMu or the engine operation lock. Legacy broker lifecycle relays release settings locks across worker calls and refresh snapshots afterward. Unit executors now explicitly provide test-only broker authority; production has no missing-parent fallback. Production start caller inventory: StartWith is called by Executor.Start, Manager.runOp's start closure (engine:start and engine:install with start=true), controlServer.handleStart (the target of engine:remote-start), and controlServer.handleInstall (remote install autostart). Manager.runOp also calls Restart; Manager.runSetPort calls SetPort; Action calls restartAfterAction; RestoreEnabled calls restoreEnabled. Direct doStart callers are StartWith, Restart, restoreEnabled, restartAfterAction, SetPort's new-port restart and persistence-failure old-port restart, and ConfigureLaunch's candidate restart and rollback restart. All of them pass the same doStart authorization check. The broker has no direct Go Start or StartWith call. relayToEngineNow forwards local start/restart, remote-start and legacy lifecycle requests. restoreEnabledEngines requests saved-ON restoration from initial startup through restoreEnabledEnginesAfterPortGate/runEngineAvailabilityAfterPortGates and from spawnEngineMgr on worker respawn. runSettingsOperationLocked requests ConfigureLaunch for Apply, recovery and handleSettingsPortRPC's server/proxy port changes. Legacy internal engine:set-port calls in prepareManagedLMStudioFacadeWithPortCheck and reconcileProxyPortOnReady (including its rollback) also reach the guarded SetPort restart. No client configure-launch request is allowed through. TestRecoveryGateBlocksLocalAndRemoteStart covers failed and successful recovery for both entry points. On unmodified 3e9f700 with only the final test file added, go test -count=1 -run '^TestRecoveryGateBlocksLocalAndRemoteStart$/remote=true$' ./... fails with 'unreconciled engine started'; it passes with this fix. TestRecoveryGateAllowsApplyRollbackRestart exercises real compensation. TestRecoveryGateCoversLifecycleStarts, TestRecoveryGateRejectsMissingBrokerAndRevokedGrant and TestStartChokepointRefusesMissingAuthorization cover the other worker paths and fail-closed boundary. Broker tests TestStartGateRetriesRecoveryAndWithdrawsAdvertisement, TestConfigureRevokesStartGrantAndAuthorizesRollbackWithoutSettingsLocks and TestEngineStartGateRelay cover failed/interrupted/unreadable journals, stale grants, engine isolation and lock-safe reverse relay authorization. Validation: fresh go test -race -count=1 ./... in both affected modules; go vet ./... for darwin, linux and windows in both; gofmt; git diff --check; SPDX (1344 checked, zero missing); desktop npm ci --no-audit --no-fund and npm run -s service-contracts:check all pass. Existing opt-in live tests remain skipped; no live engines or cross-process suite were run. Document the internal gate in ENGINE_SETTINGS.md and the worker README. Keep versions unchanged as requested by the maintainer. Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
Managed Ollama reconciliation held engineConfigMu while SetPort asked the broker to prepare-start, so the reverse recovery relay deadlocked until both the move and rollback hit their five-second deadlines. Snapshot the journal, ownership plan and worker handles, release the lock for worker I/O, then revalidate before consuming any result. Changed state is reconciled from current authoritative configuration rather than an old candidate. The broker lock audit changed every engineConfigMu-held call site in reconcileProxyPortOnReady: the managed backend move and rollback, facade bind, fallback rebind, runningEnginePorts/get-installed lookup and final corrective proxy rebind. Current-state recovery also performs engine:status unlocked. settingsApplyMu is never held on these paths. Audited settings snapshot/preview and advertisement reads, ConfigureLaunch recovery, legacy lifecycle relays, scheduler delivery, discovery and manual-node callbacks: no additional worker request waited on a callback needing its caller's held lock. ConfigureLaunch callbacks need only relay state; ordinary launch preparation precedes the worker operation lock. Broker-only internal:set-port operations carry a unique ID tied to the captured configuration and worker. On timeout, internal:cancel-set-port cancels and joins that operation on the captured worker before fallback or rollback. Worker managedPortsMu protects registration only and is released before execution or cancellation joins. SetPort rechecks context cancellation and start authorization after acquiring opMu and before persistence, including stopped engines. Unconfirmed cancellation retains the ownership gate even across duplicate ready events. Public engine:set-port remains unchanged; internal protocol documentation and generated contracts are updated. Regression evidence: copying the final tests onto b674ab1 reproduces a 10.003-second reverse-relay timeout/fallback and canceled/revoked queued moves persisting their port. The fixed real-worker relay completes in 447 ms, excluding compilation. Tests cover timeout/late-reply fencing, a concurrent explicit settings apply, cancellation joins, stale queued grants and unconfirmed-cancel readiness. Isolate the cross-process fixture's broker lifetime from the process-global teardown clock. Validation: go test -race -count=1 ./... in broker and engine-manager; GOOS=darwin/linux/windows go vet ./... in both; gofmt and SPDX (zero missing); desktop npm ci --no-audit --no-fund, typecheck, lint, 892 unit tests, dead-code:check and service-contracts:check. No service versions changed, as requested. Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
A delayed unversioned reconciliation bind could arrive after a newer Apply, and the stale-state retry returned without restoring the accepted proxy port. Give each engine one port-operation mutex in Broker.portOperations, acquired before settingsApplyMu and engineConfigMu and retained across worker I/O, compensation and the final desired-port convergence. Never acquire port-op from a reverse callback or while holding either settings lock. Write-site audit: enginesettings.go runSettingsOperationLocked sends engine:configure-launch under Apply or restoration port-op ownership; rebindSettingsProxy sends the selected proxy bind as a delegated callback. engine_settings_read.go rebind/rollback callbacks borrow that registered parent operation, including the captured previous startup port. The parent seals callback admission and joins in-flight writes before releasing port-op. proxyport.go reconcileProxyPortOnReady owns port-op across the facade bind, fallback vacate, engine move, engine rollback and engine-wins corrective proxy bind. Its moveManagedOllamaPort writes in managedport.go retain the existing captured-worker cancellation join and authorization fencing. reconcileCurrentOllamaPorts takes the same mutex and invokes the in-operation reconciler without reacquiring it. lmstudioport.go prepareManagedLMStudioFacadeWithPortCheck owns port-op for its engine:set-port; readiness owns it across rebindLMStudioProxy and every fallback/collision bind. broker.go relayToEngineNow owns it across legacy engine:set-port, engine:start with a port and engine:install with start+port, including the post-call settings refresh. Port-only UI/TUI RPCs continue through Apply, which takes the same mutex. The Ollama/LM Studio/oMLX startup planners own port-op across explicit settings restoration and all managed/fallback startup-port choices. spawnProxy, spawnLMStudioProxy and spawnOMLXProxy own it across startup arguments, worker spawn and handle publication. recoverProxyBindFailure owns it for reader-dispatched fallback choices; finishOllamaProxyTerminal and the missing-LM-Studio startup path own it for terminal fallback choices. recoverEngineSettingsForEngine and the nonblocking start-recovery executor own it for journal restoration and its configure/rollback writes. portoperation.go finishPortOperation performs the final corrective proxy write under the operation's mutex, including early and stale-result exits. All unversioned proxy writes use proxyport_write.go writeProxyPort and join the response or worker exit, rather than allowing a local timeout to release ownership before a late bind. A hung proxy requires manual worker restart. Convergence failure withdraws availability and revokes start grants. Explicit accepted proxy settings never get replaced by a stray ready observation. prepare-start uses only short engineConfigMu sections. Recovery runs in a separate executor with nonblocking port-op admission; an active operation fails preparation closed instead of waiting for its own callback. Rebind, rollback and authorize-start never acquire port-op. ENGINE_SETTINGS.md records the lock order, delegation, joining and final convergence rules. TestPortOperationSerializesDelayedReconcileWithApply fails on e45aebf with the old bind persisted on 11434 after Apply accepted another port. With the fix, Apply queues behind the old write (reloading a legitimately advanced baseline revision if needed). TestPortOperationCorrectsStaleReadyToAcceptedPort checks final proxy and persisted choices for all three engines; TestPrepareStartCompletesWhilePortOperationHeld checks healthy and fail-closed reverse callbacks. TestPortOperationConvergenceFailureBlocksStart checks the failure gate and revocation, including initial recovery-map allocation. All six e45aebf tests remain, together with b674ab1's recovery-gate tests. Validation: go test -race -count=1 ./... in broker and engine-manager; -race -count=20 on broker concurrency/recovery/gate tests and engine-manager fencing/gate tests; GOOS=darwin/linux/windows go vet ./... in both modules; gofmt and git diff --check; SPDX zero missing; own desktop npm ci --no-audit --no-fund and service-contracts:check. An independent read-only review found no blocking issues. No wire contracts or versions changed. Signed-off-by: Jared Ping <13906915+JaredP94@users.noreply.github.com>
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
Add engine launch settings on this device and verified paired devices. Users can edit server/proxy ports and literal launch arguments/environment assignments, validate before saving, confirm only required engine restarts, follow apply progress, and see one safe failure message. Concurrent edits reload saved settings rather than overwrite them. oMLX exposes only its proxy port; server settings stay in the oMLX app.
Port and adapt the launch-settings work from NVIDIA/Personal-AI-Router@0df32b0, authored by Noah (Terve) Tervalon. The implementation uses the fork's existing components and three separate proxy workers.
Scope
services/nvpair-ui-broker/ENGINE_SETTINGS.md.c322a84): if saving, the proxy rebind, engine start or readiness fails after the engine stopped, the previous configuration, proxy port, listening scope and running state are restored under the operation lock, and the failure says so. If restoration itself fails, the engine stays stopped and is never left listening more widely than before. Persistence is atomic. An additive internalrollbackrelay restores only the broker-captured previous proxy port; public request/result fields are unchanged.Validation
Go, on macOS arm64 in isolated worktrees:
go test -race ./...andgo test -count=1 ./...inservices/nvpair-engine-managerandservices/nvpair-ui-broker, plus every other touched module — passed.go vet ./...withGOOS=darwin,linuxandwindows— passed;gofmt -lclean.TestSettingsApplyRestoresPreviousState/{persist,rebind,start,readiness,rollback}failed oncb6452eand pass with the rollback fix.Desktop checks on macOS arm64, Node v26.7.0 / npm 11.19.0, from an isolated worktree with its own
npm ci --no-audit --no-fund:cd desktop && npm run -s typecheck— passed.cd desktop && npm run -s lint— passed, zero warnings.cd desktop && npm run -s test:unit— passed, 892 tests in 89 files.cd desktop && npm run -s dead-code:check— passed.cd desktop && npm run -s service-contracts:check— passed.node scripts/spdx-headers.mjs— zero missing headers.git diff --check— passed.cd desktop && npm run -s build:renderer— passed.No live engine installation/start, Electron end-to-end interaction, or real paired-device runtime was exercised. PR CI covers the cross-process suite on Linux and macOS.
Risk
Settings changes can restart an engine or rebind its proxy; the owning Go node coordinates those operations. Unsupported formats/devices and disconnected devices remain read-only. Revisions guard concurrent edits, and launch values remain private configuration displayed only in their editor. Live multi-device behavior and platform-specific engine launches still need runtime validation.
Checklist
git commit -s), certifying the Developer Certificate of Origin.services/versions.json, and described user-visible changes above so they reach the release notes. Existing appropriate unreleased minor bumps are retained as explained above.