Repository navigation
chore(ci): make vendor upgrade PRs self-consistent so Validate is green by construction - #374
Conversation
|
@claude /review |
|
Claude finished @theCodeDrift's task in 8m 15s —— View job Review completeReview mode: incremental — read 0 prior review thread(s) before reviewing.
Overall assessment: this is a well-reasoned, well-tested change —
No security issues, no test-adequacy gaps beyond what's noted above, and no CLAUDE.md convention violations found in the diff. |
4a105f4 to
6ba8a27
Compare
Read. The medium item (filtered — AI Coding Agent |
61817a0 to
c992194
Compare
…pgrades sg-detect.cjs --write and vale-upgrade-detect.cjs --write now also rewrite AST_GREP_VERSION / VALE_VERSION in packages/cli/src/rules/capabilities.ts, via a new bumpVersionConstant in pin-bump.cjs that anchors on the exact declaration line, fails unless it is found exactly once, and leaves every other byte alone. Vale's constant takes the base version the binary reports, not the stamped npm version. engine-version-consistency.test.ts holds the constant to the pins, so a bot commit that moved only the pins failed Validate by construction (#368). The test stays; the bot commit becomes consistent.
…ance comment ast-grep-upgrade.yml is about to refetch the schema on every scheduled run and hand it to vendor-pr.cjs, which force-pushes the rolling branch only when the proposed files differ. A wall-clock stamp in $comment made the artifact differ on every run, so an unchanged upstream would still rewrite the branch. The version and URL are the provenance; git has the date. Regenerated: the only byte that changed is that comment.
…hing it Both upgrade workflows now install after the pin bump, regenerate the engine artifact from the new version (the Vale vocabulary from the new binary; the ast-grep rule schema from upstream's tag), run engine-version-consistency against the result, and only then hand the files to vendor-pr.cjs. A failing check fails the run and proposes nothing. The contract tests (vale-schema-contract, vale-vendor-contract, ast-grep-vendor-contract) are deliberately not part of that gate: they record what the binary does, and a new engine that changes a behaviour should surface as a red Validate on a pull request carrying upstream's notes, not as a scheduled run failing with nothing to read. That edit, the ledger, any migration and the changeset prose stay in the child. Measured locally by driving the exact steps against Vale 3.22.0 (ahead on npm today) and ast-grep 0.45.2 (rewound), see the workflow comments.
…not pin literals
reconcile-marker.test.ts pinned { sg: "0.45.3", vale: "3.21.0" } as
literals. The test is about the marker carrying the engine versions, not
their values, and engine-version-consistency already holds the constants
to the pins; the literal was one more thing a bot pin bump broke by
construction. The other version literals under test/ are measured facts
("changed at 0.45.3", a "Vale 3.21.0" block) and stay.
engine-version-consistency's docblock now says the bot bumps satisfy it
by construction and what the check is still for.
sg-detect.cjs and vale-upgrade-detect.cjs computed the package.json rewrite, wrote it, and only then computed the capabilities.ts rewrite, so a constant declaration that had moved left package.json bumped on disk without its constant, which is exactly the half-done bump the surrounding comment promised could not happen. Both rewrites are now computed before either file is written; a refused run leaves a clean tree. One test per script pins that. vale-upgrade-detect.cjs also computes baseVersion(upstream) once, in main(), instead of at three call sites.
c992194 to
46c7468
Compare
What
The bot pin-bump workflows (
vale-upgrade.yml→vendor/vale/upgrade,ast-grep-upgrade.yml→vendor/ast-grep/upgrade) now produce a commit that is self-consistent underengine-version-consistency.test.ts, and run that test beforevendor-pr.cjspushes anything.Why
VALE_VERSION/AST_GREP_VERSIONinpackages/cli/src/rules/capabilities.tsare maintained by hand, andtest/engine-version-consistency.test.tsholds them to the pins inpackages/cli/package.json. That check is deliberate and the constant is deliberately not derived frompackage.json(the test's docblock says why). The bot moved only the pins, so every bot PR failed Validate by construction.Today's instance: #368 (red) with child #372, which had to carry the constant, the regenerated Vale vocabulary and a test literal along with its real work, and the stack could not use GitHub's landing because its base was red. Neither open PR is affected by this change; see the rollout note.
What the bot now does
Both engines
--writeinsg-detect.cjs/vale-upgrade-detect.cjsalso rewrites theexport const <NAME> = "…";line incapabilities.ts, via a newbumpVersionConstantinpin-bump.cjs. It anchors on the exact declaration, fails the run unless it is found exactly once, and leaves every other byte alone (a{@link VALE_VERSION}or a version in a docblock is not a candidate). Covered bynode --test: constant rewritten, unrelated constant untouched, missing declaration throws, doubled declaration refused, idempotent.pnpm install(registry-only, defaultGITHUB_TOKEN, noNODE_AUTH_TOKEN; under CI pnpm applies--frozen-lockfileitself and the just-regenerated lockfile satisfies it).pnpm --filter @taskless/cli test --project cli engine-version-consistencybeforevendor-pr.cjs. It needs no build. A failure fails the run and proposes nothing.Vale:
VALE_VERSIONtakes the base version (3.22.0, not the stamp).pnpm --filter @taskless/cli generate:vale-schemaregeneratessrc/generated/vale-vocabulary.tsandvale-vocabulary-report.mdfrom the new binary. Its generator refuses a binary that does not reportVALE_VERSION, which is why the constant moves first, andvale-rule.tstypechecksVALE_VOCABULARY_VERSIONagainstVALE_VERSION, which is why the vocabulary has to move at all.ast-grep:
pnpm --filter @taskless/cli generate:ast-grep-schemarefetchessrc/generated/ast-grep-rule-schema.jsonfromraw.githubusercontent.comby the new tag. The job already reaches GitHub for release notes, so this is the same network. The script used to stamp a wall-clock time into$comment, which would have made the artifact differ on every scheduled run and defeatedvendor-pr.cjs's "unchanged, do not force-push" guard; the stamp is dropped (the version and URL are the provenance, git has the date). The committed schema is regenerated here and the comment is the only byte that changed.What stays in the child PR
Judgment, not bookkeeping: the measured vendor contract (
vale-vendor-contract,vale-schema-contract,ast-grep-vendor-contract), theupdateledger, any migration, and the changeset prose.One deliberate deviation from the brief: the contract tests are not in the bot's gate, only
engine-version-consistencyis. They hold a recorded corpus of what the binary does, so a new engine that adds a language or changes a verdict fails them, correctly, and the fix is exactly the child's work. Gated in the bot job, that signal would become a scheduled run failing every day with no PR and no changelog to read; left on Validate, it is a red check on a PR that already carries upstream's notes. Measured: rewinding ast-grep to 0.45.2 through the exact workflow steps passedengine-version-consistencyand failed four behaviours the contract recorded at 0.45.3. So "green by construction" means the bookkeeping is consistent; a red contract on a bot PR is upstream telling us something.Also
test/reconcile-marker.test.tsasserted{ sg: "0.45.3", vale: "3.21.0" }as literals. It now asserts against the constants; the test is about the marker carrying the engine versions, not their values. Other version literals undertest/are measured facts ("changed at 0.45.3", a "Vale 3.21.0" block) and stay.engine-version-consistencydocblock describe the new division of labour. Validate is untouched and the consistency test is not weakened.How verified
Locally, in a worktree:
pnpm test:scripts(453 pass),pnpm typecheck,pnpm lint(builds, thenpnpm cli check: no issues),pnpm --filter @taskless/cli test(96 files, 1588 pass),prettier --checkon every touched file, both workflows parsed with theyamlpackage.actionlintis not installed here.node .github/scripts/vale-upgrade-detect.cjs --writemoved six pins andVALE_VERSION3.21.0 → 3.22.0;pnpm install --lockfile-only --ignore-scripts;CI=1 pnpm install;generate:vale-schemaagainst the 3.22.0 binary (6s, diff is the version string only, prettier-clean);pnpm --filter @taskless/cli test --project cli engine-version-consistency vale-schema-contract21/21 pass, with the binary-spawning assertion confirmed to run against the 3.22.0 package;pnpm --filter @taskless/cli typecheckclean. Then reverted and reinstalled.bumpPins+bumpVersionConstant, then the same lockfile / install /generate:ast-grep-schema/ test steps:engine-version-consistencypassed,ast-grep-vendor-contractfailed on four 0.45.3-measured behaviours (the case described above). Then reverted.pnpm … test -- <filter>with a literal--reaches vitest and runs the whole suite; the workflow steps omit it.The workflows themselves run next on the next upstream release (Vale daily, ast-grep weekly, or
workflow_dispatch).Rollout
No effect on the open #368/#372: those branches were built by the old workflow and land as planned. The next bot PR is the first exercise. If
vale-upgrade.ymlis dispatched after this merges and before #368 lands,vendor-pr.cjswill rebuildvendor/vale/upgradefrommainwith the fuller commit; its foreign-commit guard still refuses to touch a branch with a human commit on it.