Skip to content

POC: Local Quick Start — one-click local DocumentDB provisioning & management#756

Draft
guanzhousongmicrosoft wants to merge 38 commits into
mainfrom
feature/local-quickstart/POC
Draft

POC: Local Quick Start — one-click local DocumentDB provisioning & management#756
guanzhousongmicrosoft wants to merge 38 commits into
mainfrom
feature/local-quickstart/POC

Conversation

@guanzhousongmicrosoft

Copy link
Copy Markdown
Contributor

Status: Draft / Proof-of-Concept for demo — not for production merge.
This branch proves the end-to-end value of the Local Quick Start design
(local-quickstart-v2.md)
with the smallest credible vertical slice. The full decision log, implementation plan, and
multi-agent reviews are recorded under
docs/ai-and-plans/PRs/local-quickstart-poc/.

One-sentence goal

From an empty machine-with-Docker to an open, browsable local DocumentDB connection, in one click, without leaving VS Code.

What the POC does (demo narrative)

  1. Quick Start – Install & try entry point in the Connections view (rocket empty state) / command palette.
  2. A card-based webview (Query-Insights design language) shows Docker readiness + a "what we'll do" summary.
  3. On click, the real container is pulled → created → started via @microsoft/vscode-container-client (Docker).
  4. The webview shows lightweight staged progress — Checking → Pulling → Creating → Starting → Waiting → Done — driven by a tRPC subscription (stage-level only; no docker pull % streaming).
  5. A wire-protocol readiness probe (direct ping, up to 180s) confirms the DB actually accepts connections ("running ≠ ready").
  6. The connection is saved; the webview auto-closes; an inline managed instance appears under the Quick Start tree node.
  7. The user expands and browses real databases/collections using the extension's existing tree/browse code, end to end — including a seeded sampledb (users / products / orders / analytics).

Lifecycle management (v1.0 management layer)

The inline instance row is a full control surface, state-gated:

  • Actions: Start · Stop · Restart · Delete Container · Copy Connection String · Copy Password · View Logs.
  • State machine: NotInstalled · Provisioning · Starting · Running · Stopping · Stopped · Error, plus a Missing badge when the extension holds metadata but Docker has no matching container.
  • Live freshness: the tree re-checks live Docker state on expand (no polling subsystem).
  • Safety: every destructive op verifies the vscode.documentdb.quickstart label on the container before acting; Delete uses a modal confirm; the generated password is masked in all Output-channel writes.

Key technical decisions

  • Standalone QuickStartService (async-generator of stage events + per-attempt AbortSignal) instead of the single-use Task base class — fits cancellation + retry + the in-webview checklist model. (Deviation D13, logged.)
  • Restart-safe sample data: the container runs with only --username/--password; the image's built-in sampledb is seeded once after readiness by running the image's native init script via docker exec. We deliberately do not bake --init-data true into the run args — that re-runs on every docker start, hits a duplicate-key error, and crashes the container. start()/restart() also confirm the container stays running before declaring Running.
  • Windows shell provider: docker runner is given a Cmd/Bash shell provider so Go-template --format args quote correctly on Windows (otherwise info/inspect/list break).
  • Inline browse for free: the instance renders as a read-only DocumentDBClusterItem with emulatorConfiguration = { isEmulator: true, disableEmulatorSecurity: true } → TLS-allow-invalid + full browse via the existing tree, appearing only under the Quick Start node.
  • Secrets: auto-generated credentials in VS Code SecretStorage; masked everywhere in the dedicated "DocumentDB Local Quick Start" Output channel (D14).

Image: ghcr.io/documentdb/documentdb/documentdb-local:latest · port 10260 · conn string mongodb://<U>:<P>@localhost:10260/?tls=true&tlsAllowInvalidCertificates=true.

Out of scope (deferred — POC, not production)

Legacy emulator migration (§4) · TLS-exception wizard (§7) · full action matrix details (§6) · port-fallback random band (§8.3, POC pre-checks 10260 and errors clearly) · container adoption / label-conflict (§10) · multi-window coordination / Docker events (§12) · advanced panel custom creds/image (§5.2) · categorized Docker diagnosis (§9) · telemetry (§14) · data-volume persistence (ephemeral by design). A short list of v1.0 readiness polish (platform check, Start-Docker-Desktop action, success-card buttons) is tracked in review-and-resolutions.md.

Verification

  • Gates: npm run build ✅ · npm run lint ✅ · npx jest --no-coverage (2055/2055) ✅ · npm run webpack-prod ✅. 16 new unit tests for output-masking + credential composition.
  • Live (real Docker on Windows): full provision → readiness → browse; lifecycle stop → start stays running → restart with sample data persisting (users 5 · products 5 · orders 4 · analytics 2); label-ownership checks; Missing badge.

How to test

See the step-by-step checklist in docs/ai-and-plans/PRs/local-quickstart-poc/review-and-resolutions.md. In short: npm run webpack-prod → launch with --extensionDevelopmentPath=distQuick Start – Install & try → expand & browse → exercise Stop / Start / Restart / Delete.

Process record (for reviewers & future agents)

Note: this branch also carries the iteration-2 design doc commits (authored by @tnaumowicz) for context; the POC implementation starts at the feat(quickstart): … (WI-0) commit.


🤖 Generated with GitHub Copilot CLI

guanzhousongmicrosoft and others added 26 commits May 18, 2026 22:55
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Guanzhou Song <guanzhousong@microsoft.com>
- Add local-quickstart-v2.md: simplified design that removes the dedicated
  local connection subtree, uses a webview for container creation, gates
  TLS exceptions in the regular connection wizard, and migrates legacy
  emulator connections on first launch.
- Mark local-quickstart.md as iteration 1 with a forward reference.
…decision note

- terminal-first create progress for v1.0 (staged in-webview card deferred to v1.1)
- adopt @microsoft/vscode-container-client (Docker+Podman) as the runtime layer
- port fallback only for the default port; read the bound port from docker inspect
- distinguish create-vs-start failure; pre-check connection name AND container name
- scope prereq checks v1.0/v1.1; add section 18.1 PostgreSQL source-benchmark learnings
- add docs/ai-and-plans/PRs/653-local-quickstart-design/description.md decision note

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-agent review

Adds a demo-focused proof-of-concept plan for Local Quick Start under

docs/ai-and-plans/PRs/local-quickstart-poc/:

- description.md: POC goal, scope (focus vs leave-out), deliberate deviations, reuse strategy, real-world image findings

- poc-implementation-plan.md: process contract, architecture map, 14 decisions, 9 work items (Core WI-0..6 + Stretch WI-7..8), risks, demo script

- review-and-resolutions.md: two rounds of 5-agent review (design/manager/impl/scope/risk) with every finding and resolution; consensus reached at rev. 3

No shipping code; planning only.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add @microsoft/vscode-container-client dependency (validates OPEN-3: post-image args supported via runContainer command[])

- ContainerRuntime: isDockerReady/isPortFree/pullImage/createAndRunContainer/inspect/start/stop/remove/listByLabel/followLogs

- Masked, line-buffered OutputChannel writes so the generated password never leaks (D14), incl. split-chunk safety

- quickStartTypes: image/port/label constants, InstanceState, StageEvent, InstanceMetadata

- Unit tests for masking (8 passing)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Standalone service (documented deviation from D13 Task-composition: Task is single-use + numeric-notification progress, ill-fitting the in-webview stage checklist + Retry; D13 permits standalone)

- provision() async generator yields StageEvents (checking/pulling/creating/starting/waiting/done); per-attempt AbortSignal; cleanup in finally (pull-cancel removes nothing; create/start-cancel removes by id, D12)

- wire-protocol readiness probe via connectToClient (TLS-allow-invalid), 180s + backoff (D7)

- credentials: URL-safe alphabet, percent-encoded conn string (D6); stored in SecretStorage

- activation reconcile(): adopt labelled container if creds stored, else clean-remove

- unit tests for credentials/conn-string (16 passing total)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- localQuickStartController (extends WebviewControllerBase; closePanel via this.panel.dispose, not this.dispose)

- localQuickStartRouter: getDockerStatus/getStatus queries, startQuickStart subscription (mirrors ctx.signal to cancel provisioning + docker), closePanel mutation; imports tRPC primitives from ./trpc

- mounted localQuickStart in appRouter; registered LocalQuickStart in WebviewRegistry (auto-bundled)

- openLocalQuickStart command + registration; attach QuickStartService (reconcile + dispose) at activation

- minimal React entry calling getDockerStatus (full UI in WI-3/WI-4)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Review: 4 metric cards (Docker/Port/Data=Ephemeral(POC)/Security) + What-we-do summary + Start

- Docker-not-ready variant with Retry (opt-in; never auto-starts Docker)

- Progress: lightweight staged checklist (D3) driven by startQuickStart subscription + elapsed timer + spinner; Cancel unsubscribes

- Failure: inline error + Retry; View Docker output reveals the channel

- Success: brief card then auto-close via closePanel (panel.dispose) -> tree handoff

- added showOutput mutation; moved DockerStatusResult to pure types module (no router runtime in webview bundle)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…-5, WI-6)

- LocalQuickStartItem root node: rocket empty-state row (opens webview) when NotInstalled; inline DocumentDBClusterItem when Running/Stopped (expand to browse); Provisioning/Error rows

- QuickStartClusterItem subclass stamps a static 'Running . localhost:port' description (D2 design review)

- QuickStartService pre-populates CredentialCache (setAuthCredentials) on success + reconcile so the inline item browses without a re-prompt

- ConnectionsBranchDataProvider: render the node UNCONDITIONALLY incl. the zero-connections empty state (mandated option A); prepend in normal path; fix savedConnections telemetry count

- refresh the tree on QuickStartService status change

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ClustersExtension: refresh Connections tree on QuickStartService status change (WI-6 wiring)

- prettier formatting; eslint-disable for initial-load setState-in-effect (matches DocumentView)

- record standalone-service deviation from D13 + -dt/customOptions note in the plan

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Functional/security/tree/webview/design review fixes:

- D14: followLogs now line-buffered via MaskingLineBuffer (split-secret safety)

- stop followLogs on success: cts.cancel() in finally (was leaking docker logs -f)

- orphan sweep if cancelled during create window (createAttempted + label sweep)

- clear stale ClustersClient on fresh provision so re-run browses with new creds

- webview: emit terminal error when busy + onComplete handler (no stuck 'provisioning'); unsubscribe-before-resubscribe + null-on-terminal (no double-click leak); review-screen Cancel button

- readiness probe: direct MongoClient w/ 3s serverSelectionTimeout (Cancel responsive); remove redundant -t (detached already adds --tty)

- optional sample-doc seed so the tree isn't empty to browse

- Learn more... row; savedConnections telemetry counts real connections/folders

Gates: lint, jest 2055, build, webview bundle all pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…utions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… Windows

Root cause: ShellStreamCommandRunnerFactory without a shellProvider drops each arg's quoting metadata and sets windowsVerbatimArguments on Windows, splitting Go-template args like '--format {{json .}}' on the space. This made 'docker info' (and inspect/list) fail, so isDockerReady reported the daemon unreachable even when Docker was running.

Fix: provide a platform shell provider (Cmd on Windows, Bash elsewhere) to every runner; switch makeRunner to strict:false (non-zero exit still rejects; harmless stderr warnings don't). Add @microsoft/vscode-processutils dependency.

Verified live on Windows: info, run (with credential args + labels), inspect (bound port), listByLabel, remove all succeed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s shell-provider)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adopt the image's native sample-data mechanism (documentdb-local --init-data true / INIT_DATA=true) instead of a bespoke driver-side seed — matches design 8.4 (use the image's standard init-script convention; portable, identical to running the image by hand).

- pass '--init-data true' as post-image args alongside --username/--password

- loads the rich sampledb (users/products/orders/analytics) vs the prior single doc

- remove seedSampleData() driver hack

- add capped, non-fatal waitForSampleData() so the tree reliably shows data on first expand (sample data loads just after gateway readiness)

Verified live on Windows: --init-data true populates sampledb.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…shell provider)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Missing badge

Turns the provision-and-browse POC into a managed instance (design §6.2/§11).

- States: add Starting/Stopping; Stopped now reachable; Missing badge (§6.1) when metadata exists but Docker has no container

- Service: start/stop/restart/deleteContainer/refreshLiveState; all destructive ops verify the quickstart label before acting (§9/§13.1); lifecycleBusy guard

- Tree: state-aware rows with a Quick-Start-specific contextValue (treeItem_quickStartInstance + state token) so the instance shows Quick Start actions, not generic cluster menus; live-refresh on expand (cheap multi-window/external-change freshness, §12)

- Commands: Start/Stop/Restart/Delete Container/Copy Connection String/Copy Password/View Logs (inline + context menu, gated by state)

- Delete uses a one-line modal confirm (§11); password masked in View Logs (D14)

Verified live on Windows: run/stop(exited)/start(running)/remove + label check. Gates: lint, jest 2055, build, webpack-prod all pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ocker exec)

Baked '--init-data true' re-ran the image's sample-data init on every docker start, hit a duplicate-key error, and crashed the container (set -e); start() also inspected too early and falsely reported Running. Now run with only credentials and seed the built-in sampledb once after readiness via the image's native init script (docker exec), and require the container to stay running (confirmStaysRunning) before declaring Running. Verified live: stop->start stays running and sample data persists.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread src/services/localQuickStart/quickStartCredentials.ts Fixed
…ased-cryptographic-random)

Use rejection sampling so every URL-safe alphabet character is equally likely; a plain byte % 62 over-represented the first 8 characters. Flagged high-severity by CodeQL on PR #756.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tnaum-ms

Copy link
Copy Markdown
Collaborator

🚀 amazing!

…tance, ownership-bounded)

Production v1 design decision for the multiple-instance / existing-container edge case raised by German Eichberger: Quick Start manages exactly one labelled instance it created; users attach their own containers via the regular wizard; multi-instance/adopt/auto-discovery deferred to v1.2 (labels keep the model forward-compatible). Identifies unlabelled name/port collision safety as the one concrete v1 hardening item. No code changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
guanzhousongmicrosoft and others added 10 commits June 26, 2026 12:28
… Docker diagnosis

P0: persistent named volume at /data (data survives recreate; Missing->recreate reuses stored creds+volume; idempotent sample seeding; explicit Delete drops the volume). Credentials now pass via a temp --env-file (mode 600, deleted in finally) as USERNAME/PASSWORD instead of CLI args (verified the image authenticates via env). Port-conflict fallback band [10260,10360) with bound-port readback. P1: DockerReadiness gains host arch/platformSupported; Docker-not-ready view rebuilt into per-check cards + Start Docker Desktop action + Install/Troubleshooting links; review Data card now 'Persistent volume'. Verified live + gates (lint/jest 2055/build/webpack/l10n).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
P1-3: success card adds Open Connection (focuses Connections view) + Copy Connection String, with a longer auto-close so the buttons are usable. P3-2: start/stop/restart re-check live Docker state via liveStateGuard before acting and inform the user if another window already changed it (design §12). P3-1: documentDB.quickstart.provision telemetry (result/reused/portFallback/provisionMs), getDockerStatus reports dockerReadiness+platformSupported, lifecycle commands tag action; no names/ports/creds sent (§14). Gates: l10n/prettier/lint/jest 2055/build/webpack-prod.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e coupling)

5-agent rubber-duck review (GPT-5.4/5.5 + Opus 4.8 REJECT; Opus 4.6/4.7 missed it) found a release blocker: emulatorConfiguration.isEmulator is overloaded as both the storage-zone selector and the TLS-allow-invalid trigger, so an emulator connection cannot be moved into the Clusters zone correctly. Reverted the migration cut. Recorded the prerequisite P2-0 (decouple storage-zone from isEmulator, the §7 work) which P2-1 and P2-2 both depend on.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…lator migration (§4, §7)

P2-0: add explicit storageZone to ConnectionClusterModel + resolveStorageZone(cluster) helper (prefers the explicit zone, falls back to the old isEmulator inference). Stamp storageZone at the 3 construction sites and route every zone decision through it (DocumentDBClusterItem x3, removeConnection, moveItems, rename/updateCredentials/updateConnectionString wizards). isEmulator is kept only for behavior (TLS/timeouts/icons). +resolveStorageZone unit tests.

P2-1: one-time migration copies each Emulators-zone connection into a 'Local Connections (Legacy)' folder in the Clusters zone (creds/auth/emulatorConfiguration preserved; isEmulator normalized so TLS still works; routed correctly via the new storageZone). Keeps the Emulators zone as read-only rollback; retires LocalEmulatorsItem once complete; one-time toast. create-if-missing (never overwrites user edits) + a reconciliation re-scan before the completion flag (closes the activation-window race) + isFolder guard + telemetry.

Validated by a 3-round 5-agent rubber-duck review (GPT-5.4/5.5, Opus 4.6/4.7/4.8): the original isEmulator/zone blocker is resolved, the migration is data-safe/idempotent, TLS preserved, no regression. Pre-existing folder-aware deep-link reveal limitation documented as a follow-up. Gates: build/lint/jest 2058/l10n/prettier.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ort 10260 (§13.5)

The manual local-connection wizard defaulted the DocumentDB emulator to 10255; the canonical DocumentDB local port is 10260 (matches Quick Start + the image). The Cosmos DB Mongo (RU) emulator legitimately keeps 10255. PromptPortStep's default/placeholder is now experience-aware.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…wizard (§7)

Replaces the emulator-only TLS handling with a gated TLS-exception step in the
regular new-connection wizard, per design §7.

- Decouple TLS-allow-invalid from `isEmulator`: it now keys off
  `emulatorConfiguration.disableEmulatorSecurity` alone, so a regular local
  connection can accept a self-signed cert without being treated as an emulator
  (all 5 MongoClient option builders).
- Gated wizard step (`PromptTlsExceptionStep`): offered only when every seed
  host is local/private; defaults to "Enable TLS".
- Host classifier (`hostClassification.ts`): loopback/RFC1918/link-local/ULA/
  `.local`/single-word, IDNA-normalized so a Unicode-dot homograph
  (`example。com`) cannot masquerade as a local host.
- Write-time canonicalizer (`tlsException.ts`) is the security boundary: it
  strips every TLS-bypass URL param (cert/hostname/tlsInsecure/rejectUnauthorized)
  from the stored connection string and host-gates the exception, so the wizard,
  deep links and connection-string edits can never create an allow-invalid
  exception for a public host.
- Hybrid runtime policy (`resolveAllowInvalidCertificates`): the stored flag is
  honored only for local/private hosts; on a public host a bare orphaned flag is
  inert (no allow-invalid, fail-fast timeout, local error copy, or tree badge),
  while an explicit URL param the user deliberately set is still honored.
- Shell `isEmulator` now derives from credentials (not the timeout proxy);
  `updateConnectionString` host-gates both flags against the edited hosts.

Verified across 8 five-agent review rounds (GPT-5.4/5.5, Opus 4.6/4.7/4.8) to
unanimous consensus. The §7.3 connection-edit dialog remains a separate issue.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…nning

Manual-testing UX feedback:

- Success page no longer auto-closes after provisioning. The 4s auto-dismiss is
  removed and `Open Connection` no longer closes the panel — only the new
  explicit `Close` button dismisses it. Added a `Next steps` block (reusing
  the in-view successBox/Card pattern) and wired the shared Announcer for a11y.
- `Delete Container…` is now offered while the instance is Running (menu gate
  += state_running). The confirmation is a stronger, state-aware data-loss
  warning (all data, logs and credentials are permanently lost; the running
  container is stopped first). deleteContainer() already force-removes
  (docker rm -f) and drops the data volume, so no backend change was needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ample-data)

Adds a collapsible Advanced panel to the Quick Start review screen for a custom
host port, credentials, image tag, and a sample-data toggle (design §5.2), with
security and data-safety hardening from a 4-round 5-agent review.

Security (credentials off the host shell, §8.2):
- Seed sample data by referencing $USERNAME/$PASSWORD from the container's OWN
  environment inside a ShellQuoting.Strong-quoted `sh -c`, so credentials never
  reach the host argv / process list on either bash or cmd. Credentials are now
  validated control-char-only (the env-file newline-injection vector stays blocked
  at zod + writeEnvFile; a `%` password round-trips safely).

Data safety:
- The reuse decision is keyed on stored credentials existing (live SecretStorage),
  not the in-memory Missing flag, so re-running setup can never silently wipe a
  reusable data volume; a fresh, volume-wiping provision is strictly the explicit
  Delete-then-recreate path.

Recreate fidelity:
- Persist the instance's image ref (metadata + a durable globalState record,
  backfilled on reconcile/adopt, cleared on Delete) so a recreate — even across a
  window reload — reuses the original image, not `latest`.
- Surface a `willReuse` flag computed from the same predicate provision() uses; the
  webview hides the credential/image inputs and relabels the summary exactly when
  the service will reuse.

Also: server-side both-or-neither credential refine (parity with the client);
whitespace trim consistent client/zod/service; custom port preserved in the success
message + connection string via a chosenPort inspect fallback; telemetry stays
booleans-only (customPort/customCreds/customImage/sampleData).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… (v1.1)

Makes the provisioning flow usable with a keyboard and screen reader (WCAG 2.4.3,
3.3.1, 1.1.1, 4.1.3), reviewed by a 3-agent cross-model pass.

- Per-field validation: the Advanced inputs now surface errors via FluentUI
  `Field` validationState/validationMessage (programmatically associated,
  aria-invalid + role="alert") instead of one detached bottom message; credential
  and image-tag checks are skipped while reusing an existing instance (those inputs
  are hidden), and the offending field is highlighted.
- Progress announcements: a polite live region streams the current provisioning
  stage; the failed and Docker-not-ready states are announced; the existing
  success announcement is unchanged. The failure announcer is polite so it does not
  clip the focus move, and the progress message is suppressed once a stage errors.
- Stage rows: the list is exposed as role="list"/"listitem" with a natural
  row aria-label ("Pulling official image, done"); decorative icons are hidden. On
  failure the active stage flips to the error state so it no longer reads/looks like
  "in progress".
- Focus management: focus moves to the primary result action (Open Connection /
  Retry) when provisioning ends, so keyboard/screen-reader users are not stranded on
  <body> when the Cancel button unmounts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Logs / Start over (v1.1)

Implements §9.1: a wire-protocol readiness timeout no longer tears the container
down. It is kept running (it may just be slow to initialize) and the webview offers
Wait longer, View Docker output, and Start over, reviewed across 3 rounds by 5 agents.

- Wait longer: re-probes the SAME retained container for another readiness window via
  a new `resumeReadiness` generator + `waitLonger` subscription — no re-pull, keeping
  the already-completed stages visible and streaming live logs.
- Start over: `discardTimedOutInstance` removes the container and wipes the volume ONLY
  for a fresh (non-reusing) attempt; a reusing attempt's real data is always kept.
- Reopen-safe: a `canResumeReadiness` status flag (gated on !busy) rehydrates the
  recovery actions when the panel is reopened instead of stranding the container.

Data-safety / correctness:
- Refactored the provision try/catch/finally to extract a shared, non-yielding
  `finalizeReadyInstance`, preserving the setStatus(Running)->success ordering so an
  unsubscribe after the terminal event can never tear down a healthy container.
- Terminal events (timeout and hard error) are buffered and yielded AFTER `finally`,
  so provisioning/lifecycleBusy are clear before the webview shows Wait longer / Retry
  — no fast-click race with the "already in progress" guard.
- `reconcile()` only removes an orphaned container, never its volume (a missing secret
  does not prove the volume is disposable — avoids irreversible data loss).
- A webview stream-generation guard ignores trailing callbacks from a superseded or
  cancelled stream. Resume emits booleans/enum-only telemetry.

Known limitation (v1.2): after a reload, reconcile adopts a reusing timed-out container
as Running without re-probing; recoverable via Restart/Delete, no data loss.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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