feat(builder): one mapping between the canvas frame and the host - #683
Conversation
The canvas renders in an iframe and the editor's chrome is drawn over it in the host document, so every overlay has to answer the same question: where is this canvas rectangle in host coordinates. Two modules answering it separately agree the day they are written and drift afterwards, and the symptom is an indicator a few pixels off the gap it names - which neither module's tests catch, because each is correct about the question it asked. The functions take plain numbers rather than DOM nodes, so the mapping is exercisable without a browser and the DOM reads stay at the edge. Scale applies to size as well as position: an overlay sized from the unscaled rectangle is correct at 100% and wrong everywhere else, and 100% is where it gets looked at. A frame that cannot describe a mapping throws. Every value that could stand in is wrong in a way that looks right - zero collapses the canvas to a point, a negative mirrors it, a non-finite yields NaN coordinates - and all three place an overlay somewhere wrong while reporting nothing. A sibling guard reads the AST for getBoundingClientRect and getClientRects and allows them only in this module, so the second implementation cannot arrive quietly. It carries its own positive control, because a visitor that matches nothing reports the same clean pass as one that found nothing.
|
@codex please review this PR |
|
Warning Review limit reached
Next review available in: 54 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughChangesThe builder package now provides validated frame geometry APIs for iframe content origins, point conversions, and rectangle conversions. Canvas E2E helpers use these APIs and account for iframe borders. Module discovery and test patterns now share supported extensions, including Frame geometry and canvas mapping
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant poc-driver
participant coordinate-mapping
participant builder-geometry
Browser->>poc-driver: Measure iframe border box and client insets
poc-driver->>builder-geometry: Calculate frameContentOrigin
poc-driver->>coordinate-mapping: Map point or rectangle
coordinate-mapping->>builder-geometry: Apply pointToHost or rectToHost
builder-geometry-->>poc-driver: Return host-space geometry
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7852bb1902
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
@nextlyhq/adapter-drizzle
@nextlyhq/adapter-mysql
@nextlyhq/adapter-postgres
@nextlyhq/adapter-sqlite
@nextlyhq/admin
@nextlyhq/admin-css
@nextlyhq/blocks-engine
@nextlyhq/blocks-react
@nextlyhq/builder
create-nextly-app
nextly
@nextlyhq/plugin-form-builder
@nextlyhq/plugin-page-builder
@nextlyhq/plugin-sdk
@nextlyhq/plugin-seo
@nextlyhq/storage-s3
@nextlyhq/storage-uploadthing
@nextlyhq/storage-vercel-blob
@nextlyhq/ui
commit: |
…against it Two ways the one-mapping claim was wider than what it enforced. The ownership guard exempted by suffix, so overlay-geometry.ts and nested/frame-geometry.ts were allowed to read a rectangle across the frame - which are the names a second implementation would actually be given. Matched by basename equality now, with a case pinning that the three names are told apart. And the mapping already existed. e2e/tests/canvas/coordinate-mapping.ts carries the same three conversions with the same arithmetic, and both the acceptance spec and the canvas driver use it, so a module added under the heading of one mapping was the second one. The e2e helper now adapts the editor's functions rather than restating them: same arithmetic, a call shape a Playwright test can supply. A browser harness with its own copy certifies its own copy - the two agree until either is corrected, and then the suite validates a stale implementation while reporting the editor is fine. Behaviour changes for that helper in one place: a frame that describes no mapping now throws instead of yielding NaN coordinates. No caller passes such a frame; a test measuring an unrendered element gets an error naming the problem rather than an assertion about meaningless numbers.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b3a17c0fb3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The guard was presented as enforcing one mapping. It enforces one place where a rectangle is READ across the frame, which is narrower: a module handed an origin and a scale can open-code the arithmetic without touching the DOM, and a duplicate implementation added beside it passes every assertion. Two numbers multiplied and added are indistinguishable from any other code, so no scan can tell a second mapping from ordinary arithmetic - the same reason the builder's draws-with-blocks-react rule is a review-time convention rather than a checked one. The test is renamed to what it checks, and both it and the module say which half review is holding. Narrowing the claim rather than the guard: the DOM read is the door this can actually hold, and a guard advertised wider than it reaches is worse than one that says where it stops.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4c5645632a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…thout a build Two more spellings the guard let through, and a build I made e2e depend on. The ownership allowance was narrowed from suffix to basename last round, and a basename test still exempts overlays/geometry.ts - a nested module whose file name is identical, which is exactly what a second implementation would be called. Each narrowing left one more spelling open, so the allowance is now the one relative path and no choice of filename can widen it. That is the third iteration on this guard; matching a shape of name was the wrong instrument rather than the wrong pattern. And importing @nextlyhq/builder from the e2e helper broke the standalone typecheck: check-types deliberately does not build dependencies, so resolving through the package manifest needs a dist a freshly installed tree does not have. Mapped to source in e2e's tsconfig, which is what packages/admin already does for nextly. Verified by removing dist and running e2e's check-types: clean with the mapping, TS2307 without it.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 41627354c3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… origin The guard's extension pattern omitted .mts and .cts, so a module written with either was invisible to it - a bypass file with that extension passed all four ownership tests. The same pattern was copy-pasted into layering.test.ts, so the hole was in both guards; the list now lives in one importless module both read, because two copies of what counts as a source module drift the moment TypeScript grows an extension. Verified by adding the .mts bypass: caught by name, and gone when the file is removed. And origin was documented as the frame's viewport but taken from getBoundingClientRect, which reports the BORDER box. Rectangles read inside the frame are relative to the content viewport, so on a frame with any border the two differ by clientLeft/clientTop and every mapped point lands a scaled couple of pixels out. A canvas that does not reset the browser's default iframe border has that from the first render, and it reads as the indicator feeling slightly off rather than as a fault. The correction belongs to whoever reads the DOM, since this module takes numbers so it can run without a browser - so origin is now documented as the CONTENT origin and the two measurement sites satisfy it: the canvas driver and the acceptance spec both add clientLeft/clientTop. The fixture sets border: none, which is why the border-box version passed; the contract is now stated where the next measurement will read it.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1771e39745
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The layering guard relaxes its import allowlist for anything it considers a test, and the runner decided the same question separately. Discovery had been widened to .mts/.cts while both the guard's name pattern and the vitest globs still said .ts/.tsx, so a probe.test.mts was classified as a test, exempted from the allowlist, and never run. That direction is the dangerous one: a shipped module could reach any import it liked by choosing its filename. All three now derive from one extension list, so the guard and the runner cannot mean different things by "test". Listing the extensions also drops .mtsx and .ctsx, which the previous pattern admitted and no compiler follows.
boundingBox() reports a post-transform corner while clientLeft stays in the frame's own untransformed pixels, so adding the inset raw misplaces the content origin by (1 - scale) * inset. Zero at 100%, which is where a canvas gets developed, and growing as it zooms out. The sum lived at two call sites because the geometry module had pushed it out to "whoever reads the DOM". That conflated the DOM read with the arithmetic after it: reading clientLeft needs a browser, converting it does not. Both callers duly wrote it themselves and both wrote it wrong. frameContentOrigin now owns it and both callers ask. Adds a bordered-and-scaled acceptance case, since every existing one runs against border: none and agrees either way. It asserts the border applied and that the raw sum fails the same tolerance, so neither half can pass vacuously.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c8868f8268
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… rect read Three findings from the second review pass. Turbo's input globs listed .ts/.tsx and not .mts/.cts, so the new positive control was absent from the builder's test, check-types and lint inputs — a change confined to it could not move the task hash and CI would replay a cached green over code nothing ran. Confirmed by dry run in both directions: ABSENT before, IN INPUTS after, for all three tasks. The ownership guard missed a rectangle read taken off the element by destructuring and called through a new name, in both the renamed and shorthand spellings. Added, with a positive control for each. It also now records what it CANNOT see. Three narrowings have each been followed by another spelling walking past, which says the design is the limit rather than the coverage: a scan over syntax has an unbounded surface. The claim is narrowed to a review aid over a bounded set of spellings, with a passing test asserting a computed name goes unseen so the limit is written down rather than discovered. The README described a package that ships nothing while the entry exports the geometry contract.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b8ad32a18a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… origin readIndicatorRect built its own origin from iframe.boundingBox(), which is the BORDER box, so on a bordered canvas every indicator rectangle it reported was inset * scale out — the same fault in a third place. Three sites is the design telling us no caller should assemble this. It now asks driver.frameOrigin(), which is the one reader that measures the inset and hands it to frameContentOrigin.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 594701ff78
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A comment recounted how the scan had been narrowed over time, which is review history rather than a description of the code, and the convention is that comments describe the code only. Replaced with what the scan does and does not recognise. The module header also read as though the sibling test enforced single ownership. It does not: it recognises a bounded set of spellings and its own tests assert that a computed name walks past. Nothing checks the arithmetic half at all. Both are review-time conventions and now say so, so the header cannot be read as a guarantee the code does not provide.
The zone centre was scaled and added inline instead of going through mapFramePointToHost. It used the right origin, so it was correct — but written out it is two numbers multiplied and added, which is the shape no import scan can separate from ordinary arithmetic, and therefore the one that keeps a stale copy of the mapping after the mapping is corrected.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bd9b334404
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The module header still read as enforcement — "a convention cannot hold that, so it is checked" — while the last test in the same file asserts a computed name walks past. The same claim was corrected in geometry.ts and left standing here, which is worse than either alone: a reader who opens the guard sees the stronger statement.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 10989ca863
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The note said a guard ensures no other module reads a rectangle across the frame. The scan recognises a bounded set of spellings and its own test asserts a computed name walks past, so the note promised users a guarantee the code does not make.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a2182e619f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The note recounted what an earlier version of itself had said and why that was wrong. That is edit history; a comment describes the code. Replaced with the reason the arithmetic lives with the module rather than at each call site.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@e2e/tests/canvas/poc-driver.ts`:
- Around line 179-183: Update the frame scale handling in the flow calling
frameContentOrigin to return DOMMatrixReadOnly.a directly instead of applying a
|| 1 fallback, preserving zero scales so frameContentOrigin can throw
FrameGeometryError for collapsed frames while identity transforms still yield 1.
In `@packages/builder/src/geometry.ts`:
- Around line 16-32: Rewrite the comments in packages/builder/src/geometry.ts
lines 16-32, packages/builder/src/geometry.test.ts lines 75-85, and
packages/builder/src/geometry-ownership.test.ts lines 11-34 to describe only
implementation behavior and rationale: explain the AST guard’s bounded detection
scope, that scale 1 cannot distinguish scaled from raw inset arithmetic, and the
supported AST patterns, respectively. Remove review-process, historical-review,
task, and convention wording without changing code behavior.
In `@packages/builder/src/source-modules.ts`:
- Around line 27-29: Remove historical remediation language from the comments at
packages/builder/src/source-modules.ts:27-29,
packages/builder/src/source-modules.ts:39-41,
packages/builder/src/layering.test.ts:541-543, and
packages/builder/src/module-extensions.test.mts:15-18. Keep the current
rationale: explain explicit extension filtering and unsupported suffix
rejection, tool support for .mts/.cts, the non-vacuous assertion, and the
collection failure mode without mentioning replaced patterns, prior omissions,
failures, or remediation history.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 93976caa-bb15-47eb-a5a1-bc76d7bec5f8
⛔ Files ignored due to path filters (2)
.changeset/builder-frame-geometry.mdis excluded by!.changeset/**pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!**/pnpm-lock.yaml
📒 Files selected for processing (15)
e2e/package.jsone2e/tests/canvas/coordinate-mapping.spec.tse2e/tests/canvas/coordinate-mapping.tse2e/tests/canvas/poc-driver.tse2e/tsconfig.jsonpackages/builder/README.mdpackages/builder/src/geometry-ownership.test.tspackages/builder/src/geometry.test.tspackages/builder/src/geometry.tspackages/builder/src/index.tspackages/builder/src/layering.test.tspackages/builder/src/module-extensions.test.mtspackages/builder/src/source-modules.tspackages/builder/vitest.config.tsturbo.jsonc
…g one frameScale() ended in `|| 1`, which reads as "default when absent" and also fires on a measured 0. A collapsed frame therefore reached the mapping as a usable 1, so the FrameGeometryError for a zero scale could not fire through the driver at all — the guard existed and its only real path was blocked. Measured in Chromium: transform "none" parses to the identity whose `a` is already 1, so the fallback was not needed for the untransformed case either; scale(0) reports `a` 0, which is now preserved. Also removes review-process and edit-history wording from comments across the files this branch touches, per the convention that a comment describes the code. Ten sites, swept rather than fixed individually.
The layering guard and the geometry-ownership guard each carried a byte-identical directory walk. The shared extension list cannot stop the walks themselves diverging — one skipping a directory, one matching a different part of the path — and a guard that walks past a file reports clean about code it never read. Reading the directory is injected rather than imported, so source-modules keeps importing nothing: a node:fs import there would put a Node dependency inside src, where the layering guard is entitled to refuse it.
The existing positive control asserts the file list is non-empty and contains an index.ts. Both survive a walk narrowed to .ts alone, so neither separates full coverage from partial — and a scan going quiet on one extension is the dangerous direction, since the files it stops reading are the ones it reports clean. Naming a less common extension is what separates them; narrowing the walk now fails this and nothing else.
|
@codex please review this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5bfac2feea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| * must RUN it. The first two are asserted below. The third cannot be asserted | ||
| * from inside — it is proved by this file executing at all, which is why it is | ||
| * `.mts` rather than a `.ts` file with `.mts` in a string. |
There was a problem hiding this comment.
Anchor the discovery control outside the derived glob
When TEST_GLOBS accidentally drops .mts, this control disappears from the run along with the behavior it is meant to verify, so executing the file cannot prove that discovery remains configured. I reproduced the failure mode by narrowing TEST_GLOBS to .ts: Vitest reported 3 files and 57 tests passing, while silently omitting both tests here; the remaining config assertion only checks that include references the TEST_GLOBS identifier. Add an independent assertion or external expected-count check that still runs when this glob loses an extension.
AGENTS.md reference: AGENTS.md:L121-L124
Useful? React with 👍 / 👎.
| return { | ||
| x: borderBox.x + inset.left * scale, | ||
| y: borderBox.y + inset.top * scale, | ||
| }; |
There was a problem hiding this comment.
Include iframe padding in the content origin
When an iframe has nonzero CSS padding, its nested viewport begins after both the border and the padding, but callers construct inset solely from clientLeft/clientTop, which report the border-side inset and exclude padding. This therefore maps every frame-local point toward the border by the scaled padding width; the bordered acceptance case cannot expose it because it sets only a border. Measure the complete border-to-content offset (including computed padding) or make the API accept the actual content-box corner.
Useful? React with 👍 / 👎.
Plan 04 B-4. Depends only on B-1, so it is independent of #682 (B-2) and can
land in either order.
D-04.3: one place geometry crosses the frame
The canvas renders inside an iframe; the editor's chrome — insertion indicator,
selection outlines, drag affordances — is drawn in the host document above it.
Every one of those answers the same question: where is this canvas rectangle, in
host coordinates?
Two modules answering that separately agree on the day they are written and drift
the first time anything changes — a scroll offset one forgot, a zoom the other
did not apply. The symptom is an indicator drawn a few pixels off the gap it
names, and neither module's tests fail, because each is correct about the
question it asked. That is the overlay-desync class of bug.
What is here
pointToHost,pointToCanvas,rectToHost, over plain numbers rather than DOMnodes — so the mapping is exercisable without a browser and DOM reads stay at the
edge.
Two things worth calling out:
unscaled rectangle is correct at 100% and wrong everywhere else — and 100% is
where it gets looked at.
inside the frame is already relative to the frame's viewport, so subtracting
its scroll counts it twice. That is the difference between an overlay that is
wrong by a constant and one that drifts as the canvas scrolls.
A frame that describes no mapping throws
Zero scale collapses the canvas to a point, a negative one mirrors it, a
non-finite one yields
NaNcoordinates. Each has a plausible-looking answer andeach places an overlay somewhere wrong while reporting nothing — which is the
exact failure this module exists to prevent, so it is loud instead.
The ownership guard
geometry-ownership.test.tsreads the AST forgetBoundingClientRectandgetClientRectsand allows them only ingeometry.ts. The AST rather than atext search because
el["getBoundingClientRect"]()is the same call spelled so agrep does not see it.
A convention could not hold this: the second implementation looks reasonable in
isolation and arrives when someone needs a rectangle and has a DOM node to hand.
Verified in both directions. Adding
el.getBoundingClientRect()toops.tsfails it with
ops.ts reads getBoundingClientRect. The guard also carries its ownpositive control — it asserts it can see both spellings — because a visitor that
matches nothing reports the same clean pass as one that found nothing, and it
asserts it read files at all, because a renamed directory would otherwise pass.
Scope note
Plan 04 lists B-4 as "the single mapping function + overlay host element". Only
the mapping is here. The overlay element has no meaningful test until there is an
indicator to position, so it belongs with B-7 where that assertion lives —
flagged rather than silently dropped.
packages/builder: 43 tests pass,check-typesandeslint --max-warnings 0clean. Changeset generated from the fixed group (23/23, checked by the guard from
#676).
Summary by CodeRabbit