Skip to content

fix(bulma-ui): keep a hasName File's CTA corners rounded while there is no name - #990

Merged
allxsmith merged 20 commits into
mainfrom
fix/978-file-is-empty
Oct 9, 2026
Merged

allxsmith merged 20 commits into
mainfrom
fix/978-file-is-empty

Conversation

@allxsmith

@allxsmith allxsmith commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

With hasName and nothing to show yet (before a pick, or fileName=""), File rendered .file.has-name with no .file-name. Under has-name, Bulma squares the button's inner corners to meet the name area, so the button sat alone with two flat corners. Since #963 that is the first thing the hasName docs example and the picked-file stories show.

In bulma-ui, the root now takes Bulma's is-empty while hasName has no name to show. Bulma's own is-empty rule rounds the button again in the default and isRight layouts. Its is-boxed rules come later in its sheet and square a boxed button's bottom corners again, so _file.scss gives them back with a selector that outranks Bulma's whichever order the two sheets load in. Markup with a name is unchanged. jsdom computes none of this cascade, so a styles test works out each corner's radius across Bulma's sheet and the partial, in both orders and in a prefixed build. A NoNameYet story shows the layouts side by side.

The conformance rule that a partial registers the variables in its own namespace asked _file.scss to register --bulma-file-radius, which Bulma registers itself. The rule now skips a key Bulma registers, and it is a pure function with fixture tests for both cases.

In bestax-migrate, the bulma-classes source converts a .file only when File renders the same markup, so it moves with the component. A has-name .file with no .file-name converts when is-empty is written on it, and the class is absorbed into the component. Without it, the .file stays markup with a defaults:File TODO naming the class to add. A condition on is-empty can't stand in, since File renders it whatever the condition says. Next to a .file-name, is-empty stays a class, as before. The skill's component map and its defaults recipe say so, and the fixture pair covers both cases.

In bestax-mcp, lookup_bulma_classes now says that File renders is-empty itself when hasName has no .file-name. Its agreement test, which runs the codemod's planner beside the lookup, gives a has-name .file a name, as the codemod's own truth tests now do.

I checked it in Chromium through Storybook in light and dark mode. Before a pick, all four corners are rounded in the default, isRight and isBoxed layouts, and after one the button meets the name the way Bulma draws it.

Merge note: merge this with a merge commit, not a squash. The commits carry the bulma-ui, bestax-migrate and bestax-mcp scopes, and a merge commit releases each of those packages from its own commit. A squash would release only the package its title names.

pnpm all passes locally.

Fixes #978

Summary by CodeRabbit

  • New Features
    • Named file inputs now hide the filename area until a name is available and apply Bulma’s empty-state styling. Migration preserves is-empty and keeps the filename hidden when converting matching markup.
    • Added a Storybook example of named file inputs before a filename is present.
  • Bug Fixes
    • Restored the expected CTA corner rounding for boxed, named file inputs in the empty state.
  • Documentation
    • Clarified the empty state of named file inputs and the requirements for converting matching markup.

…is no name

With hasName and nothing to show yet (before a pick, or an empty fileName), File rendered
.file.has-name with no .file-name. Bulma squares the CTA's inner corners under has-name to meet
the name area, so the button sat alone with two flat corners.

- The root takes Bulma's is-empty while hasName has no name to show, which rounds the CTA again
  in the default and isRight layouts. The markup with a name is unchanged.
- Bulma's is-boxed rules come after its is-empty rule and square a boxed CTA's bottom corners
  again, so _file.scss gives them back with a selector that outranks Bulma's in either order.
- The conformance check's rule that a partial registers its own variables asked _file.scss to
  register --bulma-file-radius, which Bulma registers itself. It now skips a key Bulma
  registers, and is a pure function held by fixture tests.
…is-empty

File now renders Bulma's is-empty on a has-name .file with no .file-name, to keep its button's
corners rounded, so the bulma-classes source moves with it and every conversion still renders
the markup it replaces.

- A has-name .file with no .file-name converts when is-empty is written on it, and the class
  goes with the rest of the tree, since File renders it there itself.
- Without is-empty it stays markup with a defaults:File TODO that names the class to add. A
  condition on is-empty can't stand in, since File renders it whatever the condition says.
- Beside a .file-name, is-empty stays in className, since File renders none there.
- The skill's component map and its defaults recipe say so. The truth tests give a has-name
  .file a name unless a case is about having none, and so does the MCP agreement test, which
  runs this planner beside lookup_bulma_classes.
…no name

lookup_bulma_classes says how a .file's tree becomes File's props. It now adds that with hasName
and no .file-name, File renders Bulma's is-empty itself, so that class isn't needed there.
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: allxsmith/bestax/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 285954b9-80d3-4dd3-a7bf-6d6a9420f032
📥 Commits

Reviewing files that changed from the base of the PR and between df6f32b and 111d9e0.

📒 Files selected for processing (7)
  • bestax-mcp/src/__tests__/server.test.ts
  • bestax-migrate/src/sources/bulma-classes/__tests__/component-map-doc.test.ts
  • bulma-ui/src/form/CLAUDE.md
  • bulma-ui/src/form/File.tsx
  • docs/docs/api/form/file.md
  • scripts/check-conformance.mjs
  • scripts/scss-conformance.test.mjs
🚧 Files skipped from review as they are similar to previous changes (2)
  • bulma-ui/src/form/CLAUDE.md
  • docs/docs/api/form/file.md

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

File now applies Bulma’s is-empty modifier when hasName is enabled and no name is displayed. Class lookup and migration planning account for this state. The boxed empty state restores CTA corner radii. SCSS conformance checks now exempt variables registered by Bulma.

Changes

File empty-name behavior

Layer / File(s) Summary
File empty state and CTA corners
bulma-ui/src/form/File.tsx, bulma-ui/src/scss/form/_file.scss, bulma-ui/src/form/__tests__/*, bulma-ui/src/form/File.stories.tsx, bulma-ui/src/form/CLAUDE.md, docs/docs/api/form/file.md
File applies is-empty when hasName is enabled and no name is shown. The boxed empty state restores CTA corner radii. Tests cover name state and corner behavior; the story and documentation describe the empty state.
Lookup verdicts for is-empty
bestax-mcp/src/bulma-classes.ts, bestax-mcp/data/components/File.json, bestax-mcp/src/__tests__/*
Class lookup reports is-empty as rendered by File when no .file-name exists, and as a class beside a .file-name. Agreement and server tests cover these cases.
File migration planning and guidance
bestax-migrate/src/sources/bulma-classes/*, bestax-migrate/e2e/*, skills/bestax-migrate/references/bulma-classes/*, bestax-mcp/data/skills.json
The planner requires static is-empty when hasName is set and no filename is built. With the class, it sets fileName=""; otherwise it leaves the markup unconverted and adds a TODO. Fixtures, tests, end-to-end cases, and references cover these outcomes.

SCSS variable conformance

Layer / File(s) Summary
Check variable registration
scripts/check-conformance.mjs, scripts/scss-conformance.test.mjs
The conformance check loads Bulma’s registered Sass keys and exempts them from unregistered-variable violations. Tests cover Bulma and partial registrations, namespaces, comments, concurrent calls, and retry after failure.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~30 minutes

Change: Bug fix · Severity of issue fixed: Low

Merge Risk: ⚪ Minimal · up to 111d9

The empty-name behavior and matching conversion appear ready to merge after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 46.15% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 16 files. (2 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check Passed The title clearly identifies the primary change: keeping a hasName File CTA rounded when no name is displayed. It is concise and specific.
Description check Passed The description provides a detailed change summary, identifies the affected packages, links issue #978, documents testing and Storybook verification, and explains migration and MCP updates. It does no…
Linked Issues check Passed Issue #978 requires rounded CTA corners for an empty hasName File in the default, isRight, and isBoxed layouts. File.tsx applies is-empty when no name is shown, and _file.scss restores t…
Out of Scope Changes check Passed The changes stay within Issue #978. The conformance rule and tests support the required Bulma variable exception. Stories, documentation, migration guidance, MCP lookup behavior, generated metadata, a…
Full details: Docstring Coverage

Explanation

Docstring coverage is 46.15% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 16 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

bestax-mcp/src/__tests__/server.test.ts

Parsing error: "parserOptions.project" has been provided for @typescript-eslint/parser.
The file was not found in any of the provided project(s): bestax-mcp/src/tests/server.test.ts


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://1cd8f60f.bestax.pages.dev

Comment thread bulma-ui/src/form/File.tsx Outdated
@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: fresh

The last run on 3186d9a was cancelled at the runner limit after it posted one thread (on bulma-ui/src/form/File.tsx) but before its summary. Read it, don't post it again, and count it as a row in this review's table. Then carry on with the rest: _file.scss and its styles test, the conformance rule change, the bestax-migrate class map and fixtures, and the bestax-mcp note. The files under bestax-mcp/data/ and the generated props tables come from pnpm gen, and CI's staleness checks hold them to the source.

…und corners

The hasName TSDoc, the docs page and the File story said Bulma's is-empty keeps the CTA's corners
rounded. It does in the default and isRight layouts, but a boxed File gets its bottom corners back
from _file.scss, which ships only in the bestax extras, so on Bulma's CSS alone they stay flat.
The clause is gone from each, and from the codemod's defaults:File TODO and the two migrate skill
references that repeated it, where a bulma-classes app usually has Bulma's CSS alone.
@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: fresh

Runs on 3186d9a were cancelled at the runner limit before posting a summary; between them they posted one thread (on bulma-ui/src/form/File.tsx). Read it, don't post it again, and count it as a row in this review's table. Then carry on with _file.scss and its styles test, the conformance rule change, the bestax-migrate class map and fixtures, and the bestax-mcp note.

Comment thread bestax-mcp/src/bulma-classes.ts Outdated
@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: fresh

Runs on 3186d9a were cancelled at the runner limit before posting a summary; between them they posted two threads (on bulma-ui/src/form/File.tsx and bestax-mcp/src/bulma-classes.ts). Read them, don't post them again, and count each as a row in this review's table. Then carry on with what they don't cover: _file.scss and its styles test, the conformance rule change, and the bestax-migrate class map and fixtures.

…t kept as a class

lookup_bulma_classes said in its File note that is-empty isn't needed beside hasName with no
.file-name, while the is-empty row in the same answer said the class stays in className, which is
what the codemod's planner no longer does there. The row now reads rendered by File, with no
.file-name in the tree, and says that beside one it stays in className.

The agreement test had stopped seeing the case, since it gave every has-name .file a name. It now
gives one the tree the lookup's answer describes, with no name when is-empty marks the slot empty,
and checks that case directly.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review — 1 blocking · 1 advisory

# Severity Area Finding Location
1 🟡 Minor Correctness lookup_bulma_classes' is-empty row still says "stays in className" where the planner absorbs it, and the agreement test no longer reaches the nameless tree bestax-mcp/src/bulma-classes.ts:839
2 🔵 Advisory Correctness the hasName prose credits the rounding to Bulma's is-empty; in the isBoxed layout it comes from _file.scss, which ships only in the bestax extras bulma-ui/src/form/File.tsx:68

Both rows are the threads the two cancelled runs on this commit managed to post before the runner limit; I re-checked each against the current code and both still stand (leftoverReason → passthroughReason at bulma-classes.ts:255 still feeds the generic row rendered at :907, and plan.ts:775 still puts is-empty in converted). This pass raised nothing new.

Overall: The change is sound, and the hard part — the cascade — is right. I read Bulma's sass/form/file.scss directly: .file.has-name.is-empty .file-cta (0,4,0) outranks .file.is-right .file-cta (0,3,0), so the default and isRight layouts round from Bulma alone; .file.is-boxed.has-name .file-cta ties at (0,4,0) and comes later, which is exactly what the new (0,5,0) extras selector is for, and it wins in either sheet order and in isBoxed+isRight. 'is-empty': hasName && !shownName is the same predicate that gates the .file-name render, so the class and the element cannot disagree. The riskiest piece is the bespoke cascade resolver in File.styles.test.tsx — it stands in for a browser, so it is worth knowing what it does and does not model (below); I confirmed empirically that it is not vacuous, since squares the corners beside a name only passes if jsdom enumerates and ranks Bulma's logical radius longhands, which it does. Focus first on row 1: it is the one place where two surfaces of the shipped product now give an agent opposite instructions for the same input.

Notes from the areas the steer asked me to carry on with, all of which came back clean:

  • Conformance rule. unregisteredVarViolations is a faithful extraction — same comment stripping, same ${rel}:${i + 1} anchoring, only the violation ordering within a partial changes. pnpm exec node scripts/check-conformance.mjs --only=scss-conformance passes, which is itself the proof that bulmaKeys() finds file-radius (_file.scss registers nothing, so only the Bulma set can be exempting it). bulma is a root devDependency, so the createRequire resolve is not phantom. The new exemption cannot change any existing partial's verdict — !registered.has(key) is evaluated first — and because the gate is already key.startsWith(partialName + '-'), a cross-namespace Bulma key can never exempt anything. All 11 cases in scripts/scss-conformance.test.mjs pass.
  • bestax-migrate. The four tree/token combinations all round-trip: has-name+is-empty+no name absorbs the class (className: null); has-name+is-empty+.file-name keeps it (className: 'is-empty', and the class order happens to match because the component appends className last); has-name+no name+no is-empty refuses with defaults:File; a conditional is-empty refuses too. I specifically chased the case the guard cannot see — a conditional has-name — and it is safe by accident of the map rather than by the guard: 'has-name' carries onlyTrue: true (class-map.ts:1715), so flag is false in the conditional loop, the class stays in the joiner, writes.has('hasName') is false, and markup and component both render .file.has-name with no is-empty. The e2e conditional sweep at bulma-classes-truth.test.ts:917 exercises exactly that against rendered HTML.
  • Fixtures and TODOs. addTodo dedupes on comment text, not on the rule key, so the new defaults:File message cannot swallow or be swallowed by another defaults:File one. The refusal is idempotent: add is-empty, re-run, it converts; leave it, re-run, same TODO.
  • Skill docs. The component-map.md worked example at :298 still carries a .file-name, so it converts as written and the new paragraph does not contradict it. prop-map.md's .file row is a class→prop table and is-empty has no prop, so leaving it out is right.

Residual risk:

  • A Bulma radius rule moving under an at-rule. cornersOf walks only top-level CSSStyleRules and ignores !important, so a .file-cta radius declaration inside @media/@supports/@layer would be invisible and the test would stay green while the bug returned. Refuted for today's Bulma: I scanned bulma/css/bulma.css for at-rule blocks containing a .file … radius declaration (0 found) and for !important on one (none). The comment above the helper already scopes itself to "the top-level rules of css".
  • Other layouts squaring the CTA. Refuted by reading sass/form/file.scss end to end: the only radius declarations touching .file-cta are the has-name, has-name.is-empty, is-boxed.has-name and is-right rules plus the (0,1,0) .file-cta, .file-name base. is-small/medium/large, is-fullwidth, is-centered and the colour modifiers set no radius, so no untested modifier combination can re-square it.
  • RTL and vertical writing modes. Refuted: the new declaration is the physical border-radius shorthand with a single value, so all four corners get the same radius whatever the inline direction — unlike Bulma's logical longhands, it has no side to get wrong.
  • A consumer on stock Bulma CSS with no bestax extras. Open, and inherent to the fix: the boxed layout's rounding lives in _file.scss, which ships only in extras.css/bestax.css. Row 2 is the documentation half of this; there is no code change that would close it without duplicating the rule into Bulma.
  • className="is-empty" beside a real name. Refuted as a hazard: Bulma's own is-empty block sets .file-name { display: none }, so in that state no name area is visible and rounding all four CTA corners is the correct drawing — the extras rule is more right there than Bulma's cascade, not less.

🏄 Tiny class, gnarly cascade — but they paddled out, read the whole set in Bulma's sheet, and landed a specificity bump that holds in either stylesheet order and in a prefixed build. One stale sentence and one MCP row still telling agents the opposite of what the codemod does; patch those two and this one is clean all the way to the beach.

@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: verify

Every open thread has a reply: fixed, with the commit, or refuted with a reason. This settles them on e53ee6c.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://a7ebf48a.bestax.pages.dev

@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: verify

Every open thread has a reply: fixed, with the commit, or refuted with a reason. This settles them on df6f32b.

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://917fafd8.bestax.pages.dev

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review (verify) — 2 resolved · 0 open

ID Severity Area Thread Outcome
1 🔵 Advisory Robustness defaults:File TODO read as already satisfied when is-empty was conditional — bestax-migrate/src/sources/bulma-classes/plan.ts:805 ✅ Verified fixed (53306087)
2 🔵 Advisory Robustness Rule 4 exemption set came from an untested reader — scripts/check-conformance.mjs:631 ✅ Verified fixed (3d82419d)

Overall: This pass settled threads and reviewed no commits. Both open advisories are genuinely closed rather than reworded away: the defaults:File refusal now states the condition the guard actually checks, and plan.test.ts:1202-1211 plans the conditional shape and asserts that wording, so the gap can fail again; bulmaKeys() is exported and held to the real Bulma sass/ tree, with a negative (tabs-vertical-min-width) that the namespace gate cannot cover — a sharper choice than the collapse-duration I had suggested. Nothing is left for a human on my threads.

Residual risk:

  • fileName="" drifting out of the two prose surfaces that teach it — refuted for now: the lookup note (bestax-mcp/src/bulma-classes.ts:856-859) is pinned by server.test.ts, the CLI TODO by plan.test.ts:1199 and __testfixtures__/file.output.tsx:5; the skill prose is pinned to neither, which is the standing gap the earlier thread already recorded.
  • Rule 4 failing open on a wider registerVarsEntries read — refuted: the new case walks the real Bulma tree and pins both directions (file-radius in, tabs-vertical-min-width out), so a wider read now reds pnpm test:scripts.
  • Stale generated index — refuted: the byte counts skills.json records for the two edited reference files (23915 / 24617) match the files exactly.
  • Verification note: pnpm --filter bestax-migrate run test -- src/sources/bulma-classes is 398/398 green and scripts/scss-conformance.test.mjs is 12/12. pnpm run test:scripts has one failure in this sandbox — eslint-plugin/dist is absent; run its build first (scripts/constants-subpath.test.mjs:272) — an unbuilt sibling package, not this change.

🏄 Paddled back out just to close the last two sets, and both were already clean — the author even picked a gnarlier test key than I asked for. Nothing left bobbing out here, this one is good to go.

@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: fresh

The threads from the last run are settled, and main is merged in (including the Handlebars lockfile fix). The run on 187000a failed after posting its threads and left no summary, so this is a full review of df6f32b, posting every finding, advisory included, as its own thread.

Comment thread scripts/check-conformance.mjs Outdated
Comment thread skills/bestax-migrate/references/bulma-classes/component-map.md

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review — 0 blocking · 2 advisory

# Severity Area Finding Location
1 🔵 Advisory Robustness bulmaKeys() assigns its cache before filling it, so a concurrent caller reads a half-built set (unreachable today, fails loud) scripts/check-conformance.mjs:637
2 🔵 Advisory Coverage the two skill references are the only surfaces teaching the is-empty / fileName="" recipe that no test pins to the planner skills/bestax-migrate/references/bulma-classes/component-map.md:324

Overall: Sound, and the hard part — the cascade — is right. I read Bulma 1.0.4's sass/form/file.scss and the compiled bulma.css directly: the only rules that set a radius on .file-cta are the base %control/.file-cta pair (0,1,0), .file.has-name (0,3,0, bulma.css:6033), .file.has-name.is-empty (0,4,0, :6041), .file.is-boxed.has-name (0,4,0, :6074) and .file.is-right (0,3,0, :6100) — so the default and isRight layouts round from Bulma alone, while .file.is-boxed.has-name ties at (0,4,0) and comes later, which is exactly what the new (0,5,0) extras selector is for, and it wins in either sheet order. 'is-empty': hasName && !shownName is the same predicate that gates the .file-name render, so the class and the element cannot disagree, and the shorthand border-radius in _file.scss sets all four corners, so nothing new is direction-sensitive. The riskiest piece is the bespoke cascade resolver in File.styles.test.tsx, but it fails loud rather than vacuous (below) and I confirmed it is live. Neither advisory blocks: the first is latent and noisy-not-quiet, the second is a drift guard on prose that is accurate today.

Empirical pass, all on df6f32b6:

What Result
jest src/form/__tests__/File.test.tsx File.styles.test.tsx 79 pass
pnpm --filter bestax-migrate run test (whole package) 54 suites, 2309 pass
jest e2e/bulma-classes-truth.test.ts e2e/bulma-classes-props.test.ts 526 pass
pnpm --filter bestax-mcp run test 7 suites, 316 pass
node --test scripts/scss-conformance.test.mjs 12 pass
node scripts/check-conformance.mjs --only=scss-conformance ✓
build, then grep the flavors the rule ships in dist/extras.css and dist/versions/bestax-prefixed.css

Residual risk:

  • A layout combination the styles test misses — refuted. is-centered, the ten colors and the three sizes set no radius anywhere in Bulma's sheet (and --bulma-file-radius is rem-based, so a font-size modifier cannot scale it either), so has-name × is-boxed × is-right is the whole space and LAYOUTS covers all four cells.
  • A conditional has-name making File add an is-empty the markup never had — refuted. class-map.ts:1731 marks has-name onlyTrue, and plan.ts's conditional loop requires !modifier.onlyTrue before a condition becomes a prop, so a conditional has-name stays in the className joiner and File's own hasName is false — the converted element renders no is-empty either. The mirror case (static has-name, conditional is-empty) refuses, pinned at plan.test.ts:1199-1203.
  • A static is-empty beside a .file-name — refuted. file.fileName is defined, so the new block is skipped and is-empty stays in className (plan.test.ts:1213-1216); the raw markup carried the same class over the same Bulma-hidden .file-name, and normalizeHtml sorts class tokens, so the truth test's with a name, and is-empty beside it case really does compare the two.
  • The cascade resolver going vacuous — refuted. It reads only top-level CSSStyleRules, so a radius rule moved into an @media/@supports/@layer block leaves that corner absent from the resolved map and both toEqual(ALL_ROUND) and toBe('0') fail rather than pass. It is also live today: squares the corners beside a name passes only because jsdom enumerates and ranks Bulma's logical longhands (border-start-end-radius, border-end-end-radius).
  • Rule 4's exemption quietly widening — refuted. I checked every <partialName>-* key consumed via cv.getVar in scss/{components,elements,form} against Bulma's register-vars keys: file-radius is the only collision, and tabs-*, checkbox-*, radio-*, steps-*, toast-* and tooltip-* have no Bulma counterpart at all. A future Bulma key in one of those namespaces would also register it, so the exemption stays semantically correct, and the new negative assertion reds the suite if Bulma ever registers tabs-vertical-min-width.
  • Boxed rounding needs the bestax stylesheet — open and accepted; the over-claim that said otherwise was settled in an earlier pass. Only isBoxed is fixed from _file.scss, so a consumer on plain bulma.css with no bestax.css/extras.css still sees the two squared bottom corners. The docs previews are safe: docs/src/components/ShadowPreview/shadowStyles.js:19,25 adopts extras.css beside bulma.min.css, so Boxed with Name and Sizes with Boxed and Name do get the rule.
  • --bulma-file-radius unresolvable — open, exotic, not posted as a finding. This is the first rule in _file.scss whose unresolved var() makes things worse than no rule: a border-radius invalid at computed-value time falls back to 0, squaring all four corners instead of two. It needs an app that compiles Bulma with a non-default $cssvars-prefix and links the prebuilt extras.css rather than building src/scss.
  • Unmeasured gates — this sandbox denied pnpm test:scripts, the three gen:*:check staleness checks, both typechecks and format:check, so treat those as no signal rather than a pass. By hand I confirmed that only two files carry the hasName sentence (bestax-mcp/data/components/File.json and docs/docs/api/form/file.md) and both were regenerated with the TSDoc's wording, and that skills.json's byte counts match the two edited references exactly (24617 / 23915).

🏄 Clean barrel, dude — all four corners rounding the way Bulma meant, one tiny extras rule holding the boxed line, and a hand-rolled cascade resolver that actually paddles out instead of posing. Nothing blocking in the lineup; both advisories are driftwood on the beach. Good to go.

bulmaKeys() assigned its cache to an empty set before the walk over
Bulma's sass tree filled it, so a caller arriving during one of the
awaits got a partial set, and a read that threw left one cached for
good. Nothing calls it that way today, but it is exported now.

The cache is now the promise of the finished set, through a small
onceAsync helper: a caller mid-read waits for the whole set, and a
read that throws is forgotten so the next call reads it again. The
scss conformance test pins both halves on the helper, and that
bulmaKeys hands a later caller the same set.
…eferences to the planner

component-map.md and unmappables.md both teach what a has-name .file
with no .file-name needs to convert: is-empty written as a static
class, a condition on it not standing in, and fileName="" on the File
it becomes. The planner's own TODO, the fixture and the MCP lookup were
already pinned to that rule, but no test read either paragraph, so a
change to the guard in plan.ts would have left both teaching the old
one.

component-map-doc.test.ts now runs the planner on the three cases,
the class written, missing and conditional, and checks each claim in
both paragraphs against what it decides. The unmappables paragraph is
looked up under the section the refusal's rule names, which is where
the TODO sends an agent.
…empty

# Conflicts:
#	docs/docs/api/form/file.md
@allxsmith

Copy link
Copy Markdown
Owner Author

deep-review: verify

Every open thread has a reply: fixed, with the commit, or refuted with a reason. This settles them on 111d9e0.

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://c3bb0b20.bestax.pages.dev

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deep review (verify) — 2 resolved · 0 open

# Severity Area Finding Location
1 🔵 Advisory Robustness bulmaKeys() published its cache before it was filled — verified fixed, resolved scripts/check-conformance.mjs:645
2 🔵 Advisory Coverage The two skill references teaching the is-empty recipe were pinned by nothing — verified fixed, resolved skills/bestax-migrate/references/bulma-classes/component-map.md:324

Overall: This pass settled open threads and reviewed no commits. Both remaining advisories had author replies claiming fixes, and both hold up: the cache is now a memoized promise (onceAsync, with a rejected build dropped so a failed read does not stick), and both skill paragraphs are held to the planner's own decisions rather than to literals. Nothing of mine is left open — a maintainer wanting the current code reviewed should ask for a fresh pass.

Residual risk:

  • Cache publication — refuted. onceAsync at check-conformance.mjs:631 assigns the promise, not the Set, so a caller arriving mid-walk awaits the first build; scss-conformance.test.mjs:191 proves it by parking a build on a gate and asserting the second caller has not settled, and :219 proves a throwing build is forgotten and rebuilt. Both pass.
  • Prose drift in the two references — refuted. component-map-doc.test.ts:107-223 derives the rule string and the unmappables heading from plan's own output, so a change to the plan.ts guard moves the lookup and fails the test rather than leaving the paragraphs teaching the old recipe; the paragraph() helper returns the empty string on a missing heading, so there is no silent-pass shape.
  • Not re-examined by design: everything outside these two threads. A verify pass reads no commits.
  • For the record: pnpm test:scripts also reports failures reading eslint-plugin/dist is absent — a build-order artefact of this sandbox, unrelated to this PR. The bestax-migrate suite ran green (54 suites, 2311 tests).

🏄 Both leftover ripples got cleaned up proper, dude — the cache now waits for the whole set, and the skill docs are leashed to the planner instead of floating free. Zero threads open, this one's good to paddle in.

@github-actions github-actions Bot added the review-converged Deep review converged: no blocking findings, all review threads resolved, checks green label Oct 9, 2026
@allxsmith
allxsmith merged commit 7f56cc5 into main Oct 9, 2026
61 checks passed
@allxsmith
allxsmith deleted the fix/978-file-is-empty branch October 9, 2026 01:20
@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 5.27.3 🎉

The release is available on:

Your semantic-release bot 📦🚀

@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 2.25.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 1.14.3 🎉

The release is available on:

Your semantic-release bot 📦🚀

@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 4.2.15 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deep-review needs-human-review Loop converged (or contested): awaiting owner review + manual merge released review-converged Deep review converged: no blocking findings, all review threads resolved, checks green

Projects

None yet

Development

Successfully merging this pull request may close these issues.

File: a hasName File with no name squares its CTA's corners

1 participant