feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection - #189

Merged
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning
Jul 20, 2026
Merged

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection#189
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning

Conversation

@kateebonner

Copy link
Copy Markdown
Contributor

Implements the Slack-thread decision (option 1: extension-provisioned venv; Aaron + Kate aligned). Issue to be filed from the thread — will re-title fix(#NN) when it exists.

Summary

Fresh installs cannot connect to Pasqal: the fork's validator spawn resolves $AMICO_PYTHON → bare python3, no ambient interpreter has pasqal-cloud, the validator exits 1 ("SDK not installed"), and the panel misrenders the config lane as "Service unreachable" (found live-testing v0.0.3-alpha; root-caused against the shipped amicode.8 binary, whose AMICO_PYTHON support was verified live before this was written).

  • Provisioning owner: the extension. pasqal_python.ts (mirrors pasqal_assets.ts): probe host python3 ≥ 3.10 (PATH + well-known absolute candidates — Dock-launched VS Code inherits the launchd-minimal PATH), -m venv under <opsDir>/venvs/pasqal-connector, pip install -r the staged requirements.txt. Hash-gated: stamp written only after pip exit 0, so failed provisions retry free next activation; fast path is stat+hash, zero subprocesses.
  • Env seam / S37 exception: injected via the single buildServerSpawnEnv builder used by all three spawn sites (boot, solver-mode respawn, vault respawn) — no respawn path can drop it. S37 ("no AMICO_* env propagation") note amended in place: this is server-child plumbing for the fork's validator spawn, NOT amico-run contract; amico-run still receives nothing via env.
  • Fail-closed AMICO_PYTHON: provisioning failure never sets the var (absent, not empty — the fork's fallback is byte-identical to today), logs ONE actionable line per lane (no python / venv failed / pip failed-offline). Slow path runs in the background, never blocks activation; on success it mutates the live spawn env (ServerManager re-reads at start()) and bounces via the existing amicode.restartServer, so a fresh install self-heals without a reload.
  • Override precedence: host $AMICO_PYTHON wins outright and skips provisioning (the $AMICO_PASQAL_VALIDATOR convention; absent-not-empty semantics match the fork's resolver).
  • Token safety: provisioner child env is built from scratch as { PATH, HOME } — poison-token test proves no secret rides argv, env, or failure copy.

Freeze respected

release.yml untouched, no tag cut. amico-run argv contract untouched. launch.ts zero-line diff. Unprovisioned sessions: buildServerSpawnEnv output byte-identical.

Deferred (out of scope)

Fork-side rendering of the config-lane error text (panel currently shows state-generic "Service unreachable" copy; the route already returns the precise message). amico-pasqal launcher interpreter unification (submit path). Windows venv layout (lock targets darwin-arm64/linux-x64 only). Staging of the 3 submit-path connector scripts.

Gate results

  • extension vitest: 713 pass / 15 skip (+13: 10 pasqal_python incl. real-interpreter venv lane, +1 server_auth, +3 gate mutation) · tsc --noEmit clean · prettier clean
  • boot smoke: [smoke] PASS (vendored v1.17.3-amicode.8)
  • new behavioral gate assert_provisioned_python.mjs (mirrors assert_packaged_cli.mjs): local run 4/4 PASS — pin parse, real venv+pip from shipped assets, SDK import at ==0.23.0, validator env-guard smoke. Wired in ci.yml only: fast job (source lane) + vsix-gate job (assets unzipped from the real artifact).
  • Julia solve E2E: n/a (no template/Julia changes)

🤖 Generated with Claude Code

…jection
The fresh-install fix: the fork's validator spawn resolves $AMICO_PYTHON →
bare python3, and on a fresh machine no ambient interpreter has pasqal-cloud,
so the validator exits 1 and the panel misreports 'Service unreachable'. The
extension now owns the interpreter: venv from the STAGED requirements.txt
(hash-gated, stamp-on-success), injected via the single buildServerSpawnEnv
seam so no respawn path drops it; background slow path self-heals via the
existing restart command. Host $AMICO_PYTHON wins outright. Behavioral CI
gate (source + vsix lanes) proves the shipped assets provision a working
interpreter.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
ContributorAuthor

Verification record (merging on this evidence):

  • CI: green — including both new provisioning-gate lanes (source-staged in fast, artifact lane in vsix-gate against the unzipped .vsix), each doing a real venv + PyPI install + SDK import at the pin on clean ubuntu runners.
  • Unit: extension vitest 713 pass / 15 skip (+13 this PR: provisioning module incl. real-interpreter lane + poison-token/env-allowlist adversarial lanes, seam test, gate mutation tests) · tsc clean · prettier clean · boot smoke PASS on vendored amicode.8.
  • Sandbox E2E on the CI artifact (isolated $HOME, no AMICO_PYTHON anywhere): staged → background-provisioned in ~145s cold → venv imports pasqal-cloud 0.23.0 → self-heal restart delivered AMICO_PYTHON=<venv python> into the live server env → real-credential Pasqal connect succeeded (state connected, FRESNEL devices enumerated, token-only pasqal.json at 0600). Second boot takes the stat+hash fast path (zero subprocess); a requirements change re-provisions (stamp rotates); a genuine disk-full pip failure exercised the no-stamp retry lane and recovered on the next activation.
  • Known transient (deferred, fork-side): on a truly fresh machine the first ~2.5 min before self-heal completes can still fail a very eager first connect with the generic "unreachable" copy — the fork-side error-rendering fix covers this window.

🤖 Generated with Claude Code

@kateebonner
kateebonner marked this pull request as ready for review July 20, 2026 20:46
@kateebonner
kateebonner merged commit 0bf3cc4 into mainJul 20, 2026
5 checks passed
jack-champagne added a commit to harmoniqs/opencode that referenced this pull request Jul 28, 2026
The unit job died with exit 137 and reported nothing. Not an OOM (peak
0.37GB of 32GB, zero faults) — a segfault inside @napi-rs/keyring's
native setPassword(), reached from the pasqal submit success path.
Install the in-memory secret store, as the sibling
amicode-connections.test.ts already does. Production is unaffected: the
same write succeeds under `bun run … serve`, verified end-to-end against
Pasqal with real credentials.
Also swap the stub validator from a bun-executed .mjs to a
python3-executed .py. amicode provisions <opsDir>/venvs/pasqal-connector
and passes it as AMICO_PYTHON (harmoniqs/amicode#189), so the production
interpreter is always a real python; bun-as-interpreter tested a
configuration that never ships.
Drop the windows unit lane: opencode.lock.json ships darwin-arm64 and
linux-x64 only, and it was the ~50min long pole while red for an
unrelated reason (#76).
Refs #82, #76
Sign up for freeto 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.

1 participant

@kateebonner
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection - #189

Merged
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning
Jul 20, 2026
Merged

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection#189
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning

Conversation

@kateebonner

Copy link
Copy Markdown
Contributor

Implements the Slack-thread decision (option 1: extension-provisioned venv; Aaron + Kate aligned). Issue to be filed from the thread — will re-title fix(#NN) when it exists.

Summary

Fresh installs cannot connect to Pasqal: the fork's validator spawn resolves $AMICO_PYTHON → bare python3, no ambient interpreter has pasqal-cloud, the validator exits 1 ("SDK not installed"), and the panel misrenders the config lane as "Service unreachable" (found live-testing v0.0.3-alpha; root-caused against the shipped amicode.8 binary, whose AMICO_PYTHON support was verified live before this was written).

  • Provisioning owner: the extension. pasqal_python.ts (mirrors pasqal_assets.ts): probe host python3 ≥ 3.10 (PATH + well-known absolute candidates — Dock-launched VS Code inherits the launchd-minimal PATH), -m venv under <opsDir>/venvs/pasqal-connector, pip install -r the staged requirements.txt. Hash-gated: stamp written only after pip exit 0, so failed provisions retry free next activation; fast path is stat+hash, zero subprocesses.
  • Env seam / S37 exception: injected via the single buildServerSpawnEnv builder used by all three spawn sites (boot, solver-mode respawn, vault respawn) — no respawn path can drop it. S37 ("no AMICO_* env propagation") note amended in place: this is server-child plumbing for the fork's validator spawn, NOT amico-run contract; amico-run still receives nothing via env.
  • Fail-closed AMICO_PYTHON: provisioning failure never sets the var (absent, not empty — the fork's fallback is byte-identical to today), logs ONE actionable line per lane (no python / venv failed / pip failed-offline). Slow path runs in the background, never blocks activation; on success it mutates the live spawn env (ServerManager re-reads at start()) and bounces via the existing amicode.restartServer, so a fresh install self-heals without a reload.
  • Override precedence: host $AMICO_PYTHON wins outright and skips provisioning (the $AMICO_PASQAL_VALIDATOR convention; absent-not-empty semantics match the fork's resolver).
  • Token safety: provisioner child env is built from scratch as { PATH, HOME } — poison-token test proves no secret rides argv, env, or failure copy.

Freeze respected

release.yml untouched, no tag cut. amico-run argv contract untouched. launch.ts zero-line diff. Unprovisioned sessions: buildServerSpawnEnv output byte-identical.

Deferred (out of scope)

Fork-side rendering of the config-lane error text (panel currently shows state-generic "Service unreachable" copy; the route already returns the precise message). amico-pasqal launcher interpreter unification (submit path). Windows venv layout (lock targets darwin-arm64/linux-x64 only). Staging of the 3 submit-path connector scripts.

Gate results

  • extension vitest: 713 pass / 15 skip (+13: 10 pasqal_python incl. real-interpreter venv lane, +1 server_auth, +3 gate mutation) · tsc --noEmit clean · prettier clean
  • boot smoke: [smoke] PASS (vendored v1.17.3-amicode.8)
  • new behavioral gate assert_provisioned_python.mjs (mirrors assert_packaged_cli.mjs): local run 4/4 PASS — pin parse, real venv+pip from shipped assets, SDK import at ==0.23.0, validator env-guard smoke. Wired in ci.yml only: fast job (source lane) + vsix-gate job (assets unzipped from the real artifact).
  • Julia solve E2E: n/a (no template/Julia changes)

🤖 Generated with Claude Code

…jection
The fresh-install fix: the fork's validator spawn resolves $AMICO_PYTHON →
bare python3, and on a fresh machine no ambient interpreter has pasqal-cloud,
so the validator exits 1 and the panel misreports 'Service unreachable'. The
extension now owns the interpreter: venv from the STAGED requirements.txt
(hash-gated, stamp-on-success), injected via the single buildServerSpawnEnv
seam so no respawn path drops it; background slow path self-heals via the
existing restart command. Host $AMICO_PYTHON wins outright. Behavioral CI
gate (source + vsix lanes) proves the shipped assets provision a working
interpreter.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
ContributorAuthor

Verification record (merging on this evidence):

  • CI: green — including both new provisioning-gate lanes (source-staged in fast, artifact lane in vsix-gate against the unzipped .vsix), each doing a real venv + PyPI install + SDK import at the pin on clean ubuntu runners.
  • Unit: extension vitest 713 pass / 15 skip (+13 this PR: provisioning module incl. real-interpreter lane + poison-token/env-allowlist adversarial lanes, seam test, gate mutation tests) · tsc clean · prettier clean · boot smoke PASS on vendored amicode.8.
  • Sandbox E2E on the CI artifact (isolated $HOME, no AMICO_PYTHON anywhere): staged → background-provisioned in ~145s cold → venv imports pasqal-cloud 0.23.0 → self-heal restart delivered AMICO_PYTHON=<venv python> into the live server env → real-credential Pasqal connect succeeded (state connected, FRESNEL devices enumerated, token-only pasqal.json at 0600). Second boot takes the stat+hash fast path (zero subprocess); a requirements change re-provisions (stamp rotates); a genuine disk-full pip failure exercised the no-stamp retry lane and recovered on the next activation.
  • Known transient (deferred, fork-side): on a truly fresh machine the first ~2.5 min before self-heal completes can still fail a very eager first connect with the generic "unreachable" copy — the fork-side error-rendering fix covers this window.

🤖 Generated with Claude Code

@kateebonner
kateebonner marked this pull request as ready for review July 20, 2026 20:46
@kateebonner
kateebonner merged commit 0bf3cc4 into mainJul 20, 2026
5 checks passed
jack-champagne added a commit to harmoniqs/opencode that referenced this pull request Jul 28, 2026
The unit job died with exit 137 and reported nothing. Not an OOM (peak
0.37GB of 32GB, zero faults) — a segfault inside @napi-rs/keyring's
native setPassword(), reached from the pasqal submit success path.
Install the in-memory secret store, as the sibling
amicode-connections.test.ts already does. Production is unaffected: the
same write succeeds under `bun run … serve`, verified end-to-end against
Pasqal with real credentials.
Also swap the stub validator from a bun-executed .mjs to a
python3-executed .py. amicode provisions <opsDir>/venvs/pasqal-connector
and passes it as AMICO_PYTHON (harmoniqs/amicode#189), so the production
interpreter is always a real python; bun-as-interpreter tested a
configuration that never ships.
Drop the windows unit lane: opencode.lock.json ships darwin-arm64 and
linux-x64 only, and it was the ~50min long pole while red for an
unrelated reason (#76).
Refs #82, #76
Sign up for freeto 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.

1 participant

@kateebonner
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection - #189

Merged
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning
Jul 20, 2026
Merged

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection#189
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning

Conversation

@kateebonner

Copy link
Copy Markdown
Contributor

Implements the Slack-thread decision (option 1: extension-provisioned venv; Aaron + Kate aligned). Issue to be filed from the thread — will re-title fix(#NN) when it exists.

Summary

Fresh installs cannot connect to Pasqal: the fork's validator spawn resolves $AMICO_PYTHON → bare python3, no ambient interpreter has pasqal-cloud, the validator exits 1 ("SDK not installed"), and the panel misrenders the config lane as "Service unreachable" (found live-testing v0.0.3-alpha; root-caused against the shipped amicode.8 binary, whose AMICO_PYTHON support was verified live before this was written).

  • Provisioning owner: the extension. pasqal_python.ts (mirrors pasqal_assets.ts): probe host python3 ≥ 3.10 (PATH + well-known absolute candidates — Dock-launched VS Code inherits the launchd-minimal PATH), -m venv under <opsDir>/venvs/pasqal-connector, pip install -r the staged requirements.txt. Hash-gated: stamp written only after pip exit 0, so failed provisions retry free next activation; fast path is stat+hash, zero subprocesses.
  • Env seam / S37 exception: injected via the single buildServerSpawnEnv builder used by all three spawn sites (boot, solver-mode respawn, vault respawn) — no respawn path can drop it. S37 ("no AMICO_* env propagation") note amended in place: this is server-child plumbing for the fork's validator spawn, NOT amico-run contract; amico-run still receives nothing via env.
  • Fail-closed AMICO_PYTHON: provisioning failure never sets the var (absent, not empty — the fork's fallback is byte-identical to today), logs ONE actionable line per lane (no python / venv failed / pip failed-offline). Slow path runs in the background, never blocks activation; on success it mutates the live spawn env (ServerManager re-reads at start()) and bounces via the existing amicode.restartServer, so a fresh install self-heals without a reload.
  • Override precedence: host $AMICO_PYTHON wins outright and skips provisioning (the $AMICO_PASQAL_VALIDATOR convention; absent-not-empty semantics match the fork's resolver).
  • Token safety: provisioner child env is built from scratch as { PATH, HOME } — poison-token test proves no secret rides argv, env, or failure copy.

Freeze respected

release.yml untouched, no tag cut. amico-run argv contract untouched. launch.ts zero-line diff. Unprovisioned sessions: buildServerSpawnEnv output byte-identical.

Deferred (out of scope)

Fork-side rendering of the config-lane error text (panel currently shows state-generic "Service unreachable" copy; the route already returns the precise message). amico-pasqal launcher interpreter unification (submit path). Windows venv layout (lock targets darwin-arm64/linux-x64 only). Staging of the 3 submit-path connector scripts.

Gate results

  • extension vitest: 713 pass / 15 skip (+13: 10 pasqal_python incl. real-interpreter venv lane, +1 server_auth, +3 gate mutation) · tsc --noEmit clean · prettier clean
  • boot smoke: [smoke] PASS (vendored v1.17.3-amicode.8)
  • new behavioral gate assert_provisioned_python.mjs (mirrors assert_packaged_cli.mjs): local run 4/4 PASS — pin parse, real venv+pip from shipped assets, SDK import at ==0.23.0, validator env-guard smoke. Wired in ci.yml only: fast job (source lane) + vsix-gate job (assets unzipped from the real artifact).
  • Julia solve E2E: n/a (no template/Julia changes)

🤖 Generated with Claude Code

…jection
The fresh-install fix: the fork's validator spawn resolves $AMICO_PYTHON →
bare python3, and on a fresh machine no ambient interpreter has pasqal-cloud,
so the validator exits 1 and the panel misreports 'Service unreachable'. The
extension now owns the interpreter: venv from the STAGED requirements.txt
(hash-gated, stamp-on-success), injected via the single buildServerSpawnEnv
seam so no respawn path drops it; background slow path self-heals via the
existing restart command. Host $AMICO_PYTHON wins outright. Behavioral CI
gate (source + vsix lanes) proves the shipped assets provision a working
interpreter.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
ContributorAuthor

Verification record (merging on this evidence):

  • CI: green — including both new provisioning-gate lanes (source-staged in fast, artifact lane in vsix-gate against the unzipped .vsix), each doing a real venv + PyPI install + SDK import at the pin on clean ubuntu runners.
  • Unit: extension vitest 713 pass / 15 skip (+13 this PR: provisioning module incl. real-interpreter lane + poison-token/env-allowlist adversarial lanes, seam test, gate mutation tests) · tsc clean · prettier clean · boot smoke PASS on vendored amicode.8.
  • Sandbox E2E on the CI artifact (isolated $HOME, no AMICO_PYTHON anywhere): staged → background-provisioned in ~145s cold → venv imports pasqal-cloud 0.23.0 → self-heal restart delivered AMICO_PYTHON=<venv python> into the live server env → real-credential Pasqal connect succeeded (state connected, FRESNEL devices enumerated, token-only pasqal.json at 0600). Second boot takes the stat+hash fast path (zero subprocess); a requirements change re-provisions (stamp rotates); a genuine disk-full pip failure exercised the no-stamp retry lane and recovered on the next activation.
  • Known transient (deferred, fork-side): on a truly fresh machine the first ~2.5 min before self-heal completes can still fail a very eager first connect with the generic "unreachable" copy — the fork-side error-rendering fix covers this window.

🤖 Generated with Claude Code

@kateebonner
kateebonner marked this pull request as ready for review July 20, 2026 20:46
@kateebonner
kateebonner merged commit 0bf3cc4 into mainJul 20, 2026
5 checks passed
jack-champagne added a commit to harmoniqs/opencode that referenced this pull request Jul 28, 2026
The unit job died with exit 137 and reported nothing. Not an OOM (peak
0.37GB of 32GB, zero faults) — a segfault inside @napi-rs/keyring's
native setPassword(), reached from the pasqal submit success path.
Install the in-memory secret store, as the sibling
amicode-connections.test.ts already does. Production is unaffected: the
same write succeeds under `bun run … serve`, verified end-to-end against
Pasqal with real credentials.
Also swap the stub validator from a bun-executed .mjs to a
python3-executed .py. amicode provisions <opsDir>/venvs/pasqal-connector
and passes it as AMICO_PYTHON (harmoniqs/amicode#189), so the production
interpreter is always a real python; bun-as-interpreter tested a
configuration that never ships.
Drop the windows unit lane: opencode.lock.json ships darwin-arm64 and
linux-x64 only, and it was the ~50min long pole while red for an
unrelated reason (#76).
Refs #82, #76
Sign up for freeto 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.

1 participant

@kateebonner
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection - #189

Merged
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning
Jul 20, 2026
Merged

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection#189
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning

Conversation

@kateebonner

Copy link
Copy Markdown
Contributor

Implements the Slack-thread decision (option 1: extension-provisioned venv; Aaron + Kate aligned). Issue to be filed from the thread — will re-title fix(#NN) when it exists.

Summary

Fresh installs cannot connect to Pasqal: the fork's validator spawn resolves $AMICO_PYTHON → bare python3, no ambient interpreter has pasqal-cloud, the validator exits 1 ("SDK not installed"), and the panel misrenders the config lane as "Service unreachable" (found live-testing v0.0.3-alpha; root-caused against the shipped amicode.8 binary, whose AMICO_PYTHON support was verified live before this was written).

  • Provisioning owner: the extension. pasqal_python.ts (mirrors pasqal_assets.ts): probe host python3 ≥ 3.10 (PATH + well-known absolute candidates — Dock-launched VS Code inherits the launchd-minimal PATH), -m venv under <opsDir>/venvs/pasqal-connector, pip install -r the staged requirements.txt. Hash-gated: stamp written only after pip exit 0, so failed provisions retry free next activation; fast path is stat+hash, zero subprocesses.
  • Env seam / S37 exception: injected via the single buildServerSpawnEnv builder used by all three spawn sites (boot, solver-mode respawn, vault respawn) — no respawn path can drop it. S37 ("no AMICO_* env propagation") note amended in place: this is server-child plumbing for the fork's validator spawn, NOT amico-run contract; amico-run still receives nothing via env.
  • Fail-closed AMICO_PYTHON: provisioning failure never sets the var (absent, not empty — the fork's fallback is byte-identical to today), logs ONE actionable line per lane (no python / venv failed / pip failed-offline). Slow path runs in the background, never blocks activation; on success it mutates the live spawn env (ServerManager re-reads at start()) and bounces via the existing amicode.restartServer, so a fresh install self-heals without a reload.
  • Override precedence: host $AMICO_PYTHON wins outright and skips provisioning (the $AMICO_PASQAL_VALIDATOR convention; absent-not-empty semantics match the fork's resolver).
  • Token safety: provisioner child env is built from scratch as { PATH, HOME } — poison-token test proves no secret rides argv, env, or failure copy.

Freeze respected

release.yml untouched, no tag cut. amico-run argv contract untouched. launch.ts zero-line diff. Unprovisioned sessions: buildServerSpawnEnv output byte-identical.

Deferred (out of scope)

Fork-side rendering of the config-lane error text (panel currently shows state-generic "Service unreachable" copy; the route already returns the precise message). amico-pasqal launcher interpreter unification (submit path). Windows venv layout (lock targets darwin-arm64/linux-x64 only). Staging of the 3 submit-path connector scripts.

Gate results

  • extension vitest: 713 pass / 15 skip (+13: 10 pasqal_python incl. real-interpreter venv lane, +1 server_auth, +3 gate mutation) · tsc --noEmit clean · prettier clean
  • boot smoke: [smoke] PASS (vendored v1.17.3-amicode.8)
  • new behavioral gate assert_provisioned_python.mjs (mirrors assert_packaged_cli.mjs): local run 4/4 PASS — pin parse, real venv+pip from shipped assets, SDK import at ==0.23.0, validator env-guard smoke. Wired in ci.yml only: fast job (source lane) + vsix-gate job (assets unzipped from the real artifact).
  • Julia solve E2E: n/a (no template/Julia changes)

🤖 Generated with Claude Code

…jection
The fresh-install fix: the fork's validator spawn resolves $AMICO_PYTHON →
bare python3, and on a fresh machine no ambient interpreter has pasqal-cloud,
so the validator exits 1 and the panel misreports 'Service unreachable'. The
extension now owns the interpreter: venv from the STAGED requirements.txt
(hash-gated, stamp-on-success), injected via the single buildServerSpawnEnv
seam so no respawn path drops it; background slow path self-heals via the
existing restart command. Host $AMICO_PYTHON wins outright. Behavioral CI
gate (source + vsix lanes) proves the shipped assets provision a working
interpreter.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
ContributorAuthor

Verification record (merging on this evidence):

  • CI: green — including both new provisioning-gate lanes (source-staged in fast, artifact lane in vsix-gate against the unzipped .vsix), each doing a real venv + PyPI install + SDK import at the pin on clean ubuntu runners.
  • Unit: extension vitest 713 pass / 15 skip (+13 this PR: provisioning module incl. real-interpreter lane + poison-token/env-allowlist adversarial lanes, seam test, gate mutation tests) · tsc clean · prettier clean · boot smoke PASS on vendored amicode.8.
  • Sandbox E2E on the CI artifact (isolated $HOME, no AMICO_PYTHON anywhere): staged → background-provisioned in ~145s cold → venv imports pasqal-cloud 0.23.0 → self-heal restart delivered AMICO_PYTHON=<venv python> into the live server env → real-credential Pasqal connect succeeded (state connected, FRESNEL devices enumerated, token-only pasqal.json at 0600). Second boot takes the stat+hash fast path (zero subprocess); a requirements change re-provisions (stamp rotates); a genuine disk-full pip failure exercised the no-stamp retry lane and recovered on the next activation.
  • Known transient (deferred, fork-side): on a truly fresh machine the first ~2.5 min before self-heal completes can still fail a very eager first connect with the generic "unreachable" copy — the fork-side error-rendering fix covers this window.

🤖 Generated with Claude Code

@kateebonner
kateebonner marked this pull request as ready for review July 20, 2026 20:46
@kateebonner
kateebonner merged commit 0bf3cc4 into mainJul 20, 2026
5 checks passed
jack-champagne added a commit to harmoniqs/opencode that referenced this pull request Jul 28, 2026
The unit job died with exit 137 and reported nothing. Not an OOM (peak
0.37GB of 32GB, zero faults) — a segfault inside @napi-rs/keyring's
native setPassword(), reached from the pasqal submit success path.
Install the in-memory secret store, as the sibling
amicode-connections.test.ts already does. Production is unaffected: the
same write succeeds under `bun run … serve`, verified end-to-end against
Pasqal with real credentials.
Also swap the stub validator from a bun-executed .mjs to a
python3-executed .py. amicode provisions <opsDir>/venvs/pasqal-connector
and passes it as AMICO_PYTHON (harmoniqs/amicode#189), so the production
interpreter is always a real python; bun-as-interpreter tested a
configuration that never ships.
Drop the windows unit lane: opencode.lock.json ships darwin-arm64 and
linux-x64 only, and it was the ~50min long pole while red for an
unrelated reason (#76).
Refs #82, #76
Sign up for freeto 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.

1 participant

@kateebonner
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection - #189

Merged
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning
Jul 20, 2026
Merged

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection#189
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning

Conversation

@kateebonner

Copy link
Copy Markdown
Contributor

Implements the Slack-thread decision (option 1: extension-provisioned venv; Aaron + Kate aligned). Issue to be filed from the thread — will re-title fix(#NN) when it exists.

Summary

Fresh installs cannot connect to Pasqal: the fork's validator spawn resolves $AMICO_PYTHON → bare python3, no ambient interpreter has pasqal-cloud, the validator exits 1 ("SDK not installed"), and the panel misrenders the config lane as "Service unreachable" (found live-testing v0.0.3-alpha; root-caused against the shipped amicode.8 binary, whose AMICO_PYTHON support was verified live before this was written).

  • Provisioning owner: the extension. pasqal_python.ts (mirrors pasqal_assets.ts): probe host python3 ≥ 3.10 (PATH + well-known absolute candidates — Dock-launched VS Code inherits the launchd-minimal PATH), -m venv under <opsDir>/venvs/pasqal-connector, pip install -r the staged requirements.txt. Hash-gated: stamp written only after pip exit 0, so failed provisions retry free next activation; fast path is stat+hash, zero subprocesses.
  • Env seam / S37 exception: injected via the single buildServerSpawnEnv builder used by all three spawn sites (boot, solver-mode respawn, vault respawn) — no respawn path can drop it. S37 ("no AMICO_* env propagation") note amended in place: this is server-child plumbing for the fork's validator spawn, NOT amico-run contract; amico-run still receives nothing via env.
  • Fail-closed AMICO_PYTHON: provisioning failure never sets the var (absent, not empty — the fork's fallback is byte-identical to today), logs ONE actionable line per lane (no python / venv failed / pip failed-offline). Slow path runs in the background, never blocks activation; on success it mutates the live spawn env (ServerManager re-reads at start()) and bounces via the existing amicode.restartServer, so a fresh install self-heals without a reload.
  • Override precedence: host $AMICO_PYTHON wins outright and skips provisioning (the $AMICO_PASQAL_VALIDATOR convention; absent-not-empty semantics match the fork's resolver).
  • Token safety: provisioner child env is built from scratch as { PATH, HOME } — poison-token test proves no secret rides argv, env, or failure copy.

Freeze respected

release.yml untouched, no tag cut. amico-run argv contract untouched. launch.ts zero-line diff. Unprovisioned sessions: buildServerSpawnEnv output byte-identical.

Deferred (out of scope)

Fork-side rendering of the config-lane error text (panel currently shows state-generic "Service unreachable" copy; the route already returns the precise message). amico-pasqal launcher interpreter unification (submit path). Windows venv layout (lock targets darwin-arm64/linux-x64 only). Staging of the 3 submit-path connector scripts.

Gate results

  • extension vitest: 713 pass / 15 skip (+13: 10 pasqal_python incl. real-interpreter venv lane, +1 server_auth, +3 gate mutation) · tsc --noEmit clean · prettier clean
  • boot smoke: [smoke] PASS (vendored v1.17.3-amicode.8)
  • new behavioral gate assert_provisioned_python.mjs (mirrors assert_packaged_cli.mjs): local run 4/4 PASS — pin parse, real venv+pip from shipped assets, SDK import at ==0.23.0, validator env-guard smoke. Wired in ci.yml only: fast job (source lane) + vsix-gate job (assets unzipped from the real artifact).
  • Julia solve E2E: n/a (no template/Julia changes)

🤖 Generated with Claude Code

…jection
The fresh-install fix: the fork's validator spawn resolves $AMICO_PYTHON →
bare python3, and on a fresh machine no ambient interpreter has pasqal-cloud,
so the validator exits 1 and the panel misreports 'Service unreachable'. The
extension now owns the interpreter: venv from the STAGED requirements.txt
(hash-gated, stamp-on-success), injected via the single buildServerSpawnEnv
seam so no respawn path drops it; background slow path self-heals via the
existing restart command. Host $AMICO_PYTHON wins outright. Behavioral CI
gate (source + vsix lanes) proves the shipped assets provision a working
interpreter.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
ContributorAuthor

Verification record (merging on this evidence):

  • CI: green — including both new provisioning-gate lanes (source-staged in fast, artifact lane in vsix-gate against the unzipped .vsix), each doing a real venv + PyPI install + SDK import at the pin on clean ubuntu runners.
  • Unit: extension vitest 713 pass / 15 skip (+13 this PR: provisioning module incl. real-interpreter lane + poison-token/env-allowlist adversarial lanes, seam test, gate mutation tests) · tsc clean · prettier clean · boot smoke PASS on vendored amicode.8.
  • Sandbox E2E on the CI artifact (isolated $HOME, no AMICO_PYTHON anywhere): staged → background-provisioned in ~145s cold → venv imports pasqal-cloud 0.23.0 → self-heal restart delivered AMICO_PYTHON=<venv python> into the live server env → real-credential Pasqal connect succeeded (state connected, FRESNEL devices enumerated, token-only pasqal.json at 0600). Second boot takes the stat+hash fast path (zero subprocess); a requirements change re-provisions (stamp rotates); a genuine disk-full pip failure exercised the no-stamp retry lane and recovered on the next activation.
  • Known transient (deferred, fork-side): on a truly fresh machine the first ~2.5 min before self-heal completes can still fail a very eager first connect with the generic "unreachable" copy — the fork-side error-rendering fix covers this window.

🤖 Generated with Claude Code

@kateebonner
kateebonner marked this pull request as ready for review July 20, 2026 20:46
@kateebonner
kateebonner merged commit 0bf3cc4 into mainJul 20, 2026
5 checks passed
jack-champagne added a commit to harmoniqs/opencode that referenced this pull request Jul 28, 2026
The unit job died with exit 137 and reported nothing. Not an OOM (peak
0.37GB of 32GB, zero faults) — a segfault inside @napi-rs/keyring's
native setPassword(), reached from the pasqal submit success path.
Install the in-memory secret store, as the sibling
amicode-connections.test.ts already does. Production is unaffected: the
same write succeeds under `bun run … serve`, verified end-to-end against
Pasqal with real credentials.
Also swap the stub validator from a bun-executed .mjs to a
python3-executed .py. amicode provisions <opsDir>/venvs/pasqal-connector
and passes it as AMICO_PYTHON (harmoniqs/amicode#189), so the production
interpreter is always a real python; bun-as-interpreter tested a
configuration that never ships.
Drop the windows unit lane: opencode.lock.json ships darwin-arm64 and
linux-x64 only, and it was the ~50min long pole while red for an
unrelated reason (#76).
Refs #82, #76
Sign up for freeto 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.

1 participant

@kateebonner
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection - #189

Merged
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning
Jul 20, 2026
Merged

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection#189
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning

Conversation

@kateebonner

Copy link
Copy Markdown
Contributor

Implements the Slack-thread decision (option 1: extension-provisioned venv; Aaron + Kate aligned). Issue to be filed from the thread — will re-title fix(#NN) when it exists.

Summary

Fresh installs cannot connect to Pasqal: the fork's validator spawn resolves $AMICO_PYTHON → bare python3, no ambient interpreter has pasqal-cloud, the validator exits 1 ("SDK not installed"), and the panel misrenders the config lane as "Service unreachable" (found live-testing v0.0.3-alpha; root-caused against the shipped amicode.8 binary, whose AMICO_PYTHON support was verified live before this was written).

  • Provisioning owner: the extension. pasqal_python.ts (mirrors pasqal_assets.ts): probe host python3 ≥ 3.10 (PATH + well-known absolute candidates — Dock-launched VS Code inherits the launchd-minimal PATH), -m venv under <opsDir>/venvs/pasqal-connector, pip install -r the staged requirements.txt. Hash-gated: stamp written only after pip exit 0, so failed provisions retry free next activation; fast path is stat+hash, zero subprocesses.
  • Env seam / S37 exception: injected via the single buildServerSpawnEnv builder used by all three spawn sites (boot, solver-mode respawn, vault respawn) — no respawn path can drop it. S37 ("no AMICO_* env propagation") note amended in place: this is server-child plumbing for the fork's validator spawn, NOT amico-run contract; amico-run still receives nothing via env.
  • Fail-closed AMICO_PYTHON: provisioning failure never sets the var (absent, not empty — the fork's fallback is byte-identical to today), logs ONE actionable line per lane (no python / venv failed / pip failed-offline). Slow path runs in the background, never blocks activation; on success it mutates the live spawn env (ServerManager re-reads at start()) and bounces via the existing amicode.restartServer, so a fresh install self-heals without a reload.
  • Override precedence: host $AMICO_PYTHON wins outright and skips provisioning (the $AMICO_PASQAL_VALIDATOR convention; absent-not-empty semantics match the fork's resolver).
  • Token safety: provisioner child env is built from scratch as { PATH, HOME } — poison-token test proves no secret rides argv, env, or failure copy.

Freeze respected

release.yml untouched, no tag cut. amico-run argv contract untouched. launch.ts zero-line diff. Unprovisioned sessions: buildServerSpawnEnv output byte-identical.

Deferred (out of scope)

Fork-side rendering of the config-lane error text (panel currently shows state-generic "Service unreachable" copy; the route already returns the precise message). amico-pasqal launcher interpreter unification (submit path). Windows venv layout (lock targets darwin-arm64/linux-x64 only). Staging of the 3 submit-path connector scripts.

Gate results

  • extension vitest: 713 pass / 15 skip (+13: 10 pasqal_python incl. real-interpreter venv lane, +1 server_auth, +3 gate mutation) · tsc --noEmit clean · prettier clean
  • boot smoke: [smoke] PASS (vendored v1.17.3-amicode.8)
  • new behavioral gate assert_provisioned_python.mjs (mirrors assert_packaged_cli.mjs): local run 4/4 PASS — pin parse, real venv+pip from shipped assets, SDK import at ==0.23.0, validator env-guard smoke. Wired in ci.yml only: fast job (source lane) + vsix-gate job (assets unzipped from the real artifact).
  • Julia solve E2E: n/a (no template/Julia changes)

🤖 Generated with Claude Code

…jection
The fresh-install fix: the fork's validator spawn resolves $AMICO_PYTHON →
bare python3, and on a fresh machine no ambient interpreter has pasqal-cloud,
so the validator exits 1 and the panel misreports 'Service unreachable'. The
extension now owns the interpreter: venv from the STAGED requirements.txt
(hash-gated, stamp-on-success), injected via the single buildServerSpawnEnv
seam so no respawn path drops it; background slow path self-heals via the
existing restart command. Host $AMICO_PYTHON wins outright. Behavioral CI
gate (source + vsix lanes) proves the shipped assets provision a working
interpreter.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
ContributorAuthor

Verification record (merging on this evidence):

  • CI: green — including both new provisioning-gate lanes (source-staged in fast, artifact lane in vsix-gate against the unzipped .vsix), each doing a real venv + PyPI install + SDK import at the pin on clean ubuntu runners.
  • Unit: extension vitest 713 pass / 15 skip (+13 this PR: provisioning module incl. real-interpreter lane + poison-token/env-allowlist adversarial lanes, seam test, gate mutation tests) · tsc clean · prettier clean · boot smoke PASS on vendored amicode.8.
  • Sandbox E2E on the CI artifact (isolated $HOME, no AMICO_PYTHON anywhere): staged → background-provisioned in ~145s cold → venv imports pasqal-cloud 0.23.0 → self-heal restart delivered AMICO_PYTHON=<venv python> into the live server env → real-credential Pasqal connect succeeded (state connected, FRESNEL devices enumerated, token-only pasqal.json at 0600). Second boot takes the stat+hash fast path (zero subprocess); a requirements change re-provisions (stamp rotates); a genuine disk-full pip failure exercised the no-stamp retry lane and recovered on the next activation.
  • Known transient (deferred, fork-side): on a truly fresh machine the first ~2.5 min before self-heal completes can still fail a very eager first connect with the generic "unreachable" copy — the fork-side error-rendering fix covers this window.

🤖 Generated with Claude Code

@kateebonner
kateebonner marked this pull request as ready for review July 20, 2026 20:46
@kateebonner
kateebonner merged commit 0bf3cc4 into mainJul 20, 2026
5 checks passed
jack-champagne added a commit to harmoniqs/opencode that referenced this pull request Jul 28, 2026
The unit job died with exit 137 and reported nothing. Not an OOM (peak
0.37GB of 32GB, zero faults) — a segfault inside @napi-rs/keyring's
native setPassword(), reached from the pasqal submit success path.
Install the in-memory secret store, as the sibling
amicode-connections.test.ts already does. Production is unaffected: the
same write succeeds under `bun run … serve`, verified end-to-end against
Pasqal with real credentials.
Also swap the stub validator from a bun-executed .mjs to a
python3-executed .py. amicode provisions <opsDir>/venvs/pasqal-connector
and passes it as AMICO_PYTHON (harmoniqs/amicode#189), so the production
interpreter is always a real python; bun-as-interpreter tested a
configuration that never ships.
Drop the windows unit lane: opencode.lock.json ships darwin-arm64 and
linux-x64 only, and it was the ~50min long pole while red for an
unrelated reason (#76).
Refs #82, #76
Sign up for freeto 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.

1 participant

@kateebonner
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection - #189

Merged
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning
Jul 20, 2026
Merged

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection#189
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning

Conversation

@kateebonner

Copy link
Copy Markdown
Contributor

Implements the Slack-thread decision (option 1: extension-provisioned venv; Aaron + Kate aligned). Issue to be filed from the thread — will re-title fix(#NN) when it exists.

Summary

Fresh installs cannot connect to Pasqal: the fork's validator spawn resolves $AMICO_PYTHON → bare python3, no ambient interpreter has pasqal-cloud, the validator exits 1 ("SDK not installed"), and the panel misrenders the config lane as "Service unreachable" (found live-testing v0.0.3-alpha; root-caused against the shipped amicode.8 binary, whose AMICO_PYTHON support was verified live before this was written).

  • Provisioning owner: the extension. pasqal_python.ts (mirrors pasqal_assets.ts): probe host python3 ≥ 3.10 (PATH + well-known absolute candidates — Dock-launched VS Code inherits the launchd-minimal PATH), -m venv under <opsDir>/venvs/pasqal-connector, pip install -r the staged requirements.txt. Hash-gated: stamp written only after pip exit 0, so failed provisions retry free next activation; fast path is stat+hash, zero subprocesses.
  • Env seam / S37 exception: injected via the single buildServerSpawnEnv builder used by all three spawn sites (boot, solver-mode respawn, vault respawn) — no respawn path can drop it. S37 ("no AMICO_* env propagation") note amended in place: this is server-child plumbing for the fork's validator spawn, NOT amico-run contract; amico-run still receives nothing via env.
  • Fail-closed AMICO_PYTHON: provisioning failure never sets the var (absent, not empty — the fork's fallback is byte-identical to today), logs ONE actionable line per lane (no python / venv failed / pip failed-offline). Slow path runs in the background, never blocks activation; on success it mutates the live spawn env (ServerManager re-reads at start()) and bounces via the existing amicode.restartServer, so a fresh install self-heals without a reload.
  • Override precedence: host $AMICO_PYTHON wins outright and skips provisioning (the $AMICO_PASQAL_VALIDATOR convention; absent-not-empty semantics match the fork's resolver).
  • Token safety: provisioner child env is built from scratch as { PATH, HOME } — poison-token test proves no secret rides argv, env, or failure copy.

Freeze respected

release.yml untouched, no tag cut. amico-run argv contract untouched. launch.ts zero-line diff. Unprovisioned sessions: buildServerSpawnEnv output byte-identical.

Deferred (out of scope)

Fork-side rendering of the config-lane error text (panel currently shows state-generic "Service unreachable" copy; the route already returns the precise message). amico-pasqal launcher interpreter unification (submit path). Windows venv layout (lock targets darwin-arm64/linux-x64 only). Staging of the 3 submit-path connector scripts.

Gate results

  • extension vitest: 713 pass / 15 skip (+13: 10 pasqal_python incl. real-interpreter venv lane, +1 server_auth, +3 gate mutation) · tsc --noEmit clean · prettier clean
  • boot smoke: [smoke] PASS (vendored v1.17.3-amicode.8)
  • new behavioral gate assert_provisioned_python.mjs (mirrors assert_packaged_cli.mjs): local run 4/4 PASS — pin parse, real venv+pip from shipped assets, SDK import at ==0.23.0, validator env-guard smoke. Wired in ci.yml only: fast job (source lane) + vsix-gate job (assets unzipped from the real artifact).
  • Julia solve E2E: n/a (no template/Julia changes)

🤖 Generated with Claude Code

…jection
The fresh-install fix: the fork's validator spawn resolves $AMICO_PYTHON →
bare python3, and on a fresh machine no ambient interpreter has pasqal-cloud,
so the validator exits 1 and the panel misreports 'Service unreachable'. The
extension now owns the interpreter: venv from the STAGED requirements.txt
(hash-gated, stamp-on-success), injected via the single buildServerSpawnEnv
seam so no respawn path drops it; background slow path self-heals via the
existing restart command. Host $AMICO_PYTHON wins outright. Behavioral CI
gate (source + vsix lanes) proves the shipped assets provision a working
interpreter.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
ContributorAuthor

Verification record (merging on this evidence):

  • CI: green — including both new provisioning-gate lanes (source-staged in fast, artifact lane in vsix-gate against the unzipped .vsix), each doing a real venv + PyPI install + SDK import at the pin on clean ubuntu runners.
  • Unit: extension vitest 713 pass / 15 skip (+13 this PR: provisioning module incl. real-interpreter lane + poison-token/env-allowlist adversarial lanes, seam test, gate mutation tests) · tsc clean · prettier clean · boot smoke PASS on vendored amicode.8.
  • Sandbox E2E on the CI artifact (isolated $HOME, no AMICO_PYTHON anywhere): staged → background-provisioned in ~145s cold → venv imports pasqal-cloud 0.23.0 → self-heal restart delivered AMICO_PYTHON=<venv python> into the live server env → real-credential Pasqal connect succeeded (state connected, FRESNEL devices enumerated, token-only pasqal.json at 0600). Second boot takes the stat+hash fast path (zero subprocess); a requirements change re-provisions (stamp rotates); a genuine disk-full pip failure exercised the no-stamp retry lane and recovered on the next activation.
  • Known transient (deferred, fork-side): on a truly fresh machine the first ~2.5 min before self-heal completes can still fail a very eager first connect with the generic "unreachable" copy — the fork-side error-rendering fix covers this window.

🤖 Generated with Claude Code

@kateebonner
kateebonner marked this pull request as ready for review July 20, 2026 20:46
@kateebonner
kateebonner merged commit 0bf3cc4 into mainJul 20, 2026
5 checks passed
jack-champagne added a commit to harmoniqs/opencode that referenced this pull request Jul 28, 2026
The unit job died with exit 137 and reported nothing. Not an OOM (peak
0.37GB of 32GB, zero faults) — a segfault inside @napi-rs/keyring's
native setPassword(), reached from the pasqal submit success path.
Install the in-memory secret store, as the sibling
amicode-connections.test.ts already does. Production is unaffected: the
same write succeeds under `bun run … serve`, verified end-to-end against
Pasqal with real credentials.
Also swap the stub validator from a bun-executed .mjs to a
python3-executed .py. amicode provisions <opsDir>/venvs/pasqal-connector
and passes it as AMICO_PYTHON (harmoniqs/amicode#189), so the production
interpreter is always a real python; bun-as-interpreter tested a
configuration that never ships.
Drop the windows unit lane: opencode.lock.json ships darwin-arm64 and
linux-x64 only, and it was the ~50min long pole while red for an
unrelated reason (#76).
Refs #82, #76
Sign up for freeto 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.

1 participant

@kateebonner
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection - #189

Merged
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning
Jul 20, 2026
Merged

feat(pasqal): python provisioning — activation venv + AMICO_PYTHON injection#189
kateebonner merged 1 commit into
mainfrom
kate/pasqal-venv-provisioning

Conversation

@kateebonner

Copy link
Copy Markdown
Contributor

Implements the Slack-thread decision (option 1: extension-provisioned venv; Aaron + Kate aligned). Issue to be filed from the thread — will re-title fix(#NN) when it exists.

Summary

Fresh installs cannot connect to Pasqal: the fork's validator spawn resolves $AMICO_PYTHON → bare python3, no ambient interpreter has pasqal-cloud, the validator exits 1 ("SDK not installed"), and the panel misrenders the config lane as "Service unreachable" (found live-testing v0.0.3-alpha; root-caused against the shipped amicode.8 binary, whose AMICO_PYTHON support was verified live before this was written).

  • Provisioning owner: the extension. pasqal_python.ts (mirrors pasqal_assets.ts): probe host python3 ≥ 3.10 (PATH + well-known absolute candidates — Dock-launched VS Code inherits the launchd-minimal PATH), -m venv under <opsDir>/venvs/pasqal-connector, pip install -r the staged requirements.txt. Hash-gated: stamp written only after pip exit 0, so failed provisions retry free next activation; fast path is stat+hash, zero subprocesses.
  • Env seam / S37 exception: injected via the single buildServerSpawnEnv builder used by all three spawn sites (boot, solver-mode respawn, vault respawn) — no respawn path can drop it. S37 ("no AMICO_* env propagation") note amended in place: this is server-child plumbing for the fork's validator spawn, NOT amico-run contract; amico-run still receives nothing via env.
  • Fail-closed AMICO_PYTHON: provisioning failure never sets the var (absent, not empty — the fork's fallback is byte-identical to today), logs ONE actionable line per lane (no python / venv failed / pip failed-offline). Slow path runs in the background, never blocks activation; on success it mutates the live spawn env (ServerManager re-reads at start()) and bounces via the existing amicode.restartServer, so a fresh install self-heals without a reload.
  • Override precedence: host $AMICO_PYTHON wins outright and skips provisioning (the $AMICO_PASQAL_VALIDATOR convention; absent-not-empty semantics match the fork's resolver).
  • Token safety: provisioner child env is built from scratch as { PATH, HOME } — poison-token test proves no secret rides argv, env, or failure copy.

Freeze respected

release.yml untouched, no tag cut. amico-run argv contract untouched. launch.ts zero-line diff. Unprovisioned sessions: buildServerSpawnEnv output byte-identical.

Deferred (out of scope)

Fork-side rendering of the config-lane error text (panel currently shows state-generic "Service unreachable" copy; the route already returns the precise message). amico-pasqal launcher interpreter unification (submit path). Windows venv layout (lock targets darwin-arm64/linux-x64 only). Staging of the 3 submit-path connector scripts.

Gate results

  • extension vitest: 713 pass / 15 skip (+13: 10 pasqal_python incl. real-interpreter venv lane, +1 server_auth, +3 gate mutation) · tsc --noEmit clean · prettier clean
  • boot smoke: [smoke] PASS (vendored v1.17.3-amicode.8)
  • new behavioral gate assert_provisioned_python.mjs (mirrors assert_packaged_cli.mjs): local run 4/4 PASS — pin parse, real venv+pip from shipped assets, SDK import at ==0.23.0, validator env-guard smoke. Wired in ci.yml only: fast job (source lane) + vsix-gate job (assets unzipped from the real artifact).
  • Julia solve E2E: n/a (no template/Julia changes)

🤖 Generated with Claude Code

…jection
The fresh-install fix: the fork's validator spawn resolves $AMICO_PYTHON →
bare python3, and on a fresh machine no ambient interpreter has pasqal-cloud,
so the validator exits 1 and the panel misreports 'Service unreachable'. The
extension now owns the interpreter: venv from the STAGED requirements.txt
(hash-gated, stamp-on-success), injected via the single buildServerSpawnEnv
seam so no respawn path drops it; background slow path self-heals via the
existing restart command. Host $AMICO_PYTHON wins outright. Behavioral CI
gate (source + vsix lanes) proves the shipped assets provision a working
interpreter.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kateebonner

Copy link
Copy Markdown
ContributorAuthor

Verification record (merging on this evidence):

  • CI: green — including both new provisioning-gate lanes (source-staged in fast, artifact lane in vsix-gate against the unzipped .vsix), each doing a real venv + PyPI install + SDK import at the pin on clean ubuntu runners.
  • Unit: extension vitest 713 pass / 15 skip (+13 this PR: provisioning module incl. real-interpreter lane + poison-token/env-allowlist adversarial lanes, seam test, gate mutation tests) · tsc clean · prettier clean · boot smoke PASS on vendored amicode.8.
  • Sandbox E2E on the CI artifact (isolated $HOME, no AMICO_PYTHON anywhere): staged → background-provisioned in ~145s cold → venv imports pasqal-cloud 0.23.0 → self-heal restart delivered AMICO_PYTHON=<venv python> into the live server env → real-credential Pasqal connect succeeded (state connected, FRESNEL devices enumerated, token-only pasqal.json at 0600). Second boot takes the stat+hash fast path (zero subprocess); a requirements change re-provisions (stamp rotates); a genuine disk-full pip failure exercised the no-stamp retry lane and recovered on the next activation.
  • Known transient (deferred, fork-side): on a truly fresh machine the first ~2.5 min before self-heal completes can still fail a very eager first connect with the generic "unreachable" copy — the fork-side error-rendering fix covers this window.

🤖 Generated with Claude Code

@kateebonner
kateebonner marked this pull request as ready for review July 20, 2026 20:46
@kateebonner
kateebonner merged commit 0bf3cc4 into mainJul 20, 2026
5 checks passed
jack-champagne added a commit to harmoniqs/opencode that referenced this pull request Jul 28, 2026
The unit job died with exit 137 and reported nothing. Not an OOM (peak
0.37GB of 32GB, zero faults) — a segfault inside @napi-rs/keyring's
native setPassword(), reached from the pasqal submit success path.
Install the in-memory secret store, as the sibling
amicode-connections.test.ts already does. Production is unaffected: the
same write succeeds under `bun run … serve`, verified end-to-end against
Pasqal with real credentials.
Also swap the stub validator from a bun-executed .mjs to a
python3-executed .py. amicode provisions <opsDir>/venvs/pasqal-connector
and passes it as AMICO_PYTHON (harmoniqs/amicode#189), so the production
interpreter is always a real python; bun-as-interpreter tested a
configuration that never ships.
Drop the windows unit lane: opencode.lock.json ships darwin-arm64 and
linux-x64 only, and it was the ~50min long pole while red for an
unrelated reason (#76).
Refs #82, #76
Sign up for freeto 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.

1 participant

@kateebonner