Skip to content

Repair the UI e2e suite and run it in CI (gate PRs + auto-fix on main) - #53

Open
zeroliu wants to merge 2 commits into
mainfrom
claude/zen-khayyam-aae6f9
Open

zeroliu wants to merge 2 commits into
mainfrom
claude/zen-khayyam-aae6f9

Conversation

@zeroliu

@zeroliu zeroliu commented Jun 28, 2026 •

Copy link
Copy Markdown
Owner

What

Two related changes that make the Playwright UI e2e suite both correct and enforced:

  1. Repair the rotted suite (test/ui/*.e2e.ts) — it had drifted across several intentional UI refactors and no longer matched the app.
  2. Run it in CI (.github/workflows/e2e.yml) — it previously had no automated gate, which is exactly how it rotted silently across 0.1.4–0.1.6 (the release workflow runs typecheck + bun test + build, never e2e).

All product code (src/) is unchanged — this is test + harness + CI only.

Why the specs failed (not SSE/daemon bugs)

I reproduced the failures and verified the index/session-status SSE and the revision-banner SSE both emit correctly in the hermetic e2e env. The specs simply encoded a pre-refactor UI:

  • Index is now the app-shell sidebar (.sl-row + status glyphs), not .card/.chip; approved sessions live in a collapsed approved (n) disclosure.
  • New-revision banner renders only from r2 (revision ≥ 2, DECISIONS "banner from r2"); r1 is a first review with no banner.
  • An agent revision reply shows inline on the open thread, not a .thread-resolved collapse — only the reviewer's Resolve closes a thread.
  • A thread whose quote a later revision deletes detaches inline & muted; there is no orphan tray.
  • A Save-approve of the viewed session redirects home, so the artifact is asserted on disk.
  • The live console no longer auto-expands; the header switcher was replaced by the ☰ mobile session sheet.
  • Settings gained an "update" section; the rail jump lives on the quote/meta row, not the whole card.

Harness contention fix

The full suite shares one real daemon; high concurrency saturates it (keep-alive ECONNRESET, scaling ≈1 → 8 → 24 at 2 → 4 → 9 workers). playwright.config.ts now pins workers: 2 + retries: 2 (a test-harness concern, not a daemon bug — prod otacond serves one human + their agent). Recorded in DECISIONS.md.

CI workflow (.github/workflows/e2e.yml)

  • e2e job runs bun run e2e:ui (bun + Playwright chromium --with-deps) on every PR and on every push to main. PRs are gated; merges to main are verified.
  • autofix job runs only when the suite fails on a push to main: it sets up bun + the browser, then hands the failure to the Claude Code action (anthropics/claude-code-action@v1) to reproduce, fix the right side (app or stale test), and open a PR. Skipped on PRs (there the red check is the gate).

⚠️ One-time setup the autofix job needs (verified missing on this repo)

  1. Add an ANTHROPIC_API_KEY repository secret (Settings → Secrets and variables → Actions). (Currently no secrets are set.)
  2. Enable "Allow GitHub Actions to create and approve pull requests" (Settings → Actions → General → Workflow permissions). (Currently off.)

The e2e gating works without either — only the auto-fix step depends on them.

Verification

  • bun run e2e:ui → 58 passed, exit 0 (run twice; the retry budget absorbed transient resets).
  • bun test → 1066 pass, 0 fail.
  • bun run typecheck → clean.
  • This PR's own e2e check is the first real CI run of the suite (developed/verified on macOS; CI is Linux).

🤖 Generated with Claude Code

The Playwright UI e2e suite had rotted across several intentional UI
refactors and no longer matched the app. Two specs were known-failing
(acceptance, review), but `bun run e2e:ui` exercises the whole suite and
8 more specs were stale from the same changes.

The failures were NOT SSE/daemon bugs — verified the index/session-status
SSE and the revision-banner SSE both emit correctly in the hermetic e2e
environment. The specs encoded a pre-refactor UI:

- index is now the app-shell sidebar (`.sl-row` + status glyphs), not
  `.card`/`.chip`; approved sessions sit in a collapsed disclosure.
- the new-revision banner renders only from r2 (DECISIONS "banner from
  r2"); r1 is a first review with no banner.
- an agent revision reply is a response shown inline on the open thread,
  not a `.thread-resolved` collapse (only the reviewer's Resolve closes).
- a thread whose quote a later revision deletes detaches inline & muted —
  there is no orphan tray.
- a Save-approve of the viewed session redirects home, so the artifact is
  asserted on disk rather than via the (unseen) approved note.
- the live console no longer auto-expands; the header switcher is gone,
  replaced by the ☰ mobile session sheet.
- settings gained an "update" section; the rail jump lives on the quote/
  meta row, not the whole card.

Also cap the harness at `workers: 2` + `retries: 2`: the whole suite
shares one real daemon, and high concurrency saturates it (keep-alive
`ECONNRESET`, scaling with worker count). This is a test-harness concern,
not a daemon bug — production otacond serves one human plus their agent.

Verification: `bun run e2e:ui` green (58 passed, exit 0), `bun test`
(1066 pass), `bun run typecheck` clean. No product (`src/`) changes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 28, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Updates Playwright UI e2e tests to use sidebar row/glyph selectors, inline detached-thread assertions, approve-flow disk checks, responsive phone behavior changes, and Playwright concurrency limits. DECISIONS.md documents the harness constraint, and a new workflow runs E2E and main-branch autofix jobs.

Changes

UI e2e Test Suite Updates

Layer / File(s) Summary
Playwright harness config and docs
playwright.config.ts, DECISIONS.md
Sets workers: 2 and retries: 2; DECISIONS.md adds an entry describing the shared-daemon UI test setup and ECONNRESET behavior.
Sidebar row and glyph selectors
test/ui/index.e2e.ts, test/ui/delete.e2e.ts, test/ui/activity.e2e.ts
Replaces card/chip selectors with .sl-row, .sl-glyph, and .sl-unread, adds progress posting and row helpers, and updates row-based deletion and now-playing console interactions.
Inline detached thread and revision banners
test/ui/review.e2e.ts, test/ui/revisions.e2e.ts, test/ui/threads.e2e.ts
Changes revision-banner expectations and replaces resolved/orphan-tray assertions with inline muted/detached thread checks; thread jumping now targets the quote element.
Acceptance revision loop and approve verification
test/ui/acceptance.e2e.ts
Updates index glyph checks, r1 banner absence, r2/r3 inline reply and diff assertions, and approve-flow verification with .otacon/plans polling, mutation refusal, and approved read-only state checks.
Grill approve and phone layout checks
test/ui/grill.e2e.ts, test/ui/phone.e2e.ts
Adds filesystem-backed approved-artifact checks and sidebar glyph transitions in grill tests; updates phone approve flow, session sheet behavior, clean/delete paths, and responsive layout assertions.
Settings checks and E2E workflow automation
test/ui/settings.e2e.ts, .github/workflows/e2e.yml
Tightens settings assertions and adds the E2E workflow plus the main-branch autofix job.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: fixing the UI e2e suite and adding CI gating with an autofix job.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/zen-khayyam-aae6f9

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

… failure

The Playwright UI e2e suite had no automated gate — only the release
workflow runs (and it runs typecheck + bun unit tests + build, never
e2e), which is how the suite silently rotted across 0.1.4–0.1.6.

Add `.github/workflows/e2e.yml`:
- `e2e` job runs `bun run e2e:ui` (bun + Playwright chromium, --with-deps)
  on every pull_request and on every push to main. PRs are now gated;
  merges to main are verified.
- `autofix` job runs only when the suite fails on a push to main: it sets
  up bun + the browser, then hands the failure to the Claude Code action
  (anthropics/claude-code-action@v1) to reproduce, fix the right side
  (app or stale test), and open a PR. Skipped on PRs (the red check is the
  gate there).

One-time setup the workflow needs: the ANTHROPIC_API_KEY repo secret, and
"Allow GitHub Actions to create and approve pull requests" (Settings →
Actions → General) so the autofix job can open the PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@zeroliu zeroliu changed the title Repair the rotted UI e2e suite against the current UI Repair the UI e2e suite and run it in CI (gate PRs + auto-fix on main) Jun 28, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/e2e.yml:
- Around line 29-35: The e2e job is checking out repository code without
restricting the job token, so harden the workflow before running untrusted
repo-controlled steps. In the e2e job, add an explicit read-only permissions
block and update the actions/checkout@v4 step to disable credential persistence
with persist-credentials set to false, so the job does not retain broader token
access than needed.
- Around line 32-33: The workflow uses tag-pinned actions for actions/checkout
and oven-sh/setup-bun, which can be retargeted upstream. Update the uses
references in the e2e workflow to immutable full commit SHAs, and if helpful
keep the current semver tags in comments for readability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 10445395-57f9-4a60-9cfd-d9c05276ffb8

📥 Commits

Reviewing files that changed from the base of the PR and between 9dd5d12 and e364274.

📒 Files selected for processing (1)
  • .github/workflows/e2e.yml

Comment thread .github/workflows/e2e.yml
Comment on lines +29 to +35
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Harden the e2e job before running repository-controlled code.

actions/checkout leaves the repo token available to the job, so add an explicit read-only permissions: block and set persist-credentials: false on checkout. That keeps the test job from inheriting broader token access than it needs.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 32-32: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 29-51: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block

(excessive-permissions)


[error] 32-32: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 33-33: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[info] 29-29: workflow or action definition without a name (anonymous-definition): this job

(anonymous-definition)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/e2e.yml around lines 29 - 35, The e2e job is checking out
repository code without restricting the job token, so harden the workflow before
running untrusted repo-controlled steps. In the e2e job, add an explicit
read-only permissions block and update the actions/checkout@v4 step to disable
credential persistence with persist-credentials set to false, so the job does
not retain broader token access than needed.

Comment thread .github/workflows/e2e.yml
Comment on lines +32 to +33
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Pin workflow actions to immutable SHAs. The current uses: refs are tag-pinned only, so they can be retargeted upstream; pin each action to a full commit SHA and, if needed, keep the semver in a comment for readability.

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 32-32: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 32-32: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 33-33: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/e2e.yml around lines 32 - 33, The workflow uses tag-pinned
actions for actions/checkout and oven-sh/setup-bun, which can be retargeted
upstream. Update the uses references in the e2e workflow to immutable full
commit SHAs, and if helpful keep the current semver tags in comments for
readability.

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