Skip to content

fix(pi): preserve runtime dependencies in profile snapshots - #334

Open
thimpeng wants to merge 2 commits into
SeemSeam:mainfrom
thimpeng:fix/pi-profile-snapshot-dependencies-main
Open

fix(pi): preserve runtime dependencies in profile snapshots#334
thimpeng wants to merge 2 commits into
SeemSeam:mainfrom
thimpeng:fix/pi-profile-snapshot-dependencies-main

Conversation

@thimpeng

@thimpeng thimpeng commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a follow-up bug fix for #328, which introduced shared Pi profile-asset snapshots. After that PR was merged, valid local Pi packages could be copied into the isolated CCB cache without the runtime dependency topology they resolved from in the source workspace.

The observed startup failures were:

  • pi-accounts could not resolve proper-lockfile, which npm had hoisted outside the copied package directory.
  • pi-antigravity loaded effect, but effect could not resolve its pnpm-linked transitive dependency fast-check after snapshot isolation.

Both packages declared their dependencies correctly. The regression was in CCB snapshot materialization, and the same defect class could affect other local, Git, or direct Pi package directories whose effective production dependency closure extends beyond the selected directory.

Root cause

PR #328 copied package directories into a content-addressed cache as standalone trees. That preserved package files but not dependencies resolved through npm workspace hoisting or pnpm store symlinks. Pi then loaded the copied snapshot as the new authority, where Node resolution could no longer reach those external dependencies.

Fix

  • Normalize package-style local, Git, and direct extension directories into a self-contained production dependency closure before publication.
  • Resolve declared dependencies using Node-style ancestor node_modules lookup, covering npm hoisting and pnpm-linked package roots.
  • Preserve required, present optional, bundled, scoped, aliased, transitive, and circular dependency behavior.
  • Keep Pi host-provided peer dependencies outside the copied closure; third-party runtime modules remain the package's dependencies responsibility.
  • Perform no network installation and run no lifecycle scripts during managed-agent startup.
  • Fail before publishing settings when required dependencies or dependency declarations are missing or malformed.
  • Verify cache bytes, file/directory/root modes, self-contained relative symlinks, source drift, staging copies, cache hits, and concurrent publication winners.
  • Reject absolute, dangling, cyclic, escaping, or late-substituted symlinks.
  • Revalidate direct extension file snapshots after seeding and include current npm tree contents in cache identity even when the lockfile is unchanged.

Compatibility and impact

The fix retains the shared projected-asset API used by Codex and Copilot. Existing call signatures remain compatible; package normalization is limited to package-style Pi snapshot sources. npm-managed Pi packages continue to use the shared complete npm tree.

No global CCB installation, config reload, or endpoint restart is part of this PR.

Verification

All verification below was run on final commit bb148731, directly above upstream main commit 2dc46cf:

  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 python -m pytest -q test/test_native_cli_providers.py test/test_projected_assets.py test/test_copilot_home.py test/test_provider_profiles.py
    • 268 passed
  • Targeted scoped / missing optional / bundled / circular dependency selection:
    • 4 passed
  • Python byte compilation: passed.
  • git diff --check: passed.
  • Real current Pi profile materialization followed by PI_OFFLINE=1 pi --help: exited 0 without missing-module or extension-load errors.

Regression coverage includes npm-hoisted and pnpm-linked transitive dependencies, circular loading through Node, cache tampering, executable and directory modes, source drift, scoped and bundled packages, absent optional dependencies, unsafe symlinks, and concurrent cache publication.

Independent review

  • Fresh CCB reviewer gate on final HEAD: ACCEPT, no blocker, major, or minor findings; independently reproduced the 268-test suite.
  • Independent GLM-5.3/high gate on final HEAD: ACCEPT, no blocker or major findings.

Non-blocking follow-ups noted during review include measuring warm-cache hashing cost, considering a bound for ancestor dependency lookup, reducing duplicate closure copies in very large graphs, tightening a few package-name edge cases, and adding more optional-dependency variants. These do not affect the observed regression or the correctness of this fix.

Commits

  • 821bd540 — production fix
  • bb148731 — review follow-up tests and Node availability guard

Checklist

  • Based on current upstream main at review and submission time
  • Focused and shared compatibility tests pass
  • Real offline Pi startup smoke passes
  • Independent CCB reviewer accepted final HEAD
  • Independent GLM-5.3/high review accepted final HEAD

Related: #328

Follow-up bug fix for PR SeemSeam#328, which introduced shared Pi profile asset snapshots. Local, Git, and direct package snapshots could lose npm-hoisted or pnpm-linked runtime dependencies after being copied into the isolated cache, causing valid extensions such as pi-accounts and pi-antigravity to fail at startup.

Normalize package-style snapshots into a self-contained production dependency closure without network installs or lifecycle scripts. Verify cache bytes, modes, symlinks, concurrent publication, and missing or malformed dependency failures before publishing settings.

Tests: 265 focused Pi, projected-asset, Codex, and Copilot profile tests passed on upstream main; Python byte compilation and diff checks passed; a real current-profile PI_OFFLINE=1 pi --help smoke test exited 0 without extension load errors.
Add committed regression coverage for scoped package placement, absent optional dependencies, and bundled dependencies identified during the GLM-5.3 review.

Skip the executable circular-dependency probe when Node.js is unavailable so non-Node test hosts report the environment limitation instead of failing collection.

Tests: 268 focused Pi, projected-asset, Codex, and Copilot profile tests passed; targeted boundary tests passed 4/4; py_compile and git diff --check passed.
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.

1 participant