Skip to content

Design: Element-anchored review comments with selective agent feedback routing#2117

Merged
teleaziz merged 4 commits into
mainfrom
public-comments
Jul 14, 2026
Merged

Design: Element-anchored review comments with selective agent feedback routing#2117
teleaziz merged 4 commits into
mainfrom
public-comments

Conversation

@teleaziz

Copy link
Copy Markdown
Contributor

Reviewers can pin comments directly on design elements — in the editor, Present
mode, or a public share link — and feedback resolves with real edits, not just
chat suggestions.

What's included

  • Pinned comment threads anchored to stable node ids (percent-point
    fallback), rendered across editor, Present, and public share views. Works in
    sandboxed iframes via a postMessage hit-test bridge.
  • Comment or send to agent: every composer offers a human-only comment or
    agent-targeted feedback. Editors can selectively route any open thread to the
    agent (send-review-thread-to-agent, new core action), or apply the whole
    queue with one "Apply feedback (N)" button. The agent resolves each thread
    only after the edit is persisted and verified.
  • Review status (draft / in review / approved / changes requested) shown in
    the editor header and share surfaces; agent-readable via view-screen.
  • Core kit hardening: SQL-side queue filtering with a new index,
    transactional reply routing, resolutionNote on resolved threads, per-comment
    canDelete capabilities, and identity redaction for anonymous/public viewers.
  • Anonymous visitors read threads without a session (no authed queries or
    app-state writes fire) and sign in to post.
  • Localized into all 11 catalogs; ~380 new/extended tests across core and the
    design template.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@teleaziz teleaziz changed the title Design: Element-anchored review comments with selective agent feedbac… Design: Element-anchored review comments with selective agent feedback routing Jul 14, 2026
…comments

# Conflicts:
#	templates/design/app/pages/Present.tsx
@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Here's a visual recap of what changed:

Visual recap

Open the full interactive recap

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

builder-io-integration[bot]

This comment was marked as outdated.

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Builder reviewed your changes and found 2 potential issues 🟡

Review Details

Incremental Code Review Summary

The latest PR update fixes the previously reported view-screen privacy issue: review data is now redacted through shared identity helpers before being included in the agent-facing response, so that existing comment has been resolved. The broader review architecture remains sound, with action-backed mutations, scoped access checks, transactional routing, and server-side public/private access behavior.

New Findings

🟡 MEDIUM

  • Public identity redaction still allows email addresses embedded in display names or mention labels, such as Alice <[email protected]>, to reach anonymous viewers.
  • A dropped iframe focus response can leave the pending nonce stuck indefinitely, preventing future retries for the same thread focus request.

🟢 LOW

  • In the non-transactional reply-routing fallback, a cleanup failure can mask the original routing error. This is diagnostic-only and non-blocking.

🧪 Browser testing: Skipped — browser executors again lacked Chrome automation tools. The planner verified relevant public/private behavior server-side and seeded grounded test data, but all 14 UI cases remain unverified.

Comment on lines +60 to +67
function safeReviewDisplayName(
value: string | null | undefined,
): string | null {
const name = value?.trim();
if (!name || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(name)) {
return null;
}
return name;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Redact emails embedded in public display names

safeReviewDisplayName() only rejects a value when the entire string is an email address. Public comments and mentions accept caller-supplied labels, so values such as Alice <[email protected]> or [email protected] (Acme) are returned verbatim to anonymous viewers. Treat any display name containing an email address as unsafe, or derive a validated public display name server-side.

Fix in Builder

Comment on lines +433 to +446
if (pendingFocusNonceRef.current === nonce) return false;
const iframe = canvas.querySelector<HTMLIFrameElement>(
"iframe[data-design-preview-iframe]",
);
if (!iframe?.contentWindow) return false;
const correlationId = crypto.randomUUID();
pendingFocusNonceRef.current = nonce;
frameCallbacksRef.current.set(correlationId, (payload) => {
pendingFocusNonceRef.current = null;
if (payload.focused === true) {
lastFocusNonceRef.current = nonce;
setLayoutTick((current) => current + 1);
}
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Retry iframe focus requests after dropped responses

When the iframe bridge is used, pendingFocusNonceRef is set before posting review-focus and is only cleared by the response callback. If the iframe is still loading or the message/response is dropped, later effect runs return early for the same nonce, leaving jump-to-thread focus permanently disabled until a reload or unrelated screen change. Add timeout/fallback cleanup or re-arm the request when the iframe becomes ready.

Fix in Builder

@teleaziz teleaziz merged commit f2ed084 into main Jul 14, 2026
90 checks passed
@teleaziz teleaziz deleted the public-comments branch July 14, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants