Skip to content

Regenerate the stale framework candidate list and gate it - #3195

Merged
kwakayama merged 3 commits into
mainfrom
refactor/framework-candidates-freshness
Jul 31, 2026
Merged

Regenerate the stale framework candidate list and gate it#3195
kwakayama merged 3 commits into
mainfrom
refactor/framework-candidates-freshness

Conversation

@kojiwakayama

Copy link
Copy Markdown
Contributor

What

Two commits:

  1. Regenerate framework-candidates.generated.ts — the committed artifact no longer matched its sources.
  2. Add --check to prebundle-client-scripts.ts and wire it into generate:manifests:check, so this cannot silently recur.

The staleness, and how it was found

framework-candidates.generated.ts was last regenerated at c6ffd43e5 (#3092). UI components have landed since — anchored-surface.tsx, disclosure.ts, floating.tsx, modal-surface.tsx — so running the real generator on a pristine checkout of main produces a 27-token difference, every time, on every machine.

This surfaced as a workflow problem rather than a bug report. Across a multi-lane session, deno task generate (which deno task test and the pre-push hook both run) kept dirtying otherwise-clean worktrees. Each lane independently hit it, diagnosed it as possible cross-worktree contamination or generator nondeterminism, and worked around it by restoring the file before committing. It is neither of those: every lane's regeneration was correct, and each one was producing content that main had simply never committed.

Honest scope: no CSS changed

The 27-token delta is entirely extractor noise — identifiers and prose lifted out of comments:

"warnedMissingAnchor"  "React.Ref<HTMLButtonElement>"  "console.warn("
"including"  "warns"  "opened"  "carried"  "session,"  "[ui]"  "19)."

The one token that looks like a class, positioning-anchor, is a phrase inside a JSDoc comment in anchored-surface.tsx, not a className. The single dropped token, Anchor, is likewise not a class.

So no utility class was missing from the candidate set and no stylesheet output changes. The cost of this staleness was developer time and tree hygiene, not user-visible CSS. Worth stating plainly so the fix is not mistaken for a rendering bugfix.

The gate

prebundle-client-scripts.ts only ever wrote its two generated files, so a source change without a regenerate was invisible until someone noticed the file missing from a PR diff — which, for months, nobody did.

It now takes --check, matching the existing generate-templates-manifest.ts and generate-dev-ui-manifest.ts, and runs as part of generate:manifests:check — the first step of verify:quick. Drift now fails fast, naming the file and the fix.

Both generated files are gated. templates.ts is in sync today and regenerates byte-identically from a copy another machine committed at 0e2f403b5, which is the evidence that gating it will not be flaky.

Two implementation details:

  • Formatting moved from write-then-deno fmt <path> to deno fmt -, because --check has to compare against the same shape the write path lands on disk rather than the pre-format text. The emitted files are byte-identical to before — verified by running write mode and confirming templates.ts does not appear in git status.
  • Stale files are collected rather than exited on at the first miss, so one run tells you everything that needs regenerating.

Cost: ~0.15s warm. esbuild is fast enough that gating this is free on verify:quick.

Verification

  • --check exercised in all three states: both fresh (exit 0); candidates drifted (exit 1, names only that file, reports templates.ts as current); both drifted (exit 1, reports both).
  • Every verify:quick gate individually, plus the test-typecheck baseline gate.
  • deno test across framework-candidates.generated.test.ts, templates.test.ts, src/html/styles-builder/, src/server/handlers/dev/ — 35 passed, 371 steps.
  • Pre-push hook full suite: 2806 passed, 22753 steps, 0 failed.
  • The direct proof: after this change, the pre-push deno task generate left the working tree completely clean, where before it reliably dirtied it.
  • deno.lock untouched.

Known pre-existing failures on main, untouched by this PR: lint:cli-boundary (cli/shared/deployment/_deploy-test-support.ts) and docs:validate (@example on src/release-assets/index.ts).

@kojiwakayama
kojiwakayama requested a review from kwakayama as a code owner July 31, 2026 12:37
Copilot AI review requested due to automatic review settings July 31, 2026 12:37
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Repo admins can enable using credits for code reviews in their settings.

Copilot AI 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.

Pull request overview

Regenerates the committed framework Tailwind candidate artifact and adds a --check gate to the generator pipeline so drift is detected early (via generate:manifests:check).

Changes:

  • Regenerated framework-candidates.generated.ts to match current extraction sources.
  • Added --check support to prebundle-client-scripts.ts, including stale-file aggregation and stdin-based formatting for byte-stable comparisons.
  • Wired the new check into deno task generate:manifests:check.

Verification

  • Not run in this review environment (relies on the PR’s stated verification).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/server/handlers/dev/framework-candidates.generated.ts Updates the generated candidate list to match current extractor output.
scripts/build/prebundle-client-scripts.ts Adds --check mode and makes formatting/checking deterministic for generated TS artifacts.
deno.json Ensures the new --check gate runs as part of generate:manifests:check.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/build/prebundle-client-scripts.ts Outdated
Copilot AI review requested due to automatic review settings July 31, 2026 13:08

Copilot AI 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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@kwakayama
kwakayama enabled auto-merge July 31, 2026 13:26
kwakayama
kwakayama previously approved these changes Jul 31, 2026
@kwakayama
kwakayama added this pull request to the merge queue Jul 31, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Jul 31, 2026
framework-candidates.generated.ts was last regenerated at c6ffd43 (#3092).
UI components have landed since — anchored-surface.tsx, disclosure.ts,
floating.tsx, modal-surface.tsx — so the committed artifact no longer matches
the sources it is extracted from. Running the real generator on a clean
checkout of main produces a 27-token difference every time.

That is why `deno task generate` has been dirtying otherwise-clean worktrees
this session: every lane's test run regenerates this file correctly, and each
one then has to notice and restore it before committing. The regeneration is
deterministic, not flaky — the same 27 tokens appear on every machine.

The token delta is entirely extractor noise: identifiers and comment prose
("warnedMissingAnchor", "React.Ref<HTMLButtonElement>", "including", "warns"),
plus "positioning-anchor" which is a phrase from a JSDoc comment rather than a
class name. The one dropped token, "Anchor", is likewise not a class. So no
utility class was missing from the candidate set and no stylesheet output
changes — the cost of this staleness was developer time, not CSS.

Constraint: generated content only; the generator itself is unchanged in this
commit.

Tested: deno run -A scripts/build/prebundle-client-scripts.ts leaves the tree
clean afterwards; deno test --no-check --allow-all
src/server/handlers/dev/framework-candidates.generated.test.ts
src/build/production-build/templates.test.ts src/html/styles-builder/
src/server/handlers/dev/ (35 passed, 371 steps).
Nothing caught the drift the previous commit fixed. prebundle-client-scripts.ts
only ever wrote its two generated files, so a source change without a
regenerate was invisible until someone noticed the file missing from a PR diff
— which, for eight months, nobody did.

It now takes --check, matching generate-templates-manifest.ts and
generate-dev-ui-manifest.ts, and runs as part of generate:manifests:check. That
is the first step of verify:quick, so drift now fails fast with the file name
and a regenerate instruction. Both generated files are gated: templates.ts is
in sync today and regenerates byte-identically from a copy another machine
committed, which is the evidence that gating it will not be flaky.

Two details worth knowing. Formatting moved from write-then-`deno fmt <path>`
to `deno fmt -`, because --check has to compare against the same shape the
write path lands on disk rather than the pre-format text; the emitted files are
byte-identical to before. And stale files are collected rather than exited on
at the first miss, so one run tells you everything that needs regenerating
instead of making you rerun to find the second one.

The check adds about 0.15s warm — esbuild is fast enough that gating this costs
nothing measurable on verify:quick.

Constraint: write-mode output unchanged; this adds a mode, it does not alter
what gets generated.

Tested: --check exercised in all three states — both files fresh (exit 0),
candidates drifted (exit 1, names only that file, reports templates.ts as
current), both drifted (exit 1, reports both); deno task
generate:manifests:check; every verify:quick gate individually; deno run
--allow-read --allow-run scripts/lint/check-test-typecheck-baseline.ts. Known
pre-existing and untouched: lint:cli-boundary
(cli/shared/deployment/_deploy-test-support.ts), docs:validate @example on
src/release-assets/index.ts.
formatTypeScript threw "Failed to format generated output", which is unhelpful
in a script that generates two files — templates.ts and
framework-candidates.generated.ts go through the same helper, so the failure
told you a format broke but not which artifact to look at.

The path is already the caller's argument; it is now threaded through and named
in the error, matching the message the pre-refactor writeFormattedTypeScriptFile
produced before --check moved formatting to stdin.

Not covered by a test: the branch only fires when `deno fmt` itself fails on
generated output, which cannot be provoked without breaking the formatter.

Constraint: no behaviour change on any successful path.

Tested: write mode leaves both generated files byte-identical (only the script
shows in git status); --check passes when fresh and exits 1 naming the drifted
file; deno task fmt:check; deno task lint; deno task generate:manifests:check.
Copilot AI review requested due to automatic review settings July 31, 2026 14:01
@kojiwakayama
kojiwakayama force-pushed the refactor/framework-candidates-freshness branch from 6030a0d to ce12249 Compare July 31, 2026 14:01

Copilot AI 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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@kwakayama
kwakayama enabled auto-merge July 31, 2026 14:19
@kwakayama
kwakayama added this pull request to the merge queue Jul 31, 2026
Merged via the queue into main with commit f7ffc32 Jul 31, 2026
31 checks passed
@kwakayama
kwakayama deleted the refactor/framework-candidates-freshness branch July 31, 2026 14:28
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.

3 participants