Skip to content

build(typescript): eliminate every hand-written .mjs/.js/.cjs (and hand-written .d.ts) and lock it with a permanent CI gate #9527

Description

@JSONbored

Context

Part of #9515. The epic's "nothing hand-maintained" principle extends to the language layer: hand-written .mjs/.js files are untyped surfaces that TypeScript can't protect and that drift exactly like hand-copied schemas do. metagraphed finished this migration and then made it permanent with validate:no-hand-written-mjs — a git ls-files scan failing the build for any tracked .mjs/.js/.cjs outside a small commented allowlist, run unconditionally in CI. LoopOver has no such gate, and hand-written JS remains:

  • packages/loopover-miner/scripts/generate-env-reference.mjs (249 lines — a load-bearing generator, run by root miner:env-reference/:check in test:ci; it even imports from the ORB generator and carries a "skip a .js with a same-basename .ts sibling" guard — migration-era logic that outlived the migration)
  • packages/loopover-mcp/scripts/strip-bin-sourcemap.mjs + check-syntax.mjs (build steps of the published MCP package)
  • scripts/control-plane-coverage.mjs (root control-plane:coverage)
  • packages/loopover-miner/scripts/benchmark.mjs, packages/loopover-miner/scripts/cross-repo-evaluation.mjs, packages/loopover-engine/scripts/load-test-iterate-loop.mjs
  • plus whatever a full git ls-files '*.mjs' '*.js' '*.cjs' inventory turns up (the requirement below starts there — the list above is the investigation's sample, not the census)

Hand-written ambient .d.ts files are in scope the same way: where one exists it either becomes a real .ts module or is proven to be generated. Generated artifacts (worker-configuration.d.ts via cf-typegen, dist/**, node_modules) are explicitly out of scope — the gate targets tracked, hand-written files only.

Requirements

  1. Census first: git ls-files '*.mjs' '*.js' '*.cjs' '*.d.ts' inventory committed to the PR description (not the repo), each file classified: migrate / generated (exempt) / allowlist-with-reason.
  2. Migrate every hand-written .mjs/.js/.cjs to .ts, preserving behavior: generators keep byte-identical output (their --check modes prove it), build scripts keep identical effects (npm run build:mcp output unchanged, test:mcp-pack allowlist updated for renamed script paths — scripts/mcp-package-allowlist.ts lists them per file), coverage/benchmark scripts keep identical CLI contracts. Runner is the repo's existing conventions (tsx or node --experimental-strip-types, matching how each script's siblings already run).
  3. Migrate or justify every hand-written .d.ts: convert to .ts where it carries real logic/types consumed at build time; allowlist with a comment where an ambient declaration is genuinely required.
  4. The permanent gate: scripts/validate-no-hand-written-js.ts, run in test:ci unconditionally (no docs-only skip), failing on any tracked .mjs/.js/.cjs (and hand-written .d.ts) outside a small, commented allowlist. Allowlist entries require an inline reason; the check fails on allowlist entries that no longer exist (metagraphed's rot lesson — a watched path that disappears must fail loudly, not silently pass).
  5. Clean up migration-era guards made obsolete: the .js-sibling skip in the env-reference generator, and any dist/-era special cases the census surfaces.
  6. Full branch-counted coverage on migrated generators' logic where it's importable; fix-what-you-find applies (expect stale paths in the older benchmark/load-test scripts).

Non-goals

  • Generated files (worker-configuration.d.ts, dist/**, lockfiles) — exempt by definition.
  • Rewriting script logic beyond the language port (generators must stay output-identical in the same PR as their port).
  • review-enrichment/ if its census shows a separate runtime constraint — classify and record, don't force.

Deliverables

  • Census in the PR description; every hand-written .mjs/.js/.cjs ported to .ts (or allowlisted with reason)
  • Hand-written .d.ts files ported or allowlisted
  • validate-no-hand-written-js gate in test:ci, unconditional, with existence-checked allowlist
  • Generator --check modes prove byte-identical outputs across the port
  • Obsolete migration-era guards removed

Expected outcome

git ls-files shows zero hand-written JavaScript outside a tiny, reasoned allowlist; the gate makes regression impossible; every script that generates artifacts or ships in a package is typed. Combined with the rest of #9515, "hand-maintained" is extinct at both the contract layer and the language layer.

References

Part of #9515. Independent of the other sub-issues (can start immediately). Pattern source: metagraphed's validate:no-hand-written-mjs post-epic sweep.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions