* plan-10 Phase 1: ship deterministic plugin runtime dependency closure Approach A — commit & ship plugin/bun.lock so the plugin's runtime node_modules install is deterministic, fixing the recurring `Cannot find module 'zod/v3'` (#2730). - align generated plugin zod range to root (^4.4.3) in build-hooks.js - new scripts/gen-plugin-lockfile.cjs generates plugin/bun.lock as a build artifact after build-hooks.js writes plugin/package.json - track & ship plugin/bun.lock (.gitignore negation, .npmignore, files allowlist) - install with `bun install --frozen-lockfile --ignore-scripts` at runtime Refs #2783, #2730 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * plan-10 Phase 2: fail loud at install time on a broken dependency closure Strengthen verifyCriticalModules to assert each dependency is actually importable via require.resolve (not merely a directory), and assert the worker-required zod subpaths resolve: zod/v3, zod/v4, zod/v4-mini. A partial/stale install now fails `npx claude-mem install` immediately instead of surfacing later as a Stop-hook `Cannot find module 'zod/v3'`. Bin-only packages (e.g. tree-sitter-cli, which has no bare-name entry point) fall back to resolving <dep>/package.json so a healthy install isn't falsely rejected. Adds tests/cli/verify-critical-modules.test.ts covering a missing zod/v3 subpath (throws), a complete zod (passes), and a bin-only dep (passes). Refs #2783, #2730 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * plan-10 Phase 3: clean-room install + import smoke test (#2730 backstop) Add scripts/smoke-clean-room.cjs and a `smoke:clean-room` npm script. Against fresh temp dirs (never the repo's node_modules) it: - copies plugin/, runs `bun install --frozen-lockfile --ignore-scripts`, asserts zod, zod/v3, zod/v4, zod/v4-mini resolve, and boots the bundled worker asserting no `Cannot find module` — the direct #2730 regression guard; - `npm pack`s, installs the tarball into a second temp dir, and load-tests the published bin entrypoint, warning loudly on any declared main/exports target missing from the tarball (latent #2537 gap). Exits non-zero naming the missing module on any failure; cleans up all temp dirs and the tarball in a finally. Refs #2783, #2730 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * plan-10 Phase 4: gate CI and publish on the clean-room dependency closure - ci.yml: new `clean-room-deps` job (between build and the docker e2e job) runs a frozen-lockfile drift check on the committed plugin lockfile, then `npm run build` + `npm run smoke:clean-room`. The drift step catches a contributor who changed plugin deps without regenerating plugin/bun.lock. - npm-publish.yml: add setup-bun and run `npm run smoke:clean-room` between build and `npm publish`, so a broken runtime closure cannot be published on a tag push (ci.yml does not run on tags). Secrets block untouched. Refs #2783, #2730 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * plan-10: doc recluster note + Phase 0 execution slice for #2730 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * plans: backlog recluster (2026-06-04) — cross-cluster execution order + plan-13 doc Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * plan-10: gen-plugin-lockfile degrades gracefully when bun is absent The Windows build CI job has no bun on PATH; regenerating the lockfile there threw and failed the build. The committed plugin/bun.lock is already the deterministic closure, so skip regeneration (non-fatal) when bun is missing and a lockfile exists; fail loud only when neither is available. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2.2 KiB
[plan-09] Data-Pipeline Integrity & Migration Transparency — stop "healthy worker, frozen observations"
Defect
The worker can report healthy while data silently fails to reach or be retrievable from the store, and the failures are swallowed so distinct root causes present identically. Session identity is stamped inconsistently across the live-observer / re-sync / manual paths; generated summaries and observations are not stamped with the originating content_session_id at write time; EXCLUDED_PROJECTS is honored on capture but not in the Stop hook so excluded projects still get summaries; the FTS5 index omits the type column so a type-token conjunction returns zero; and manual memory-write tools are blocked in the worker runtime. The fix is a verified, consistent write-and-read contract: stamp identity once at write time on every path, apply exclusion uniformly, index every queryable column, and keep the manual write tools functional.
Children
- #2769 — Stamp originating content_session_id onto generated session_summaries/observations at write time
- #2772 — Chroma
memory_session_idholds the content session id on the live-observer path (inconsistent with re-sync/manual) - #2767 —
EXCLUDED_PROJECTSdoes not block the Stop hook — summaries still generated for excluded projects - #2729 — FTS5 conjunction with type-token returns 0 (
typecolumn not in the search index) - #2705 — Manual memory-write tools (
observation_add/memory_add) blocked in the worker runtime
Fix sequence
Design doc: plans/09-data-pipeline-integrity.md. Stamp content_session_id at write time on all three paths; apply EXCLUDED_PROJECTS in the Stop hook; add type (and other queried columns) to the FTS5 schema with a migration; re-enable the worker-runtime write tools; assert the field→column→trigger chain.
Test matrix
| Path | Required behavior |
|---|---|
| live observer / re-sync / manual | identical content_session_id stamping |
| excluded project | Stop hook generates nothing |
search type:bugfix + token |
returns matching rows |
| worker runtime | observation_add / memory_add succeed |
Out of scope
Observer output validity (plan-11); grammar/parse coverage (plan-13).