PER-10496 feat: emit machine identity for slow-build diagnostics - #2384

Open
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity
Open

PER-10496 feat: emit machine identity for slow-build diagnostics#2384
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity

Conversation

@Shivanshu-07

@Shivanshu-07Shivanshu-07 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

CLI side of Build-processing diagnostics (slow builds) — PER-10496. Pairs with percy-api https://github.com/percy/percy-api/pull/6715, which validates and consumes everything sent here for per-machine liveness on parallel builds (naming the dead CI machine when one stops sending snapshots).

  • env.machine getter (@percy/env): { id, hostname, runUrl } — sanitized-hostname id suffixed with the CI node index where the provider exposes one (CIRCLE_NODE_INDEX, BUILDKITE_PARALLEL_JOB), and the CI run URL for circle/buildkite/github/gitlab. Deliberately excluded from the env getter debug logging (like token) — those debug logs are uploaded with build logs, and hostnames should not ride along.
  • Build create (@percy/client): machine-id / machine-hostname / machine-ci-run-url attributes (only when an id exists).
  • X-Percy-Machine-Id header on snapshot-create and build-finalize calls, attached per-call via machineHeaders() — never in headers(), so it cannot leak to off-domain requests (validateDomain).

Server-side: percy-api enforces charset/length limits and an https + CI-host allowlist on the URL, and treats all of it as advisory. Old CLI versions degrade gracefully (the feature falls back to non-machine-specific messaging).

Testing

  • @percy/env: 5 new specs (sanitized id, node-index suffix + run URL on circle, composed GitHub Actions run URL, null run URL fallback, debug-logging exclusion). Suite green (128/128).
  • @percy/client: header specs for snapshot + finalize, machine attributes on build create; existing exact-payload expectations updated. Suite green under node 14 except one pre-existing environmental failure (proxy getProxy should return undefined if no proxy is set) that also fails on a clean checkout on this machine (local proxy present) — unrelated to this change.

Post-Deploy Monitoring & Validation

  • What to monitor: percy-api warn logs "machine identity ingest skipped" (should stay ≈0); Redis key growth percy:api:build-machines:* (bounded by active builds, 25h TTL).
  • Validation: run a parallel build with this CLI against an org with the slow-build-diagnostics flag ON → build show JSON carries machine facts in diagnosis; kill one shard → machine named in the receiving-state alert.
  • Expected healthy behavior: zero change for orgs with the flag off; no additional CLI network calls (attributes/header ride existing requests).
  • Failure signal / rollback: any snapshot POST regression correlated with the header → revert this PR; the API ignores absent identity entirely.
  • Window & owner: first minor release post-merge, @shivanshusingh.

🤖 Generated with Claude Code

New env.machine getter (hostname-based id with CI node-index suffix,
per-provider run URL) sent as build-create attributes plus an
X-Percy-Machine-Id header on snapshot/finalize calls so percy-api can
track per-machine liveness on parallel builds and name the dead
machine when one stops sending.
The getter is excluded from env debug logging (those logs are uploaded
with build logs) and the header is attached per-call, never in
headers(), so it cannot reach off-domain requests. percy-api validates
everything server-side; old CLIs degrade gracefully.
@percy/env enforces 100% line and branch coverage; the new machine
getter left the buildkite/gitlab cases, the hostname failure path and
the optional-var fallbacks uncovered.
@percy/client also enforces 100% branch coverage; the build-attribute
spread and machineHeaders() fallbacks (old CLI / no resolvable hostname)
were untested.
@Shivanshu-07

Copy link
Copy Markdown
ContributorAuthor

CI is green (30/30). For the record on the two reds seen along the way:

  • Test @percy/env and Test @percy/client were mine: both packages enforce 100% line and branch coverage via test:coverage (a different command from test, which is what I'd run locally), and the new machine getter left the buildkite/gitlab cases, the hostname-failure path, and the no-machine-identity fallbacks uncovered. Fixed in ee8b24d and 3c6ceff — both packages now report 100/100/100/100.
  • Test @percy/core (Windows leg only) failed on should retry by default on the snapshot discovery upto 3 times, which observed 2 retry log lines instead of 3. That is a timing assertion in packages/core; this PR touches only packages/env and packages/client, and the Linux core leg passed on the same commit. Re-ran the job and it passed, so it was flaky rather than related.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@Shivanshu-07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

PER-10496 feat: emit machine identity for slow-build diagnostics - #2384

Open
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity
Open

PER-10496 feat: emit machine identity for slow-build diagnostics#2384
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity

Conversation

@Shivanshu-07

@Shivanshu-07Shivanshu-07 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

CLI side of Build-processing diagnostics (slow builds) — PER-10496. Pairs with percy-api https://github.com/percy/percy-api/pull/6715, which validates and consumes everything sent here for per-machine liveness on parallel builds (naming the dead CI machine when one stops sending snapshots).

  • env.machine getter (@percy/env): { id, hostname, runUrl } — sanitized-hostname id suffixed with the CI node index where the provider exposes one (CIRCLE_NODE_INDEX, BUILDKITE_PARALLEL_JOB), and the CI run URL for circle/buildkite/github/gitlab. Deliberately excluded from the env getter debug logging (like token) — those debug logs are uploaded with build logs, and hostnames should not ride along.
  • Build create (@percy/client): machine-id / machine-hostname / machine-ci-run-url attributes (only when an id exists).
  • X-Percy-Machine-Id header on snapshot-create and build-finalize calls, attached per-call via machineHeaders() — never in headers(), so it cannot leak to off-domain requests (validateDomain).

Server-side: percy-api enforces charset/length limits and an https + CI-host allowlist on the URL, and treats all of it as advisory. Old CLI versions degrade gracefully (the feature falls back to non-machine-specific messaging).

Testing

  • @percy/env: 5 new specs (sanitized id, node-index suffix + run URL on circle, composed GitHub Actions run URL, null run URL fallback, debug-logging exclusion). Suite green (128/128).
  • @percy/client: header specs for snapshot + finalize, machine attributes on build create; existing exact-payload expectations updated. Suite green under node 14 except one pre-existing environmental failure (proxy getProxy should return undefined if no proxy is set) that also fails on a clean checkout on this machine (local proxy present) — unrelated to this change.

Post-Deploy Monitoring & Validation

  • What to monitor: percy-api warn logs "machine identity ingest skipped" (should stay ≈0); Redis key growth percy:api:build-machines:* (bounded by active builds, 25h TTL).
  • Validation: run a parallel build with this CLI against an org with the slow-build-diagnostics flag ON → build show JSON carries machine facts in diagnosis; kill one shard → machine named in the receiving-state alert.
  • Expected healthy behavior: zero change for orgs with the flag off; no additional CLI network calls (attributes/header ride existing requests).
  • Failure signal / rollback: any snapshot POST regression correlated with the header → revert this PR; the API ignores absent identity entirely.
  • Window & owner: first minor release post-merge, @shivanshusingh.

🤖 Generated with Claude Code

New env.machine getter (hostname-based id with CI node-index suffix,
per-provider run URL) sent as build-create attributes plus an
X-Percy-Machine-Id header on snapshot/finalize calls so percy-api can
track per-machine liveness on parallel builds and name the dead
machine when one stops sending.
The getter is excluded from env debug logging (those logs are uploaded
with build logs) and the header is attached per-call, never in
headers(), so it cannot reach off-domain requests. percy-api validates
everything server-side; old CLIs degrade gracefully.
@percy/env enforces 100% line and branch coverage; the new machine
getter left the buildkite/gitlab cases, the hostname failure path and
the optional-var fallbacks uncovered.
@percy/client also enforces 100% branch coverage; the build-attribute
spread and machineHeaders() fallbacks (old CLI / no resolvable hostname)
were untested.
@Shivanshu-07

Copy link
Copy Markdown
ContributorAuthor

CI is green (30/30). For the record on the two reds seen along the way:

  • Test @percy/env and Test @percy/client were mine: both packages enforce 100% line and branch coverage via test:coverage (a different command from test, which is what I'd run locally), and the new machine getter left the buildkite/gitlab cases, the hostname-failure path, and the no-machine-identity fallbacks uncovered. Fixed in ee8b24d and 3c6ceff — both packages now report 100/100/100/100.
  • Test @percy/core (Windows leg only) failed on should retry by default on the snapshot discovery upto 3 times, which observed 2 retry log lines instead of 3. That is a timing assertion in packages/core; this PR touches only packages/env and packages/client, and the Linux core leg passed on the same commit. Re-ran the job and it passed, so it was flaky rather than related.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@Shivanshu-07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

PER-10496 feat: emit machine identity for slow-build diagnostics - #2384

Open
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity
Open

PER-10496 feat: emit machine identity for slow-build diagnostics#2384
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity

Conversation

@Shivanshu-07

@Shivanshu-07Shivanshu-07 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

CLI side of Build-processing diagnostics (slow builds) — PER-10496. Pairs with percy-api https://github.com/percy/percy-api/pull/6715, which validates and consumes everything sent here for per-machine liveness on parallel builds (naming the dead CI machine when one stops sending snapshots).

  • env.machine getter (@percy/env): { id, hostname, runUrl } — sanitized-hostname id suffixed with the CI node index where the provider exposes one (CIRCLE_NODE_INDEX, BUILDKITE_PARALLEL_JOB), and the CI run URL for circle/buildkite/github/gitlab. Deliberately excluded from the env getter debug logging (like token) — those debug logs are uploaded with build logs, and hostnames should not ride along.
  • Build create (@percy/client): machine-id / machine-hostname / machine-ci-run-url attributes (only when an id exists).
  • X-Percy-Machine-Id header on snapshot-create and build-finalize calls, attached per-call via machineHeaders() — never in headers(), so it cannot leak to off-domain requests (validateDomain).

Server-side: percy-api enforces charset/length limits and an https + CI-host allowlist on the URL, and treats all of it as advisory. Old CLI versions degrade gracefully (the feature falls back to non-machine-specific messaging).

Testing

  • @percy/env: 5 new specs (sanitized id, node-index suffix + run URL on circle, composed GitHub Actions run URL, null run URL fallback, debug-logging exclusion). Suite green (128/128).
  • @percy/client: header specs for snapshot + finalize, machine attributes on build create; existing exact-payload expectations updated. Suite green under node 14 except one pre-existing environmental failure (proxy getProxy should return undefined if no proxy is set) that also fails on a clean checkout on this machine (local proxy present) — unrelated to this change.

Post-Deploy Monitoring & Validation

  • What to monitor: percy-api warn logs "machine identity ingest skipped" (should stay ≈0); Redis key growth percy:api:build-machines:* (bounded by active builds, 25h TTL).
  • Validation: run a parallel build with this CLI against an org with the slow-build-diagnostics flag ON → build show JSON carries machine facts in diagnosis; kill one shard → machine named in the receiving-state alert.
  • Expected healthy behavior: zero change for orgs with the flag off; no additional CLI network calls (attributes/header ride existing requests).
  • Failure signal / rollback: any snapshot POST regression correlated with the header → revert this PR; the API ignores absent identity entirely.
  • Window & owner: first minor release post-merge, @shivanshusingh.

🤖 Generated with Claude Code

New env.machine getter (hostname-based id with CI node-index suffix,
per-provider run URL) sent as build-create attributes plus an
X-Percy-Machine-Id header on snapshot/finalize calls so percy-api can
track per-machine liveness on parallel builds and name the dead
machine when one stops sending.
The getter is excluded from env debug logging (those logs are uploaded
with build logs) and the header is attached per-call, never in
headers(), so it cannot reach off-domain requests. percy-api validates
everything server-side; old CLIs degrade gracefully.
@percy/env enforces 100% line and branch coverage; the new machine
getter left the buildkite/gitlab cases, the hostname failure path and
the optional-var fallbacks uncovered.
@percy/client also enforces 100% branch coverage; the build-attribute
spread and machineHeaders() fallbacks (old CLI / no resolvable hostname)
were untested.
@Shivanshu-07

Copy link
Copy Markdown
ContributorAuthor

CI is green (30/30). For the record on the two reds seen along the way:

  • Test @percy/env and Test @percy/client were mine: both packages enforce 100% line and branch coverage via test:coverage (a different command from test, which is what I'd run locally), and the new machine getter left the buildkite/gitlab cases, the hostname-failure path, and the no-machine-identity fallbacks uncovered. Fixed in ee8b24d and 3c6ceff — both packages now report 100/100/100/100.
  • Test @percy/core (Windows leg only) failed on should retry by default on the snapshot discovery upto 3 times, which observed 2 retry log lines instead of 3. That is a timing assertion in packages/core; this PR touches only packages/env and packages/client, and the Linux core leg passed on the same commit. Re-ran the job and it passed, so it was flaky rather than related.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@Shivanshu-07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

PER-10496 feat: emit machine identity for slow-build diagnostics - #2384

Open
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity
Open

PER-10496 feat: emit machine identity for slow-build diagnostics#2384
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity

Conversation

@Shivanshu-07

@Shivanshu-07Shivanshu-07 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

CLI side of Build-processing diagnostics (slow builds) — PER-10496. Pairs with percy-api https://github.com/percy/percy-api/pull/6715, which validates and consumes everything sent here for per-machine liveness on parallel builds (naming the dead CI machine when one stops sending snapshots).

  • env.machine getter (@percy/env): { id, hostname, runUrl } — sanitized-hostname id suffixed with the CI node index where the provider exposes one (CIRCLE_NODE_INDEX, BUILDKITE_PARALLEL_JOB), and the CI run URL for circle/buildkite/github/gitlab. Deliberately excluded from the env getter debug logging (like token) — those debug logs are uploaded with build logs, and hostnames should not ride along.
  • Build create (@percy/client): machine-id / machine-hostname / machine-ci-run-url attributes (only when an id exists).
  • X-Percy-Machine-Id header on snapshot-create and build-finalize calls, attached per-call via machineHeaders() — never in headers(), so it cannot leak to off-domain requests (validateDomain).

Server-side: percy-api enforces charset/length limits and an https + CI-host allowlist on the URL, and treats all of it as advisory. Old CLI versions degrade gracefully (the feature falls back to non-machine-specific messaging).

Testing

  • @percy/env: 5 new specs (sanitized id, node-index suffix + run URL on circle, composed GitHub Actions run URL, null run URL fallback, debug-logging exclusion). Suite green (128/128).
  • @percy/client: header specs for snapshot + finalize, machine attributes on build create; existing exact-payload expectations updated. Suite green under node 14 except one pre-existing environmental failure (proxy getProxy should return undefined if no proxy is set) that also fails on a clean checkout on this machine (local proxy present) — unrelated to this change.

Post-Deploy Monitoring & Validation

  • What to monitor: percy-api warn logs "machine identity ingest skipped" (should stay ≈0); Redis key growth percy:api:build-machines:* (bounded by active builds, 25h TTL).
  • Validation: run a parallel build with this CLI against an org with the slow-build-diagnostics flag ON → build show JSON carries machine facts in diagnosis; kill one shard → machine named in the receiving-state alert.
  • Expected healthy behavior: zero change for orgs with the flag off; no additional CLI network calls (attributes/header ride existing requests).
  • Failure signal / rollback: any snapshot POST regression correlated with the header → revert this PR; the API ignores absent identity entirely.
  • Window & owner: first minor release post-merge, @shivanshusingh.

🤖 Generated with Claude Code

New env.machine getter (hostname-based id with CI node-index suffix,
per-provider run URL) sent as build-create attributes plus an
X-Percy-Machine-Id header on snapshot/finalize calls so percy-api can
track per-machine liveness on parallel builds and name the dead
machine when one stops sending.
The getter is excluded from env debug logging (those logs are uploaded
with build logs) and the header is attached per-call, never in
headers(), so it cannot reach off-domain requests. percy-api validates
everything server-side; old CLIs degrade gracefully.
@percy/env enforces 100% line and branch coverage; the new machine
getter left the buildkite/gitlab cases, the hostname failure path and
the optional-var fallbacks uncovered.
@percy/client also enforces 100% branch coverage; the build-attribute
spread and machineHeaders() fallbacks (old CLI / no resolvable hostname)
were untested.
@Shivanshu-07

Copy link
Copy Markdown
ContributorAuthor

CI is green (30/30). For the record on the two reds seen along the way:

  • Test @percy/env and Test @percy/client were mine: both packages enforce 100% line and branch coverage via test:coverage (a different command from test, which is what I'd run locally), and the new machine getter left the buildkite/gitlab cases, the hostname-failure path, and the no-machine-identity fallbacks uncovered. Fixed in ee8b24d and 3c6ceff — both packages now report 100/100/100/100.
  • Test @percy/core (Windows leg only) failed on should retry by default on the snapshot discovery upto 3 times, which observed 2 retry log lines instead of 3. That is a timing assertion in packages/core; this PR touches only packages/env and packages/client, and the Linux core leg passed on the same commit. Re-ran the job and it passed, so it was flaky rather than related.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@Shivanshu-07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

PER-10496 feat: emit machine identity for slow-build diagnostics - #2384

Open
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity
Open

PER-10496 feat: emit machine identity for slow-build diagnostics#2384
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity

Conversation

@Shivanshu-07

@Shivanshu-07Shivanshu-07 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

CLI side of Build-processing diagnostics (slow builds) — PER-10496. Pairs with percy-api https://github.com/percy/percy-api/pull/6715, which validates and consumes everything sent here for per-machine liveness on parallel builds (naming the dead CI machine when one stops sending snapshots).

  • env.machine getter (@percy/env): { id, hostname, runUrl } — sanitized-hostname id suffixed with the CI node index where the provider exposes one (CIRCLE_NODE_INDEX, BUILDKITE_PARALLEL_JOB), and the CI run URL for circle/buildkite/github/gitlab. Deliberately excluded from the env getter debug logging (like token) — those debug logs are uploaded with build logs, and hostnames should not ride along.
  • Build create (@percy/client): machine-id / machine-hostname / machine-ci-run-url attributes (only when an id exists).
  • X-Percy-Machine-Id header on snapshot-create and build-finalize calls, attached per-call via machineHeaders() — never in headers(), so it cannot leak to off-domain requests (validateDomain).

Server-side: percy-api enforces charset/length limits and an https + CI-host allowlist on the URL, and treats all of it as advisory. Old CLI versions degrade gracefully (the feature falls back to non-machine-specific messaging).

Testing

  • @percy/env: 5 new specs (sanitized id, node-index suffix + run URL on circle, composed GitHub Actions run URL, null run URL fallback, debug-logging exclusion). Suite green (128/128).
  • @percy/client: header specs for snapshot + finalize, machine attributes on build create; existing exact-payload expectations updated. Suite green under node 14 except one pre-existing environmental failure (proxy getProxy should return undefined if no proxy is set) that also fails on a clean checkout on this machine (local proxy present) — unrelated to this change.

Post-Deploy Monitoring & Validation

  • What to monitor: percy-api warn logs "machine identity ingest skipped" (should stay ≈0); Redis key growth percy:api:build-machines:* (bounded by active builds, 25h TTL).
  • Validation: run a parallel build with this CLI against an org with the slow-build-diagnostics flag ON → build show JSON carries machine facts in diagnosis; kill one shard → machine named in the receiving-state alert.
  • Expected healthy behavior: zero change for orgs with the flag off; no additional CLI network calls (attributes/header ride existing requests).
  • Failure signal / rollback: any snapshot POST regression correlated with the header → revert this PR; the API ignores absent identity entirely.
  • Window & owner: first minor release post-merge, @shivanshusingh.

🤖 Generated with Claude Code

New env.machine getter (hostname-based id with CI node-index suffix,
per-provider run URL) sent as build-create attributes plus an
X-Percy-Machine-Id header on snapshot/finalize calls so percy-api can
track per-machine liveness on parallel builds and name the dead
machine when one stops sending.
The getter is excluded from env debug logging (those logs are uploaded
with build logs) and the header is attached per-call, never in
headers(), so it cannot reach off-domain requests. percy-api validates
everything server-side; old CLIs degrade gracefully.
@percy/env enforces 100% line and branch coverage; the new machine
getter left the buildkite/gitlab cases, the hostname failure path and
the optional-var fallbacks uncovered.
@percy/client also enforces 100% branch coverage; the build-attribute
spread and machineHeaders() fallbacks (old CLI / no resolvable hostname)
were untested.
@Shivanshu-07

Copy link
Copy Markdown
ContributorAuthor

CI is green (30/30). For the record on the two reds seen along the way:

  • Test @percy/env and Test @percy/client were mine: both packages enforce 100% line and branch coverage via test:coverage (a different command from test, which is what I'd run locally), and the new machine getter left the buildkite/gitlab cases, the hostname-failure path, and the no-machine-identity fallbacks uncovered. Fixed in ee8b24d and 3c6ceff — both packages now report 100/100/100/100.
  • Test @percy/core (Windows leg only) failed on should retry by default on the snapshot discovery upto 3 times, which observed 2 retry log lines instead of 3. That is a timing assertion in packages/core; this PR touches only packages/env and packages/client, and the Linux core leg passed on the same commit. Re-ran the job and it passed, so it was flaky rather than related.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@Shivanshu-07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

PER-10496 feat: emit machine identity for slow-build diagnostics - #2384

Open
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity
Open

PER-10496 feat: emit machine identity for slow-build diagnostics#2384
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity

Conversation

@Shivanshu-07

@Shivanshu-07Shivanshu-07 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

CLI side of Build-processing diagnostics (slow builds) — PER-10496. Pairs with percy-api https://github.com/percy/percy-api/pull/6715, which validates and consumes everything sent here for per-machine liveness on parallel builds (naming the dead CI machine when one stops sending snapshots).

  • env.machine getter (@percy/env): { id, hostname, runUrl } — sanitized-hostname id suffixed with the CI node index where the provider exposes one (CIRCLE_NODE_INDEX, BUILDKITE_PARALLEL_JOB), and the CI run URL for circle/buildkite/github/gitlab. Deliberately excluded from the env getter debug logging (like token) — those debug logs are uploaded with build logs, and hostnames should not ride along.
  • Build create (@percy/client): machine-id / machine-hostname / machine-ci-run-url attributes (only when an id exists).
  • X-Percy-Machine-Id header on snapshot-create and build-finalize calls, attached per-call via machineHeaders() — never in headers(), so it cannot leak to off-domain requests (validateDomain).

Server-side: percy-api enforces charset/length limits and an https + CI-host allowlist on the URL, and treats all of it as advisory. Old CLI versions degrade gracefully (the feature falls back to non-machine-specific messaging).

Testing

  • @percy/env: 5 new specs (sanitized id, node-index suffix + run URL on circle, composed GitHub Actions run URL, null run URL fallback, debug-logging exclusion). Suite green (128/128).
  • @percy/client: header specs for snapshot + finalize, machine attributes on build create; existing exact-payload expectations updated. Suite green under node 14 except one pre-existing environmental failure (proxy getProxy should return undefined if no proxy is set) that also fails on a clean checkout on this machine (local proxy present) — unrelated to this change.

Post-Deploy Monitoring & Validation

  • What to monitor: percy-api warn logs "machine identity ingest skipped" (should stay ≈0); Redis key growth percy:api:build-machines:* (bounded by active builds, 25h TTL).
  • Validation: run a parallel build with this CLI against an org with the slow-build-diagnostics flag ON → build show JSON carries machine facts in diagnosis; kill one shard → machine named in the receiving-state alert.
  • Expected healthy behavior: zero change for orgs with the flag off; no additional CLI network calls (attributes/header ride existing requests).
  • Failure signal / rollback: any snapshot POST regression correlated with the header → revert this PR; the API ignores absent identity entirely.
  • Window & owner: first minor release post-merge, @shivanshusingh.

🤖 Generated with Claude Code

New env.machine getter (hostname-based id with CI node-index suffix,
per-provider run URL) sent as build-create attributes plus an
X-Percy-Machine-Id header on snapshot/finalize calls so percy-api can
track per-machine liveness on parallel builds and name the dead
machine when one stops sending.
The getter is excluded from env debug logging (those logs are uploaded
with build logs) and the header is attached per-call, never in
headers(), so it cannot reach off-domain requests. percy-api validates
everything server-side; old CLIs degrade gracefully.
@percy/env enforces 100% line and branch coverage; the new machine
getter left the buildkite/gitlab cases, the hostname failure path and
the optional-var fallbacks uncovered.
@percy/client also enforces 100% branch coverage; the build-attribute
spread and machineHeaders() fallbacks (old CLI / no resolvable hostname)
were untested.
@Shivanshu-07

Copy link
Copy Markdown
ContributorAuthor

CI is green (30/30). For the record on the two reds seen along the way:

  • Test @percy/env and Test @percy/client were mine: both packages enforce 100% line and branch coverage via test:coverage (a different command from test, which is what I'd run locally), and the new machine getter left the buildkite/gitlab cases, the hostname-failure path, and the no-machine-identity fallbacks uncovered. Fixed in ee8b24d and 3c6ceff — both packages now report 100/100/100/100.
  • Test @percy/core (Windows leg only) failed on should retry by default on the snapshot discovery upto 3 times, which observed 2 retry log lines instead of 3. That is a timing assertion in packages/core; this PR touches only packages/env and packages/client, and the Linux core leg passed on the same commit. Re-ran the job and it passed, so it was flaky rather than related.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@Shivanshu-07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

PER-10496 feat: emit machine identity for slow-build diagnostics - #2384

Open
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity
Open

PER-10496 feat: emit machine identity for slow-build diagnostics#2384
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity

Conversation

@Shivanshu-07

@Shivanshu-07Shivanshu-07 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

CLI side of Build-processing diagnostics (slow builds) — PER-10496. Pairs with percy-api https://github.com/percy/percy-api/pull/6715, which validates and consumes everything sent here for per-machine liveness on parallel builds (naming the dead CI machine when one stops sending snapshots).

  • env.machine getter (@percy/env): { id, hostname, runUrl } — sanitized-hostname id suffixed with the CI node index where the provider exposes one (CIRCLE_NODE_INDEX, BUILDKITE_PARALLEL_JOB), and the CI run URL for circle/buildkite/github/gitlab. Deliberately excluded from the env getter debug logging (like token) — those debug logs are uploaded with build logs, and hostnames should not ride along.
  • Build create (@percy/client): machine-id / machine-hostname / machine-ci-run-url attributes (only when an id exists).
  • X-Percy-Machine-Id header on snapshot-create and build-finalize calls, attached per-call via machineHeaders() — never in headers(), so it cannot leak to off-domain requests (validateDomain).

Server-side: percy-api enforces charset/length limits and an https + CI-host allowlist on the URL, and treats all of it as advisory. Old CLI versions degrade gracefully (the feature falls back to non-machine-specific messaging).

Testing

  • @percy/env: 5 new specs (sanitized id, node-index suffix + run URL on circle, composed GitHub Actions run URL, null run URL fallback, debug-logging exclusion). Suite green (128/128).
  • @percy/client: header specs for snapshot + finalize, machine attributes on build create; existing exact-payload expectations updated. Suite green under node 14 except one pre-existing environmental failure (proxy getProxy should return undefined if no proxy is set) that also fails on a clean checkout on this machine (local proxy present) — unrelated to this change.

Post-Deploy Monitoring & Validation

  • What to monitor: percy-api warn logs "machine identity ingest skipped" (should stay ≈0); Redis key growth percy:api:build-machines:* (bounded by active builds, 25h TTL).
  • Validation: run a parallel build with this CLI against an org with the slow-build-diagnostics flag ON → build show JSON carries machine facts in diagnosis; kill one shard → machine named in the receiving-state alert.
  • Expected healthy behavior: zero change for orgs with the flag off; no additional CLI network calls (attributes/header ride existing requests).
  • Failure signal / rollback: any snapshot POST regression correlated with the header → revert this PR; the API ignores absent identity entirely.
  • Window & owner: first minor release post-merge, @shivanshusingh.

🤖 Generated with Claude Code

New env.machine getter (hostname-based id with CI node-index suffix,
per-provider run URL) sent as build-create attributes plus an
X-Percy-Machine-Id header on snapshot/finalize calls so percy-api can
track per-machine liveness on parallel builds and name the dead
machine when one stops sending.
The getter is excluded from env debug logging (those logs are uploaded
with build logs) and the header is attached per-call, never in
headers(), so it cannot reach off-domain requests. percy-api validates
everything server-side; old CLIs degrade gracefully.
@percy/env enforces 100% line and branch coverage; the new machine
getter left the buildkite/gitlab cases, the hostname failure path and
the optional-var fallbacks uncovered.
@percy/client also enforces 100% branch coverage; the build-attribute
spread and machineHeaders() fallbacks (old CLI / no resolvable hostname)
were untested.
@Shivanshu-07

Copy link
Copy Markdown
ContributorAuthor

CI is green (30/30). For the record on the two reds seen along the way:

  • Test @percy/env and Test @percy/client were mine: both packages enforce 100% line and branch coverage via test:coverage (a different command from test, which is what I'd run locally), and the new machine getter left the buildkite/gitlab cases, the hostname-failure path, and the no-machine-identity fallbacks uncovered. Fixed in ee8b24d and 3c6ceff — both packages now report 100/100/100/100.
  • Test @percy/core (Windows leg only) failed on should retry by default on the snapshot discovery upto 3 times, which observed 2 retry log lines instead of 3. That is a timing assertion in packages/core; this PR touches only packages/env and packages/client, and the Linux core leg passed on the same commit. Re-ran the job and it passed, so it was flaky rather than related.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@Shivanshu-07
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

PER-10496 feat: emit machine identity for slow-build diagnostics - #2384

Open
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity
Open

PER-10496 feat: emit machine identity for slow-build diagnostics#2384
Shivanshu-07 wants to merge 4 commits into
masterfrom
feat/per-10496-machine-identity

Conversation

@Shivanshu-07

@Shivanshu-07Shivanshu-07 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

CLI side of Build-processing diagnostics (slow builds) — PER-10496. Pairs with percy-api https://github.com/percy/percy-api/pull/6715, which validates and consumes everything sent here for per-machine liveness on parallel builds (naming the dead CI machine when one stops sending snapshots).

  • env.machine getter (@percy/env): { id, hostname, runUrl } — sanitized-hostname id suffixed with the CI node index where the provider exposes one (CIRCLE_NODE_INDEX, BUILDKITE_PARALLEL_JOB), and the CI run URL for circle/buildkite/github/gitlab. Deliberately excluded from the env getter debug logging (like token) — those debug logs are uploaded with build logs, and hostnames should not ride along.
  • Build create (@percy/client): machine-id / machine-hostname / machine-ci-run-url attributes (only when an id exists).
  • X-Percy-Machine-Id header on snapshot-create and build-finalize calls, attached per-call via machineHeaders() — never in headers(), so it cannot leak to off-domain requests (validateDomain).

Server-side: percy-api enforces charset/length limits and an https + CI-host allowlist on the URL, and treats all of it as advisory. Old CLI versions degrade gracefully (the feature falls back to non-machine-specific messaging).

Testing

  • @percy/env: 5 new specs (sanitized id, node-index suffix + run URL on circle, composed GitHub Actions run URL, null run URL fallback, debug-logging exclusion). Suite green (128/128).
  • @percy/client: header specs for snapshot + finalize, machine attributes on build create; existing exact-payload expectations updated. Suite green under node 14 except one pre-existing environmental failure (proxy getProxy should return undefined if no proxy is set) that also fails on a clean checkout on this machine (local proxy present) — unrelated to this change.

Post-Deploy Monitoring & Validation

  • What to monitor: percy-api warn logs "machine identity ingest skipped" (should stay ≈0); Redis key growth percy:api:build-machines:* (bounded by active builds, 25h TTL).
  • Validation: run a parallel build with this CLI against an org with the slow-build-diagnostics flag ON → build show JSON carries machine facts in diagnosis; kill one shard → machine named in the receiving-state alert.
  • Expected healthy behavior: zero change for orgs with the flag off; no additional CLI network calls (attributes/header ride existing requests).
  • Failure signal / rollback: any snapshot POST regression correlated with the header → revert this PR; the API ignores absent identity entirely.
  • Window & owner: first minor release post-merge, @shivanshusingh.

🤖 Generated with Claude Code

New env.machine getter (hostname-based id with CI node-index suffix,
per-provider run URL) sent as build-create attributes plus an
X-Percy-Machine-Id header on snapshot/finalize calls so percy-api can
track per-machine liveness on parallel builds and name the dead
machine when one stops sending.
The getter is excluded from env debug logging (those logs are uploaded
with build logs) and the header is attached per-call, never in
headers(), so it cannot reach off-domain requests. percy-api validates
everything server-side; old CLIs degrade gracefully.
@percy/env enforces 100% line and branch coverage; the new machine
getter left the buildkite/gitlab cases, the hostname failure path and
the optional-var fallbacks uncovered.
@percy/client also enforces 100% branch coverage; the build-attribute
spread and machineHeaders() fallbacks (old CLI / no resolvable hostname)
were untested.
@Shivanshu-07

Copy link
Copy Markdown
ContributorAuthor

CI is green (30/30). For the record on the two reds seen along the way:

  • Test @percy/env and Test @percy/client were mine: both packages enforce 100% line and branch coverage via test:coverage (a different command from test, which is what I'd run locally), and the new machine getter left the buildkite/gitlab cases, the hostname-failure path, and the no-machine-identity fallbacks uncovered. Fixed in ee8b24d and 3c6ceff — both packages now report 100/100/100/100.
  • Test @percy/core (Windows leg only) failed on should retry by default on the snapshot discovery upto 3 times, which observed 2 retry log lines instead of 3. That is a timing assertion in packages/core; this PR touches only packages/env and packages/client, and the Linux core leg passed on the same commit. Re-ran the job and it passed, so it was flaky rather than related.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for freeto 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.

1 participant

@Shivanshu-07