Skip to content

mrd-viz: deterministic two-tier backend resolution - #86

Open
ccapetz wants to merge 9 commits into
carter-mrd-vizfrom
mrd-viz-backend-resolution-core
Open

mrd-viz: deterministic two-tier backend resolution#86
ccapetz wants to merge 9 commits into
carter-mrd-vizfrom
mrd-viz-backend-resolution-core

Conversation

@ccapetz

@ccapetz ccapetz commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Replaces the 5-candidate backend search with deterministic two-tier resolution.

Why

The old resolver probed 5 candidates in a fixed order (override -> bundled -> managed venv -> repo .venv -> python on PATH), silently using whatever answered. That produced the "which Python is actually used?" confusion and let a broken candidate be picked and fail late. Design: docs/BACKEND_INSTALL_MODES.md.

What

  • Two tiers, no silent fallback: if mrdViz.backendPath is set it is the only candidate (fail loud if broken); otherwise use the bundled binary. The repo backend/.venv is tried first only in the F5 Development host.
  • New mrdViz.backendPath (interpreter or binary), machine-scoped so a path can't be committed to a workspace or synced across machines - this structurally prevents the host-path-leaks-into-container ENOENT bug. mrdViz.pythonPath is deprecated but still honored when explicitly set.
  • Setup/select persist the interpreter to backendPath, so the managed venv is a first-class override rather than an implicit candidate.
  • Tailored backend-missing page: distinguishes a broken override from a bundled backend that won't run.

Notes

  • Not included: the old-glibc Linux binary (tracked separately as an odin dependency); until then, unsupported platforms hit the fail-loud recovery path.
  • Tests: planBackendCandidates ordering/no-fallback/binary-classification + the tailored page. All 18 pass; compile + lint clean.

ccapetz added 6 commits August 4, 2026 15:44
…ementation plan

Design docs backing the deterministic backend-resolution work: current-state analysis, the two-audience target architecture, levels-of-abstraction diagram, and the phased implementation plan. Base commit for the resolver rewrite (PR1).
Replace the 5-candidate search with a pure planBackendCandidates(): a configured override is the ONLY candidate (no silent fallback), otherwise the bundled binary, with the repo .venv tried first only in the F5 Development host. Adds BackendKind and getConfiguredBackendPath (backendPath, then legacy explicit pythonPath). Drops managed-venv and PATH candidates.
selectInterpreter and the guided setup now write the machine-scoped mrdViz.backendPath (no more workspace scope-clearing needed), so the managed venv becomes a first-class override rather than an implicit resolver candidate. Config invalidation watches backendPath and pythonPath.
Lead with the relevant explanation and primary action: a broken mrdViz.backendPath override vs. a bundled backend that won't run on this platform. Update references to backendPath.
Uses mrdViz.backendPath (applied as a container remote setting) instead of the deprecated pythonPath, so the container interpreter can't leak to the host.
…implemented

Unit-test planBackendCandidates (override no-fallback, dev vs prod order, binary classification, empty) and the tailored override page. Update BACKEND_INSTALL_MODES (target -> implemented) and DEVCONTAINER (machine-scoped backendPath, leak now structurally prevented).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors MRD Viz backend selection to a deterministic two-tier resolver, centering resolution around an explicit machine-scoped override (mrdViz.backendPath) or the bundled backend binary, with a Development-host-only escape hatch to prefer the repo venv.

Changes:

  • Replaces the previous 5-candidate “silent fallback” resolver with planBackendCandidates() + fail-loud behavior.
  • Introduces machine-scoped mrdViz.backendPath, deprecates mrdViz.pythonPath, and persists managed-venv installs / interpreter selection into backendPath.
  • Updates the backend-missing webview UX, adds resolver-order tests, and refreshes devcontainer/docs to match the new model.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
mrd-viz/extension/mrd-viz/src/webviewHtml.ts Tailors backend-missing page messaging/actions based on override vs bundled failure; updates guidance text to backendPath.
mrd-viz/extension/mrd-viz/src/test/extension.test.ts Adds tests for tailored backend-missing UX and deterministic candidate ordering.
mrd-viz/extension/mrd-viz/src/extension.ts Persists managed venv to mrdViz.backendPath, updates config invalidation, and switches interpreter selection to write backendPath.
mrd-viz/extension/mrd-viz/src/backendResolver.ts Implements two-tier deterministic resolution with explicit override, bundled binary, and dev-host repo venv ordering.
mrd-viz/extension/mrd-viz/package.json Adds mrdViz.backendPath (machine scope) and deprecates mrdViz.pythonPath.
mrd-viz/docs/DEVCONTAINER.md Updates devcontainer guidance and leak runbook text to backendPath and legacy pythonPath behavior.
mrd-viz/docs/BACKEND_RESOLUTION_IMPLEMENTATION_PLAN.md Adds an implementation-plan doc describing the new resolution model and phases.
mrd-viz/docs/BACKEND_INSTALL_MODES.md Adds a detailed doc describing install modes and the new target architecture (now implemented).
.devcontainer/mrd-viz/devcontainer.json Switches devcontainer settings from mrdViz.pythonPath to mrdViz.backendPath.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread mrd-viz/extension/mrd-viz/src/webviewHtml.ts
Comment thread mrd-viz/extension/mrd-viz/src/backendResolver.ts
Comment thread mrd-viz/extension/mrd-viz/src/webviewHtml.ts
Comment thread mrd-viz/extension/mrd-viz/src/extension.ts Outdated
Comment thread mrd-viz/docs/BACKEND_INSTALL_MODES.md Outdated
@yuliadub

yuliadub commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Nice work on the deterministic resolver — planBackendCandidates is clean and well-tested, and the machine-scoped backendPath closes the host→container leak for the new setting. A few follow-ups below, mostly centered around clean up and I think it makes sense to get them done as part of this PR.

1. Stale mrdViz.pythonPath references outside the diff

These files still reference the old setting or the removed PATH fallback and will confuse users of this exact PR. Rename to mrdViz.backendPath and drop any "python vs python3 on PATH" language:

  • mrd-viz/extension/mrd-viz/README.md
  • mrd-viz/docs/PACKAGING_AND_INSTALL_RUNBOOK.md (§6 and §6c, including the "Why set this explicitly?" callout)
  • mrd-viz/docs/TECHNICAL_DESIGN.md (~line 249)
  • .devcontainer/mrd-viz/postCreate.sh (comment ~line 49)

2. Stale test fixture

In mrd-viz/extension/mrd-viz/src/test/extension.test.ts, the "renders a guided backend-missing view" test uses sources the new resolver can never emit (mrdViz.pythonPath setting (<x>), "python" on PATH). Update to realistic new-world sources, e.g. mrdViz.backendPath setting (…) and bundled backend (…).

3. Override label misleads when the legacy setting was used

configuredBackend() in backendResolver.ts labels the source as mrdViz.backendPath setting (…) even when the value came from the legacy mrdViz.pythonPath fallback. The webview intro in webviewHtml.ts has the same hard-coded string. Fix by having getConfiguredBackendPath() return which key it read, and threading that through the source label and the UI intro.

4. Four execFile sites, four different configs

The extension launches subprocesses in four places, each with its own timeout, buffer size, and error shaping. Sooner or later they'll drift - it would be good to consolidate.

Site Timeout maxBuffer Signal On error
validateBackend (backendResolver.ts) clamp(t, 1000, 15000) node default no return {ok:false, detail}
execBackend (backendRunner.ts) options.timeoutMs unclamped 64 MB yes reject if no stdout
isPython312OrNewer (extension.ts) 10000 hardcoded node default no resolve false
runProvisioningStep (extension.ts) 600000 hardcoded 10 MB no log + reject

5. Magic numbers should be named

Add mrd-viz/extension/mrd-viz/src/backendConstants.ts (or similar) and replace the scattered literals. (some of these can likely be consolidated)

export const BACKEND_TIMEOUT_MS_DEFAULT = 30_000;              // must match package.json default
export const PROBE_TIMEOUT_MS_MIN = 1_000;
export const PROBE_TIMEOUT_MS_MAX = 15_000;
export const PYTHON_VERSION_PROBE_TIMEOUT_MS = 10_000;
export const PROVISIONING_STEP_TIMEOUT_MS = 10 * 60 * 1_000;   // pip installs can be slow
export const BACKEND_RESPONSE_MAX_BUFFER_BYTES = 64 * 1024 * 1024;
export const PROVISIONING_LOG_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
export const PYTHON_MODULE_ARGS = ['-m', 'mrd_viz.cli'] as const;
export const PYPI_PACKAGE_NAME = 'mrd-viz';
export const PROVISIONING_PYTHON_CANDIDATES = ['python3.12', 'python3', 'python'] as const;

There may be more constants to consolidate in the frontend too.

6. Dead pip install mrd-viz branch

extension.ts (~line 187):

const installArgs = installTarget === 'mrd-viz'
    ? ['-m', 'pip', 'install', 'mrd-viz']
    : ['-m', 'pip', 'install', '-e', installTarget];

The 'mrd-viz' branch only fires when no local mrd-viz/backend/ is on disk — i.e. the PyPI path, which per this PR's docs 404s. Options:

  1. Drop it and fail loud (matches the resolver's philosophy).
  2. Keep with // TODO(publish-pypi) so the intent is explicit.
  3. At minimum move the package name to PYPI_PACKAGE_NAME (see §7) so the same string doesn't live in the webview HTML too.

Also: pass --disable-pip-version-check --no-input to both pip calls. Removes "A new release of pip is available…" noise and prevents pip from blocking on a prompt in restricted environments.

7. Minor

  • getConfiguredBackendPath is exported in backendResolver.ts but has no external callers — drop the export.
  • PYTHON_MODULE_ARGS is duplicated as a string in postCreate.sh and mrd-viz/backend/tests/test_cli.py; cross-language, can't dedupe, just noting.

ccapetz added 2 commits August 7, 2026 10:24
…et/toast/doc

- Override candidate/logs and the backend-missing page now name the setting the value came from (backendPath vs legacy pythonPath) instead of always backendPath.
- Setup snippet installs editable from a checkout (mrd-viz is not on PyPI).
- Interpreter-selection toast is setting-neutral (path may be a binary).
- Reconcile BACKEND_INSTALL_MODES intro (pre-refactor, not current).
- Tests for the legacy-setting labeling.
- centralize magic timeouts/buffers/names in backendConstants.ts

- add runProcess() execFile wrapper; use it in resolver, runner, provisioning

- use PYPI package name mrd-viz and add --disable-pip-version-check --no-input to pip; TODO(publish-pypi)

- drop unused getConfiguredBackendPath export

- refresh stale mrdViz.pythonPath -> mrdViz.backendPath references in docs and postCreate

- update backend-missing test fixture to realistic post-refactor sources
@ccapetz

ccapetz commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed issues:

  1. renamed stale pythonPath references to backendPath in relevant docs, other small fixes for up-to-date info in the docs
  2. fixed backend-missing view test
  3. page now names the exact setting the broken override came from
  4. added subprocess.ts with a single wrapper used by each of the items you mentioned so that each caller can keep its own error shaping
  5. centralized numbers in backendConstants.ts
  6. kept install path but renamed and added a todo
  7. dropped the export and now its module private

The un-scoped legacy setting could leak across machines (e.g. a Linux path synced into Windows User settings) and, treated as an exclusive override, suppressed the bundled binary and forced the backend-not-found page. Only the machine-scoped mrdViz.backendPath is honored now.

- resolver reads only mrdViz.backendPath; remove legacy inspect() branch and settingKey plumbing

- remove deprecated mrdViz.pythonPath declaration and config-change watch

- simplify backend-missing intro to name mrdViz.backendPath; drop two legacy tests
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.

3 participants