Skip to content

Add clear script environment cache command (PEP 723 PR 13/16) - #8

Closed
StellaHuang95 wants to merge 7 commits into
mainfrom
pep723-pr13-clear-cache-v2
Closed

Add clear script environment cache command (PEP 723 PR 13/16)#8
StellaHuang95 wants to merge 7 commits into
mainfrom
pep723-pr13-clear-cache-v2

Conversation

@StellaHuang95

@StellaHuang95 StellaHuang95 commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Fork-review PR; do not send upstream yet.

Part of microsoft#1602. Complete roadmap PR13 lifecycle cleanup implementation.

Summary

  • safely delete the versioned inline-script cache bucket
  • clear PR7 persisted associations, in-memory state, validation caches, and pending rehydrations
  • remove exact inline-script pythonProjects[] entries with workspace/workspace-folder/multiroot correctness
  • emit environment/project/selection changes only for affected scripts
  • preserve unrelated projects, settings, managers, and caches

Destructive safety and locking

  • physical cache-root containment and symlink/junction rejection
  • deterministic create/clear serialization
  • held, retained, stale, orphaned, malformed, missing, and unavailable lock classification
  • explicit cleanup of retained and definitely stale locks while refusing live/unverifiable operations
  • fail-closed ordering and surfaced partial failures

Default-off guarantee

When python-envs.inlineScripts.enabled is absent/false:

  • the cleanup command is not contributed in package.json or command-palette menus
  • the internal command ID is not registered by the extension
  • the inline manager is not constructed or registered
  • the existing broad python-envs.clearCache command is unchanged
  • generic removePythonProjectSetting() and existing project remove/delete behavior match bde7cf8
  • comprehensive source-aware project cleanup lives in a separate inline-only helper reachable only from the enabled internal command
  • added lockfile and venv helpers do not alter existing lock acquisition or venv removal semantics

The command remains internal until the PEP 723 user experience is intentionally exposed.

Scope

TTL eviction remains PR14; routing, setup UX, telemetry, and status treatment remain separate roadmap work.

Validation

  • TypeScript test and extension compilation
  • ESLint and diff checks
  • full unit suite: 1616 passing, 5 expected platform skips
  • targeted registration/activation smoke coverage
  • comprehensive cleanup reviews plus dedicated default-off review; no significant findings remain

@StellaHuang95 StellaHuang95 changed the title Add conservative inline script cache clearing (preview) Add clear script environment cache command (PEP 723 PR 13/16) Aug 17, 2026
@StellaHuang95

Copy link
Copy Markdown
Owner Author

🔒 Automated review in progress — @StellaHuang95 is auto-reviewing this PR.

Comment thread src/managers/builtin/inlineScript/envManager.ts Outdated
Comment thread src/features/settings/settingHelpers.ts
Comment thread src/common/lockfile.apis.ts
Comment thread src/managers/builtin/inlineScript/envManager.ts
Comment thread src/managers/builtin/inlineScript/envManager.ts
Comment thread src/common/lockfile.apis.ts Outdated
Comment thread src/features/settings/settingHelpers.ts
Comment thread src/test/features/settings/settingHelpers.unit.test.ts
Comment thread src/test/managers/builtin/inlineScript/envManager.unit.test.ts
Comment thread src/test/smoke/registration.smoke.test.ts
@StellaHuang95 StellaHuang95 added the review-auto:changes-requested Automated review: posted blocking findings to address. label Aug 17, 2026
## Summary

Adds a package-manager-centric integration baseline that intentionally
precedes and de-risks microsoft#1686, so the package-manager command refactor is
exercised against behavior established on `main`.

- drives one stateful install/list/direct-package/uninstall lifecycle
per active profile
- uses unique disposable projects and manager-owned disposable
environments
- exercises the live registered manager instances through a
runtime-gated integration-test bridge
- guards registry completeness so every registered package-manager ID
has an active fixture or explicit deferral
- covers normal Pip execution and Conda when their runtime prerequisites
are available
- records an uncached baseline instead of assuming a newly created
environment is empty
- restores workspace-scoped configuration from `inspect()` snapshots and
performs guarded failure-safe cleanup
- defers Poetry pending a Poetry-owned project/lockfile lifecycle
- defers uv-backed Pip because changing the machine-scoped selection
reliably within one extension host was not stable on `main`, while
available-version lookup would also introduce `uv tool run pip` network
seeding
- pins the disposable integration-test user profile to normal Pip
execution

## Validation

- `npm run compile`
- `npm run compile-tests`
- `npm run lint`
- `npm run unittest`
- targeted `packageManagement.integration.test.js`: 3 passing, 2
prerequisite skips locally
- Pip skipped because quick create selected Python 3.15.0 alpha, whose
bundled Pip metadata is incomplete
  - Conda skipped because Conda is not installed
- reviewer specialist: clean, no Critical or Important findings

The active Pip and Conda fixtures require package-index/network access
when their runtime prerequisites are present.

Fixes microsoft#1701

---------

Copilot-Session: 6b2fe9b5-38ea-442f-b07a-b6c71134d480
Copilot-Session: 3fd1a810-6840-4ac9-ac33-c8a9fda4bfc4
@StellaHuang95

Copy link
Copy Markdown
Owner Author

Additional review findings addressed in 6c5f4dd:

  • the public generic clear path now excludes the preview-only inline manager, so only the dedicated confirmed lifecycle performs destructive inline cleanup and project-setting removal;
  • partial deletion failures are aggregated while associations/events remain consistent with entries actually removed and valid survivors remain usable;
  • physical root and entry ownership are revalidated immediately before deletion, narrowing reparse-point races without claiming protection from an arbitrary same-user filesystem attacker;
  • all behavior remains unreachable when python-envs.inlineScripts.enabled is absent/false.

Comment thread src/common/lockfile.apis.ts Outdated
Comment thread src/features/envManagers.ts
Comment thread src/features/settings/settingHelpers.ts
}
await fsapi.rename(ownerMarker, retainedMarker);
} catch (_error) {
throw createLockError('Failed to mark the lock as retained', 'ERETAINFAILED', lockPath);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Warning · Non-blocking recommendation

Set state to retained only after the rename succeeds. If retain() fails today, release() will not remove the surviving owner marker because the lock is already marked retained; add a retain-failure-then-release regression test.

);
try {
await fsapi.rename(path.join(lockPath, snapshot.marker), claimedMarker);
} catch (error) {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Warning · Non-blocking recommendation

If the process is interrupted after renaming to .reclaim-* but before unlinking it, future inspection permanently classifies the lock as malformed. Add identity-safe recovery for abandoned reclaim markers and cover interruption between claim and unlink.


if (workspaceEntries.length === 0) {
return [];
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Warning · Non-blocking recommendation

With no open workspace folders, this returns before inspecting global pythonProjects, so inline entries can remain after cache deletion. Handle global configuration independently and add an empty-window test.

if (manager) {
if (manager && manager.id !== INLINE_SCRIPT_MANAGER_ID) {
await manager.clearCache();
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Warning · Non-blocking recommendation

The generic registry now hardcodes the inline manager's cache-clearing policy, including silently ignoring an explicitly scoped clear. Express bulk-clear eligibility as a manager capability or keep this routing policy in the command layer.

const activeCreatesAtStart = this.activeCreateOperations;
return this.enqueueCacheMaintenance(() =>
this.enqueueSelection(() => this.clearCacheInternal(activeCreatesAtStart)),
);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Warning · Non-blocking recommendation

A create queued behind clear A increments activeCreateOperations before passing the barrier, causing queued clear B to reject even though creation cannot start until B finishes. Count active creation only after the barrier and add a clear-create-clear ordering test.


private async clearCacheInternal(activeCreatesAtStart: number): Promise<void> {
if (activeCreatesAtStart > 0) {
const message = l10n.t(

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Warning · Non-blocking recommendation

Locking, physical ownership checks, deletion, persistence reconciliation, and event invalidation are now embedded in an already broad manager. Extract an inline-cache maintenance component before TTL eviction extends this path further.

@StellaHuang95 StellaHuang95 added review-auto:approved Automated review: no blocking findings (approval posted). and removed review-auto:changes-requested Automated review: posted blocking findings to address. labels Aug 18, 2026
mrleemurray and others added 3 commits August 18, 2026 11:07
)

Replace the existing activity bar icon with a new design more aligned
with the wider codicon design language.


![image.png](https://github.com/user-attachments/assets/65b0c66b-0e1a-4610-89d7-94206fafa044)

Co-authored-by: mrleemurray <mrleemurray@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3cb82ae9-7424-40a4-9156-8c54ac6e0895
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3cb82ae9-7424-40a4-9156-8c54ac6e0895
StellaHuang95 and others added 3 commits August 18, 2026 14:44
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3cb82ae9-7424-40a4-9156-8c54ac6e0895
Coordinate per-entry deletion locks, keep partial failures consistent, and clean inline project settings safely.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6b12d843-8011-4bfc-9ba9-f75761eadee2
Claim exact stale or retained lock markers before inline cache cleanup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6b12d843-8011-4bfc-9ba9-f75761eadee2
@StellaHuang95
StellaHuang95 force-pushed the pep723-pr13-clear-cache-v2 branch from fa55826 to 8fb0a8b Compare August 18, 2026 21:47
@StellaHuang95

Copy link
Copy Markdown
Owner Author

Upstream review continues in microsoft#1724. Closing this fork-only review PR as superseded.

export type ProcessLiveness = 'live' | 'dead' | 'unavailable';
export type FileLockState = 'missing' | 'held' | 'retained' | 'stale' | 'orphaned' | 'malformed' | 'unavailable';

export interface InspectFileLockOptions {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Issue · Please address or respond

ProcessLiveness, FileLockState, InspectFileLockOptions, and getProcessLiveness have no external consumers. Keep them module-private; callers can use the injected callback structurally without exporting these implementation details.

}

function resolvePythonProjectSettingSource(
setting: PythonProjectSettings,

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Issue · Please address or respond

Move these named interfaces to the bottom of the file to comply with the repository's typescript-named-types-at-bottom convention.


export async function addPythonProjectSetting(edits: EditProjectSettings[]): Promise<void> {
const noWorkspace: EditProjectSettings[] = [];
const workspaces = new Map<WorkspaceFolder, EditProjectSettings[]>();

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Warning · Non-blocking recommendation

This generic settings module now selects inline-owned entries and decides which loaded projects to unload. Keep source-resolution primitives here, but move inline lifecycle orchestration behind an inline-script-owned maintenance boundary.

@StellaHuang95

Copy link
Copy Markdown
Owner Author

GitHub cannot anchor PR review comments to unchanged lines in the diff. Falling back to a general PR comment for src/managers/builtin/inlineScript/envManager.ts:L1724.

Warning · Non-blocking recommendation

This manager now combines maintenance coordination, lock reclamation, containment, deletion, persistence, and invalidation while depending on destructive-path predicates from venvUtils. Extract a cache-maintenance boundary and move shared destructive-path helpers to a common filesystem utility before TTL work expands this surface.

cacheRoot,
physicalCacheRootPath,
entryName,
);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Warning · Non-blocking recommendation

Another process can create a previously absent cache entry after this enumeration, letting cleanup report success while cache contents remain. Use a cross-process root maintenance lock shared with creation, or prove completeness through repeated locked enumeration.

const updatedSettings = cloneSettings(value as PythonProjectSettings[] | undefined);
if (configurationTarget === ConfigurationTarget.Workspace) {
sharedWorkspaceValue = updatedSettings;
} else if (configurationTarget === ConfigurationTarget.WorkspaceFolder) {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Issue · Please address or respond

Move createProjectConfig, cloneSettings, and createSharedWorkspaceConfigs to the end of the enclosing suite to comply with tests-helper-placement.

sinon.stub(windowApis, 'showWarningMessage').resolves('Clear Cache' as never);
const removeInlineSettings = sinon.stub(settingHelpers, 'removeInlineScriptPythonProjectSettings').resolves([]);

await assert.rejects(clearScriptEnvironmentCacheCommand(envManagers, projectManager), /could not be deleted/);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Issue · Please address or respond

This rejection assertion uses a partial regex for a deterministic stubbed error. Capture the rejection and compare its complete message or a stable structured identity.


await assert.rejects(
unsafeManager.clearCache(),
/unsafe cache root/,

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Issue · Please address or respond

The clear-cache suite uses partial regex assertions for deterministic PR-authored errors. Capture and assert complete messages, normalizing only genuinely dynamic path portions.

await assert.rejects(
() => Promise.resolve(vscode.commands.executeCommand('python-envs.clearScriptEnvCache')),
/not found/i,
);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Issue · Please address or respond

/not found/i is an undocumented partial assertion. The exact command-list assertion already proves absence; remove this host-text check or use the documented dynamic-output exception with stable validation.


integration-tests-multiroot:
name: Integration Tests (Multi-Root)
runs-on: ${{ matrix.os }}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Warning · Non-blocking recommendation

This cache-cleanup PR also includes API 1.2, package-management behavior, network integration, pip parsing, and logo changes. Split these feature streams so cache lifecycle changes can be reviewed, reverted, and released independently.

@StellaHuang95 StellaHuang95 added review-auto:changes-requested Automated review: posted blocking findings to address. and removed review-auto:approved Automated review: no blocking findings (approval posted). labels Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-auto:changes-requested Automated review: posted blocking findings to address.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants