You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 4b2ada4
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: AGENTS.md
+8-5Lines changed: 8 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@
5
5
- The repository is DebateLab. Never infer its directory from an old repository name.
6
6
- Run `git rev-parse --show-toplevel` and stay inside that returned worktree. On Adam's VPS, `/home/codex/Projects/DebateLab` is the primary checkout, but Superset and other agents use linked worktrees elsewhere.
7
7
- Before editing, inspect the branch and working tree. Preserve unrelated changes.
8
-
- Use Node 22, npm, and the committed `package-lock.json`. Install with `npm ci`.
8
+
- Use Node 22, npm, and the committed `package-lock.json`. `.nvmrc` pins 22, but the VPS default is Node 24: check `node -v` and run `nvm use` (with `NVM_DIR=$HOME/.nvm` set) when it isn't 22. Install with `npm ci` when `node_modules` is missing.
9
9
10
10
## Parallel Superset workspaces
11
11
@@ -30,7 +30,7 @@ The frontend is hosted on Vercel at `https://debate.pi-stack.org`. Merging to `m
30
30
## Normal ports
31
31
32
32
- Vite development server: `8080` by default outside Superset; Superset allocates `8080-8179` per worktree.
33
-
- Automated browser server: isolated `127.0.0.1:18080`, never an existing dev server.
33
+
- Automated browser server: a per-worktree port from `18100-18179`, printed by `bash .superset/e2e-port.sh`, never an existing dev server. Protected staging keeps `127.0.0.1:18080`, the origin deployed CORS allows.
34
34
- Tailnet previews for Adam: `npm run dev:preview` listens locally on `9200-9299` and is published on tailnet HTTPS `9100-9149`; it pins the app to staging. See [docs/development.md](docs/development.md#preview-on-the-tailnet).
35
35
- Local Supabase: CLI defaults beginning at `54321`. The stack is not parallel-safe across worktrees.
36
36
@@ -46,17 +46,20 @@ npm test
46
46
npm run test:collaboration
47
47
npm run test:edge
48
48
npm run build
49
-
CI=1 PORT=18080 PLAYWRIGHT_BASE_URL=http://127.0.0.1:18080 npm run test:e2e
49
+
P=$(bash .superset/e2e-port.sh)&&CI=1 PORT=$P PLAYWRIGHT_BASE_URL=http://127.0.0.1:$P npm run test:e2e
50
50
```
51
51
52
52
`npm run verify` runs the credential-free ladder with the desktop Chromium `@smoke` browser set (about a minute). `npm run verify:full` adds the full desktop and mobile suite.
53
53
54
54
If GitHub Actions jobs fail within 2 to 5 seconds with no logs, they did not run: the account is out of Actions minutes (billing), not failing on the code. In that case run the same checks locally at the final head (`npm run verify` and the database gate) and record the exact results in the PR. A local pass is not a CI pass; say which one you have.
55
55
56
+
When a CI job fails, start with `npm run ci:failures -- <pr>`. It prints the failing jobs and specs, downloads the failure artifact into `.ci-failures/`, and shows each failed test's error and the dialogs and headings on the page from its `error-context.md`. Read that before guessing at timeouts or infrastructure.
57
+
56
58
Database migrations and pgTAP policies use a separate Docker-backed gate. In Superset, use the locking wrapper:
57
59
58
60
```bash
59
61
./.superset/db-gate.sh
62
+
./.superset/db-gate.sh --db-only # pgTAP and database scripts only
60
63
```
61
64
62
65
Outside Superset, run the underlying commands directly:
@@ -73,7 +76,7 @@ WebKit is a separate release smoke test:
73
76
74
77
```bash
75
78
npx playwright install --with-deps webkit
76
-
CI=1 PORT=18080 PLAYWRIGHT_BASE_URL=http://127.0.0.1:18080 npm run test:e2e:webkit
79
+
P=$(bash .superset/e2e-port.sh)&&CI=1 PORT=$P PLAYWRIGHT_BASE_URL=http://127.0.0.1:$P npm run test:e2e:webkit
77
80
```
78
81
79
82
## Verifying features in the real app
@@ -134,7 +137,7 @@ Open only what the task needs:
134
137
-[docs/testing.md](docs/testing.md): what each gate proves, browser matrices, staging, artifacts, and cleanup.
135
138
-[docs/operations.md](docs/operations.md): CI, Vercel hosting, staging, deployment, rollback, and live verification.
-[plans/README.md](plans/README.md): work in progress, the backlog, and shipped plans. Every plan lives in `plans/`; write new plans there. Revalidate every plan against current source before executing it.
140
+
-[plans/README.md](plans/README.md): work in progress, the backlog, and shipped plans. Every plan lives in `plans/` and opens with a `**Status:**` line; write new plans there. Commit a plan before splitting it across agent threads, and put its path in each thread's prompt. Revalidate every plan against current source before executing it.
138
141
-[docs/README.md](docs/README.md): complete documentation index and freshness labels.
139
142
140
143
When commands, ports, workflows, or runtime boundaries change, update the owning focused document in the same change. Do not copy large source trees, schemas, dependency lists, or model catalogs into documentation.
Copy file name to clipboardExpand all lines: docs/development.md
+4-3Lines changed: 4 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,9 +25,10 @@ Never overwrite unrelated changes. Do not switch to the primary checkout because
25
25
- Playwright browser binaries for browser gates
26
26
- Xcode and CocoaPods or Swift Package Manager support for native iOS work
27
27
28
-
Install the locked JavaScript tree:
28
+
Install the locked JavaScript tree with the Node version from `.nvmrc`:
29
29
30
30
```bash
31
+
nvm use
31
32
npm ci
32
33
```
33
34
@@ -47,7 +48,7 @@ For another explicit local port:
47
48
npm run dev -- --host 127.0.0.1 --port 8081
48
49
```
49
50
50
-
Automated browser tests own `127.0.0.1:18080` by default and always start a fresh server.
51
+
Automated browser tests always start a fresh server. `npm run verify` puts it on this worktree's port from `18100-18179` (`bash .superset/e2e-port.sh`); a bare Playwright run falls back to `127.0.0.1:18080`.
51
52
52
53
## Preview on the tailnet
53
54
@@ -142,7 +143,7 @@ Never point local tests at staging or production. Never apply a migration to an
142
143
[`playwright.config.ts`](../playwright.config.ts) starts Vite on an isolated port and refuses to reuse an existing server.
143
144
144
145
```bash
145
-
CI=1 PORT=18080 PLAYWRIGHT_BASE_URL=http://127.0.0.1:18080 npm run test:e2e
146
+
P=$(bash .superset/e2e-port.sh)&&CI=1 PORT=$P PLAYWRIGHT_BASE_URL=http://127.0.0.1:$P npm run test:e2e
146
147
```
147
148
148
149
Failure artifacts go to ignored `test-results/` and `playwright-report/`. Protected staging disables traces, screenshots, and video.
Copy file name to clipboardExpand all lines: docs/operations.md
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -36,7 +36,7 @@ If Actions jobs fail within 2 to 5 seconds with no runner and no logs, the accou
36
36
37
37
## Frontend hosting on Vercel
38
38
39
-
Vercel builds and serves the frontend from the Git repository. Merging to `main` starts a production deployment to `https://debate.pi-stack.org`; pull requests get two preview deployments (see [Per-PR previews](#per-pr-previews)). The production canary runs after each successful Vercel `Production` deployment.
39
+
Vercel builds and serves the frontend from the Git repository. Merging to `main` starts a production deployment to `https://debate.pi-stack.org`; pull requests get two preview deployments (see [Per-PR previews](#per-pr-previews)). For a staging-pinned preview on the tailnet, use `npm run dev:preview` (see [development.md](development.md#preview-on-the-tailnet)). The production canary runs after each successful Vercel `Production` deployment.
40
40
41
41
[`vercel.json`](../vercel.json) owns:
42
42
@@ -66,14 +66,14 @@ The staging browser suite disables trace, screenshot, and video capture. It crea
66
66
67
67
Do not enable the staging repository variable before every prerequisite is present. A skipped staging job is not a pass.
68
68
69
-
`STAGING_E2E_ENABLED` has been `true` since 2026-09-18, and the job passed through 2026-09-23. Since then it has been skipped because the `Quality` run it waits for fails before any runner starts (see [When GitHub Actions cannot run](#when-github-actions-cannot-run)). Restoring Actions minutes restores the staging job; nothing in the workflow needs changing.
69
+
`STAGING_E2E_ENABLED` has been `true` since 2026-09-18. The job runs after every successful `Quality` run from a push to `main`. Quality runs from pull requests also trigger it, and those show as skipped by design. Check the latest real result with `gh run list --workflow staging-e2e.yml` and `npm run ci:failures -- <run-id>`, not this page. The run uploads no artifact, so the job log is the only evidence.
70
70
71
71
## Staging sync
72
72
73
73
Staging is project `debate-trainer-staging` (`brifeyypjauyusmkptkx`). Production is `debate-trainer` (`uziwdtkzofptihahfooo`). Every backend change goes to staging first, passes the staging browser suite, and only then goes to production. Steps 1 and 2 are read-only. Steps 3 and 4 change staging and need Adam's authorization each time.
74
74
75
75
1. Confirm the target. `supabase projects list` must show the staging ref under the staging name. Stop if a command, link, or environment variable points at the production ref.
76
-
2. Find what is pending. Run `npm run backend:status -- --project-ref brifeyypjauyusmkptkx --check` from a checkout of the commit you mean to ship. It compares staging with the committed tree and exits 1 when a migration is not applied. Where that script is not available, run its two read-only queries directly:
76
+
2. Find what is pending. Run `npm run backend:status -- --project-ref brifeyypjauyusmkptkx --check` from a checkout of the commit you mean to ship. It compares staging with the committed tree and exits 1 when a migration is not applied. It also lists expected function secrets the project lacks (names only) and prints the Auth site URL and redirect allowlist. Where that script is not available, run its two read-only queries directly:
77
77
78
78
```bash
79
79
supabase migration list --project-ref brifeyypjauyusmkptkx
@@ -110,7 +110,7 @@ The staging project's name must not start with `debate-navigator-`, or productio
110
110
111
111
## Backend drift check
112
112
113
-
`npm run backend:status` shows what the current commit has that a Supabase project lacks. It inspects the project the Supabase CLI resolves, which is `SUPABASE_PROJECT_ID` when that is set and the linked project otherwise; `npm run backend:status -- --project-ref <ref>` inspects another one. It runs `supabase migration list`and `supabase functions list`and changes no schema, data, functions, or secrets. To connect to the database, the CLI creates its usual short-lived login role.
113
+
`npm run backend:status` shows what the current commit has that a Supabase project lacks. It inspects the project the Supabase CLI resolves, which is `SUPABASE_PROJECT_ID` when that is set and the linked project otherwise; `npm run backend:status -- --project-ref <ref>` inspects another one. It runs `supabase migration list`, `supabase functions list`and `supabase secrets list`, reads the Auth site URL and redirect allowlist from the Management API with the CLI's access token (`SUPABASE_ACCESS_TOKEN`, or the `access-token` file in `SUPABASE_HOME`, default `~/.supabase`), and changes no schema, data, functions, or secrets. It prints secret names only, never values or digests. To connect to the database, the CLI creates its usual short-lived login role.
114
114
115
115
The comparison uses the committed tree at `HEAD`, so commit or stash local edits first. It reports:
Copy file name to clipboardExpand all lines: docs/testing.md
+6-4Lines changed: 6 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -107,12 +107,12 @@ Run this after `npm run build`. It serves `dist/` through Vite preview and prove
107
107
## Credential-free browser gate
108
108
109
109
```bash
110
-
CI=1 PORT=18080 PLAYWRIGHT_BASE_URL=http://127.0.0.1:18080 npm run test:e2e
110
+
P=$(bash .superset/e2e-port.sh)&&CI=1 PORT=$P PLAYWRIGHT_BASE_URL=http://127.0.0.1:$P npm run test:e2e
111
111
```
112
112
113
113
Pull requests run only tests tagged `@smoke` on desktop Chromium (`npm run test:e2e:smoke`, about 30 tests). Tag a test `@smoke` only when it covers a whole user path that would otherwise go unchecked until the nightly run.
114
114
115
-
Playwright starts a new Vite server on `127.0.0.1:18080` and runs:
115
+
`.superset/e2e-port.sh` gives each worktree its own port from `18100-18179`, recorded in `~/.superset/debatelab-ports/allocations.json`, so two worktrees can run the gate at once. Without `PORT`, Playwright falls back to `18080`. Playwright starts a new Vite server on that port and runs:
116
116
117
117
- desktop Chromium at 1280 by 800
118
118
- mobile Chromium using the Pixel 5 device profile
@@ -165,7 +165,7 @@ In Superset, run:
165
165
./.superset/db-gate.sh
166
166
```
167
167
168
-
The wrapper acquires `~/.superset/debatelab-db.lock`, starts full local Supabase, runs `npm run test:db`, then holds the same lock while a controlled Mailpit relay, collaboration process, fake model provider, and Vite client run the real-Auth desktop/mobile workspace and full-stack feature journeys. The `Database` workflow runs this same gate on pull requests that touch its paths, and retains its logs and browser traces on failure. It stops every owned process and the stack on exit, including after failure. Outside Superset, run only the database portion with:
168
+
The wrapper acquires `~/.superset/debatelab-db.lock`, starts full local Supabase, runs `npm run test:db`, then holds the same lock while a controlled Mailpit relay, collaboration process, fake model provider, and Vite client run the real-Auth desktop/mobile workspace and full-stack feature journeys. The `Database` workflow runs this same gate on pull requests that touch its paths, and retains its logs and browser traces on failure. It stops every owned process and the stack on exit, including after failure. To run only the database portion under the same lock, use `./.superset/db-gate.sh --db-only`. Outside Superset, run it with:
CI=1 PORT=18080 PLAYWRIGHT_BASE_URL=http://127.0.0.1:18080 npm run test:e2e:webkit
268
+
P=$(bash .superset/e2e-port.sh)&&CI=1 PORT=$P PLAYWRIGHT_BASE_URL=http://127.0.0.1:$P npm run test:e2e:webkit
269
269
```
270
270
271
271
This is the Safari-engine smoke gate. State explicitly when it did not run.
@@ -319,6 +319,8 @@ Tests are not the proof that a change works; using it is. Two local recipes that
319
319
320
320
[`.github/workflows/live-e2e.yml`](../.github/workflows/live-e2e.yml) runs the live provider journeys, and [`.github/workflows/prod-canary.yml`](../.github/workflows/prod-canary.yml) runs the production canary. `main` has no branch protection or rulesets (checked 2026-10-01; GitHub Free does not enforce them on private repositories), so no check is required. Path-filtered workflows that skip therefore don't block merges. Read the PR's checks before merging.
321
321
322
+
To see why a run failed, use `npm run ci:failures` (current branch's PR), `npm run ci:failures -- <pr>` or `npm run ci:failures -- <run-id>`. It works while the run is still going, as soon as a job fails. It lists failed jobs and steps, prints the Playwright or Vitest summary from each job log, downloads the `*-failure-<run-id>` artifacts into ignored `.ci-failures/`, and prints each failed test's error plus the dialogs and headings from its `error-context.md` page snapshot. A dialog the spec never answered shows up there. Protected staging uploads no artifact, so only its job log is available.
0 commit comments