[pull] main from Open-Legal-Products:main

✅ merged · #10 · admariner/mike ← Open-Legal-Products/mike · opened 1mo ago by pull[bot] · merged 1mo ago by pull[bot] · +2,863-67 across 30 files · ↗ on GitHub

From the PR description

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

Our analysis

Merge fork updates — read the full analysis →

Think the analysis missed something the PR description covers?

Commits in this PR (39)

SHA Subject Author Date
a8cf33ae Remove unused Supabase request auth helper mahaprasad nanda 2026-06-19 ↗ GitHub
94987e6b test: Playwright e2e suite (auth, chat, projects, tabular reviews, workflows) Amal 2026-07-17 ↗ GitHub
commit body
Port of the amal66/mike fork's Playwright end-to-end suite onto the
upstream backend/ + frontend/ layout:

- e2e/: auth.setup (bootstraps a confirmed e2e@mike.local user via the
  Supabase admin API and saves storageState), auth-flows, critical-path
  (create project -> upload PDF -> ask a question -> streamed response),
  chat-management, project-management, tabular-reviews,
  workflows-account; fixtures/test.pdf
- playwright.config.ts: single-worker (shared test user), setup project
  + chromium project with saved auth state; webServer adapted from the
  fork's monorepo command (npm run dev --workspace apps/web) to
  upstream's layouts: backend `npm run dev` (health-checked on :3001)
  and frontend `npm run dev` (:3000)
- root package.json (upstream has none): @playwright/test, typescript
  dev-deps and test:e2e scripts, trimmed from the fork's root manifest
- root tsconfig.json scoped to e2e/ + playwright.config.ts so
  `npx tsc --noEmit` typechecks the suite
- .gitignore: playwright artifacts + e2e/.auth (session tokens)

Specs select by ARIA role/name and placeholder text only - no
data-testid attributes, so no app-code changes are required.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CEguyEgXa9JjCciXCcVemC
ffad860e fix(e2e): realign selectors with the olp UI and upstream route shape Amal 2026-07-17 ↗ GitHub
commit body
upstream-main (olp's tip) ships the #215/#216 liquid-surfaces UI, so the same
selector drifts fixed on the fork's suite (commit 3d46814 on main) also apply
here. Ports those realigned hunks, plus one upstream-specific route fix.

  * Chat input placeholder is "How can I help?", not
    "Ask a question about your documents..." (ChatInput/TRChatInput). Updated in
    chat-management (rename/delete/project-assistant) and critical-path.
  * The project-assistant empty state replaced the "+ Create New" text link with
    a PillButton reading "Create" (ProjectAssistantTable) - critical-path and
    chat-management now use getByRole("button", { name: "Create" }).
  * The sidebar chat row's active marker is APP_SURFACE_ACTIVE_CLASS
    ("bg-app-surface-active"), not "bg-gray-200/60"; the row wrapper is now h-8,
    not h-9 (SidebarChatItem). The rename/delete tests locate the row accordingly.
  * The documents-toolbar folder button is "Folder" (TabPillButton wired to the
    root createFolderAction in ProjectDocumentsView), not "Add Subfolder"; it
    still opens the autofocused "Folder name" root input.
  * NewTRModal's footer submit and the tabular page CTA both read "Create", so
    the create-review helper scopes to the modal submit
    (button[name="modalAction"][value="create-review"]).
  * The built-in workflow detail test navigated to the flat /workflows/[id],
    which upstream does not route - only the typed /workflows/assistant/[id] and
    /workflows/tabular-review/[id] exist. builtin-cp-checklist is assistant-type,
    so it now navigates to /workflows/assistant/builtin-cp-checklist (the path
    the app itself links to via workflowDetailPath; works on the fork too).

Verified: full 27-test suite green against upstream-main + test-harness +
demo-mode(+provider-registry), backend + local Supabase (upstream schema.sql +
backend/migrations) + MinIO, demo model, e2e@mike.local.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CEguyEgXa9JjCciXCcVemC
d8d38174 ci(e2e): run Playwright suite on PRs as a merge gate QA Runner 2026-07-17 ↗ GitHub
commit body
Adds .github/workflows/e2e.yml adapted to this repo's backend/ + frontend/
layout: on every pull_request into main (or upstream-main), boot MinIO +
local Supabase (loading backend/schema.sql), start the API and web dev
servers, and run the Playwright suite, uploading the HTML report/traces on
pass or fail. playwright.config.ts already disables its local webServer when
CI=true, so the job owns the stack.

docs/e2e-ci.md documents the one required secret (ANTHROPIC_API_KEY) and the
branch-protection steps that make the 'e2e / playwright' check required, so a
red run blocks the merge button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
d427cc26 ci(e2e): upload the Playwright report even on timeout/cancel QA Runner 2026-07-17 ↗ GitHub
commit body
Switch the artifact step from !cancelled() to always() so a run that hits the
30-minute job timeout (the failure mode when many specs retry) still uploads
the HTML report and traces instead of skipping the upload - that partial report
is exactly what's needed to diagnose the failing specs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9daee405 ci(e2e): grant service_role table access after loading schema.sql QA Runner 2026-07-17 ↗ GitHub
commit body
The backend queries exclusively as service_role (lib/supabase.ts, service key,
'bypasses RLS'). schema.sql revokes client grants (anon/authenticated) but
assumes a hosted Supabase where service_role already has full table access - on
a fresh CLI stack loaded via psql it gets none, so the first backend write 500s
with 'permission denied for table user_profiles' and every project/chat spec
fails. Granting service_role after the schema load reproduces the production
grant posture.

Verified in CI: POST /projects 500 -> 201, GET /chat 500 -> 200.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
42346d69 ci(e2e): apply migrations, serve prod build, skip LLM specs without a key QA Runner 2026-07-17 ↗ GitHub
commit body
Three fixes that take the suite from ~everything-failing to green (verified end
to end against a local stack):

1. schema.sql lags the migrations (missing e.g. workflow_open_source_submissions,
   which GET /workflows/:id queries → 500). Apply every dated migration on top of
   schema.sql (idempotent; 0 errors on a fresh DB), grant service_role AFTER so
   new tables are covered, then reload PostgREST. Fixes the workflow specs.

2. Serve a production build (next build + next start) instead of next dev. The dev
   server's on-demand compilation (slow first hit → waitForResponse timeouts) and
   hydration-error overlay (injects nextjs__container_errors DOM that pollutes text
   locators, e.g. getByText('All') matching 'Call Stack') made the suite flaky.
   Fixes tabular-reviews list render + the timing flakes.

3. LLM-dependent specs (chat rename/delete/submit, critical-path) require a model
   key to send a message. Guard them with test.skip(!hasLlmKey) (e2e/llm.ts) and
   expose ANTHROPIC_API_KEY to the Playwright process, so a keyless run is green on
   the ~23 other specs and the LLM specs run + enforce only when the secret is set.

Local result (no key, with MinIO+LibreOffice as on ubuntu-latest): 23 passed,
4 skipped, 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
094fe565 docs(e2e): document keyless-green behavior, migrations, and prod build QA Runner 2026-07-17 ↗ GitHub
commit body
The suite is green with no secret (LLM specs skip). Update docs/e2e-ci.md and the
workflow header to reflect the migrations step, the production build, and the
optional (not required) ANTHROPIC_API_KEY.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8bb44e9c test(e2e): update built-in workflow id after upstream rename QA Runner 2026-07-20 ↗ GitHub
commit body
The workflows UI refresh (olp/main fa21ac8) renamed the built-in workflow id
builtin-cp-checklist -> builtin-draft-cp-checklist (title 'Draft CP Checklist'
unchanged). The read-only-detail spec navigated to the old id URL and got a
'workflow not found' page. Point it at the new id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5f8e4ab4 fix: batch directory-modal project fetch instead of N+1 getProject burst QA Runner 2026-07-20 ↗ GitHub
commit body
Every directory picker (AddDocumentsModal, UseWorkflowModal, the assistant
project selector) loads its "Projects" tab through useDirectoryData, which
fired one GET /projects/:id for EVERY existing project the moment the modal
opened. Each of those requests costs an auth verification against GoTrue
plus ~6 PostgREST queries, so an account with N projects produced an
~8xN-request burst on the Supabase gateway per modal open.

Under that burst the gateway genuinely falls over: measured locally against
the Supabase CLI stack, overlapping modal-open storms drove GoTrue into
Postgres connection exhaustion ("failed to connect ... context deadline
exceeded") and produced 467x 500 + 641x 504 on /auth/v1/user in a single
run - surfacing to users as failed project creates/loads, and to the e2e
suite as the intermittent Kong 502s its specs currently retry around.

Fix: GET /projects now accepts ?include=documents and returns each
project's documents from one batched query (same attach helpers as
GET /projects/:id, run once across all documents), and useDirectoryData
uses it. A modal open is now 1 API request and a fixed number of DB
queries regardless of project count. After the change the same storm
harness produced zero 5xx and zero auth failures.

[Cherry-pick overlap note: this same commit is submitted separately as the
olp-pr/directory-fetch-storm PR, where it belongs (production fix). It is
carried on this e2e branch only so the de-retried suite passes here; on
merge of both branches git resolves the duplicate cleanly.]

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
af38a450 test(e2e): drop transient-5xx retry scaffolding now that the fetch storm is fixed QA Runner 2026-07-20 ↗ GitHub
commit body
With the directory fetch storm eliminated (previous commit: batched
listProjects?include=documents instead of a getProject burst per modal
open), the local Supabase gateway no longer collapses under modal-open
load, so the specs' 5xx-oriented scaffolding is removed:

- create-with-retry loops (project create x2, chat create x2, workflow
  create, tabular-review create x10-attempt, review add-document x6)
- reload-guards for transient "Project not found" (waitForProjectLoaded,
  gotoProjectRow, project-assistant tab loop)
- networkidle settle-waits whose purpose was to let the per-project fetch
  burst drain before submitting (NewProjectModal / NewTRModal)
- oversized per-test timeouts justified by the storm (180s -> 60-120s)

Kept, deliberately:
- the title-generation settle logic in chat rename/delete
- chat submit's model-seeding retry loop (guards a documented
  useSelectedModel localStorage hydration race, unrelated to the gateway)
- account display-name toPass block (guards a documented profile
  hydration race, unrelated to the gateway)
- generic short networkidle settles after login/logout navigation
- Playwright's own retries: 2 on CI

Verified: with the fix, 3 consecutive full-suite runs (plus 2 more before
de-retry) were green with zero Playwright retries, running against an
account seeded with ~40 projects - a larger directory fan-out than CI's
fresh database ever produces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
d4448fa8 test(e2e): select a real Claude model in LLM-gated specs (demo model is fork-only) QA Runner 2026-07-20 ↗ GitHub
commit body
The 4 LLM-gated specs (chat-management rename/delete/project-assistant and
the critical-path project flow) selected a "Demo (no key needed)" model in
the ModelToggle. That model exists only in a fork's demo provider - upstream
ModelToggle.MODELS has no such entry - so on this repo, setting the
ANTHROPIC_API_KEY secret unskipped the specs and they then failed at the
model-selection step.

Fix:
- Replace the selectDemoModel helpers with selectClaudeModel, which picks
  "Claude Sonnet 4.6" (the cheapest Anthropic entry in ModelToggle.MODELS).
  With ANTHROPIC_API_KEY exported to the backend, userApiKeys.envApiKey()
  reports the claude provider as configured, so the model is available and
  the submit is not blocked by the ApiKeyMissingModal.
- critical-path Step 8: the canned-reply assertion getByText("Demo mode")
  becomes a presence + nonempty assertion on the assistant answer container
  (MarkdownContent's "div.prose.font-serif.text-gray-900", unique to
  assistant answer content) - deterministic against nondeterministic real
  LLM output, same 60s budget.
- Comments rewritten to describe the upstream reality: specs run only when
  ANTHROPIC_API_KEY is set (e2e/llm.ts), the backend uses the env key, and
  title generation resolves to claude-haiku-4-5 via resolveTitleModel.

Verified against a local prod-build stack (backend :3001, frontend :3002,
local Supabase + MinIO), only ANTHROPIC_API_KEY configured:
- keyless Playwright env: 23 passed / 4 skipped
- ANTHROPIC_API_KEY exported: 27 passed / 0 skipped (1.2m)
- npx tsc --noEmit clean

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
916f2600 test: Playwright e2e suite (auth, chat, projects, tabular reviews, workflows) Amal 2026-07-17 ↗ GitHub
commit body
Port of the amal66/mike fork's Playwright end-to-end suite onto the
upstream backend/ + frontend/ layout:

- e2e/: auth.setup (bootstraps a confirmed e2e@mike.local user via the
  Supabase admin API and saves storageState), auth-flows, critical-path
  (create project -> upload PDF -> ask a question -> streamed response),
  chat-management, project-management, tabular-reviews,
  workflows-account; fixtures/test.pdf
- playwright.config.ts: single-worker (shared test user), setup project
  + chromium project with saved auth state; webServer adapted from the
  fork's monorepo command (npm run dev --workspace apps/web) to
  upstream's layouts: backend `npm run dev` (health-checked on :3001)
  and frontend `npm run dev` (:3000)
- root package.json (upstream has none): @playwright/test, typescript
  dev-deps and test:e2e scripts, trimmed from the fork's root manifest
- root tsconfig.json scoped to e2e/ + playwright.config.ts so
  `npx tsc --noEmit` typechecks the suite
- .gitignore: playwright artifacts + e2e/.auth (session tokens)

Specs select by ARIA role/name and placeholder text only - no
data-testid attributes, so no app-code changes are required.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CEguyEgXa9JjCciXCcVemC
e5510287 fix(e2e): realign selectors with the olp UI and upstream route shape Amal 2026-07-17 ↗ GitHub
commit body
upstream-main (olp's tip) ships the #215/#216 liquid-surfaces UI, so the same
selector drifts fixed on the fork's suite (commit 3d46814 on main) also apply
here. Ports those realigned hunks, plus one upstream-specific route fix.

  * Chat input placeholder is "How can I help?", not
    "Ask a question about your documents..." (ChatInput/TRChatInput). Updated in
    chat-management (rename/delete/project-assistant) and critical-path.
  * The project-assistant empty state replaced the "+ Create New" text link with
    a PillButton reading "Create" (ProjectAssistantTable) - critical-path and
    chat-management now use getByRole("button", { name: "Create" }).
  * The sidebar chat row's active marker is APP_SURFACE_ACTIVE_CLASS
    ("bg-app-surface-active"), not "bg-gray-200/60"; the row wrapper is now h-8,
    not h-9 (SidebarChatItem). The rename/delete tests locate the row accordingly.
  * The documents-toolbar folder button is "Folder" (TabPillButton wired to the
    root createFolderAction in ProjectDocumentsView), not "Add Subfolder"; it
    still opens the autofocused "Folder name" root input.
  * NewTRModal's footer submit and the tabular page CTA both read "Create", so
    the create-review helper scopes to the modal submit
    (button[name="modalAction"][value="create-review"]).
  * The built-in workflow detail test navigated to the flat /workflows/[id],
    which upstream does not route - only the typed /workflows/assistant/[id] and
    /workflows/tabular-review/[id] exist. builtin-cp-checklist is assistant-type,
    so it now navigates to /workflows/assistant/builtin-cp-checklist (the path
    the app itself links to via workflowDetailPath; works on the fork too).

Verified: full 27-test suite green against upstream-main + test-harness +
demo-mode(+provider-registry), backend + local Supabase (upstream schema.sql +
backend/migrations) + MinIO, demo model, e2e@mike.local.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CEguyEgXa9JjCciXCcVemC
82fd540e ci(e2e): run Playwright suite on PRs as a merge gate QA Runner 2026-07-17 ↗ GitHub
commit body
Adds .github/workflows/e2e.yml adapted to this repo's backend/ + frontend/
layout: on every pull_request into main (or upstream-main), boot MinIO +
local Supabase (loading backend/schema.sql), start the API and web dev
servers, and run the Playwright suite, uploading the HTML report/traces on
pass or fail. playwright.config.ts already disables its local webServer when
CI=true, so the job owns the stack.

docs/e2e-ci.md documents the one required secret (ANTHROPIC_API_KEY) and the
branch-protection steps that make the 'e2e / playwright' check required, so a
red run blocks the merge button.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
82cbe4d7 ci(e2e): upload the Playwright report even on timeout/cancel QA Runner 2026-07-17 ↗ GitHub
commit body
Switch the artifact step from !cancelled() to always() so a run that hits the
30-minute job timeout (the failure mode when many specs retry) still uploads
the HTML report and traces instead of skipping the upload - that partial report
is exactly what's needed to diagnose the failing specs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
28a6cb64 ci(e2e): grant service_role table access after loading schema.sql QA Runner 2026-07-17 ↗ GitHub
commit body
The backend queries exclusively as service_role (lib/supabase.ts, service key,
'bypasses RLS'). schema.sql revokes client grants (anon/authenticated) but
assumes a hosted Supabase where service_role already has full table access - on
a fresh CLI stack loaded via psql it gets none, so the first backend write 500s
with 'permission denied for table user_profiles' and every project/chat spec
fails. Granting service_role after the schema load reproduces the production
grant posture.

Verified in CI: POST /projects 500 -> 201, GET /chat 500 -> 200.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7039461c ci(e2e): apply migrations, serve prod build, skip LLM specs without a key QA Runner 2026-07-17 ↗ GitHub
commit body
Three fixes that take the suite from ~everything-failing to green (verified end
to end against a local stack):

1. schema.sql lags the migrations (missing e.g. workflow_open_source_submissions,
   which GET /workflows/:id queries → 500). Apply every dated migration on top of
   schema.sql (idempotent; 0 errors on a fresh DB), grant service_role AFTER so
   new tables are covered, then reload PostgREST. Fixes the workflow specs.

2. Serve a production build (next build + next start) instead of next dev. The dev
   server's on-demand compilation (slow first hit → waitForResponse timeouts) and
   hydration-error overlay (injects nextjs__container_errors DOM that pollutes text
   locators, e.g. getByText('All') matching 'Call Stack') made the suite flaky.
   Fixes tabular-reviews list render + the timing flakes.

3. LLM-dependent specs (chat rename/delete/submit, critical-path) require a model
   key to send a message. Guard them with test.skip(!hasLlmKey) (e2e/llm.ts) and
   expose ANTHROPIC_API_KEY to the Playwright process, so a keyless run is green on
   the ~23 other specs and the LLM specs run + enforce only when the secret is set.

Local result (no key, with MinIO+LibreOffice as on ubuntu-latest): 23 passed,
4 skipped, 0 failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
e6d53c4f docs(e2e): document keyless-green behavior, migrations, and prod build QA Runner 2026-07-17 ↗ GitHub
commit body
The suite is green with no secret (LLM specs skip). Update docs/e2e-ci.md and the
workflow header to reflect the migrations step, the production build, and the
optional (not required) ANTHROPIC_API_KEY.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9f9a280f test(e2e): update built-in workflow id after upstream rename QA Runner 2026-07-20 ↗ GitHub
commit body
The workflows UI refresh (olp/main fa21ac8) renamed the built-in workflow id
builtin-cp-checklist -> builtin-draft-cp-checklist (title 'Draft CP Checklist'
unchanged). The read-only-detail spec navigated to the old id URL and got a
'workflow not found' page. Point it at the new id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
86a0d781 test(e2e): drop transient-5xx retry scaffolding now that the fetch storm is fixed QA Runner 2026-07-20 ↗ GitHub
commit body
With the directory fetch storm eliminated (previous commit: batched
listProjects?include=documents instead of a getProject burst per modal
open), the local Supabase gateway no longer collapses under modal-open
load, so the specs' 5xx-oriented scaffolding is removed:

- create-with-retry loops (project create x2, chat create x2, workflow
  create, tabular-review create x10-attempt, review add-document x6)
- reload-guards for transient "Project not found" (waitForProjectLoaded,
  gotoProjectRow, project-assistant tab loop)
- networkidle settle-waits whose purpose was to let the per-project fetch
  burst drain before submitting (NewProjectModal / NewTRModal)
- oversized per-test timeouts justified by the storm (180s -> 60-120s)

Kept, deliberately:
- the title-generation settle logic in chat rename/delete
- chat submit's model-seeding retry loop (guards a documented
  useSelectedModel localStorage hydration race, unrelated to the gateway)
- account display-name toPass block (guards a documented profile
  hydration race, unrelated to the gateway)
- generic short networkidle settles after login/logout navigation
- Playwright's own retries: 2 on CI

Verified: with the fix, 3 consecutive full-suite runs (plus 2 more before
de-retry) were green with zero Playwright retries, running against an
account seeded with ~40 projects - a larger directory fan-out than CI's
fresh database ever produces.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
039e433a test(e2e): select a real Claude model in LLM-gated specs (demo model is fork-only) QA Runner 2026-07-20 ↗ GitHub
commit body
The 4 LLM-gated specs (chat-management rename/delete/project-assistant and
the critical-path project flow) selected a "Demo (no key needed)" model in
the ModelToggle. That model exists only in a fork's demo provider - upstream
ModelToggle.MODELS has no such entry - so on this repo, setting the
ANTHROPIC_API_KEY secret unskipped the specs and they then failed at the
model-selection step.

Fix:
- Replace the selectDemoModel helpers with selectClaudeModel, which picks
  "Claude Sonnet 4.6" (the cheapest Anthropic entry in ModelToggle.MODELS).
  With ANTHROPIC_API_KEY exported to the backend, userApiKeys.envApiKey()
  reports the claude provider as configured, so the model is available and
  the submit is not blocked by the ApiKeyMissingModal.
- critical-path Step 8: the canned-reply assertion getByText("Demo mode")
  becomes a presence + nonempty assertion on the assistant answer container
  (MarkdownContent's "div.prose.font-serif.text-gray-900", unique to
  assistant answer content) - deterministic against nondeterministic real
  LLM output, same 60s budget.
- Comments rewritten to describe the upstream reality: specs run only when
  ANTHROPIC_API_KEY is set (e2e/llm.ts), the backend uses the env key, and
  title generation resolves to claude-haiku-4-5 via resolveTitleModel.

Verified against a local prod-build stack (backend :3001, frontend :3002,
local Supabase + MinIO), only ANTHROPIC_API_KEY configured:
- keyless Playwright env: 23 passed / 4 skipped
- ANTHROPIC_API_KEY exported: 27 passed / 0 skipped (1.2m)
- npx tsc --noEmit clean

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
282b2dd2 docs(e2e): exact ANTHROPIC_API_KEY setup to enable the 4 LLM specs; correct the gate rationale QA Runner 2026-07-20 ↗ GitHub
commit body
Investigated whether the four LLM-gated specs (chat rename, chat delete,
project-assistant create+submit, critical path) could run keyless with the
demo model they select. They cannot on this codebase: no keyless model
exists here - ModelToggle's MODELS are all Anthropic/Google/OpenAI entries
gated on a configured provider key (env or user-stored,
backend/src/lib/userApiKeys.ts), ChatInput.handleSubmit hard-blocks a send
for an unavailable model, and the backend model set
(backend/src/lib/llm/models.ts ALL_MODELS) has no demo id either. The
'Demo (no key needed)' model the specs target lives only in the amal66
fork. So the blanket test.skip(!hasLlmKey, ...) guard stays as-is - the
evidence does not support narrowing it.

What this change does instead:
- docs/e2e-ci.md: new 'Enable the LLM specs' section with the exact UI
  path and gh CLI command for the ANTHROPIC_API_KEY repository secret, the
  fork-PR secrets caveat (use a maintainer branch or workflow_dispatch to
  exercise the specs), expected per-run cost, and how to confirm in the
  Actions log that the specs ran (27 passed, no skipped line) rather than
  skipped (4 skipped / 23 passed). Also documents the known gap: until the
  specs' selectDemoModel helper is pointed at a Claude model (or the demo
  provider is upstreamed), the secret unskips the specs but they fail at
  model selection.
- e2e/llm.ts: rewrite the doc comment with the precise gate rationale
  (no keyless model in this repo; title-generation 500s are best-effort
  and not the reason) and pointers to the setup docs.
- .github/workflows/e2e.yml: comment-only updates aligning the skip
  narrative (23 keyless specs, not ~20/~23) and pointing at the new docs
  section. No behavioral change anywhere.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
0cc635bd docs(e2e): mark the model-selection gap fixed - specs pick a Claude model when the key is set QA Runner 2026-07-20 ↗ GitHub
commit body
The "Known gap" paragraph predicted the 4 LLM specs would fail with the
secret set because they selected the fork-only "Demo (no key needed)"
model. That is now fixed on the e2e suite branch (#220): the helper
selects "Claude Sonnet 4.6" and the critical-path assertion checks for a
nonempty streamed assistant answer. Update the paragraph accordingly:
setting ANTHROPIC_API_KEY now yields 27 passed / 0 skipped (verified
locally; keyless stays 23 passed / 4 skipped).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
72242ff0 docs(e2e): reconcile the docs with what this branch actually contains QA Runner 2026-07-22 ↗ GitHub
commit body
The two doc commits were written against a lineage where the
selectClaudeModel spec fix lived on a separate branch, which left three
stale claims after the rebase:

- e2e/llm.ts still called selectDemoModel a known gap and pointed at a
  docs section title that no longer exists; the specs in this very
  branch already use selectClaudeModel. Replace the paragraph with the
  current behavior.
- docs/e2e-ci.md attributed the fix to "the e2e suite branch (#220)";
  this branch carries that commit itself, so say so and name the commit.
- The 23/4 keyless and 27/0 with-key figures were presented as bare
  facts ("verified locally"). Attribute them to where they were actually
  measured - the spec-fix commit's own verification against a full local
  stack - and state they have not been re-measured since the rebase onto
  current main. Drop the unattributed "~7 minutes" typical-run figure in
  favor of the structural 27-spec / 4-gated breakdown (confirmed by
  `npx playwright test --list`: 27 tests in 7 files).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
62da94be test(e2e): self-bootstrapping local Supabase stack for local runs willchen96 2026-07-25 ↗ GitHub
commit body
npm run test:e2e:local (or plain test:e2e via the webServer hook) boots
Docker-checked local Supabase, loads schema + migrations + grants, wires
backend/.env and frontend/.env.local, and raises the backend rate-limit
caps the same way CI does - a full suite run exceeds the default
300-requests/15-min general cap, after which every call 429s and the
profile/list waits time out.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cb2306c5 fix(frontend): unify full-screen loaders to remove hydration mismatch willchen96 2026-07-25 ↗ GitHub
commit body
The provider Suspense fallback, the MFA gate loader, and the (pages)
layout auth loader were three near-identical spinners with different
Tailwind classes. Server and client can resolve those gates differently
on first paint (auth settles from localStorage before the boundary
hydrates), so the differing attributes surfaced as a hydration mismatch
on nearly every dev page load. One shared FullScreenLoader makes every
branch render byte-identical DOM.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4728fd19 chore(frontend): pin turbopack.root to silence multi-lockfile warning willchen96 2026-07-25 ↗ GitHub
The repo has lockfiles at the root (Playwright harness) and in
frontend/, so Next.js guesses the workspace root and warns on every
dev-server start. Pin it explicitly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
c196f9b2 Merge remote-tracking branch 'origin/main' into olp-pr/e2e-playwright willchen96 2026-07-25 ↗ GitHub
f3173a9d ci(e2e): narrow post-migration service_role grants to match schema.sql willchen96 2026-07-26 ↗ GitHub
commit body
schema.sql now grants service_role its own narrowed privileges
(upstream "narrow service role schema grants"), so the broad GRANT ALL
workaround is obsolete - and worse, it widened the test database beyond
what prod gets, letting e2e pass on privileges a real deployment lacks.
Keep a post-migration re-grant (schema.sql's ON ALL statements can't
cover tables the migrations create) but with the identical narrowed set.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fb3ec2d6 chore: gitignore the local Supabase scaffold willchen96 2026-07-26 ↗ GitHub
commit body
backend/supabase/ is supabase-init output used only by the local e2e
stack; CI scaffolds its own fresh copy each run, so it must not be
committed - hide it from status/source-control noise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
74ceaa41 chore(backend): sync bun.lock with vitest/supertest devDeps willchen96 2026-07-26 ↗ GitHub
The backend-integration-tests PR (#233) added vitest, supertest, and
@vitest/coverage-v8 to backend/package.json but did not update
bun.lock, leaving the lockfile behind the manifest.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dad4b9d2 Merge pull request #220 from amal66/olp-pr/e2e-playwright Will Chen 2026-07-26 ↗ GitHub
[Testing 12] test: Playwright e2e suite + CI merge gate (auth, chat, projects, tabular, workflows)
154051ae Merge pull request #258 from Open-Legal-Products/olp-pr/bun-lock-sync Will Chen 2026-07-26 ↗ GitHub
chore(backend): sync bun.lock with vitest/supertest devDeps
5dbb45e9 Merge remote-tracking branch 'origin/main' into olp-pr/e2e-llm-unskip willchen96 2026-07-26 ↗ GitHub
# Conflicts:
#	.github/workflows/e2e.yml
#	.gitignore
#	docs/e2e-ci.md
#	e2e/llm.ts
#	package.json
#	playwright.config.ts
9b42994a Merge pull request #236 from amal66/olp-pr/e2e-llm-unskip Will Chen 2026-07-26 ↗ GitHub
[Docs 13] docs(e2e): exact ANTHROPIC_API_KEY setup to enable the 4 LLM-gated specs
3bea53ff Merge remote-tracking branch 'origin/main' into codex/remove-dead-supabase-auth-helper willchen96 2026-07-26 ↗ GitHub
80d14b86 test: drop mocks of removed getUserIdFromRequest helper willchen96 2026-07-26 ↗ GitHub
commit body
The integration tests landed on main after this branch was cut and
mocked the helper this PR deletes. Vitest factory mocks don't validate
against the real module shape, so the extra key was harmless but
misleading.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
416b32b1 Merge pull request #186 from user-in-search-of-a-name/codex/remove-dead-supabase-auth-helper Will Chen 2026-07-26 ↗ GitHub
[codex] Remove unused Supabase request auth helper

Capture this PR into my fork

Download a Markdown prompt that tells Claude how to port every commit in this PR into your working tree. Run it via claude -p < capture-pull-10.md from inside the repo you want the changes in.

⬇ Download capture-pull-10.md