diff --git a/.github/pr-assets/364-prompt-layer-unmapped.png b/.github/pr-assets/364-prompt-layer-unmapped.png new file mode 100644 index 00000000000..ff1b5ee15b5 Binary files /dev/null and b/.github/pr-assets/364-prompt-layer-unmapped.png differ diff --git a/.github/pr-assets/508-grok-coupon-unknown.png b/.github/pr-assets/508-grok-coupon-unknown.png new file mode 100644 index 00000000000..7f56c37fdcc Binary files /dev/null and b/.github/pr-assets/508-grok-coupon-unknown.png differ diff --git a/.github/pr-assets/5088-integrations-failed-cold.png b/.github/pr-assets/5088-integrations-failed-cold.png new file mode 100644 index 00000000000..f450e897a58 Binary files /dev/null and b/.github/pr-assets/5088-integrations-failed-cold.png differ diff --git a/.github/pr-assets/5089-claude-desktop-malformed-status.png b/.github/pr-assets/5089-claude-desktop-malformed-status.png new file mode 100644 index 00000000000..324bf077f7d Binary files /dev/null and b/.github/pr-assets/5089-claude-desktop-malformed-status.png differ diff --git a/.github/pr-assets/5197-apply-desktop.png b/.github/pr-assets/5197-apply-desktop.png new file mode 100644 index 00000000000..1a498c0d3e0 Binary files /dev/null and b/.github/pr-assets/5197-apply-desktop.png differ diff --git a/.github/pr-assets/5197-apply-narrow.png b/.github/pr-assets/5197-apply-narrow.png new file mode 100644 index 00000000000..4538af09a0d Binary files /dev/null and b/.github/pr-assets/5197-apply-narrow.png differ diff --git a/.github/pr-assets/5197-capture-receipt.json b/.github/pr-assets/5197-capture-receipt.json new file mode 100644 index 00000000000..89b06a80b15 --- /dev/null +++ b/.github/pr-assets/5197-capture-receipt.json @@ -0,0 +1,180 @@ +{ + "status": "HISTORICAL/CORRECTED-GUI-TREE", + "proofType": "fixture-rendered GUI proof from a hosted PR merge-ref build associated with the source head and GUI-tree-equivalent to the reviewed GUI; not a live backend or a literal PR-head build", + "sourceArtifact": { + "name": "PR #5197 hosted merge-ref GUI build associated with source head 07bf0a4dbe", + "artifactId": 10595174777, + "artifactName": "dashboard-preview-6c9576edb372200efec9d6ad4fea7b1e0dc35fb4", + "workflowRun": 35481230775, + "workflowAttempt": 1, + "workflowConclusion": "success", + "entrypoint": "index.html", + "javascript": "assets/index-CKL6ayU1.js", + "stylesheet": "assets/index-BTuCbqQd.css", + "buildCommit": "6c9576edb372200efec9d6ad4fea7b1e0dc35fb4", + "prHead": "07bf0a4dbe369f204c2216f5e8c07c87f52d649c", + "guiTree": "06c1f0c620cbfca2a557813f7ec54b7c11cbb540" + }, + "commands": { + "fixtureServer": "cd && python3 fixture_server.py", + "asideReplTemplate": "/usr/bin/perl -e 'alarm shift; exec @ARGV' 120 aside repl \"\"", + "desktopWindow": "Aside window {1446,762} -> CSS viewport 1280x720", + "narrowWindow": "Aside window {646,842} -> CSS viewport 480x800", + "ko390Window": "Aside native page zoom 125 percent plus window {654,900} -> observed CSS viewport 390x686" + }, + "reproduction": { + "baseUrl": "http://127.0.0.1:18799/", + "harnessScript": "fixture_server.py (scratch-only capture harness; not tracked)", + "driver": "Aside CLI repl opened the base URL in the real browser, selected fixture modes through POST /__fixture/mode, drove the dashboard controls, read back assertions, and captured each frame at the recorded CSS viewport and DPR." + }, + "fixtureRoutes": [ + "GET / and static assets", + "GET /healthz", + "GET /api/startup-health", + "GET /api/client-integrations", + "GET /api/client-integrations/opencode", + "GET /api/client-integrations/journal?client=opencode", + "POST /api/client-integrations/preview", + "PUT /api/client-integrations/opencode", + "POST /api/client-integrations/restore/preview", + "POST /api/client-integrations/restore", + "GET /api/client-integrations/aside/profiles", + "GET /api/client-integrations/aside/profiles/7", + "GET /api/client-integrations/aside/profiles/7/journal", + "POST /api/client-integrations/aside/profiles/7/preview", + "PUT /api/client-integrations/aside/profiles/7", + "POST /__fixture/mode", + "GET /__fixture/state" + ], + "requestSequences": { + "apply": [ + "POST /__fixture/mode {mode:apply}", + "GET /api/client-integrations/opencode", + "GET /api/client-integrations/journal?client=opencode", + "POST /api/client-integrations/preview {clientId:opencode,operation:apply}" + ], + "foreignOverwrite": [ + "POST /__fixture/mode {mode:overwrite}", + "GET /api/client-integrations/opencode -> conflict, reason foreign-edit", + "GET /api/client-integrations/journal?client=opencode", + "POST /api/client-integrations/preview {clientId:opencode,operation:overwrite}" + ], + "restoreDrift": [ + "POST /__fixture/mode {mode:restore}", + "GET /api/client-integrations/opencode", + "GET /api/client-integrations/journal?client=opencode -> op-restore-001", + "POST /api/client-integrations/restore/preview {opId:op-restore-001,confirmDrift:false}" + ], + "stale409Reconfirmation": [ + "POST /__fixture/mode {mode:stale}", + "GET state and journal", + "POST /api/client-integrations/preview -> initial p1:dddd... plan", + "PUT /api/client-integrations/opencode with initial binding -> 409 integration_preview_stale plus p1:eeee... fresh plan", + "GET state and journal reconciliation", + "capture before reconfirming" + ], + "koRestoreDrift390": ["select Korean in dashboard", "run restoreDrift", "capture at observed innerWidth 390"], + "koStaleReconfirm390": ["keep Korean selected", "run stale409Reconfirmation", "capture before reconfirming at innerWidth 390"], + "koProfileDisableNoop390": [ + "POST /__fixture/mode {mode:profile-noop}", + "GET /api/client-integrations/aside/profiles -> profile 7 enabled=true,state=absent", + "POST /api/client-integrations/aside/profiles/7/preview {operation:disable} -> willChange=false,changes=[],profileId=7", + "assert document no-op copy and sync-preference disclosure", + "assert primary Disable button enabled", + "assert consequence body contains neither Korean backup nor rollback text", + "capture", + "PUT /api/client-integrations/aside/profiles/7 {enabled:false,operation:disable,planFingerprint:p1:ffffffffffffffffffffffffffffffff}", + "GET /__fixture/state verifies recorded binding" + ], + "keyboardFocus": [ + "open apply dialog", + "press Tab twice to focus primary Apply", + "capture visible focus ring", + "assert dialog count 1 before Escape", + "press Escape and assert dialog count 0" + ] + }, + "captureBinding": { + "prHead": "07bf0a4dbe369f204c2216f5e8c07c87f52d649c", + "hostedBuildCommit": "6c9576edb372200efec9d6ad4fea7b1e0dc35fb4", + "sourceGuiTree": "06c1f0c620cbfca2a557813f7ec54b7c11cbb540", + "hostedBuildGuiTree": "06c1f0c620cbfca2a557813f7ec54b7c11cbb540", + "guiTreeEqual": true + }, + "interactionObservations": { + "keyboardFocusVisible": true, + "dialogCountBeforeEscape": 1, + "dialogCountAfterEscape": 0 + }, + "profileNoopVerification": { + "previewDto": { + "version": 1, + "clientId": "aside", + "operation": "disable", + "state": "absent", + "foreignEdit": "none", + "changes": [], + "fingerprint": "p1:ffffffffffffffffffffffffffffffff", + "canApply": true, + "willChange": false, + "profileId": 7 + }, + "assertions": { + "documentScopedNoopCopyVisible": true, + "syncPreferenceDisclosureVisible": true, + "primaryButtonEnabled": true, + "backupPromiseAbsent": true, + "rollbackPromiseAbsent": true + }, + "recordedBinding": { + "enabled": false, + "operation": "disable", + "planFingerprint": "p1:ffffffffffffffffffffffffffffffff" + } + }, + "viewports": [ + { + "name": "desktop", + "cssWidth": 1280, + "cssHeight": 720, + "devicePixelRatio": 2, + "pngWidth": 2560, + "pngHeight": 1440, + "files": ["apply-desktop.png","overwrite-foreign-desktop.png","restore-drift-desktop.png","stale-reconfirm-desktop.png","keyboard-focus.png"] + }, + { + "name": "narrow", + "cssWidth": 480, + "cssHeight": 800, + "devicePixelRatio": 2, + "pngWidth": 960, + "pngHeight": 1600, + "files": ["apply-narrow.png","overwrite-foreign-narrow.png","restore-drift-narrow.png","stale-reconfirm-narrow.png"] + }, + { + "name": "ko-390", + "cssWidth": 390, + "cssHeight": 686, + "devicePixelRatio": 2.5, + "browserZoomPercent": 125, + "pngWidth": 976, + "pngHeight": 1716, + "dimensionNote": "Observed CSS viewport and DPR imply a nominal 975x1715 raster; the actual PNG is 976x1716, one physical pixel per axis larger. The capture did not independently isolate the cause of that rounding difference.", + "files": ["ko-restore-drift-390.png","ko-stale-reconfirm-390.png","ko-profile-disable-noop-390.png"] + } + ], + "pngSha256": { + "apply-desktop.png": "4427b60e8885c68e2478c319e4ef428d959b4cc13ee5141a64a92777550ab420", + "apply-narrow.png": "0e2dfd18e76c26755c7b347e149de29dab2b4a40d2074e2ad293d93ced2e34e3", + "keyboard-focus.png": "29714ff85f13b35cc72fffc1a36b6d07ee820be1f9824c9f56a317f15c38feb1", + "ko-profile-disable-noop-390.png": "09baf33f610dccff7d26b77717682f046da821cb2ff8276325be829882f20648", + "ko-restore-drift-390.png": "7c51f352c24defd7cc0c669e53fd254ae314f79faf6cc48a65b9dd2589fe46de", + "ko-stale-reconfirm-390.png": "9dc051b7e97a19fd3dff66958fde432d35f94473ddc403424af13fcdc5ec5254", + "overwrite-foreign-desktop.png": "0e6d14543dfe4ff5847aa3d66d26c499f32235c02a6d741f32a528b1af12f986", + "overwrite-foreign-narrow.png": "8c9af82bc4cfe79e6400c10fb553378524c3f49074145a0cf845db52c3691b63", + "restore-drift-desktop.png": "42127e71f1f13a4902b31e59861de518dc339028a3b3cdbe130f259f0a78f5fb", + "restore-drift-narrow.png": "e7482dfe56b92350641b8a3b13ab3da79e7c8130db74a5cb5208a79e0ee9b2f9", + "stale-reconfirm-desktop.png": "307444c11e8369593b1a023fbeb2ee1ad63bf8deaa7c8bc6dfb9aa7728e6c6c1", + "stale-reconfirm-narrow.png": "8938274b183b888eaf8159bd6083ced670ac2070ef1a5cbdd6424475f4cc1b77" + } +} diff --git a/.github/pr-assets/5197-keyboard-focus.png b/.github/pr-assets/5197-keyboard-focus.png new file mode 100644 index 00000000000..98c77eba848 Binary files /dev/null and b/.github/pr-assets/5197-keyboard-focus.png differ diff --git a/.github/pr-assets/5197-ko-profile-disable-noop-390.png b/.github/pr-assets/5197-ko-profile-disable-noop-390.png new file mode 100644 index 00000000000..fa5d1bfcb02 Binary files /dev/null and b/.github/pr-assets/5197-ko-profile-disable-noop-390.png differ diff --git a/.github/pr-assets/5197-ko-restore-drift-390.png b/.github/pr-assets/5197-ko-restore-drift-390.png new file mode 100644 index 00000000000..3fcc416ae36 Binary files /dev/null and b/.github/pr-assets/5197-ko-restore-drift-390.png differ diff --git a/.github/pr-assets/5197-ko-stale-reconfirm-390.png b/.github/pr-assets/5197-ko-stale-reconfirm-390.png new file mode 100644 index 00000000000..4960694a7ac Binary files /dev/null and b/.github/pr-assets/5197-ko-stale-reconfirm-390.png differ diff --git a/.github/pr-assets/5197-overwrite-foreign-desktop.png b/.github/pr-assets/5197-overwrite-foreign-desktop.png new file mode 100644 index 00000000000..98ac20eaa87 Binary files /dev/null and b/.github/pr-assets/5197-overwrite-foreign-desktop.png differ diff --git a/.github/pr-assets/5197-overwrite-foreign-narrow.png b/.github/pr-assets/5197-overwrite-foreign-narrow.png new file mode 100644 index 00000000000..84fd9015915 Binary files /dev/null and b/.github/pr-assets/5197-overwrite-foreign-narrow.png differ diff --git a/.github/pr-assets/5197-restore-drift-desktop.png b/.github/pr-assets/5197-restore-drift-desktop.png new file mode 100644 index 00000000000..a348c662cdb Binary files /dev/null and b/.github/pr-assets/5197-restore-drift-desktop.png differ diff --git a/.github/pr-assets/5197-restore-drift-narrow.png b/.github/pr-assets/5197-restore-drift-narrow.png new file mode 100644 index 00000000000..aaa8fb53d33 Binary files /dev/null and b/.github/pr-assets/5197-restore-drift-narrow.png differ diff --git a/.github/pr-assets/5197-stale-reconfirm-desktop.png b/.github/pr-assets/5197-stale-reconfirm-desktop.png new file mode 100644 index 00000000000..7f830bda54e Binary files /dev/null and b/.github/pr-assets/5197-stale-reconfirm-desktop.png differ diff --git a/.github/pr-assets/5197-stale-reconfirm-narrow.png b/.github/pr-assets/5197-stale-reconfirm-narrow.png new file mode 100644 index 00000000000..1c17ec44dfd Binary files /dev/null and b/.github/pr-assets/5197-stale-reconfirm-narrow.png differ diff --git a/.github/scripts/issue-translation.cjs b/.github/scripts/issue-translation.cjs index c7d546bc237..41638a9d993 100644 --- a/.github/scripts/issue-translation.cjs +++ b/.github/scripts/issue-translation.cjs @@ -805,11 +805,22 @@ function sanitizeTranslationBody(raw, maxChars = 60000) { .split(MARKER).join("") .split(END_MARKER).join("") .replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, "") - // Defuse pings only: @login / @org/team — not emails, scopes, or decorators. + // Mask the @ inside email addresses first: punctuation-bearing local + // parts (x!@example.com, a=b@example.com, a/b@example.com) must not be + // read as mention boundaries. Requiring a dotted domain keeps + // "end!@octocat"-style mentions defused. \u0001 cannot appear in the + // input (control chars were stripped above), so it is a safe sentinel. .replace( - /(^|[\s(])@([A-Za-z0-9](?:[A-Za-z0-9-]{0,38})(?:\/[A-Za-z0-9._-]+)?)/g, + /[A-Za-z0-9.!#$%&'*+\/=?^_`{|}~-]+@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+/g, + (email) => email.replace("@", "\u0001"), + ) + // Defuse pings at Markdown/punctuation boundaries — a colon is a boundary + // too — but not emails, npm: scopes, or other mid-token at-signs. + .replace( + /(^|[^A-Za-z0-9._%+-])(? { assert.equal(decision.reason, "rate_limited_interval"); }); - it("defuses mention-shaped tokens without rewriting emails or mid-token at-signs", () => { - const out = sanitizeTranslationBody("see @octocat and user@example.com and npm:@scope"); + it("defuses mention-shaped tokens at Markdown and punctuation boundaries", () => { + const out = sanitizeTranslationBody( + "see @octocat, comma,@team, [@user], >@org/team, Status:@maintainer, user@example.com, npm:@scope", + ); assert.match(out, /@\u200boctocat/); + assert.match(out, /,@\u200bteam/); + assert.match(out, /\[@\u200buser\]/); + assert.match(out, />@\u200borg\/team/); + assert.match(out, /Status:@\u200bmaintainer/); assert.ok(out.includes("user@example.com")); assert.ok(out.includes("npm:@scope")); }); + it("preserves punctuation-bearing email local parts while defusing mentions", () => { + const out = sanitizeTranslationBody( + "mail x!@example.com, a=b@example.com, or a/b@example.com; end!@octocat key=@value path/@handle user.name@example.com user+tag@example.com", + ); + assert.ok(out.includes("x!@example.com")); + assert.ok(out.includes("a=b@example.com")); + assert.ok(out.includes("a/b@example.com")); + assert.ok(out.includes("user.name@example.com")); + assert.ok(out.includes("user+tag@example.com")); + assert.match(out, /end!@\u200boctocat/); + assert.match(out, /key=@\u200bvalue/); + assert.match(out, /path\/@\u200bhandle/); + }); + it("ignores forged body-embedded legacy state", () => { const forged = appendTranslationBlock(SOURCE, "English") + `\n