Skip to content

feat(builder): one mapping between the canvas frame and the host - #683

Merged
mobeenabdullah merged 18 commits into
mainfrom
feat/builder-frame-geometry
Aug 12, 2026
Merged

mobeenabdullah merged 18 commits into
mainfrom
feat/builder-frame-geometry

Conversation

@mobeenabdullah

@mobeenabdullah mobeenabdullah commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

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 DOM
nodes — so the mapping is exercisable without a browser and DOM reads stay at the
edge.

Two things worth calling out:

  • Scale applies to size, not only position. An overlay sized from the
    unscaled rectangle is correct at 100% and wrong everywhere else — and 100% is
    where it gets looked at.
  • Scroll inside the frame is deliberately not a field. A rectangle read
    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 NaN coordinates. Each has a plausible-looking answer and
each 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.ts reads the AST for getBoundingClientRect and
getClientRects and allows them only in geometry.ts. The AST rather than a
text search because el["getBoundingClientRect"]() is the same call spelled so a
grep 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() to ops.ts
fails it with ops.ts reads getBoundingClientRect. The guard also carries its own
positive 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-types and eslint --max-warnings 0
clean. Changeset generated from the fixed group (23/23, checked by the guard from
#676).

Summary by CodeRabbit

  • New Features
    • Added iframe-to-host coordinate mapping for points and rectangles, accounting for scaling and border insets.
    • Added validation for invalid geometry values with clear mapping errors.
  • Bug Fixes
    • Improved canvas positioning and indicator accuracy when iframe borders or zoom are applied.
  • Documentation
    • Documented the frame geometry capabilities and coordinate conversion behavior.
  • Tests
    • Expanded coverage for scaling, offsets, borders, module handling, and geometry validation.

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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@mobeenabdullah, you've reached your PR review limit, so we couldn't start this review.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fb4cc296-0c69-4820-b501-4268f61d0336

📥 Commits

Reviewing files that changed from the base of the PR and between ada39f5 and 348c63d.

📒 Files selected for processing (9)
  • e2e/tests/canvas/coordinate-mapping.spec.ts
  • e2e/tests/canvas/coordinate-mapping.ts
  • e2e/tests/canvas/poc-driver.ts
  • packages/builder/src/geometry-ownership.test.ts
  • packages/builder/src/geometry.test.ts
  • packages/builder/src/geometry.ts
  • packages/builder/src/index.ts
  • packages/builder/src/layering.test.ts
  • packages/builder/src/source-modules.ts
📝 Walkthrough

Walkthrough

Changes

The 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 .mts and .cts.

Frame geometry and canvas mapping

Layer / File(s) Summary
Frame geometry API
packages/builder/src/geometry.ts, packages/builder/src/index.ts, packages/builder/src/geometry.test.ts, packages/builder/README.md
Adds validated geometry types, origin calculation, point and rectangle conversions, exports, tests, and API documentation.
Canvas mapping integration
e2e/package.json, e2e/tsconfig.json, e2e/tests/canvas/coordinate-mapping.ts, e2e/tests/canvas/coordinate-mapping.spec.ts, e2e/tests/canvas/poc-driver.ts
Uses shared builder geometry for iframe origins, points, and rectangles. Adds bordered-frame coverage at scaled zoom.
Geometry ownership guard
packages/builder/src/geometry-ownership.test.ts
Scans bundled source with the TypeScript AST and verifies that cross-frame rectangle reads remain in geometry.ts.
Module discovery and test configuration
packages/builder/src/source-modules.ts, packages/builder/vitest.config.ts, packages/builder/src/layering.test.ts, packages/builder/src/module-extensions.test.mts, turbo.jsonc
Centralizes module extensions and test globs. Adds .mts coverage and updates type-check, lint, and test cache inputs.

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
Loading

Possibly related PRs

  • nextlyhq/nextly#166: Adds the E2E infrastructure and workspace files extended by this change.
  • nextlyhq/nextly#533: Introduces the canvas coordinate-mapping helpers and E2E driver refactored here.

Suggested labels: scope: core

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. 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 and concisely describes the main change: shared geometry mapping between the canvas frame and host document.
Description check ✅ Passed The description clearly explains the geometry mapping, validation, ownership guard, scope, and verification results, although it does not use all template sections.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/builder-frame-geometry

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.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread packages/builder/src/geometry-ownership.test.ts Outdated
Comment thread packages/builder/src/geometry.ts
@pkg-pr-new

pkg-pr-new Bot commented Aug 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

@nextlyhq/adapter-drizzle

npm i https://pkg.pr.new/@nextlyhq/adapter-drizzle@b277381

@nextlyhq/adapter-mysql

npm i https://pkg.pr.new/@nextlyhq/adapter-mysql@b277381

@nextlyhq/adapter-postgres

npm i https://pkg.pr.new/@nextlyhq/adapter-postgres@b277381

@nextlyhq/adapter-sqlite

npm i https://pkg.pr.new/@nextlyhq/adapter-sqlite@b277381

@nextlyhq/admin

npm i https://pkg.pr.new/@nextlyhq/admin@b277381

@nextlyhq/admin-css

npm i https://pkg.pr.new/@nextlyhq/admin-css@b277381

@nextlyhq/blocks-engine

npm i https://pkg.pr.new/@nextlyhq/blocks-engine@b277381

@nextlyhq/blocks-react

npm i https://pkg.pr.new/@nextlyhq/blocks-react@b277381

@nextlyhq/builder

npm i https://pkg.pr.new/@nextlyhq/builder@b277381

create-nextly-app

npm i https://pkg.pr.new/create-nextly-app@b277381

nextly

npm i https://pkg.pr.new/nextly@b277381

@nextlyhq/plugin-form-builder

npm i https://pkg.pr.new/@nextlyhq/plugin-form-builder@b277381

@nextlyhq/plugin-page-builder

npm i https://pkg.pr.new/@nextlyhq/plugin-page-builder@b277381

@nextlyhq/plugin-sdk

npm i https://pkg.pr.new/@nextlyhq/plugin-sdk@b277381

@nextlyhq/plugin-seo

npm i https://pkg.pr.new/@nextlyhq/plugin-seo@b277381

@nextlyhq/storage-s3

npm i https://pkg.pr.new/@nextlyhq/storage-s3@b277381

@nextlyhq/storage-uploadthing

npm i https://pkg.pr.new/@nextlyhq/storage-uploadthing@b277381

@nextlyhq/storage-vercel-blob

npm i https://pkg.pr.new/@nextlyhq/storage-vercel-blob@b277381

@nextlyhq/ui

npm i https://pkg.pr.new/@nextlyhq/ui@b277381

commit: b277381

@github-actions github-actions Bot added the type: docs Documentation only label Aug 11, 2026
…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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread packages/builder/src/geometry-ownership.test.ts
@github-actions github-actions Bot added the dependencies Dependency updates (label applied by Dependabot) label Aug 11, 2026
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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread packages/builder/src/geometry-ownership.test.ts Outdated
Comment thread e2e/tests/canvas/coordinate-mapping.ts
…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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread packages/builder/src/geometry-ownership.test.ts Outdated
Comment thread packages/builder/src/geometry.ts Outdated
… 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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread e2e/tests/canvas/coordinate-mapping.spec.ts Outdated
Comment thread packages/builder/src/source-modules.ts Outdated
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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread packages/builder/src/source-modules.ts
Comment thread packages/builder/src/geometry-ownership.test.ts
Comment thread packages/builder/src/index.ts
… 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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread e2e/tests/canvas/coordinate-mapping.spec.ts
… 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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread e2e/tests/canvas/poc-driver.ts
Comment thread packages/builder/src/geometry.ts Outdated
Comment thread packages/builder/src/geometry-ownership.test.ts Outdated
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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread packages/builder/src/geometry-ownership.test.ts Outdated
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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread .changeset/builder-frame-geometry.md Outdated
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.
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment thread packages/builder/src/geometry-ownership.test.ts Outdated
Comment thread packages/builder/src/geometry.ts Outdated
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.

@coderabbitai coderabbitai 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.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 74c82e2 and ada39f5.

⛔ Files ignored due to path filters (2)
  • .changeset/builder-frame-geometry.md is excluded by !.changeset/**
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !**/pnpm-lock.yaml
📒 Files selected for processing (15)
  • e2e/package.json
  • e2e/tests/canvas/coordinate-mapping.spec.ts
  • e2e/tests/canvas/coordinate-mapping.ts
  • e2e/tests/canvas/poc-driver.ts
  • e2e/tsconfig.json
  • packages/builder/README.md
  • packages/builder/src/geometry-ownership.test.ts
  • packages/builder/src/geometry.test.ts
  • packages/builder/src/geometry.ts
  • packages/builder/src/index.ts
  • packages/builder/src/layering.test.ts
  • packages/builder/src/module-extensions.test.mts
  • packages/builder/src/source-modules.ts
  • packages/builder/vitest.config.ts
  • turbo.jsonc

Comment thread e2e/tests/canvas/poc-driver.ts
Comment thread packages/builder/src/geometry.ts
Comment thread packages/builder/src/source-modules.ts
…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.
@mobeenabdullah
mobeenabdullah merged commit 5bfac2f into main Aug 12, 2026
11 checks passed
@mobeenabdullah

Copy link
Copy Markdown
Collaborator Author

@codex please review this PR

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 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".

Comment on lines +11 to +13
* 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

Comment on lines +156 to +159
return {
x: borderBox.x + inset.left * scale,
y: borderBox.y + inset.top * scale,
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

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

Labels

dependencies Dependency updates (label applied by Dependabot) type: docs Documentation only

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant