test(e2e): full-system browser multi-user acceptance

This commit is contained in:
weichen
2026-09-26 03:23:35 +00:00
parent 09cc76eb8d
commit 078eb4fcf0
29 changed files with 2126 additions and 1 deletions
@@ -0,0 +1,78 @@
---
title: "全系统真实浏览器多人协作验收"
task_id: "full-system-browser-e2e-2026-09-26"
status: in_progress
created: 2026-09-26
updated: 2026-09-26
owner: Cursor
task_type: validation
task_tier: large
policy_revision: "agent-governance-2026-09-21-r1 + cursor-governance-2026-09-24-r1"
branch: feature/full-system-browser-e2e-2026-09-26
worktree: .worktrees/full-system-browser-e2e-2026-09-26
write_scope: [".doc", "web"]
allowed_environments: ["env:dev"]
mutex: "full-system-browser-e2e"
review_state: pending
integration_state: pending
deployment: not_required
cleanup: pending
remote_sync: not_requested
---
# 全系统真实浏览器多人协作验收
## 用户目标与授权
- **目标**:对已清库(wipe)的 local `dev`(`BASE_URL=http://127.0.0.1:8080`)做完整、深入的**真实 Chromium / Playwright** 多人协作验收,并按测试报告规范落盘。
- **硬边界**:禁止用 API 创建项目/发消息/审批文档;仅允许登录探测、health、查控制台/落盘证据用的只读辅助。业务动作一律浏览器点击/输入。
- **交付终点**:`web/e2e/full-system-browser-e2e.spec.ts` + assets 证据 + `.doc/test-reports/2026-09-26-full-system-browser-e2e-test-report.md` + agentctl 租约内 commit。
- **保留**:测完保留测试账号与内容(前缀 `e2e26_` / 项目 `E2E全量-20260926-`)。
## 前置(已完成)
- Wipe 收据:[.doc/test-reports/assets/2026-09-26-full-system-browser-e2e/wipe-receipt.md](../../test-reports/assets/2026-09-26-full-system-browser-e2e/wipe-receipt.md)
- 清库后:schema 75;用户含 `admin` + goose `seed-*`;10 种子项目;`DISABLE_DEV_SEED_USERS=true`(runtime demo 用户未创建)
## 证据路径
| 产物 | 路径 |
|---|---|
| Playwright log | `.doc/test-reports/assets/2026-09-26-full-system-browser-e2e/playwright.log` |
| 结果账本 | `…/ui-results.json` |
| 截图 | `…/screenshots/` |
| console 落盘 | `…/console-*.jsonl` |
| 测试报告 | `.doc/test-reports/2026-09-26-full-system-browser-e2e-test-report.md` |
## 用例 ID(优先级)
| 优先级 | ID 前缀 | 覆盖 |
|---|---|---|
| P0 | FS-IAM / FS-PROJ / FS-CHAT | 建用户角色、建项目加成员分权、基础对话 |
| P0 | FS-SQUAD-WF / FS-DOC-REV / FS-NONAUTH | 工作流文档生成→审签→退回→再送→批准;non-author 编辑 vs 送审门禁 |
| P1 | FS-ASSIST / FS-SQUAD-FREE / FS-UPLOAD / FS-KB / FS-CTX | 助手任务、自由任务、上传解析、KB 只读核验、上下文观察 |
| P2 | FS-CONSOLE / 冲突 | console 汇总、双人编辑冲突(时间不够则 SKIP+理由) |
## 计划与进展
1. [x] Wipe 完成(sibling wipe task)
2. [x] 编写 Playwright full-system spec + 任务记录 + 运行脚本
3. [ ] 实跑 Playwright(**阻塞**:本会话 Cursor Shell `spawn /bin/bash ENOENT`;见 assets `shell-blocker.md`)
4. [ ] 落盘规范测试报告
5. [ ] `agentctl with` commit
## 阻塞
- Shell 工具无法 spawn `/bin/bash`(主机上 `/bin/bash` 文件存在)。Write 工具可写文件;无法 curl/playwright/agentctl。
- 恢复后执行:`bash web/scripts/run-full-system-browser-e2e.sh`(worktree 内),再写报告并租约提交。
## 验证契约
- 层级:产品 UI 真实浏览器验收(验证契约「产品 PI 基线」相关);禁止 stub/SKIP 冒充 PASS。
- 未跑项必须 `SKIP` + 理由。
- 工程规范变更附带 e2e;本任务以 UI 证据为主。
## 状态与交接
- 会话执行中;Shell 通道若异常须记录阻塞并恢复后继续实跑。
- 不 push;不合入除非另授权。
@@ -0,0 +1,82 @@
# full-system browser multi-user E2E 测试报告
## 一、 测试背景 (Background)
- 全系统浏览器多用户验收(Playwright),目标环境 `http://127.0.0.1:8080`。
- 本报告由 `ui-results.json` 在 Playwright 运行后自动生成(最小报告)。
## 二、 测试目标 (Test Objectives)
- 验证 IAM 建号、首登改密、项目成员/职责、文档审阅链路及控制台相关用例。
## 三、 测试方案与环境 (Test Plan & Environment)
- OS: Linux (uname 见 runner)
- BASE_URL: `http://127.0.0.1:8080`
- startedAt: `2026-09-26T03:22:23.576Z`
- projectName: `E2E全量-20260926-muhtqcok`
- 套件: `web/e2e/full-system-browser-e2e.spec.ts`(21 cases, serial)
- 证据目录: `.doc/test-reports/assets/2026-09-26-full-system-browser-e2e/`
## 四、 预期结果 (Expected Results)
- 全部适用用例 PASS;串行依赖下前置失败则后续 SKIP。
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
| Case | Name | Actual (截断) | Verdict | DurationMs |
|---|---|---|---|---|
| FS-IAM-01 | admin creates multi-role users | e2e26_author_muhtqcok,e2e26_reviewer_muhtqcok,e2e26_approver_muhtqcok,e2e26_member_muhtqcok,e2e26_guest_muhtqcok | PASS | 2195 |
| FS-IAM-02 | first-login password change | 5/5 password changes OK | PASS | 2090 |
| FS-PROJ-01 | create project + members | TimeoutError: locator.selectOption: Timeout 30000ms exceeded. Call log:  - waiting for getByText('发起医疗器械新项目立项', { e | FAIL | 30462 |
| FS-PROJ-02 | — | 未运行 | SKIP | — |
| FS-CHAT-01 | — | 未运行 | SKIP | — |
| FS-SQUAD-WF-01 | — | 未运行 | SKIP | — |
| FS-DOC-REV-01 | — | 未运行 | SKIP | — |
| FS-NONAUTH-01 | — | 未运行 | SKIP | — |
| FS-NONAUTH-02 | — | 未运行 | SKIP | — |
| FS-DOC-REV-02 | — | 未运行 | SKIP | — |
| FS-DOC-REV-03 | — | 未运行 | SKIP | — |
| FS-DOC-REV-04 | — | 未运行 | SKIP | — |
| FS-DOC-REV-05 | — | 未运行 | SKIP | — |
| FS-DOC-REV-06 | — | 未运行 | SKIP | — |
| FS-DOC-REV-07 | — | 未运行 | SKIP | — |
| FS-ASSIST-01 | — | 未运行 | SKIP | — |
| FS-SQUAD-FREE-01 | — | 未运行 | SKIP | — |
| FS-UPLOAD-01 | — | 未运行 | SKIP | — |
| FS-KB-01 | — | 未运行 | SKIP | — |
| FS-CTX-01 | — | 未运行 | SKIP | — |
| FS-CONSOLE-01 | — | 未运行 | SKIP | — |
### FS-PROJ-01 失败摘要
- expected: `project created`
- actual: `TimeoutError: locator.selectOption: Timeout 30000ms exceeded.
Call log:
 - waiting for getByText('发起医疗器械新项目立项', { exact: true }).locator('xpath=ancestor::div[contains(@style,"position: fixed")][1]').getByText('E2E成员-muhtqcok', { exact: true }).first().locator('xpath=ancestor::div[contains(@style,"justify-content: space-between")][1]').locator('select')
 - locator resolved to <select>…</select>
 - attempting select option action
 2 × waiting for element to be visible and enabled
 - did not find some options
 - retrying select option action
 - waiting 20ms
 2 × waiting for element to be visible and enabled
 - did not find some options
 - retrying select option action
 - waiting 100ms
 60 × waiting for element to be visible and enabled
 - did not find some options
 - retrying select option action
 - waiting 500ms
`
- 根因线索(Playwright): `selectOption` 超时 — 成员角色 `<select>` 未找到目标 option(见 `playwright.log` / `FS-PROJ-01-FAIL.png`)。
## 六、 自动化测试套件汇总 (Test Suite Execution)
- Playwright exit: 1
- PASS: 2
- FAIL: 1
- SKIP/未运行: 18
- 合计计划: 21
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
- 结论: **未通过**(FS-PROJ-01 FAIL,后续 18 用例未运行)。
- 保留账号(密码省略): e2e26_author_muhtqcok, e2e26_reviewer_muhtqcok, e2e26_approver_muhtqcok, e2e26_member_muhtqcok, e2e26_guest_muhtqcok
- 项目名: `E2E全量-20260926-muhtqcok`
- 建议: 修复立项弹窗成员角色 select 选项值/文案对齐后重跑全套。
生成时间: 2026-09-26T03:23:30.208669+00:00
@@ -0,0 +1,18 @@
{
"token": "<redacted>",
"user": {
"id": 4,
"username": "admin",
"name": "系统管理员",
"status": "active",
"must_change_password": "<redacted>",
"role_id": "role-admin",
"position": "系统管理员",
"employee_id": "SYS-000",
"department": "系统运维部",
"created_at": "2026-09-26 03:08:47",
"updated_at": "2026-09-26 03:08:47"
},
"must_change_password": "<redacted>",
"env": "dev"
}
@@ -0,0 +1,10 @@
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:24.148Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:24.151Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:24.152Z"}
{"kind":"console","level":"warning","text":"[useChatWindow] fetch window failed, falling back to local cache/fallback Error: fetchChatWindow failed: HTTP 404\n at Jx (http://127.0.0.1:8080/assets/index-I90hqfds.js:54:6112)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:436:2697","ts":"2026-09-26T03:22:24.154Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:24.155Z"}
{"kind":"console","level":"warning","text":"Failed to load date stats: Error: fetchChatDates failed: HTTP 404\n at C_ (http://127.0.0.1:8080/assets/index-I90hqfds.js:54:7112)","ts":"2026-09-26T03:22:24.155Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:24.155Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:24.156Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:24.156Z"}
{"kind":"console","level":"warning","text":"Failed to load category stats: Error: fetchChatCategories failed: HTTP 404\n at T_ (http://127.0.0.1:8080/assets/index-I90hqfds.js:54:7452)","ts":"2026-09-26T03:22:24.156Z"}
@@ -0,0 +1,58 @@
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.178Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.179Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.179Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:26.183Z"}
{"kind":"console","level":"warning","text":"Failed to load category stats: Error: fetchChatCategories failed: HTTP 404\n at T_ (http://127.0.0.1:8080/assets/index-I90hqfds.js:54:7452)","ts":"2026-09-26T03:22:26.184Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:26.184Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:26.185Z"}
{"kind":"console","level":"warning","text":"Failed to load date stats: Error: fetchChatDates failed: HTTP 404\n at C_ (http://127.0.0.1:8080/assets/index-I90hqfds.js:54:7112)","ts":"2026-09-26T03:22:26.185Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.185Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:26.185Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:26.185Z"}
{"kind":"console","level":"warning","text":"[useChatWindow] fetch window failed, falling back to local cache/fallback Error: fetchChatWindow failed: HTTP 404\n at Jx (http://127.0.0.1:8080/assets/index-I90hqfds.js:54:6112)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:436:2697","ts":"2026-09-26T03:22:26.185Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.187Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.335Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.336Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.336Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.339Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:26.339Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.580Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.580Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.582Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.582Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:26.583Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.738Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.739Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.741Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.745Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:26.745Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.948Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.948Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:26.948Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.950Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:26.950Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.105Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.105Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.105Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.108Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:27.108Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.336Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.337Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:27.337Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.337Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.338Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.493Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.495Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.510Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.511Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:27.511Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.711Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.713Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.713Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:27.714Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.714Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.869Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.871Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.871Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:27.875Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:27.875Z"}
@@ -0,0 +1,20 @@
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:28.247Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:28.248Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:28.248Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:28.251Z"}
{"kind":"console","level":"warning","text":"[useChatWindow] fetch window failed, falling back to local cache/fallback Error: fetchChatWindow failed: HTTP 404\n at Jx (http://127.0.0.1:8080/assets/index-I90hqfds.js:54:6112)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:436:2697","ts":"2026-09-26T03:22:28.251Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:28.252Z"}
{"kind":"console","level":"warning","text":"[deliverables] 工作流受控文档同步失败: Error: list project workflow documents failed: 403\n at sm (http://127.0.0.1:8080/assets/index-I90hqfds.js:55:88607)\n at async http://127.0.0.1:8080/assets/index-I90hqfds.js:463:3951","ts":"2026-09-26T03:22:28.252Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:28.252Z"}
{"kind":"console","level":"warning","text":"Failed to load category stats: Error: fetchChatCategories failed: HTTP 404\n at T_ (http://127.0.0.1:8080/assets/index-I90hqfds.js:54:7452)","ts":"2026-09-26T03:22:28.253Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:28.253Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:28.254Z"}
{"kind":"console","level":"warning","text":"Failed to load date stats: Error: fetchChatDates failed: HTTP 404\n at C_ (http://127.0.0.1:8080/assets/index-I90hqfds.js:54:7112)","ts":"2026-09-26T03:22:28.254Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:28.254Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:33.247Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:38.248Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:43.246Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:48.247Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:53.248Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 403 (Forbidden)","ts":"2026-09-26T03:22:58.247Z"}
{"kind":"console","level":"error","text":"Failed to load resource: the server responded with a status of 404 (Not Found)","ts":"2026-09-26T03:22:58.248Z"}
@@ -0,0 +1 @@
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5433,"kb_ready":true,"database_ready":true,"schema_version":75,"schema_ready":true,"task_store_ready":true,"vault_identity_ok":false,"vault_connected":false,"vault_lag_ok":true,"events_ready":true}
@@ -0,0 +1,6 @@
captured_at=2026-09-26T03:10:34+00:00
users_total=4
usernames=admin,seed-admin,seed-lizhuguan,seed-zhanggong
seed_demo_present=0
projects=10
goose_version=75
@@ -0,0 +1 @@
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5433,"kb_ready":true,"database_ready":true,"schema_version":75,"schema_ready":true,"task_store_ready":true,"vault_identity_ok":false,"vault_connected":false,"vault_lag_ok":true,"events_ready":true}
@@ -0,0 +1,4 @@
captured_at=2026-09-26T03:08:46+00:00
users=424
projects=769
goose_version=75
@@ -0,0 +1 @@
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5433,"kb_ready":true,"database_ready":true,"schema_version":75,"schema_ready":true,"task_store_ready":true,"vault_identity_ok":false,"vault_connected":false,"vault_lag_ok":true,"events_ready":true}
@@ -0,0 +1 @@
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5433,"kb_ready":true,"database_ready":true,"schema_version":75,"schema_ready":true,"task_store_ready":true,"vault_identity_ok":false,"vault_connected":false,"vault_lag_ok":true,"events_ready":true}
@@ -0,0 +1,18 @@
{
"note": "Passwords intentionally omitted. Accounts retained after E2E by design.",
"projectName": "E2E全量-20260926-muhtqcok",
"usernames": [
"e2e26_author_muhtqcok",
"e2e26_reviewer_muhtqcok",
"e2e26_approver_muhtqcok",
"e2e26_member_muhtqcok",
"e2e26_guest_muhtqcok"
],
"roles": {
"author": "e2e26_author_muhtqcok",
"reviewer": "e2e26_reviewer_muhtqcok",
"approver": "e2e26_approver_muhtqcok",
"member": "e2e26_member_muhtqcok",
"guest": "e2e26_guest_muhtqcok"
}
}
@@ -0,0 +1,29 @@
{
"startedAt": "2026-09-26T03:22:23.576Z",
"baseURL": "http://127.0.0.1:8080",
"display": "",
"headedHint": false,
"projectName": "E2E全量-20260926-muhtqcok",
"users": {
"author": {
"username": "e2e26_author_muhtqcok",
"display": "E2E编制-muhtqcok"
},
"reviewer": {
"username": "e2e26_reviewer_muhtqcok",
"display": "E2E审核-muhtqcok"
},
"approver": {
"username": "e2e26_approver_muhtqcok",
"display": "E2E批准-muhtqcok"
},
"member": {
"username": "e2e26_member_muhtqcok",
"display": "E2E成员-muhtqcok"
},
"guest": {
"username": "e2e26_guest_muhtqcok",
"display": "E2E访客-muhtqcok"
}
}
}
@@ -0,0 +1 @@
# placeholder so screenshots/ exists in git evidence tree
Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

@@ -0,0 +1,7 @@
# Shell execution blocker (agent session)
- **time**: 2026-09-26T03:12Z–ongoing
- **symptom**: Cursor Shell tool returns `spawn /bin/bash ENOENT` for every command (including `/usr/bin/bash -lc …` and `true`).
- **host evidence**: `/bin/bash` exists as a binary on the filesystem (Read tool reports “Binary files without an extension are not supported”), so this is an **execution backend / sandbox spawn** failure, not a missing host bash.
- **impact**: Playwright cannot be launched from this agent session until Shell recovers; file writes (spec/docs) succeeded via Write tool.
- **recovery plan**: re-run `web/scripts/run-full-system-browser-e2e.sh` from worktree when Shell works; then fill test report from `ui-results.json` + `playwright.log`.
@@ -0,0 +1,32 @@
# Shell still blocked — cannot fix libatk / re-run / commit
- **checked_at**: 2026-09-26T03:22:43Z
- **probe**: background Shell `/bin/sh -c 'echo via_sh_ok'` → terminal `768488.txt`
- **error**: `spawn /bin/bash ENOENT` (elapsed_ms: 12)
- **also failed**: `echo hi`, `/usr/bin/env echo hi` (768487), foreground Shell “no exit status”
- **cannot complete**:
1. `npx playwright install-deps chromium` / `apt install libatk1.0-0`
2. Re-run with `PLAYWRIGHT_CHANNEL=chrome|msedge`
3. Docker `mcr.microsoft.com/playwright` fallback (needs shell)
4. `agentctl with` commit
- **partial prior evidence** (not a full-suite PASS):
- `ui-results.json`: FS-IAM-01 PASS, FS-IAM-02 PASS only
- `playwright.log`: 2/21 listed then truncated (no exit summary)
- host Chromium historically fails on missing `libatk-1.0.so.0` (see repo prior reports)
- **recovery (for parent / host with working shell)**:
```bash
# preferred if sudo available
cd /home/weichen/projects/Agent-System/.worktrees/full-system-browser-e2e-2026-09-26/web
npx playwright install-deps chromium
# or: sudo apt-get install -y libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2
# alternate channel
export PLAYWRIGHT_CHANNEL=chrome # or msedge if installed
bash ../web/scripts/run-full-system-browser-e2e.sh
# OR docker (historical workaround when no sudo):
# docker run --rm --network host -v "$PWD:/work" -w /work/web \
# -e BASE_URL -e RUN_UI_ACCEPTANCE=1 -e UI_ACCEPTANCE_ASSETS_DIR=... \
# mcr.microsoft.com/playwright:v1.63.0-noble \
# npx playwright test e2e/full-system-browser-e2e.spec.ts --reporter=list
```
@@ -0,0 +1,17 @@
# Shell unavailable evidence (subagent)
- Timestamp: 2026-09-26T03:20:06Z
- Shell tool result for `echo hi`: "The shell command returned no exit status, so its result is unknown — do not assume it ran or succeeded."
- Same for `node -e "require('child_process').execSync('echo hi',{stdio:'inherit'})"`
- Same for `/bin/sh -c '...'` and redirect-to-file probe
- Probe file write via Shell did NOT create target path (confirmed missing via Read)
- Background Shell (`block_until_ms: 0`) DID surface failure in terminal file:
- path: `/home/weichen/.cursor/projects/home-weichen-projects-Agent-System/terminals/152517.txt`
- command: `/usr/bin/env echo hi`
- error: `spawn /bin/bash ENOENT`
- status: failed; elapsed_ms: 14
- Read on `/bin/bash`, `/usr/bin/bash`, `/bin/sh`: host FS sees binaries ("Binary files without an extension are not supported by the read executor") — but Cursor Shell spawn cannot exec `/bin/bash`
- WebFetch localhost health blocked: isolated server cannot fetch 127.0.0.1
- No agentctl / pi-subagents / exec MCP namespaces available in this subagent catalog
- Write tool works (this evidence file)
- E2E NOT RUN — do not treat as PASS
@@ -0,0 +1,106 @@
{
"FS-IAM-01": {
"id": "FS-IAM-01",
"name": "admin creates multi-role users",
"priority": "P0",
"input": "admin console → 开通受控员工账号 ×5",
"expected": "author/reviewer/approver/member/guest created",
"actual": "e2e26_author_muhtqcok,e2e26_reviewer_muhtqcok,e2e26_approver_muhtqcok,e2e26_member_muhtqcok,e2e26_guest_muhtqcok",
"verdict": "PASS",
"durationMs": 2195,
"console_errors": [
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)"
]
},
"FS-IAM-02": {
"id": "FS-IAM-02",
"name": "first-login password change",
"priority": "P0",
"input": "each e2e26_* account first login",
"expected": "all reach workbench after reset",
"actual": "5/5 password changes OK",
"verdict": "PASS",
"durationMs": 2090,
"console_errors": [
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)"
]
},
"FS-PROJ-01": {
"id": "FS-PROJ-01",
"name": "create project + members",
"priority": "P0",
"input": "create project",
"expected": "project created",
"actual": "TimeoutError: locator.selectOption: Timeout 30000ms exceeded.\nCall log:\n\u001b[2m - waiting for getByText('发起医疗器械新项目立项', { exact: true }).locator('xpath=ancestor::div[contains(@style,\"position: fixed\")][1]').getByText('E2E成员-muhtqcok', { exact: true }).first().locator('xpath=ancestor::div[contains(@style,\"justify-content: space-between\")][1]').locator('select')\u001b[22m\n\u001b[2m - locator resolved to <select>…</select>\u001b[22m\n\u001b[2m - attempting select option action\u001b[22m\n\u001b[2m 2 × waiting for element to be visible and enabled\u001b[22m\n\u001b[2m - did not find some options\u001b[22m\n\u001b[2m - retrying select option action\u001b[22m\n\u001b[2m - waiting 20ms\u001b[22m\n\u001b[2m 2 × waiting for element to be visible and enabled\u001b[22m\n\u001b[2m - did not find some options\u001b[22m\n\u001b[2m - retrying select option action\u001b[22m\n\u001b[2m - waiting 100ms\u001b[22m\n\u001b[2m 60 × waiting for element to be visible and enabled\u001b[22m\n\u001b[2m - did not find some options\u001b[22m\n\u001b[2m - retrying select option action\u001b[22m\n\u001b[2m - waiting 500ms\u001b[22m\n",
"verdict": "FAIL",
"durationMs": 30462,
"console_errors": [
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 403 (Forbidden)",
"[error] Failed to load resource: the server responded with a status of 404 (Not Found)"
]
}
}
@@ -0,0 +1,57 @@
# Wipe receipt — agent_system_dev → bootstrap-only
- **time**: 2026-09-26T03:08Z–03:10Z (UTC+0 wall clock on host)
- **operator task**: `full-system-browser-e2e-wipe-2026-09-26` (env:dev)
- Note: parent task `full-system-browser-e2e-2026-09-26` only had `docs:publish`; same-id capability expansion is denied by agentctl, so wipe used a sibling wipe task.
- **scope**: drop/create **only** `agent_system_dev` on localpg `:5433`. Did **not** touch `regulations_kb_dev`, `data/dev/pg` data directory, docker volumes, or test/main.
## Before
| field | value |
|---|---|
| health | `status=ok` `env=dev` `schema_version=75` `schema_ready=true` `database_ready=true` `kb_ready=true` |
| stats | users=424, projects=769, goose_version=75 |
| evidence | `pre-wipe/health-before.json`, `pre-wipe/ready-before.json`, `pre-wipe/pre-wipe-stats.txt` |
## Backup
| field | value |
|---|---|
| path | `.worktrees/full-system-browser-e2e-2026-09-26/.doc/test-reports/assets/2026-09-26-full-system-browser-e2e/pre-wipe/agent_system_dev.dump` |
| format | `pg_dump -Fc` (7.6M) |
| auth | app user via `CONTEXT_DB_*` (password not written) |
## Procedure
1. SIGTERM `agent-server` on `:8080` (pid 1493262); port released.
2. `pg_dump -Fc` → dump above.
3. Via unix socket trust as `postgres` (`/run/user/1000/as-pg-5433`): `DROP DATABASE agent_system_dev` + `CREATE DATABASE … OWNER app` + extensions (`vector`, `uuid-ossp`, `pg_trgm`).
4. Restart `bin/agent-server` with `DATA_DIR=./data/dev`, `.env` loaded, plus:
- `DISABLE_DEV_SEED_USERS=true`
- `SEED_DEMO_USERS=false`
- `LOCALPG_MODE=managed` `ENV=dev`
5. Wait `/health` + `/ready` ok.
## After
| field | value |
|---|---|
| health | `status=ok` `env=dev` `schema_version=75` `schema_ready=true` `database_ready=true` `kb_ready=true` |
| agent-server | pid 1585038, pgid=own session (detached) |
| seed env | `DISABLE_DEV_SEED_USERS=true`, `SEED_DEMO_USERS=false` (confirmed in `/proc/<pid>/environ`) |
| users | `admin`, `seed-admin`, `seed-lizhuguan`, `seed-zhanggong` (total 4) |
| demo BootstrapDevSeedUsers | **absent** (`zhanggong`/`lizhuguan`/`wangzong`/`guest` count=0) |
| projects | 10 (from goose `00011_…-seed-ten-projects.sql`, not runtime demo seed) |
| goose | 75 |
| admin login | `POST /api/v1/auth/login` → **HTTP 200** (token redacted in `admin-login-response.json`) |
| regulations_kb_dev | still present |
## Seed strategy (actual)
- **Runtime** `BootstrapDevSeedUsers` / `ReactivateDevSeedUsers`: gated off by env → classic demo usernames not created.
- **Config admin**: `BootstrapAdminFromConfig` → `admin` present; login OK.
- **Goose SQL seed** (`deploy/postgres/goose/00011_…`): still inserts `seed-*` IAM rows + 10 projects on empty DB migrate. This is schema seed, not `DISABLE_DEV_SEED_USERS`.
## Boundaries respected
- No `docker volume rm`; no delete of `data/dev/pg`; no test/main; no `regulations_kb_*` drop; no push; no `--force`.
+2 -1
View File
@@ -13,10 +13,11 @@
| `workflow-plan-409-frozen-duties.spec.ts` | `RUN_UI_ACCEPTANCE=1` | `npm run test:e2e:workflow-plan-409-frozen-duties` | |
| `conversation-intent-dual-tab.spec.ts` | `INTENT_DUAL_TAB=1` | `npm run test:e2e:conversation-intent-dual-tab` | 独立双标签风险口径 |
| `swboot-wizard.spec.ts` | `RUN_UI_ACCEPTANCE=1` | `npm run test:e2e:swboot-wizard` | SWBOOT L6 软件向导二次验收;需 project:create 账号 |
| `full-system-browser-e2e.spec.ts` | `RUN_UI_ACCEPTANCE=1` | `npm run test:e2e:full-system-browser` | 全系统多人真实浏览器验收;证据默认 `assets/2026-09-26-full-system-browser-e2e`;账号前缀 `e2e26_` |
约定:
- `playwright test --list` 期望:**33 tests in 10 files**(Wave 3 退役冗余 `document-revision.spec.ts` / 消灭 `DOCREV_E2E_BASE_URL`)。
- `playwright test --list` 期望随新增 spec 递增(含 `full-system-browser-e2e`);Wave 3 已退役冗余 `document-revision.spec.ts` / 消灭 `DOCREV_E2E_BASE_URL`。
- 新增 spec 必须同时补本表与 `package.json` 脚本。
- 不升 `MULTI_INTENT_PLAN_TIER`;不触碰项目 143 写路径。
- DOCREV 收口分组(依赖 UI-00.. 前置,不可安全单独中途开跑):`npm run test:ui-acceptance:groups` → UI-03 / UI-05 / UI-06 / UI-07-08-09 / UI-11 / UI-13 / post-restart。
File diff suppressed because it is too large Load Diff
+1
View File
@@ -20,6 +20,7 @@
"test:e2e:intent-plan-cards": "RUN_UI_ACCEPTANCE=1 playwright test e2e/intent-plan-cards.spec.ts --project=chromium",
"test:e2e:project143-regression": "RUN_UI_ACCEPTANCE=1 playwright test e2e/project143-regression.spec.ts --project=chromium",
"test:e2e:workflow-plan-409-frozen-duties": "RUN_UI_ACCEPTANCE=1 playwright test e2e/workflow-plan-409-frozen-duties.spec.ts --project=chromium",
"test:e2e:full-system-browser": "RUN_UI_ACCEPTANCE=1 playwright test e2e/full-system-browser-e2e.spec.ts --project=chromium",
"test:e2e:list": "playwright test --list",
"test:e2e:initial-load": "RUN_INITIAL_LOAD_BASELINE=1 playwright test e2e/initial-load-performance.spec.ts --project=chromium",
"test:e2e:initial-load:throttle": "RUN_INITIAL_LOAD_BASELINE=1 INITIAL_LOAD_THROTTLE=1 playwright test e2e/initial-load-performance.spec.ts --project=chromium -g throttled",
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
# Run full-system browser E2E against local dev (main tree serves :8080).
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
WT="$(cd "$(dirname "$0")/.." && pwd)"
ASSETS="${UI_ACCEPTANCE_ASSETS_DIR:-$WT/.doc/test-reports/assets/2026-09-26-full-system-browser-e2e}"
mkdir -p "$ASSETS/screenshots"
cd "$WT/web"
set -a
# shellcheck disable=SC1091
source "$ROOT/.env"
set +a
export BASE_URL="${BASE_URL:-http://127.0.0.1:8080}"
export RUN_UI_ACCEPTANCE=1
export UI_ACCEPTANCE_ASSETS_DIR="$ASSETS"
export DISABLE_DEV_SEED_USERS=true
EXTRA=()
if [[ -n "${DISPLAY:-}" && "${HEADED:-}" == "1" ]]; then
EXTRA+=(--headed --slow-mo 100)
fi
echo "BASE_URL=$BASE_URL ASSETS=$ASSETS DISPLAY=${DISPLAY:-}(empty=headless)" | tee "$ASSETS/run-env.txt"
npx playwright test e2e/full-system-browser-e2e.spec.ts --reporter=list "${EXTRA[@]}" 2>&1 | tee "$ASSETS/playwright.log"