Skip to content

fix(init): say when the rules need update --rules, including between nightlies - #590

Merged
theCodeDrift merged 2 commits into
mainfrom
fix/init-reconcile-notice
Oct 29, 2026
Merged

theCodeDrift merged 2 commits into
mainfrom
fix/init-reconcile-notice

Conversation

@theCodeDrift

Copy link
Copy Markdown
Member

A nightly user upgraded with init, went straight to check, and hit RULES_ENGINE_MISMATCH. init had pointed them to update, which ends in update --rules, so the flow works if you follow it. But reaching a runnable check took two hops, and nothing in init said check would refuse in the meantime.

Looking into it turned up a real bug underneath. The ledger walk compares CLI versions on their numeric core, so two nightlies of one release owe no walk. The engine gate compares exact engine versions, and ast-grep 0.51.0 and Vale 3.24.0 both landed between nightlies. In that case info and update reported walk: null (the recipe reads that as "nothing to do") while check refused.

What changed

  • rules/reconcile-status.ts: decides once whether a reconcile is due. It is due when there is a ledger walk, or when an engine with rules is recorded behind the bundled one. That second check is the same comparison check makes, so the advice and the enforcement cannot disagree again.
  • init: on every run where a reconcile is due (not only on a version move), prints what moved, says check and verify will refuse until it is recorded, and names update through to update --rules. init --json carries the same answer as rules. When the notice prints, the upgrade trailer states only the version move, so the reader is not sent to update twice.
  • info --json adds rules.reconcile, and update --json adds reconcile. walk keeps its narrower meaning: the ledger sections to read.
  • update recipe (topic v22): a null walk does not end the walk. Read rules.reconcile.required.

Example, for a project at 0.11.2 with older engines:

The CLI moved from 0.11.2 to 0.13.3.
This project's rules are not reconciled to this CLI (the ledger has entries from 0.11.2 to 0.13.3; ast-grep moved from 0.45.2 to 0.51.0; Vale moved from 3.20.0 to 3.24.0), so `check` and `verify` will refuse to run them until it is recorded. Run `./.taskless/bin/cli.mjs update` and follow it to its last step, `./.taskless/bin/cli.mjs update --rules`. It applies 2 mechanical rule rewrite(s) for you.

Not changed

init still does not run update --rules itself. That command records that the ledger walk was done, and parts of the walk need judgment. If init recorded it, the marker would claim work nobody did.

Testing

pnpm typecheck, pnpm lint, and pnpm test (2833 passed). New tests cover a nightly-style project (same CLI version, older ast-grep recorded): info, update and init (including a re-run) all report the reconcile as due, the notice does not duplicate the trailer's pointer, and it clears once update --rules runs.

…nightlies

The ledger walk compares CLI versions on their numeric core, so two nightlies
of one release owe no walk, while the engine gate compares exact engine
versions. An ast-grep or Vale bump between nightlies left info and update
reporting nothing to walk while check refused with RULES_ENGINE_MISMATCH.

Decide whether a reconcile is due once, from the walk and the same engine
comparison check makes, and report it from init (every run, human and
--json), info --json and update --json. The update recipe reads it so a
null walk no longer ends the walk before update --rules.
@theCodeDrift

Copy link
Copy Markdown
Member Author

@claude /review

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @theCodeDrift's task in 5m 7s —— View job


Review: fix(init): say when the rules need update --rules, including between nightlies

Review mode: incremental — read 0 prior review thread(s) before reviewing. .prior-review.json held no review threads, review summaries, or inline comments — only the @claude /review trigger comment itself — so this is the first substantive review of this PR and the whole diff is assessed fresh.

  • Read .prior-review.json (empty — first review)
  • Fetch PR diff, commits, file list
  • Read full contents of touched files for context not shown in the diff (engine-gate.ts, reconcile-marker.ts, rule-migrate.ts, manifest.ts, version-compare.ts, reload-notice.ts, info.ts, init.ts, upgrade-trailer.ts, agent/update.md, schemas/info.ts, changeset)
  • Review correctness, security, performance, test coverage, clarity
  • Post inline comments for concrete issues
  • Post final summary

Assessment

The core fix is sound. reconcile-status.ts correctly derives required from the same comparison check's engine gate uses (findEngineMismatches + findEnginesWithRules, both reused via the new exports from engine-gate.ts), so the "walk says nothing to do, check refuses anyway" bug the PR describes is genuinely closed — traced through compareVersions' numeric-core comparison (confirmed nightlies with the same core collapse to no walk) against the engine gate's exact-string comparison (confirmed any patch bump counts), and the notice/refusal text lines up with what requireReconciledEngines actually does.

Specific things verified:

  • reconcileStatus.engines deliberately only includes engines recorded behind bundled (filters out "ahead" mismatches), which is correct: an ahead mismatch needs a CLI downgrade, not update --rules, and the notice/required logic would otherwise send the wrong remedy. This matches the "Not changed" section's intent and is documented in the code.
  • stampNewProjectRules runs before the new reconcileStatus read in runNonInteractive, so a freshly-created project correctly reports required: false — traced through reconciliationStart/findEngineMismatches to confirm the stamped engines match bundled exactly.
  • The upgrade-trailer/reconcile-notice de-duplication (reconcileDue suppressing the trailer's own "Run update" sentence) is correct and matches the PR's own worked example and test (human.stdout.match(/update\/g)).toHaveLength(1)`).
  • The unguarded readManifest added late in runNonInteractive (init.ts:594) is safe even though uncaught, because ensureTasklessDirectory → runMigrations already reads/validates the manifest earlier in the same call and would have thrown first on unparseable JSON.
  • No leftover unused imports after the reconciliationStart/pendingRuleMigrations → reconcileStatus refactor in info.ts/init.ts.
  • Test coverage for the new nightly/engine-bump scenario is solid: info, update --json, and init (human + --json + re-run) are all exercised, plus the de-duplication and no-refusal-claimed-for-walk-alone cases in reconcile-status.test.ts.

One [New] finding posted inline on packages/cli/src/commands/init.ts (init's --json rules field is a different shape than info's rules field and update's reconcile field — all three represent the same ReconcileStatus data differently). It's a clarity/consistency concern rather than a correctness bug — nothing reads a value that doesn't exist, no test fails — so treat it as a judgment call about whether the three JSON surfaces should converge on one shape.

No correctness, security, or performance issues found. Did not run the build/lint/test suite locally; CI reports that separately.

Comment thread packages/cli/src/commands/init.ts Outdated
@theCodeDrift

Copy link
Copy Markdown
Member Author

Re: @github-actions — "Claude finished @theCodeDrift's task in 5m 7s — Review: fix(init): say when the rules need update --rules…"
#590 (comment)

Thanks. No correctness findings to act on; the one inline note on the JSON shapes is handled in its own thread.

— AI Coding Agent

init --json carried the status as a flat `rules`, info --json as
`rules.reconcile`, and update --json as a narrower `reconcile`, so the same
answer had three field paths and `rules` meant two different things. All
three now build `reconcile: { required, engines, ruleMigrations }` from one
function.
@theCodeDrift
theCodeDrift merged commit cd2357c into main Oct 29, 2026
5 checks passed
@theCodeDrift
theCodeDrift deleted the fix/init-reconcile-notice branch October 29, 2026 22:39
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