Skip to content

fix(ci): catch script declaration drift before merge#110248

Merged
steipete merged 4 commits into
mainfrom
codex/ci-script-declaration-contract
Jul 18, 2026
Merged

fix(ci): catch script declaration drift before merge#110248
steipete merged 4 commits into
mainfrom
codex/ci-script-declaration-contract

Conversation

@steipete

@steipete steipete commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Resolves a problem where an exported value could be added to an MJS maintainer script without updating its adjacent declaration sidecar, allowing a broken script type contract to reach main. This class caused the recent declaration repairs in #109358, #109373, and #109812.

Why This Change Was Made

Adds one deterministic value-export contract verifier for paired scripts/**/*.mjs and .d.mts files, including ESM star-export semantics, TypeScript value/type namespace distinctions, missing sidecars, orphaned runtime sources, and fail-closed handling when external declaration value provenance is unknowable. The same fast command now runs from changed-file checks, the aggregate check preflight, and the blocking CI guards consumed by scripts/pr prepare-run. Existing stale declarations were normalized so the new baseline starts green.

AI-assisted. The implementation was reviewed with the repository autoreview workflow until no actionable findings remained.

User Impact

No product behavior changes. Maintainers now get a pre-merge failure when script runtime exports and declaration contracts diverge, instead of discovering the break after merge.

Evidence

  • node scripts/check-script-declarations.mjs — 233 declaration contracts match.
  • node scripts/run-vitest.mjs test/scripts/check-script-declarations.test.ts — 21 passed after rebase onto current main.
  • node scripts/check-changed.mjs -- <changed files> — formatting, declaration verification, script/test typechecks, and script lint passed on Blacksmith Testbox: https://github.com/openclaw/openclaw/actions/runs/29625334881
  • Deliberate fixture drift fails; regenerating the fixture declaration passes. Additional fixtures cover missing runtime/declaration pairs, nested ESM star ambiguity/default behavior, declaration value-space resolution, external-module provenance, and deletion/rename handling.

@openclaw-barnacle openclaw-barnacle Bot added scripts Repository scripts size: L maintainer Maintainer-authored PR labels Jul 17, 2026
@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: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. merge-risk: 🚨 automation 🚨 May affect CI, automerge, proof capture, label sync, or maintainer automation. labels Jul 17, 2026
@clawsweeper

clawsweeper Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 17, 2026, 9:49 PM ET / July 18, 2026, 01:49 UTC.

Summary
Adds a verifier that compares value exports from scripts/**/*.mjs files with adjacent .d.mts declarations, wires it into changed checks and CI guards, and aligns existing declaration sidecars.

PR surface: Tests +565, Config +2, Other +585. Total +1152 across 25 files.

Reproducibility: not applicable. This PR prevents a CI contract-drift class rather than reporting a current user-facing runtime failure; the PR supplies direct before/after verifier evidence.

Review metrics: 1 noteworthy metric.

  • Enforcement paths: 3 enforcement paths added. The verifier is invoked by changed checks, aggregate checks, and CI preflight, so a false positive affects both local contributor workflow and required CI.

Stored data model
Persistent data-model change detected: database schema: scripts/mantis/build-telegram-desktop-proof-evidence.d.mts. Confirm migration or upgrade compatibility proof before merge.

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

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

Rank-up moves:

  • Confirm final-head handling of valid shared external export * bindings during maintainer review.

Risk before merge

  • [P1] This adds a global fail-closed CI guard; an unmodelled valid ESM re-export pattern could block otherwise healthy script/tooling changes until the verifier is adjusted.
  • [P1] The review discussion raised a same-external-binding export * barrel edge case, so maintainer review should confirm the final head’s opaque-export and cyclic-barrel coverage preserves valid ESM bindings before adopting the gate globally.

Maintainer options:

  1. Adopt the guard with final semantic review (recommended)
    Confirm the ESM export-star behavior and let the remaining required CI gates complete before merging this new required preflight.
  2. Limit the guard to locally resolvable exports
    Reduce false-positive exposure by treating opaque external value provenance as out of scope until a separately reviewed contract is ready.

Next step before merge

  • [P1] A protected maintainer label and the new repository-wide fail-closed CI contract require a human merge decision rather than an automated repair.

Maintainer decision needed

  • Question: Should the repository make this fail-closed declaration verifier a required global preflight guard, including its treatment of opaque external re-exports?
  • Rationale: The implementation intentionally changes merge-blocking automation for all script and tooling contributors; the acceptable false-positive boundary is a maintainer-owned CI policy choice.
  • Likely owner: steipete — They have the strongest recent merged and current-branch history for script declaration contracts.
  • Options:
    • Adopt the global guard (recommended): Keep the fail-closed policy and merge after confirming the final export-star coverage accepts valid shared external bindings.
    • Narrow the first version: Require checks only for locally resolvable exports and defer opaque external provenance handling to a follow-up.

Security
Cleared: The diff adds local deterministic source analysis and CI wiring without new dependency sources, elevated permissions, secret handling, or downloaded-code execution.

Review details

Best possible solution:

Adopt one authoritative script-declaration guard after maintainer confirmation that its fail-closed handling is limited to genuinely unverifiable contracts and valid ESM barrel patterns remain accepted.

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

Not applicable: this PR prevents a CI contract-drift class rather than reporting a current user-facing runtime failure; the PR supplies direct before/after verifier evidence.

Is this the best way to solve the issue?

Yes, with maintainer confirmation of the fail-closed boundary: a single verifier wired into existing changed-check and CI guard seams avoids repeating one-off declaration repairs.

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

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

Label justifications:

  • P3: This is internal CI and maintainer-contract hardening with no reported product-runtime behavior change.
  • merge-risk: 🚨 automation: The PR adds a required global CI guard whose export-analysis policy can block future merges if it rejects valid script declarations.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body provides after-fix terminal evidence for the verifier, a deliberate drift/recovery demonstration, focused tests, and a linked Blacksmith changed-check run.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides after-fix terminal evidence for the verifier, a deliberate drift/recovery demonstration, focused tests, and a linked Blacksmith changed-check run.
Evidence reviewed

PR surface:

Tests +565, Config +2, Other +585. Total +1152 across 25 files.

View PR surface stats
Area Files Added Removed Net
Source 0 0 0 0
Tests 3 565 0 +565
Docs 0 0 0 0
Config 2 2 0 +2
Generated 0 0 0 0
Other 20 726 141 +585
Total 25 1293 141 +1152

What I checked:

Likely related people:

  • steipete: Authored the current CI contract guard and previously merged declaration-sidecar repairs in the same scripts area. (role: recent script-contract contributor; confidence: high; commits: 484ea309d109, 78de4e201112, 42e59df60bf4; files: scripts/check-script-declarations.mjs, scripts/check-changed.mjs, test/scripts/check-script-declarations.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.
Review history (1 earlier review cycle)
  • reviewed 2026-07-17T23:54:57.498Z sha 6b31219 :: needs maintainer review before merge. :: none

@steipete
steipete force-pushed the codex/ci-script-declaration-contract branch from 6b31219 to 6277133 Compare July 18, 2026 01:07

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6277133c21

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

function createOpaqueExternalOrigin(importerPath, specifier, kind, name = null) {
return JSON.stringify(["opaque-external", importerPath, specifier, kind, name]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve same external binding through star barrels

When two script modules both re-export the same named binding from the same external package and a barrel uses export * from both, ESM still exposes that name (for example, both wrappers re-exporting foo from pkg). Including importerPath in the opaque origin makes those wrappers look like different bindings, so origins.size > 1 reports opaque external star collision and check:script-declarations blocks a valid script/declaration pair. The origin should key named external bindings by the external specifier/kind/name, not the wrapper path.

Useful? React with 👍 / 👎.

@steipete
steipete force-pushed the codex/ci-script-declaration-contract branch from 6277133 to 42e59df Compare July 18, 2026 01:46
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jul 18, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 42e59df60b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +442 to +447
} else if (!target) {
if (!isDeclaration) {
explicitExports.set(
exportedName,
new Set([createBindingOrigin(specifier.text, sourceName)]),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail missing local named re-exports

When a script has a local named re-export such as export { foo } from "./renamed.mjs" after the target was deleted or moved, resolveReexport returns null but this branch still records foo as a valid runtime export. If the adjacent .d.mts lists the same name, check:script-declarations passes even though the script cannot be linked, so the new guard misses local re-export drift that the unresolved star/declaration paths already fail closed on.

Useful? React with 👍 / 👎.

@steipete
steipete merged commit 3d1b771 into main Jul 18, 2026
120 of 122 checks passed
@steipete
steipete deleted the codex/ci-script-declaration-contract branch July 18, 2026 01:54
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 18, 2026
* fix(ci): verify script declaration contracts

* fix(ci): harden declaration export analysis

* fix(ci): cover opaque script module exports

* test(ci): cover cyclic script declaration barrels
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer Maintainer-authored PR merge-risk: 🚨 automation 🚨 May affect CI, automerge, proof capture, label sync, or maintainer automation. P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. scripts Repository scripts size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant