Skip to content

fix(T12012): derive Wave 7.5 utils-inline list + dist assert + packed-install smoke#1102

Merged
kryptobaseddev merged 1 commit into
mainfrom
task/T12012
Jun 13, 2026
Merged

fix(T12012): derive Wave 7.5 utils-inline list + dist assert + packed-install smoke#1102
kryptobaseddev merged 1 commit into
mainfrom
task/T12012

Conversation

@kryptobaseddev

Copy link
Copy Markdown
Owner

Root Cause

build.mjs Wave 7.5 surgically re-emits @cleocode/utils-consuming core source files via esbuild (inlining utils) to repair the bare import left by the playbooks tsc -b reference build. The list was hardcoded. T11989 (#1093) added a fourth consumer — packages/core/src/selfimprove/fix-gen.ts — and the hardcoded list was not updated.

Result: every cleo invocation on installed v2026.6.17 died with ERR_MODULE_NOT_FOUND: Cannot find package '@cleocode/utils' imported from @cleocode/core/dist/selfimprove/fix-gen.js. This is DHQ-099, the third packaged-install-only failure in 24h (DHQ-096 entry path, DHQ-098 studio-dist, now this).

The workspace resolves @cleocode/utils via symlinks so all CI gates passed. Only a packed npm install exposed the bare import. Two structural gates also failed to catch it: (1) bundle-budget AC1 only probed exported submodule entry points in package.json exports — selfimprove/fix-gen.js is a deep-linked file not in the exports map; (2) no packed-install smoke test existed in the release pipeline.

Changes

1. Derived list — kill the rot class (build.mjs Wave 7.5)

Replace the hardcoded 3-entry list with a build-time scan of packages/core/src/**/*.ts (excluding __tests__/ and *.test.ts) for files whose import specifiers reference @cleocode/utils. The derived list is logged at build time.

Before fix (hardcoded):

{ in: 'packages/core/src/memory/redaction.ts', out: 'memory/redaction' },
{ in: 'packages/core/src/llm/plugin-facade.ts', out: 'llm/plugin-facade' },
{ in: 'packages/core/src/docs/export-document.ts', out: 'docs/export-document' },
// selfimprove/fix-gen.ts was MISSING

After fix (scan output):

[build] Wave 7.5: re-inline @cleocode/utils into core leaf files (T11654, T12012)
  Derived 4 utils-consuming source file(s):
    packages/core/src/docs/export-document.ts -> packages/core/dist/docs/export-document.js
    packages/core/src/llm/plugin-facade.ts -> packages/core/dist/llm/plugin-facade.js
    packages/core/src/memory/redaction.ts -> packages/core/dist/memory/redaction.js
    packages/core/src/selfimprove/fix-gen.ts -> packages/core/dist/selfimprove/fix-gen.js  ← NOW INCLUDED
  Wave 7.5 complete — @cleocode/utils inlined into all consumers above.
[build] Wave 7.5 assertion passed — no bare @cleocode/utils import survives in packages/core/dist/

2. Build-time post-assertion (build.mjs, Wave 7.5)

After Wave 7.5 re-emit, scan ALL packages/core/dist/**/*.js for surviving bare @cleocode/utils import specifiers (skipping JSDoc comment lines). Hard-fails the build with the offending file list. Converts this class of latent failure into a build error.

3. Bundle-budget AC1 gate extended (packages/core/scripts/check-core-bundle-budget.mjs)

AC1 now runs two passes:

  • Pass A (original): scans exported submodule entry points from package.json exports
  • Pass B (new): full dist tree sweep — scans ALL .js files under dist/

Why the old AC1 missed it: Pass A only probes files declared in the exports map. selfimprove/fix-gen.js is a deep-linked file (not exported), invisible to Pass A. Pass B is the canonical fallback guard.

Comment-line false-positives (JSDoc examples with * import { ... } from '...') are filtered by checking the trimmed line prefix before matching.

4. Packed-install smoke script (scripts/packed-install-smoke.mjs)

New scripts/packed-install-smoke.mjs:

  1. pnpm pack all 18 published @cleocode/* packages to a temp dir (uses pnpm, not npm, to resolve workspace:* to actual version strings)
  2. npm install @cleocode/cleo into an isolated app with package.json overrides mapping every @cleocode/* to its local tarball (zero registry traffic)
  3. Run cleo --version and assert exit 0 + non-empty version string

Locally runnable: node scripts/packed-install-smoke.mjs

5. Release pipeline gate (.github/workflows/release.yml)

New step "Packed-install smoke test (T12012)" runs scripts/packed-install-smoke.mjs after the existing tarball verification steps, before pnpm publish. This is the systemic fix.

6. DHQ ledger

  • Appended DHQ-099 (this regression — root cause, structural gate gaps, and answer vehicle)
  • Flipped DHQ-097 to FIXED #1096 (T12010 merged)

Before/After Smoke Proof

BEFORE fix (analytical — build.mjs Wave 7.5 hardcoded list missing fix-gen.ts):

grep -rl "@cleocode/utils" packages/core/src/ --include="*.ts" | grep -v "__tests__"
# Output:
packages/core/src/docs/export-document.ts
packages/core/src/llm/plugin-facade.ts
packages/core/src/memory/redaction.ts
packages/core/src/selfimprove/fix-gen.ts  <-- NOT in old hardcoded list

AFTER fix (packed-install smoke output):

[packed-smoke] Step 4: running installed cleo --version...
  cleo --version => {"success":true,"data":{"version":"2026.5.126"},...}
[packed-smoke] PASS — packed install smoke test succeeded.
  Verified: npm pack + install + cleo --version exit 0 with 18 @cleocode/* tarballs

Dist grep proof

grep "@cleocode/utils" packages/core/dist/selfimprove/fix-gen.js
# → (no output) PASS: no @cleocode/utils import in dist/selfimprove/fix-gen.js

node -e "import('file:///...worktree.../packages/core/dist/selfimprove/fix-gen.js').then(()=>console.log('loads'))"
# → PASS: fix-gen.js loads

Sweep results (AC1 Pass B)

AC1 Pass B — full dist tree sweep for undeclared @cleocode/* imports:
  OK — no undeclared @cleocode/* bare imports found in any of the 247 top-level dist entries

Test results

All 104 selfimprove tests pass (src/selfimprove/__tests__/fix-gen.test.ts + run-loop.test.ts).

🤖 Generated with Claude Code

…-install smoke (v2026.6.17 dead-on-import)

Root cause: build.mjs Wave 7.5 surgically re-emits @cleocode/utils-consuming core
source files via esbuild to repair the bare import left by the playbooks tsc -b
reference build. The list of files was hardcoded. T11989 (#1093) added a fourth
consumer (selfimprove/fix-gen.ts) and the list was not updated, causing every cleo
invocation to die with ERR_MODULE_NOT_FOUND on installed v2026.6.17. This is DHQ-099,
the third packaged-install-only failure in 24h.

Changes:
- Wave 7.5: replace hardcoded 3-entry list with a build-time scan of packages/core/src
  for files importing @cleocode/utils (excluding tests). Derived list is logged.
- Build-time post-assertion: after Wave 7.5, scan ALL packages/core/dist/**/*.js for
  surviving @cleocode/utils imports (skipping comment lines). Hard-fail with offender
  list so this class of bug becomes a build error, not a production incident.
- Bundle-budget AC1 gate: add Pass B — full dist tree sweep covering ALL .js files
  under dist/ (not just exported submodule entry points). The original AC1 only probed
  the declared package.json exports map, which is why selfimprove/fix-gen.js escaped.
  Comment-line false-positives (JSDoc examples like "* import { ... } from ...") are
  filtered out by checking the trimmed line prefix before matching.
- New scripts/packed-install-smoke.mjs: pnpm pack all 18 published packages, npm
  install @cleocode/cleo with package.json overrides mapping every @cleocode/* to a
  local tarball (no registry traffic), run cleo --version, assert exit 0. Uses pnpm
  pack (not npm pack) to resolve workspace:* to actual version strings.
- release.yml: new "Packed-install smoke test (T12012)" step after tarball verification,
  before pnpm publish. This is the systemic fix for the class of workspace-private
  import regressions.
- DHQ ledger: append DHQ-099 (this regression); flip DHQ-097 to FIXED #1096.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@kryptobaseddev kryptobaseddev merged commit 07a33dd into main Jun 13, 2026
75 checks 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