feat(core): explicit runtime field gates maestro-screenshot self-hosted detection (R2)#2264
Merged
Sriram567 merged 1 commit intoJun 2, 2026
Conversation
…lf-hosted detection (R2)
Promotes the self-hosted-vs-BrowserStack discriminator in the relay's
/percy/maestro-screenshot handler from an implicit signal (sessionId
absence) to an explicit one (runtime: "selfhosted" | "browserstack"
in the SDK payload). The sessionId-absent fallback stays for backward
compatibility with SDKs that predate the runtime field.
Why: cli#2261's `let selfHosted = !sessionId;` derives the runtime
from a field's absence. If BS ever omits sessionId in a future code
path (retry, new session type), the self-hosted branch activates by
accident → wrong file-find scope → 404. Moving the declaration to the
SDK (where the knowledge originates — the SDK knows whether
PERCY_SESSION_ID was injected) eliminates that future-proofing risk.
Wire contract (additive, fully back-compat):
selfHosted = (runtime === "selfhosted") || (!runtime && !sessionId)
Unknown runtime values are NOT rejected — the relay falls back to the
sessionId check, so SDKs experimenting with future values
("maestro-cloud", "saucelabs", etc.) don't break. Two `percy.log.debug`
lines surface bidirectional inconsistencies (runtime + sessionId
disagree) for diagnostic surface, never failing the request.
R7 (BS regression) preserved — when SDK emits runtime: "browserstack"
+ sessionId, the BS branch runs byte-identically to today.
Tests:
- 9 new scenarios for the runtime field gating (8-way matrix of
runtime × sessionId presence, plus the type-validation 400).
- Existing /percy/maestro-screenshot tests unchanged.
Stacks on cli#2261; companion SDK PR (percy-maestro-app) ships the
runtime field in a future @percy/maestro-app release. Relay works
today with older SDKs via the back-compat fallback.
Origin: percy-maestro/docs/brainstorms/2026-06-02-selfhosted-followup-bundle-requirements.md (R2)
Plan: percy-maestro/docs/plans/2026-06-02-001-feat-explicit-runtime-field-plan.md (Unit 2)
Sriram567
added a commit
to percy/percy-maestro-app
that referenced
this pull request
Jun 2, 2026
…ayload Promotes the self-hosted-vs-BrowserStack discriminator from an implicit relay-side check (sessionId absence) to an explicit SDK-side declaration. The SDK now emits `runtime: "browserstack" | "selfhosted"` in every maestro-screenshot POST, derived from PERCY_SESSION_ID presence — the same discriminator that drove the implicit relay-side check before this release. Why: cli#2261's relay handler infers the runtime from a field's absence (`let selfHosted = !sessionId;`). If BS ever omits sessionId in a future code path — a new session type, a retry that doesn't re-inject — the self-hosted branch activates by accident → wrong file-find scope → 404. Moving the declaration to the SDK (which has perfect knowledge of whether PERCY_SESSION_ID was injected) eliminates that future-proofing risk. Wire-contract: additive, non-breaking. - CLIs that predate the runtime-field gating (cli ≤ #2261) ignore the field; the SDK and relay are decoupled in their roll-out. - CLIs with the field gating in place (cli#2264+) prefer this field; fall back to sessionId-absent for older SDKs. Companion CLI PR: percy/cli#2264. Origin: docs/brainstorms/2026-06-02-selfhosted-followup-bundle-requirements.md (R2) Plan: docs/plans/2026-06-02-001-feat-explicit-runtime-field-plan.md (Unit 1)
ac86447
into
feat/self-hosted-maestro-percy-v1
38 of 40 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacks on #2261. Promotes the self-hosted-vs-BrowserStack discriminator in the
/percy/maestro-screenshotrelay handler from an implicit signal (sessionIdabsence, introduced by #2261) to an explicit one —runtime: "selfhosted" | "browserstack"in the SDK payload. ThesessionId-absent fallback stays for backward compatibility with SDKs that predate the runtime field.Companion SDK change ships the field in a future
@percy/maestro-apprelease (tracked underpercy-maestro/docs/plans/2026-06-02-001-feat-explicit-runtime-field-plan.mdUnit 1, blocked behindpercy-maestro-app#7). The relay works correctly today with older SDKs via the backward-compat fallback.Why now
cli#2261's relay handler infers the runtime from a field's absence:
This works today (R7 verified on BS canary builds #22 and #23). The brittleness: if BS ever omits
sessionIdin a future code path — a new session type, a retry that doesn't re-inject — the self-hosted branch activates accidentally → wrong file-find scope → 404. Moving the declaration to the SDK (where the knowledge originates — the SDK knows whetherPERCY_SESSION_IDwas injected) eliminates that future-proofing risk.The field is also semantically clearer for code review: today
sessionIdin this handler means "BS App Automate session" but in sibling Appium SDKs it means "Appium driver session UUID" (which exists in both runtimes). Addingruntimemakes the wire contract self-documenting.What changes
packages/core/src/api.js:The
selfHostedboolean propagates through the existing handler logic unchanged — only its source-of-truth shifts from implicit to explicit.Testing
9 new scenarios under a new
describe('runtime field gating')block. Covers the 8-way matrix of(runtime ∈ {undefined, "selfhosted", "browserstack", "unknown-value"}) × (sessionId ∈ {present, absent})plus the type-validation 400. Pre-existing/percy/maestro-screenshottests are unchanged.runtimesessionId"selfhosted"Missing required env: PERCY_MAESTRO_SCREENSHOT_DIR"selfhosted""browserstack""browserstack""unknown-value""unknown-value"Invalid runtime: must be a stringR7 (BS regression) preserved — the explicit
runtime: "browserstack"+sessionIdpath runs byte-identically to today'ssessionId-only path.Origin
percy-maestro/docs/brainstorms/2026-06-02-selfhosted-followup-bundle-requirements.md(R2)percy-maestro/docs/plans/2026-06-02-001-feat-explicit-runtime-field-plan.md(Unit 2)Stacking
feat/self-hosted-maestro-percy-v1(cli#2261). Rebase tomasteronce feat(cli): self-hosted (non-BrowserStack) Maestro + Percy support — V1 #2261 merges.Post-Deploy Monitoring & Validation
percy.log.debuglines — they appear when SDK declarations andsessionIdpresence disagree. Non-zero rate in production would indicate a customer misconfiguration or an upstream BS bug.[BROWSERSTACK_TESTSUITE_PARSE_ERROR]orScreenshot not foundrate post-deploy. Should be unchanged.183.177.55.134) and iOS (103.234.68.130) Maestro v2 hosts. Expected: snapshots produce identically pre/post deploy.runtimefield yet; relay falls back tosessionId-absent path).[percy] Screenshot not founderrors on BS or self-hosted builds compared to baseline.Snapshot command was not calledpost-deploy → revert immediately (back-compat path broken).🤖 Generated with Claude Opus 4.7 via Claude Code + Compound Engineering v2.54.0