Skip to content

ci(e2e): daily production read-only canary workflow#3191

Open
punk6529 wants to merge 1 commit into
mainfrom
claude/prod-e2e-canary
Open

ci(e2e): daily production read-only canary workflow#3191
punk6529 wants to merge 1 commit into
mainfrom
claude/prod-e2e-canary

Conversation

@punk6529

@punk6529 punk6529 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Issue

Production has no scheduled E2E of any kind: the prod deploy workflow runs no post-deploy packs, and the experience can break for users with zero frontend deploys involved — backend releases, data issues, third-party SDK changes (see the 2026-07-07 wave-crash incident, where prod broke and no staging-E2E-style gate existed on the prod path). PR 3 of the E2E architecture campaign.

Fix

A daily cron workflow that answers one question: is production working for users right now, whoever's fault?

Changes

  • .github/workflows/prod-canary.yml — daily at 05:30 UTC (offset from the 04:00 Device Farm crons so failures arrive as distinct signals) + workflow_dispatch
  • Runs ./bin/6529 run e2e:packs -- --env production --trigger cron → resolves the 10 read-only production packs from tests/packs.manifest.ts (desktop chromium, workers=1), per-pack step-summary rows
  • Read-only enforced at the network layer by the readonly mutation guard, not by convention; no secrets needed (prod is public, unauthenticated packs)
  • Playwright artifacts on failure; Discord alert on scheduled failure (same pattern as Device Farm QA)

Validation

  • YAML parses; single cron 30 5 * * *
  • Pack resolution verified locally: --env production --trigger cron --list → exactly the 10 canary packs, manifest order
  • Runner hard-fails on empty resolution, so a manifest regression can't produce a silent green canary

Risk

Low. New workflow only; touches no existing paths. Merge order: requires #3190 (manifest + runner) on main first — until then the cron would fail loudly on the missing script (fail-loud, not false-green).

Review Notes

  • Estimated runtime ~30–40 min daily; zero cost beyond Actions minutes
  • Prod already gets these packs' specs — but only when a human remembers to run them manually; this makes it a heartbeat

🤖 Generated with Claude Code

Production has no scheduled E2E: the prod deploy workflow runs no
post-deploy packs, and backend releases, data issues or third-party
changes can break the user experience without any frontend deploy at
all (see the 2026-07-07 wave-crash incident). Add a daily cron that
runs the manifest-resolved production canary packs (10 read-only packs,
desktop chromium) via scripts/e2e-packs.cjs against 6529.io, with
artifact upload and a Discord alert on scheduled failure.

Read-only is enforced by the readonly mutation guard at the network
layer; no secrets are needed because production is public.

Merge order: requires #3190 (pack manifest + runner) on main first.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Punk 6529 <108035228+punk6529@users.noreply.github.com>
@punk6529
punk6529 requested a review from a team July 7, 2026 23:05
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 8 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: b8873fb6-50a4-40a2-8280-3f70111af25f

📥 Commits

Reviewing files that changed from the base of the PR and between 29dbcda and 2ca2057.

📒 Files selected for processing (1)
  • .github/workflows/prod-canary.yml
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/prod-e2e-canary

Comment @coderabbitai help to get the list of available commands.

@6529bot

6529bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

6529bot WCAG 2.2 AA analysis - 2ca2057

Verdict: No WCAG findings

This PR adds a CI-only GitHub Actions workflow (.github/workflows/prod-canary.yml) for a scheduled production E2E canary. It contains no user-facing UI, markup, styling, or client-side code, so WCAG 2.2 AA success criteria do not apply here.

@6529bot

6529bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

6529bot general PR review - 2ca2057

Verdict: Good to merge

This is a well-constructed CI workflow: pinned action SHAs, minimal contents: read permissions, persist-credentials: false, non-cancelling concurrency, and a bounded timeout. The dependency chain on #3190 (scripts/e2e-packs.cjs, tests/packs.manifest.ts) is called out in the PR description, and read-only enforcement is delegated to the network guard rather than convention.

Nice-to-have

  • .github/workflows/prod-canary.yml:83-87 — The Discord notify step references secrets.DISCORD_WEBHOOK. If that secret is unset in the repo, sarisia/actions-status-discord silently no-ops, so a real production outage could fail silently with no alert. Consider a guard (e.g. skip with a warning when the webhook is empty) or documenting that the secret must exist for the canary to be useful.
  • .github/workflows/prod-canary.yml:69-70 — The workflow always runs --trigger cron even on workflow_dispatch. That's fine functionally, but manual dispatches will look like scheduled runs; the failure notification, however, is correctly gated to github.event_name == 'schedule', so manual failures produce no alert and no cron-specific signal. Confirm that's the intended behavior for manual reruns.

No blocking or correctness issues found in the diff. Note the workflow's real behavior depends on unmerged code in #3190, which is outside this diff's scope and could not be verified here.

@6529bot

6529bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

6529bot i18n analysis - 2ca2057

Verdict: No i18n findings

This PR adds a single CI-only GitHub Actions workflow (.github/workflows/prod-canary.yml) for a scheduled production E2E canary. There is no user-facing React UI, no visible copy or accessible names, and no locale-sensitive formatting in scope.

The only strings present (workflow/job/step names and the Discord failure title/description at lines 89–90) are CI operator-facing notifications, not app UI, so the i18n message-structure and formatting-helper requirements do not apply.

Note: coverage is scoped to the single changed workflow file; no localizable frontend surfaces were touched.

@6529bot

6529bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

6529bot crypto security analysis - 2ca2057

Verdict: No security findings

This PR adds a single CI-only GitHub Actions workflow (.github/workflows/prod-canary.yml) for a scheduled read-only production E2E canary. There is no wallet, auth, signature, token, or crypto/web3 code in scope.

From a crypto-security lens the workflow is sound:

  • Minimal permissions: contents: read and persist-credentials: false (lines 23–24, 39) prevent token leakage/credential persistence in the checkout.
  • Action versions are pinned to full commit SHAs (lines 37, 42, 54, 74, 84), reducing supply-chain tampering risk.
  • The only secret used, secrets.DISCORD_WEBHOOK (line 87), is passed via env to a pinned action and never echoed; the notification body (lines 89–90) interpolates only trusted GitHub context (server_url, repository, run_id), so no injection or secret-leak path.
  • Read-only enforcement is delegated to the network-layer mutation guard (PLAYWRIGHT_READONLY / production base URL) per the comments; the actual guard logic lives in unmerged test(e2e): pack manifest as single source of truth with sync + runner #3190 and is out of scope here.

No signature, nonce, chain-id, address-normalization, session, or transaction logic is touched, so the crypto/web3 review focus does not apply to this diff.

Note: coverage is limited to the single changed workflow file; the referenced runner/manifest code in #3190 is not part of this diff and was not reviewed.

@sonarqubecloud

sonarqubecloud Bot commented Jul 7, 2026

Copy link
Copy Markdown

@6529bot

6529bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

6529bot GLM Swarm Review

Verdict: Advisory only

This GLM swarm is advisory and complements, not replaces, existing tests and existing reviewbots.

Important

  • .github/workflows/prod-canary.yml:69-70 — Read-only enforcement is not explicitly configured. The workflow relies on --env production to activate the readonly mutation guard inside scripts/e2e-packs.cjs / Playwright config, but never sets PLAYWRIGHT_READONLY explicitly nor asserts the guard is active before running. If the env→readonly mapping regresses (e.g., arg-parsing refactor, NODE_ENV vs --env branch mismatch), this cron could execute mutating tests against real production users. Add an explicit env export and/or an early fail-fast assertion that the resolved config reports readonly=true.
  • .github/workflows/prod-canary.yml:70 — No verification that the manifest yields packs for --env production --trigger cron. If tests/packs.manifest.ts resolves to zero matching packs, e2e:packs may exit 0 having run nothing, making the canary a silent no-op. Add a deterministic test asserting the manifest resolves to a non-empty list of readonly packs for {env:'production', trigger:'cron'}.

Nice-to-have

  • .github/workflows/prod-canary.yml:83-91 — Discord notification only fires for schedule events. workflow_dispatch failures produce no alert. If manual-run alerts are desired, drop the github.event_name == 'schedule' condition or add a separate dispatch notification.
  • .github/workflows/prod-canary.yml:46-50corepack prepare relies on packageManager with no assertion that the activated pnpm version matches CI elsewhere. Consider a version check step to catch drift.

Testing feedback loop

  • Add a unit test in scripts/e2e-packs.cjs's test file (or new __tests__/e2e-packs.test.cjs) asserting that parsing --env production sets the readonly guard env/config to true before Playwright launches.
  • Add tests/packs.manifest.test.ts asserting non-empty readonly pack resolution for {env:'production', trigger:'cron'}; Codex should run this on every change to the manifest or resolver.

Partial reviewer output

One or more internal advisory reviewer slices were unavailable; the synthesis used the remaining reviewer output.

  • runtime-ops-config: empty_output

@6529bot

6529bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

6529bot responsiveness review - 2ca2057

Verdict: Responsive checks passed

Root Cause / Summary

All 32 checks passed with 0 failures across web-desktop, web-mobile, native-mobile, and electron-desktop. No blank screenshots, no contentReady=false, no Next.js overlay errors, and no build-asset failures (nextAssetFailures=0 everywhere). The 14 warnings are dominated by two expected/simulation-related patterns: native Capacitor plugin shim gaps and full-page screenshot timeouts on tall pages. Layout branches and platform contracts behaved correctly (native shell markers present, Electron branch active).

Blocking Findings

None. No deterministic failures, no blank/near-uniform evidence unexplained, no missing native shell contract, no Electron branch failure, and no Next.js boot/overlay errors.

Non-Blocking Findings

  • Native EULA gate blocks page content (expected simulation behavior): On native-mobile for /, /waves, /the-memes, /meme-lab, /meme-calendar, the "End User License Agreement / Agree" modal covers the route content (the-memes, waves, meme-calendar). The modal itself renders cleanly and the bottom navigation (height 64) is present, so the app shell contract holds — this is a first-run gate, not a layout bug.

  • Native Capacitor plugin shims unavailable (simulation limitation): Every native-mobile route warns Keyboard plugin shim is unavailable and App plugin shim is unavailable. Expected in the browser-level Capacitor simulation; hasCapacitorNativeClass=true and viewport-fit=cover are correctly present, so the simulated app-shell contract is satisfied.

  • Full-page screenshot timeouts on tall routes (timing/tooling): native-mobile /network produced no screenshot (20s + 10s fallback timeout); native-mobile /the-memes and web-mobile /meme-lab fell back to viewport captures. All three still reported contentReady=true, so these are capture-timing issues on very long pages, not render failures.

  • Transient blank dev-server retry on first navigation (timing): web-desktop /meme-lab, /rememes, and /meme-calendar each retried after an initial 12s page.goto timeout, then rendered fully on retry (meme-lab, meme-calendar). Consistent with dev-server cold-compile latency.

  • Isolated console errors: electron-desktop /rememes (2), web-mobile /rememes (2), and several native routes reported 2–4 console errors. Non-fatal; pages rendered. Note the web-mobile /rememes capture shows a persistent "Fetching …" state with empty content (screenshot) — likely slow data fetch rather than a layout defect, but worth a glance given the paired console errors.

  • web-mobile /waves visibleTextLength=0: The capture shows only header + loading skeleton area (screenshot); contentReady=true via shell/interactive signals. Expected feed hydration timing, not a failure.

Platform Coverage

  • web-desktop (1440x900): WebLayout/sidebar rendered correctly across all routes; layoutRootDataMobile=false, no bottom nav. Discover, network, waves, memes, meme-lab, and calendar all look well-composed (discover, [waves

Screenshot evidence: native-mobile /the-memes, native-mobile /rememes, native-mobile /, native-mobile /meme-lab, native-mobile /discover, native-mobile /waves, native-mobile /meme-calendar, web-desktop /meme-lab, web-desktop /rememes, web-desktop /meme-calendar, web-mobile /meme-lab, electron-desktop /rememes and 19 more in the details.

Deterministic responsiveness details

Verdict: Responsive checks passed

Responsiveness runner summary

6529bot Responsiveness Summary

Status: pass
Duration: 448.4s
Profile: 6529 Seize frontend
Contexts: web-desktop, web-mobile, native-mobile, electron-desktop
Routes: /, /waves, /network, /the-memes, /meme-lab, /rememes, /meme-calendar, /discover
Checks completed: 32/32
Failures: 0
Warnings: 14

Platform Context

  • web-desktop should exercise WebLayout/sidebar at 1440x900.
  • web-mobile should exercise SmallScreenLayout, not the native AppLayout.
  • native-mobile/native-ios/native-android are fast browser-level Capacitor simulations of AppLayout, bottom navigation, viewport-fit, keyboard/app/deep-link plugins, and body class.
  • electron-desktop is a fast browser-level Electron renderer simulation using the Electron user-agent branch; it is not a packaged desktop app launch.
  • Access/restricted pages intentionally bypass the standard app layout shell.

Platform Matrix

  • electron-desktop: 8 check(s), failures=0, warnings=1, avg=24.3s
  • native-mobile: 8 check(s), failures=0, warnings=8, avg=28.2s
  • web-desktop: 8 check(s), failures=0, warnings=3, avg=35.0s
  • web-mobile: 8 check(s), failures=0, warnings=2, avg=19.4s

Warnings

  • electron-desktop /rememes: 2 console error(s)
  • native-mobile /discover: 6529 native profile: Keyboard plugin shim is unavailable; 6529 native profile: App plugin shim is unavailable; 2 console error(s)
  • native-mobile /meme-calendar: 6529 native profile: Keyboard plugin shim is unavailable; 6529 native profile: App plugin shim is unavailable; 2 console error(s)
  • native-mobile /meme-lab: 6529 native profile: Keyboard plugin shim is unavailable; 6529 native profile: App plugin shim is unavailable; 2 console error(s)
  • native-mobile /network: screenshot unavailable after content rendered: screenshot failed: page.screenshot: Timeout 20000ms exceeded. Call log: �[2m - taking page screenshot�[22m �[2m - waiting for fonts to load...�[22m �[2m - fonts loaded�[22m ; viewport fallback failed: page.screenshot: Timeout 10000ms exceeded. Call log: �[2m - taking page screenshot�[22m �[2m - waiting for fonts to load...�[22m �[2m - fonts loaded�[22m ; 6529 native profile: Keyboard plugin shim is unavailable; 6529 native profile: App plugin shim is unavailable; 2 console error(s)
  • native-mobile /rememes: 6529 native profile: Keyboard plugin shim is unavailable; 6529 native profile: App plugin shim is unavailable; 4 console error(s)
  • native-mobile /: 6529 native profile: Keyboard plugin shim is unavailable; 6529 native profile: App plugin shim is unavailable; 2 console error(s)
  • native-mobile /the-memes: full-page screenshot failed; used viewport fallback: page.screenshot: Timeout 20000ms exceeded. Call log: �[2m - taking page screenshot�[22m �[2m - waiting for fonts to load...�[22m �[2m - fonts loaded�[22m ; 6529 native profile: Keyboard plugin shim is unavailable; 6529 native profile: App plugin shim is unavailable; 2 console error(s)
  • native-mobile /waves: 6529 native profile: Keyboard plugin shim is unavailable; 6529 native profile: App plugin shim is unavailable; 2 console error(s)
  • web-desktop /meme-calendar: route check retried after transient blank dev-server attempt: /meme-calendar: 6529 app shell did not render meaningful content within 15.0s; visibleTextLength=0; visibleInteractiveElements=0; visibleAppShellElements=0; signals=none; page.goto: Timeout 12000ms exceeded. Call log: �[2m - navigating to "http://localhost:3001/meme-calendar", waiting until "commit"�[22m
  • web-desktop /meme-lab: route check retried after transient blank dev-server attempt: /meme-lab: 6529 app shell did not render meaningful content within 15.0s; visibleTextLength=0; visibleInteractiveElements=0; visibleAppShellElements=0; signals=none; page.goto: Timeout 12000ms exceeded. Call log: �[2m - navigating to "http://localhost:3001/meme-lab", waiting until "commit"�[22m
  • web-desktop /rememes: route check retried after transient blank dev-server attempt: /rememes: 6529 app shell did not render meaningful content within 15.0s; visibleTextLength=0; visibleInteractiveElements=0; visibleAppShellElements=0; signals=none; page.goto: Timeout 12000ms exceeded. Call log: �[2m - navigating to "http://localhost:3001/rememes", waiting until "commit"�[22m
  • web-mobile /meme-lab: full-page screenshot failed; used viewport fallback: page.screenshot: Timeout 20000ms exceeded. Call log: �[2m - taking page screenshot�[22m �[2m - waiting for fonts to load...�[22m �[2m - fonts loaded�[22m
  • web-mobile /rememes: 2 console error(s)

Slowest Checks

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.

1 participant