Skip to content

ci: enforce typecheck and version sync - #59

Merged
WhatsYourWhy merged 1 commit into
mainfrom
chore/ci-typecheck-and-version-guard
Aug 9, 2026
Merged

ci: enforce typecheck and version sync#59
WhatsYourWhy merged 1 commit into
mainfrom
chore/ci-typecheck-and-version-guard

Conversation

@WhatsYourWhy

Copy link
Copy Markdown
Owner

Why

Two gaps in an otherwise tight release pipeline:

  1. Nothing typechecked. esbuild strips types without checking them, and npm test runs with TS_NODE_TRANSPILE_ONLY=1. No workflow ran tsc, so a type regression could ship.
  2. Nothing validated the release tag. release.yml fires on tags: ["*"], and CLAUDE.md documents that the tag MUST equal manifest.json version because Obsidian's store matches them as plain strings — but that invariant was purely manual, as were the package.json parity and versions.json entry.

What changed

  • npm run typecheck (tsc --noEmit over both tsconfigs), wired into CI and release.
  • scripts/check-version-sync.mjs enforcing manifest/package parity, a versions.json entry matching minAppVersion, and — when given a tag — tag equality.
    • CI runs it without the tag arg, so a mis-bump fails at PR time instead of tag-push time.
    • release.yml runs it first, before npm ci; it is dependency-free, so a mistyped tag fails in seconds.
  • CLAUDE.md updated — it described these as manual steps.

Pre-existing type errors this surfaced

Adding the gate turned it red, which was the point:

  • 2× TS5097 — tests import with explicit .ts extensions for ts-node/ESM resolution. Fixed with allowImportingTsExtensions + noEmit in tsconfig.test.json.
  • 1× TS2741NoteStats.lastOpened is declared required, but metrics.ts does stats.lastOpened ?? fallbackMtime ?? now and SPEC.md documents the mtime fallback. store.ts guarantees the field post-sanitization, so the production invariant is correct and the test was constructing an intentionally degraded record. Fixed in the test with a cast rather than making the field optional, which would have made store.ts's guarantee meaningless.

No release required

main.js, styles.css and manifest.json are byte-identical to the published 0.5.0 (main.js sha256 561dc75d…). Everything here is dev tooling; nothing ships to users, so no version bump.

Verification

  • check:versions, lint, typecheck, build, test all pass locally
  • Both workflow YAMLs parse; the version-check command was executed as extracted from release.yml, not retyped
  • Guard proven on all five paths: passes on 0.5.0 and the no-tag CI form; fails on v0.5.0, package/manifest drift, missing versions.json entry, and minAppVersion mismatch
  • Committed blobs verified LF

🤖 Generated with Claude Code

esbuild strips types without checking them, so neither `build` nor `test`
(which runs with TS_NODE_TRANSPILE_ONLY=1) could catch a type error. Nothing
in CI ran tsc, so a type regression could have shipped.

Adding that gate surfaced three pre-existing errors in the test project:

- Two TS5097: tests import with explicit .ts extensions so ts-node/ESM can
  resolve them at runtime. Enabled allowImportingTsExtensions + noEmit in
  tsconfig.test.json so tsc accepts the same paths.
- One TS2741: NoteStats.lastOpened is declared required, but metrics.ts falls
  back to mtime when it is absent (SPEC 3.2). store.ts guarantees the field
  post-sanitization, so the production invariant is correct and the test was
  constructing a deliberately degraded record. Fixed in the test with a cast
  rather than weakening the type, which would have made store.ts's guarantee
  meaningless.

Also adds scripts/check-version-sync.mjs to enforce the release invariants
CLAUDE.md previously documented as manual: manifest/package version parity, a
versions.json entry mapping to minAppVersion, and (on release) tag equality.
Obsidian's plugin store matches the tag against manifest.json as a plain
string, and `on: push: tags: ["*"]` fired for any tag with nothing validating
it. CI runs the check without the tag arg so a mis-bump fails at PR time; the
release workflow runs it first, before npm ci, so a mistyped tag fails in
seconds.

No release artifact changes: main.js, styles.css and manifest.json are
byte-identical to the published 0.5.0 (main.js sha256 561dc75d…), so no
version bump or re-release is required.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@WhatsYourWhy
WhatsYourWhy merged commit 0c45a56 into main Aug 9, 2026
4 checks passed
@WhatsYourWhy
WhatsYourWhy deleted the chore/ci-typecheck-and-version-guard branch August 9, 2026 00:15
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