Skip to content

Docs' browser specs run here: on each pull request's own Worker, and on preview before prd - #2

Merged
mmkal merged 5 commits into
mainfrom
specs
Nov 6, 2026
Merged

mmkal merged 5 commits into
mainfrom
specs

Conversation

@mmkal

@mmkal mmkal commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Docs' browser specs move here from iterate/private (whose half, iterate/private#215, deletes them), and gate what ships: every pull request gets its own Docs Worker and the specs against it, and main runs them against preview before it deploys prd. Stacked on #1.

# by hand, against any Docs Worker on main on dev's platform
doppler run --project os --config preview -- env WORKER_BASE_URL=https://os.iterate-dev-preview.workers.dev \
  DOCS_BASE_URL=https://docs-pr2.iterate-dev-preview.workers.dev pnpm spec

Change / Purpose

Change Purpose
test/playwright/docs/*.spec.ts iterate/private's seven Docs specs, byte for byte, at the same paths.
test/playwright/docs/support.ts, test/helpers/proxied-app-route.ts The specs' setup: the project's docs route to the Worker under test, and @iterate-com/docs installed at this repo's pkg.pr.new build of the commit (it was iterate/private's). proxiedAppRoute is copied from iterate's preview tooling, the one thing support.ts used from it.
test/helpers/{test,forged-session,operator,screenshot,auth-config,worker-base-url,fake-ai,fixture-slug,slugify}.ts The part of iterate/private's spec harness the specs use, each naming where it came from; the only edits are imports and appOrigin's app list.
test/playwright/global-setup.ts Replaces iterate's, which read any of its platforms from its envs.ts and core/os's config parser. This one knows two: a local platform (iterate's pnpm dev) and main on dev, whose admin bearer, password and secrets key come from Doppler os/preview.
test/playwright.config.ts, test/package.json, test/tsconfig.json, root spec script, pnpm-workspace.yaml iterate's config cut down to the docs and docs-phone projects, with its e2e policy's timeouts and one CI retry written out; test is a workspace package.
envs.ts pullRequestEnv, packages/docs-app/vite.config.ts pr<N> is a deployment: docs-pr<N> on the dev account, linked as preview. Its pkgPrNewRef is the PR head (PUBLISHED_PACKAGE_COMMIT), so "Install Docs" there installs the PR's own processors.
packages/docs-app/scripts/app.ts delete-pull-request Deletes docs-pr<N>, and only that: a 404 is fine. force=true, as Cloudflare refuses to delete a Worker that defines a Durable Object (BrowserSession) without it.
.depot/workflows/specs.yml On every PR: deploy docs-pr<N>, then the specs against it (6 browsers on a 4-vCPU runner), the report uploaded on failure.
.depot/workflows/pull-request-closed.yml Deletes the PR's Worker on close, after its specs run settles (shared concurrency group), with main's code: a head whose install broke still cleans up, and no PR code runs with the Doppler token. Depot registers the closed trigger once the file is on main.
.depot/workflows/deploy.yml Main: preview, then the specs against it, then prd. A red spec run stops prd and pages.
README.md, AGENTS.md, packages/docs-app/README.md, .gitignore How to run them, and test-results/ ignored.

Risk map

  • Main on dev is shared: the specs make fixture projects on os.iterate-dev-preview.workers.dev, which iterate/private's main redeploys on every push and resets nightly. A red iterate/private main can redden Docs' specs here. That is the coupling Docs already had, in the other direction; the report says which.
  • Main's specs wait for pkg.pr.new: support.ts polls up to two minutes for the commit's build. pkg-pr-new.yml runs beside Deploy and takes about a minute.
  • The closed trigger only works from main, so this PR's own docs-pr2 stays until it closes after merging (or pnpm --dir packages/docs-app delete-pull-request --pr 2).
  • Review order: specs.yml, deploy.yml, test/playwright/global-setup.ts, envs.ts, vite.config.ts, scripts/app.ts; the copied helpers and specs last.

Evidence

Claude Code session: local_cdd673f8-107f-4d2f-8087-ac4278554ee1 ("iterate/docs repo")

🤖 Generated with Claude Code

mmkal and others added 2 commits November 5, 2026 11:05
The tree main holds, Docs' two packages as iterate/private had them, made to stand alone:

- A pnpm workspace of packages/docs and packages/docs-app, with iterate/private's catalog
  versions, pnpm settings and zod patch. `iterate` comes from npm (a main build).
- The app's UI from the shadcn registry: shadcn's components, and iterate's (the app shell,
  PostHog, the stream link) as iterate's packages/ui has them. The few packages/ui/src/apps and
  packages/shared files it used are copied to src/app, each naming where it came from.
- envs.ts and the app's vite.config.ts and scripts/app.ts: the same Worker config iterate deploys
  (preview on the dev account, prd at docs.iterate.workers.dev), cut down from iterate's
  start-app.ts the way iterate/kit's was.
- CI on Depot (typecheck, lint, format, tests, the app's build) and main's deploy (preview, then
  prd, paging #error-pulse when red); pkg.pr.new and npm publishing on GitHub Actions, as
  iterate/private does.
- @iterate-com/docs points agents at its guide on iterate/docs, and the Docs app installs this
  repo's pkg.pr.new builds for a per-commit deployment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on preview before prd

iterate/private's test/playwright/docs, with the part of its spec harness they use, at the same
paths (test/playwright/docs, test/helpers), so the specs themselves are unchanged. They run against
main on dev's platform, with Doppler os/preview's credentials, and install this repo's pkg.pr.new
build of @iterate-com/docs.

- A pull request deploys its head as `docs-pr<N>` on the dev account (envs.ts `pullRequestEnv`),
  whose "Install Docs" installs that head's build, and runs the specs against it (specs.yml). Its
  Worker is deleted when it closes (pull-request-closed.yml, `delete-pull-request`).
- Main runs them against `preview` between its preview and prd deploys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pkg-pr-new

pkg-pr-new Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@iterate-com/docs@2

commit: 36098c3

@mmkal
mmkal marked this pull request as ready for review November 6, 2026 10:20
@cursor

cursor Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Adds gating production deploys on Playwright runs against shared dev infrastructure and introduces a Cloudflare worker deletion command that uses deploy credentials; mis-tuned CI or deletes could block shipping or remove the wrong worker.

Overview
Adds a full Playwright browser-spec suite under test/ (helpers, playwright.config.ts, global setup, seven playwright/docs specs) wired through a root pnpm spec script and workspace package.

CI and environments: New Depot workflows deploy per-PR docs-pr<N> Workers and run specs against them; another runs specs on preview before prd on main, with failure artifacts uploaded. A pull-request-closed workflow deletes the PR Worker using a new delete-pull-request CLI backed by Cloudflare’s API, and envs.ts/vite.config.ts gain pr<N> environments so those Workers install the correct pkg.pr.new commit.

Docs and repo hygiene: README/AGENTS explain pnpm spec, .gitignore drops Playwright output, and lockfiles include Playwright/middlewright deps.

Risk is moderate because production deploys now depend on cross-repo Playwright runs against shared dev infrastructure and a new Cloudflare deletion path that uses deploy credentials; misconfiguration could block releases or remove the wrong worker.

Reviewed by Cursor Bugbot for commit 36098c3. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor 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.

Stale Bugbot comment from a previous run.

Comment thread packages/docs-app/scripts/app.ts Resolved
…bject

Cloudflare refuses to delete a script that defines a Durable Object
class (BrowserSession) without `force=true`; iterate/private's preview
cleanup passes it for the same reason. Found by Cursor Bugbot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mmkal
mmkal changed the base branch from standalone to main November 6, 2026 10:28
mmkal added a commit that referenced this pull request Nov 6, 2026
Docs builds, tests, publishes and deploys from iterate/docs, with nothing from iterate's monorepo but published packages. Main already holds Docs' history (56 commits, see "History" below). This PR is the one commit that makes that tree stand alone, as iterate/kit#1 did for Kit.

Its other half removes Docs from iterate/private (linked once open). The cutover order is at the end.

## What changes for people

Nothing, once both halves land: the same Workers (`docs` at docs.iterate.workers.dev, which the iterate project's `docs` slug and docs.iterate.com route to, and `docs` at docs.iterate-dev-preview.workers.dev), the same `ITERATE_APP`, the same package name. What moves:

```
before: https://pkg.pr.new/iterate/private/@iterate-com/docs@<sha>
after:  https://pkg.pr.new/iterate/docs/@iterate-com/docs@<sha>
        npm: @iterate-com/docs@<version>-main.<date>-<sha>, published from here (needs the npm step below)

before: https://raw.githubusercontent.com/iterate/packages/main/packages/docs/AGENTS.md   (what installDocs writes into a project's AGENTS.md)
after:  https://raw.githubusercontent.com/iterate/docs/main/packages/docs/AGENTS.md
```

## Change / Purpose

| Change | Purpose |
| --- | --- |
| `package.json`, `pnpm-workspace.yaml`, `pnpm-lock.yaml`, `patches/zod@4.6.5.patch`, `tsconfig.{base,app}.json`, `.nvmrc` | A two-package pnpm workspace. The catalog is iterate/private's versions for what Docs uses, so `catalog:` in the packages' manifests stays as it was. `iterate` is npm's `0.4.1-main.20261105T063432Z-a81a857` (iterate/private's main today), let past the one-day release age like the Cloudflare toolchain. zod's patch (a ZodError's message across Durable Object RPC) comes along, as Kit's did. |
| `packages/docs-app/src/components/**`, `src/hooks/use-mobile.ts`, `src/lib/plain-left-click.ts`, `src/styles/{globals,iterate,tokens}.css`, `components.json` | The UI that came from `@iterate-com/ui` in the workspace. Its npm build bundles React for no-build pages, so a Start app can't use it; the app takes the components from the shadcn registry instead, like Kit: shadcn's `base-nova` ones and iterate/packages' `project-app-shell`, `stream-link`, `posthog`, `first-project-redirect`, `environment-head-content`, `route-defaults` and their dependencies, each file byte-identical to iterate's packages/ui. |
| `packages/docs-app/src/app/*` | The six `packages/ui/src/apps` files (base path, document, head, providers, router, server) and two `packages/shared` ones (`ITERATE_APP`'s schema, the PostHog proxy) the app imported, copied with a header naming where from. |
| `packages/docs-app/src/**` imports | `@iterate-com/ui/…` and `@iterate-com/shared/…` become `#/components/…` and `#/app/…`. No other change to what the app does. |
| `envs.ts`, `packages/docs-app/vite.config.ts`, `packages/docs-app/scripts/app.ts` | The Worker config iterate's `startAppWorkerConfig` wrote for Docs, cut down the way Kit's was: same name, account, bindings, compatibility date, observability, `run_worker_first` and `ITERATE_APP` (every link, `denyZones` copied from iterate's `ownZones()`). `deploy --env <name>` builds, `wrangler deploy`s with `_shared`'s Cloudflare token, and smokes `/healthz`; `generate-route-tree` as before. |
| `packages/docs-app/src/routes/_auth/projects.$slug.$repo.$.tsx` | "Install Docs" on a per-commit deployment installs `pkg.pr.new/iterate/docs/…@<commit>`; `iterate/package-builds` `buildVersion` names iterate/private's builds. Production still installs npm's `main`. |
| `packages/docs/src/install.ts` (+ test) | `docsAgentGuide` names iterate/docs. iterate/private's half keeps the old URL answering with a pointer here. |
| `packages/docs/src/processor.test.ts` | Casts where the test passes an engine or checkpoint table between `iterate/stream/processor` and `iterate/stream/test-support`. iterate's npm build declares those classes twice (`core/lib/tsdown.config.ts` builds test-support in its node build), so TypeScript sees two `#private` fields. One class at runtime; a fix in core/lib would drop the casts. |
| `packages/docs/src/processor.ts`, the `$.tsx` route | Two `oxlint-disable` comments for iterate's own lint plugin, which isn't here, become plain comments. |
| `.depot/workflows/ci.yml`, `.depot/actions/setup`, `scripts/ci/toolchain.sh` (+ test) | Depot CI: typecheck, lint, format, both Vitest suites and the app's build on every PR and main push. The setup and toolchain are iterate's and Kit's. |
| `.depot/workflows/deploy.yml`, `scripts/ci/page.ts` | Main deploys `preview`, then `prd`; a red run pages #error-pulse (Kit's pager, with `_shared/prd`'s bot token). |
| `.github/workflows/pkg-pr-new.yml` | `@iterate-com/docs` on pkg.pr.new for every main commit and every PR head (iterate/private published a PR only when a package's inputs changed; here nearly every PR touches the package or the app that installs it). |
| `.github/workflows/npm-publish.yml`, `scripts/ci/npm-publish.ts` (+ test) | iterate/private's npm publish, unchanged but for where it finds the package list and the repo it names in setup commands. |
| `README.md`, `AGENTS.md`, `doppler.yaml`, `LICENSE`, `.oxlintrc.json`, `.oxfmtrc.json`, `.gitignore`, package READMEs | The repo's map, rules and history; Apache-2.0, as both packages were. Lint config is Kit's (iterate's less its own plugin). |

## History

Main starts with Docs' own commits, the tip's tree byte-identical to iterate/private@a541c9d's `packages/docs` and `packages/docs-app`:

- 36 from the iterate/iterate archive (2026-07-29 to 2026-10-02): `packages/docs`, and `apps/docs` written as `packages/docs-app`. Each title's `(#N)` reads `(iterate/iterate#N)`, and each ends in `Original-Commit: iterate/iterate@<sha>`.
- 20 from iterate/packages, the public copies of iterate/private's commits since, whose messages copybara already cut to what is public. Each ends in `Original-Commit: iterate/packages@<sha>` beside copybara's `GitOrigin-RevId`.

## Done outside the diff

- **Repo**: iterate/docs, public (projects install its package; agents read its AGENTS.md), with iterate/kit's merge settings (squash with the PR's title and body). No rulesets yet.
- pkg.pr.new's and Depot's GitHub Apps are on every iterate repo, so neither needed setting up.

## Still to do

- **npm**: `@iterate-com/docs`'s trusted publisher names iterate/private's `npm-publish.yml`. Until a maintainer adds iterate/docs (`npx npm@latest trust github @iterate-com/docs --repo iterate/docs --file npm-publish.yml --allow-publish`, then tick "Allow npm dist-tag" at https://www.npmjs.com/package/@iterate-com/docs/access), **npm / check** stays red here and main's npm run fails. Its job summary prints the commands.
- **Browser specs**: iterate/private's `test/playwright/docs` move here in a follow-up PR, run against the dev platform.

## Risk map

- **The copied UI is the riskiest part**: the app's look and its base-path handling under a project's routes now run on copies (`src/app/*`, `src/components/**`), not the workspace's packages/ui. They are byte-identical to iterate/private@a541c9d, so the risk is drift later, not a difference now.
- **Two writers until the cutover**: while iterate/private still has `deploy-docs.yml` and `preview-parents.yml`, a main push there redeploys the same Workers from its copy. The code is the same today, so stale, not broken; the cutover order below avoids it.
- **npm**: main's npm job is red here until the trusted publisher moves (above), and iterate/private keeps publishing `@iterate-com/docs` until its half lands.
- Review order: `packages/docs-app/vite.config.ts` and `envs.ts` (what deploys where), `.depot/workflows/deploy.yml`, the two `.github/workflows`, `packages/docs-app/src/routes/_auth/projects.$slug.$repo.$.tsx`, `packages/docs/src/install.ts`; the copied files (`src/app`, `src/components`) only for their headers.

## Cutover

1. Merge iterate/private's half. Its `deploy-docs.yml`, Docs' per-PR previews and `preview-parents.yml`'s Docs redeploy go with it, and the Workers keep their last deploy.
2. Merge this. Main deploys `preview` and `prd`.
3. The npm step above, then re-run npm's failed job here.

## Evidence

- **CI** on Depot (typecheck, lint, format, both Vitest suites, the app's build) green on this PR with no setup beyond the push; **pkg.pr.new** published `@iterate-com/docs` for its head (`pkg.pr.new/iterate/docs/@iterate-com/docs2cf1c08…` answers 200).
- **npm / check** red, as expected: "@iterate-com/docs does not trust this workflow to publish it (npm answered 404 …)", with the setup commands in its summary.
- **iterate's Docs specs against this build**: built with `CLOUDFLARE_ENV=preview`, deployed to a throwaway Worker on the dev account (`docs-standalone-check`), and iterate/private's own `--project docs` specs run from its main against it, served through fixture projects on main on dev: `8 passed (53.8s)`. Then the same specs from #2, installing this PR's pkg.pr.new build: `10 passed (50.2s)` with the phone runs.
- `CLOUDFLARE_ENV=preview vite build` writes the Worker config iterate/private's `startAppWorkerConfig` writes for Docs: name, account, compatibility date and flags, bindings, observability, `run_worker_first` and `ITERATE_APP` (every link and deny zone) equal.
- Not exercised yet: `deploy.yml` (main only), `scripts/ci/page.ts` (a red main run only), npm's `publish` job (main only, and needs the trusted publisher).

Claude Code session: `local_cdd673f8-107f-4d2f-8087-ac4278554ee1` ("iterate/docs repo")

🤖 Generated with [Claude Code](https://claude.com/claude-code)
… has

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

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 90c7895. Configure here.

The close workflow checked out the pull request, so a head that broke
the install could not delete its own docs-pr<N>, and the PR's code ran
with the Doppler token. Found by Cursor Bugbot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mmkal
mmkal merged commit fba5c21 into main Nov 6, 2026
6 of 7 checks passed
@mmkal
mmkal deleted the specs branch November 6, 2026 10:37
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