Skip to content

ci(framework): assert capability packages ship a runtime entry (no dts-only / half-built)#2432

Merged
os-zhuang merged 1 commit into
mainfrom
claude/capability-build-guard
Jun 28, 2026
Merged

ci(framework): assert capability packages ship a runtime entry (no dts-only / half-built)#2432
os-zhuang merged 1 commit into
mainfrom
claude/capability-build-guard

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Why

Capability packages under packages/{services,triggers,plugins} are loaded by the cloud multi-tenant runtime via a dynamic import of their published entry. If one ships a dts-only / half-built / 0-byte dist (an interrupted build, or a package retired in source but still referenced), the import resolves to nothing and that capability silently fails to load — e.g. AI-built record-change automation registers but never fires, with no user-visible signal.

The shared tsup config always emits JS (the only toggle, OS_SKIP_DTS, drops declarations, not JS), so a dts-only dist can only happen by accident — and nothing in CI caught it. (This came up while debugging a cloud-side triggers capability that wasn't loading; the framework package itself was fine, but there was no guard proving it.)

What

Extend the existing Verify build outputs step (runs right after pnpm build, so no build-ordering ambiguity) with a filesystem assertion that every buildable capability package produced its declared main runtime entry.

Self-maintaining and false-positive-safe:

  • reads each package's own main (defaults to dist/index.js);
  • skips dirs with no package.json (a retired service-feed / service-ai leftover);
  • skips packages with no scripts.build;
  • -s catches 0-byte half-writes.

Validation

  • Passes against a freshly-built tree (all capability packages have runtime entries).
  • Negative test: removing trigger-record-change/dist/index.js is caught and fails the step.
  • ci.yml parses.

🤖 Generated with Claude Code

…s-only / half-built)

Capability packages (services / triggers / plugins) are loaded by the
multi-tenant runtime via a DYNAMIC import of their published entry. If a package
ships a dts-only / half-built / 0-byte dist — an interrupted build, or a package
retired in source but still referenced — the import resolves to nothing and the
capability SILENTLY fails to load (e.g. record-change automation never fires,
with no user-visible signal). The shared tsup config always emits JS, so this
can only happen by accident, and nothing in CI caught it.

Extend "Verify build outputs" (which runs right after the full `pnpm build`)
with a filesystem assertion that every buildable capability package actually
produced its declared `main` runtime entry. Self-maintaining: reads each
package's own manifest, skips dirs with no package.json (e.g. a retired
service-feed / service-ai leftover) and packages without a build script.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 28, 2026 3:51pm

Request Review

@os-zhuang
os-zhuang merged commit 6775736 into main Jun 28, 2026
15 checks passed
@os-zhuang
os-zhuang deleted the claude/capability-build-guard branch June 28, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant