Skip to content

fix(build): forward default exports through stable runtime aliases#99678

Merged
vincentkoc merged 2 commits into
openclaw:mainfrom
headbouyJB:fix/runtime-alias-default-reexport-forkbase
Jul 4, 2026
Merged

fix(build): forward default exports through stable runtime aliases#99678
vincentkoc merged 2 commits into
openclaw:mainfrom
headbouyJB:fix/runtime-alias-default-reexport-forkbase

Conversation

@headbouyJB

@headbouyJB headbouyJB commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Fixes #99677.

🤖 AI-assisted (Claude Code). This bug was caught, diagnosed, and this fix proposed by the reporter's AI agent operating a live local OpenClaw deployment; I'm submitting as the deployment owner. Evidence is real measured behavior; validation below. (Prior contribution from this setup: #98267.)

What Problem This Solves

runtime-postbuild writes stable runtime aliases as bare export * from "./X-HASH.js" — but export * from never re-exports default. One shipped alias (2026.6.10 and 2026.6.11 tarballs) points at a chunk whose only export is default (the compaction-reconcile runtime), so its lazy consumer destructuring default gets undefined; the remaining stable aliases are latent instances of the same generator defect (corrected from an earlier "seven affected" count — see the issue's correction note). Proven-broken path: after every successful auto-compaction,

late compaction count reconcile failed: TypeError: reconcile is not a function

(selection chunk lazy-imports { default: reconcile } through the compaction runtime alias) — so the persisted compactionCount never updates. On local-model deployments the resulting repeat compactions each trigger a multi-minute full re-prefill (observed: 3 compactions in 25 minutes = an unresponsive agent).

Why This Change Was Made

The alias writers (writeStableRootRuntimeAliases, writeLegacyRootRuntimeCompatAliases) now build alias source via a shared helper: if the target chunk contains a default export, the alias additionally emits export { default } from .... Aliases for targets without a default are byte-identical to before. Conservative detection (anchored export-statement patterns) so aliases never claim a default their target lacks (which would be a hard SyntaxError at import time).

User Impact

  • Post-compaction bookkeeping persists again (the silent per-compaction failure stops for all users).
  • Fixes the compaction-storm presentation on local models (each avoided re-compaction saves a multi-minute prefill).
  • The six latent aliases stop being footguns for future default lazy-imports.

Evidence

  • Published-tarball verification: the compaction alias in [email protected] is a bare star re-export whose target's only export is default; the reconcile caller destructures default (see issue for excerpts + correction note).
  • Detection robustness, live-tested: naive text matching for as default false-positives on string content in minified chunks — appending export { default } to an alias whose target lacks one is a hard SyntaxError at import (we hit exactly this on our deployment with a hasty local hotfix). This PR's anchored export-statement pattern was verified against all 7 real shipped chunks: no false positives, correct match on the compaction chunk.
  • Live deployment: appending the default re-export to the 7 dist aliases stopped the error immediately; auto-compactions now reconcile (no repeat-compaction loop since).
  • Tests: added a regression test mirroring the real reconcile chunk shape (star-only alias would fail it). pnpm exec vitest run test/scripts/runtime-postbuild.test.ts29 passed (29).

Note for maintainers

scripts/stage-bundled-plugin-runtime.mjs emits the same bare export * from pattern for plugin runtime staging — I have not verified whether any plugin runtime target exports default; flagging as a possible sibling rather than expanding this PR's scope.

Maintainer follow-up

Maintainer review found and repaired two same-surface edge cases before landing:

  • direct export { default } from ... aliases now propagate their default through legacy compatibility aliases;
  • generated default-forwarding wrappers are excluded from implementation-candidate selection, so repeated postbuild runs remain idempotent instead of deleting the stable alias.

Additional evidence on the repaired branch:

  • node scripts/run-vitest.mjs test/scripts/runtime-postbuild.test.ts — 29/29 passed, including import-level stable/legacy and repeated-run coverage;
  • targeted oxlint — clean;
  • Testbox-through-Crabbox tbx_01kwn4h68kbccmctj63t0s6h23: pnpm check:changed and pnpm build passed;
  • final structured autoreview on pushed head 8f29406f58df15538052ebaa76ff764e17771be0 — no actionable findings.

@openclaw-barnacle openclaw-barnacle Bot added scripts Repository scripts size: S labels Jul 3, 2026
@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 3, 2026, 7:16 PM ET / 23:16 UTC.

Summary
The PR changes runtime-postbuild alias generation to explicitly forward a target chunk's default export when present, and adds a regression test for default-only runtime chunks.

PR surface: Tests +29, Other +33. Total +62 across 2 files.

Reproducibility: yes. source-level reproduction is high confidence: current main emits wildcard-only aliases, the compaction caller imports default through such an alias, the runtime helper exports default, and a Node ESM probe confirms wildcard re-exports omit default. I did not run a packaged live compaction flow in this read-only review.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: scripts/runtime-postbuild.mjs, serialized state: test/scripts/runtime-postbuild.test.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #99677
Summary: This PR is the candidate fix for the canonical issue about stable runtime aliases dropping default exports; broader compaction reports overlap symptoms but not the alias root cause.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Risk before merge

  • [P1] Required CI was still in progress on head a2eb826 when checked; no code-level blocker was found in this read-only review.

Maintainer options:

  1. Decide the mitigation before merge
    Land this focused generator fix after required CI and maintainer review, leaving broader compaction guardrail work to its separate canonical issues.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • No automated repair lane is needed; the PR should proceed through normal maintainer review once required CI finishes.

Security
Cleared: Cleared: the diff changes a local build script and its focused test only, with no dependency, lockfile, workflow, secret, download, or permission expansion.

Review details

Best possible solution:

Land this focused generator fix after required CI and maintainer review, leaving broader compaction guardrail work to its separate canonical issues.

Do we have a high-confidence way to reproduce the issue?

Yes, source-level reproduction is high confidence: current main emits wildcard-only aliases, the compaction caller imports default through such an alias, the runtime helper exports default, and a Node ESM probe confirms wildcard re-exports omit default. I did not run a packaged live compaction flow in this read-only review.

Is this the best way to solve the issue?

Yes, this is the best fix boundary: the generated alias is the layer dropping the default export, while the caller and runtime helper agree on a default import/export contract. Changing only the compaction caller would leave the alias generator as a latent footgun.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against c45124ab8554.

Label changes

Label changes:

  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster. Replaced prior rating: 🦐 gold shrimp.
  • remove rating: 🦐 gold shrimp: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.

Label justifications:

  • P1: The PR fixes a shipped runtime packaging bug that can break post-compaction bookkeeping and make local-model sessions repeatedly refill context.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster. Replaced prior rating: 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): Sufficient: the PR body includes published-artifact analysis, copied runtime error output, live deployment after-fix observation, and a focused regression test command; any additional logs should stay redacted.
  • proof: sufficient: Contributor real behavior proof is sufficient. Sufficient: the PR body includes published-artifact analysis, copied runtime error output, live deployment after-fix observation, and a focused regression test command; any additional logs should stay redacted.
Evidence reviewed

PR surface:

Tests +29, Other +33. Total +62 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 0 0 0 0
Tests 1 29 0 +29
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 1 35 2 +33
Total 2 64 2 +62

What I checked:

Likely related people:

  • steipete: Commit 9857d40 introduced writeStableRootRuntimeAliases with wildcard-only stable runtime aliases in scripts/runtime-postbuild.mjs. (role: introduced alias behavior; confidence: high; commits: 9857d40923ad; files: scripts/runtime-postbuild.mjs, test/scripts/runtime-postbuild.test.ts)
  • vincentkoc: Commit 599abac changed the compaction reconcile wrapper to lazy-import a default export from the runtime helper. (role: recent compaction wrapper contributor; confidence: high; commits: 599abac902f7; files: src/agents/embedded-agent-subscribe.handlers.compaction.ts, src/agents/embedded-agent-subscribe.handlers.compaction.runtime.ts, src/agents/embedded-agent-subscribe.handlers.compaction.test.ts)
  • 849261680: Commit c51933d recently changed runtime-postbuild alias behavior and adjacent regression tests for runtime import stability. (role: recent runtime-postbuild contributor; confidence: medium; commits: c51933dc23c8; files: scripts/runtime-postbuild.mjs, test/scripts/runtime-postbuild.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P1 High-priority user-facing bug, regression, or broken workflow. labels Jul 3, 2026
@headbouyJB
headbouyJB force-pushed the fix/runtime-alias-default-reexport-forkbase branch from 75f4081 to 712f7dc Compare July 3, 2026 23:06
@headbouyJB

Copy link
Copy Markdown
Contributor Author

Fixed the check-lint failure in 712f7dca: no-useless-assignment on the dead targetSource initializer in buildRuntimeAliasSource (declare-without-initializer; the catch path early-returns, so the variable is definitely assigned before use). oxlint scripts/runtime-postbuild.mjs clean locally; test/scripts/runtime-postbuild.test.ts still 29/29. No other changes.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@headbouyJB
headbouyJB force-pushed the fix/runtime-alias-default-reexport-forkbase branch from 712f7dc to a2eb826 Compare July 3, 2026 23:12
@vincentkoc vincentkoc self-assigned this Jul 3, 2026
headbouyJB and others added 2 commits July 3, 2026 17:02
runtime-postbuild writes stable aliases (`X.runtime.js`) for hashed runtime
chunks as bare `export * from "./X-HASH.js"` — but `export * from` never
re-exports `default`. In the shipped 2026.6.10/2026.6.11 artifacts the
compaction runtime alias points at a chunk whose only export is default, so
its lazy consumer destructuring `{ default: reconcile }` gets undefined:
every successful auto-compaction logs "late compaction count reconcile
failed: TypeError: reconcile is not a function" and the persisted
compactionCount never updates. On local-model deployments the resulting
repeat compactions each cost a multi-minute full re-prefill (observed:
3 compactions in 25 minutes). Other stable aliases are latent instances of
the same generator defect for any target that gains a default export.

Fix: when the alias target has a default export, also emit
`export { default } from ...` (applies to both the stable-alias and
legacy-compat writers). Detection is an anchored export-statement pattern,
verified against all 7 shipped runtime chunks (no false positives; naive
text matching would both miss and over-match — an alias claiming a default
its target lacks is a hard SyntaxError at import). Adds a regression test
mirroring the real compaction-reconcile chunk shape.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01H6Hz9UEpxQ4W3d8XecvupH
@vincentkoc
vincentkoc force-pushed the fix/runtime-alias-default-reexport-forkbase branch from 8f29406 to 34c7a93 Compare July 4, 2026 00:06
@vincentkoc

Copy link
Copy Markdown
Member

Maintainer land-ready proof for 34c7a9325a6805ebfca529c61815d8a93a25a2d0:

  • Reproduced the ESM contract failure: wildcard re-exports omit default, while the compaction consumer imports a default-only runtime helper through the generated alias.
  • The generator now detects declaration, local-alias, and direct default re-exports in both stable and legacy alias writers. Named-only aliases remain unchanged and repeated postbuild runs stay idempotent.
  • node scripts/run-vitest.mjs test/scripts/runtime-postbuild.test.ts: 29 passed.
  • Targeted oxlint and git diff --check: passed.
  • Testbox pnpm check:changed and pnpm build: passed.
  • The previously failing runtime-inventory-drift-check QA scenario passed in isolation, then the rebased exact head passed the full QA Smoke CI profile.
  • Fresh autoreview on the rebased exact head: clean, confidence 0.95.
  • Exact-head hosted CI, review artifacts, merge-tree, and OPENCLAW_TESTBOX=1 scripts/pr prepare-run 99678: clean.

Known proof gaps: none for the generated runtime alias behavior.

@vincentkoc
vincentkoc merged commit 24dba4b into openclaw:main Jul 4, 2026
82 checks passed
@vincentkoc

Copy link
Copy Markdown
Member

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 4, 2026
…penclaw#99678)

* fix(build): forward default exports through stable runtime aliases

runtime-postbuild writes stable aliases (`X.runtime.js`) for hashed runtime
chunks as bare `export * from "./X-HASH.js"` — but `export * from` never
re-exports `default`. In the shipped 2026.6.10/2026.6.11 artifacts the
compaction runtime alias points at a chunk whose only export is default, so
its lazy consumer destructuring `{ default: reconcile }` gets undefined:
every successful auto-compaction logs "late compaction count reconcile
failed: TypeError: reconcile is not a function" and the persisted
compactionCount never updates. On local-model deployments the resulting
repeat compactions each cost a multi-minute full re-prefill (observed:
3 compactions in 25 minutes). Other stable aliases are latent instances of
the same generator defect for any target that gains a default export.

Fix: when the alias target has a default export, also emit
`export { default } from ...` (applies to both the stable-alias and
legacy-compat writers). Detection is an anchored export-statement pattern,
verified against all 7 shipped runtime chunks (no false positives; naive
text matching would both miss and over-match — an alias claiming a default
its target lacks is a hard SyntaxError at import). Adds a regression test
mirroring the real compaction-reconcile chunk shape.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01H6Hz9UEpxQ4W3d8XecvupH

* fix(build): preserve defaults through legacy runtime aliases

---------

Co-authored-by: headbouyJB <[email protected]>
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
@headbouyJB

Copy link
Copy Markdown
Contributor Author

Follow-up on the "possible sibling" note in the description: verified — scripts/stage-bundled-plugin-runtime.mjs is NOT affected. Its writeRuntimeModuleWrapper already pairs every export * from with an explicit default forwarder (hasDefaultExport check, nested-.default unwrapping, namespace fallback in the no-default branch), so neither the undefined-default failure this PR fixed nor a missing-export SyntaxError can occur on that path. No further change needed. Thanks for the fast review + merge, @vincentkoc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. scripts Repository scripts size: S status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stable runtime aliases drop default exports — "reconcile is not a function" after every auto-compaction; compaction bookkeeping never persists

2 participants