diff --git a/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.i18n.yaml index e72ccbece5..62ea89bc3b 100644 --- a/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.md -2026-07-30-command-row-copy-contract.md: f6d5199389b3907780c501894e2861e6add85e77 -2026-07-30-command-row-copy-contract.zh.md: 86f0c044e841a6a0148b1f785582868bba5bb3d0 +2026-07-30-command-row-copy-contract.md: d410adf62dbbc4445936c70309d5902bc184b16f +2026-07-30-command-row-copy-contract.zh.md: 0f680f9beb8b335dd6311cadc6c7e022809fb8f2 diff --git a/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.md b/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.md index f6d5199389..d410adf62d 100644 --- a/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.md +++ b/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.md @@ -32,4 +32,4 @@ The log is unchanged: `command/run` keeps the structured `name`/`args` split, so ## Consequences -Every command row gets shorter, and the rule scales: a new command's author writes its outcome without knowing which surface renders it, and no surface has to de-duplicate. The cost is that the dispatched arguments leave the collapsed row — while a command is still executing the row shows only its name and `执行中…` — and that the no-caption rule is a convention the reviewer enforces, not a gate. The `/permission` texts are pinned by the permission package's command tests, and the assembled row copy by the [seeded-history](../../../../apps/web/tests/snapshots/seeded-history/command-row.expected.md) web golden, which reaches a real settled command row keylessly because `/permission` runs entirely on the host. +Every command row gets shorter, and the rule scales: a new command's author writes its outcome without knowing which surface renders it, and no surface has to de-duplicate. The cost is that the dispatched arguments leave the collapsed row — while a command is still executing the row shows only its name and `执行中…` — and that the no-caption rule is a convention the reviewer enforces, not a gate. The `/permission` texts are pinned by the permission package's command tests, and the assembled row copy by the [seeded-history](../../../../snapshots/web/seeded-history/command-row.expected.md) web golden, which reaches a real settled command row keylessly because `/permission` runs entirely on the host. diff --git a/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.zh.md b/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.zh.md index 86f0c044e8..0f680f9beb 100644 --- a/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-30-command-row-copy-contract.zh.md @@ -32,4 +32,4 @@ Web 命令条目由一对落库的[命令生命周期事件](../../proposed/arch ## 后果 -每一条命令条目都变短了,而且这条规则可扩展:新命令的作者写结果时无需知道由哪个界面渲染,任何界面也都不必再去重。代价是分派参数离开了折叠行——命令仍在执行时,行上只有名字和 `执行中…`——以及「不加题头」这条规则是靠评审执行的约定,而非门禁。`/permission` 的文案由 permission 包的命令测试钉住,装配后的行文案由 [seeded-history](../../../../apps/web/tests/snapshots/seeded-history/command-row.expected.md) web 预期输出钉住:由于 `/permission` 完全在 host 上执行,该预期输出无需密钥即可覆盖一条真实的已落定命令条目。 +每一条命令条目都变短了,而且这条规则可扩展:新命令的作者写结果时无需知道由哪个界面渲染,任何界面也都不必再去重。代价是分派参数离开了折叠行——命令仍在执行时,行上只有名字和 `执行中…`——以及「不加题头」这条规则是靠评审执行的约定,而非门禁。`/permission` 的文案由 permission 包的命令测试钉住,装配后的行文案由 [seeded-history](../../../../snapshots/web/seeded-history/command-row.expected.md) web 预期输出钉住:由于 `/permission` 完全在 host 上执行,该预期输出无需密钥即可覆盖一条真实的已落定命令条目。 diff --git a/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.i18n.yaml b/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.i18n.yaml index 8e15854fdc..41bd67bef1 100644 --- a/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.md -2026-08-08-bounded-session-persistence-write-batching.md: 6d77ef90276dcf143bb63019f801379b702b43b2 -2026-08-08-bounded-session-persistence-write-batching.zh.md: e773f20ade706e97a5f84d4a4cc15cc9d3b2d836 +2026-08-08-bounded-session-persistence-write-batching.md: fc22a10537ebb9009ab1ae1ec21ca625c9025651 +2026-08-08-bounded-session-persistence-write-batching.zh.md: c2763e157fcfc2e004b14116694054c604fbfb9c diff --git a/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.md b/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.md index 6d77ef9027..fc22a10537 100644 --- a/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.md +++ b/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.md @@ -12,7 +12,7 @@ Dropping chunk events or replacing them with assembled messages would reduce log ### Quantified baseline -Repository fixtures make the logical volume concrete. Decoding the current packed rows in [`goal-multi-turn-actions`](../../../../apps/web/tests/snapshots/goal-multi-turn-actions/session.jsonl) yields 2,098 events: 2,017 chunks (96.1%). Their unpacked JSONL lines occupy 332,647 of 379,225 event bytes (87.7%), while chunk packing reduces the committed file to 89,176 bytes and 182 storage rows, including 23 packed chunk rows. [`permission-policy-context`](../../../../apps/web/tests/snapshots/permission-policy-context/session.jsonl) yields 813 events: 746 chunks (91.8%) and 118,935 of 184,821 unpacked event bytes (64.4%); its packed file is 84,917 bytes and 123 storage rows, including 14 packed rows. These are tracked deterministic fixtures, not a production workload distribution, but they demonstrate why deleting chunks would reduce logical volume and why the existing packed-row layout already removes much of their JSON envelope cost. +Repository fixtures make the logical volume concrete. Decoding the current packed rows in [`goal-multi-turn-actions`](../../../../snapshots/web/goal-multi-turn-actions/session.jsonl) yields 2,098 events: 2,017 chunks (96.1%). Their unpacked JSONL lines occupy 332,647 of 379,225 event bytes (87.7%), while chunk packing reduces the committed file to 89,176 bytes and 182 storage rows, including 23 packed chunk rows. [`permission-policy-context`](../../../../snapshots/web/permission-policy-context/session.jsonl) yields 813 events: 746 chunks (91.8%) and 118,935 of 184,821 unpacked event bytes (64.4%); its packed file is 84,917 bytes and 123 storage rows, including 14 packed rows. These are tracked deterministic fixtures, not a production workload distribution, but they demonstrate why deleting chunks would reduce logical volume and why the existing packed-row layout already removes much of their JSON envelope cost. SQLite stores one row per logical event, so those same logical logs would retain 2,098 and 813 event rows respectively; batching does not change those counts. JSONL writes one Zstandard frame and fsync per durable append batch, while SQLite performs one transaction and one session-revision increment per batch. Runtime files do not record former append boundaries, so fixture row counts cannot honestly be presented as fsync or transaction counts. diff --git a/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.zh.md b/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.zh.md index e773f20ade..c2763e157f 100644 --- a/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.zh.md +++ b/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.zh.md @@ -12,7 +12,7 @@ Status: implemented ### 量化基线 -仓库 fixture(测试前置数据)让逻辑数据量有了具体依据。对当前 [`goal-multi-turn-actions`](../../../../apps/web/tests/snapshots/goal-multi-turn-actions/session.jsonl) 中的打包行进行解码,可得到 2,098 个事件,其中 2,017 个是分片(96.1%)。这些分片解包后的 JSONL 行共 332,647 字节,占全部事件 379,225 字节的 87.7%;分片打包则把仓库中的已提交文件缩小到 89,176 字节和 182 个存储行,其中包括 23 个打包分片行。[`permission-policy-context`](../../../../apps/web/tests/snapshots/permission-policy-context/session.jsonl) 可得到 813 个事件,其中 746 个是分片(91.8%);这些分片解包后的 JSONL 行共 118,935 字节,占全部事件 184,821 字节的 64.4%。其打包文件为 84,917 字节,共 123 个存储行,其中包括 14 个打包行。这些是纳入版本控制的确定性 fixture,不代表生产工作负载分布;但它们说明了删除分片为何会降低逻辑数据量,也说明现有打包行布局已经消除了大量 JSON 包装开销。 +仓库 fixture(测试前置数据)让逻辑数据量有了具体依据。对当前 [`goal-multi-turn-actions`](../../../../snapshots/web/goal-multi-turn-actions/session.jsonl) 中的打包行进行解码,可得到 2,098 个事件,其中 2,017 个是分片(96.1%)。这些分片解包后的 JSONL 行共 332,647 字节,占全部事件 379,225 字节的 87.7%;分片打包则把仓库中的已提交文件缩小到 89,176 字节和 182 个存储行,其中包括 23 个打包分片行。[`permission-policy-context`](../../../../snapshots/web/permission-policy-context/session.jsonl) 可得到 813 个事件,其中 746 个是分片(91.8%);这些分片解包后的 JSONL 行共 118,935 字节,占全部事件 184,821 字节的 64.4%。其打包文件为 84,917 字节,共 123 个存储行,其中包括 14 个打包行。这些是纳入版本控制的确定性 fixture,不代表生产工作负载分布;但它们说明了删除分片为何会降低逻辑数据量,也说明现有打包行布局已经消除了大量 JSON 包装开销。 SQLite 每个逻辑事件存储一行,因此同样的逻辑日志会分别保留 2,098 和 813 个事件行;批处理不会改变这些数量。JSONL 每个持久化追加批次会写入一个 Zstandard 帧并执行一次 fsync,SQLite 每个批次会执行一次事务并递增一次会话修订版本。运行时文件不记录原有追加边界,因此不能把 fixture 的存储行数当作 fsync 或事务次数。 diff --git a/.agents/notes/implemented/feature/2026-07-30-web-search-card.i18n.yaml b/.agents/notes/implemented/feature/2026-07-30-web-search-card.i18n.yaml index a85925a70e..dd2137f023 100644 --- a/.agents/notes/implemented/feature/2026-07-30-web-search-card.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-30-web-search-card.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-30-web-search-card.md -2026-07-30-web-search-card.md: 930a705fc227d7961e9cb1a51b0b04774a62c6a4 -2026-07-30-web-search-card.zh.md: 7771097423bda24c7fe254d5747205c1f06a5474 +2026-07-30-web-search-card.md: 7b16c401a4cac45a218ba0b42743b38171f99d9e +2026-07-30-web-search-card.zh.md: 4fd653ef519d3ba1cb5e6e3e9c9275b3cc8127bb diff --git a/.agents/notes/implemented/feature/2026-07-30-web-search-card.md b/.agents/notes/implemented/feature/2026-07-30-web-search-card.md index 930a705fc2..7b16c401a4 100644 --- a/.agents/notes/implemented/feature/2026-07-30-web-search-card.md +++ b/.agents/notes/implemented/feature/2026-07-30-web-search-card.md @@ -56,7 +56,7 @@ Three sites consume the derivation, mirroring the terminal card's placement exac `packages/client/ui-primitives/tests/search-block.client.spec.tsx` pins the component at per-file 100%: both kinds, the folded pre-cap total in the summary, the empty arm, per-file collapse/re-expand without touching neighbours, a file header counting as one capped row alongside its matches, the tail slice restoring its owning file header when the cut falls mid-file, the head/tail cap and its expand control across both shapes and the no-tail and default-cap edges, and the copy control writing the whole structured result on the accepted and refused clipboard paths. -`packages/client/ui-tool/tests/search-card.client.spec.tsx` pins the wiring at every render site: `searchCardModel`'s derivation for both kinds, the truncation signal, the replacement title, the recovery text surfaced only when capped, each null arm (running, no views, generic, terminal, unknown card, an uncompiled `kind`, and a known kind with a missing/malformed shape); the chat row's expand-gated matches and paths bodies through `GenericToolCard` (with the recovery footer) against the non-search args-JSON body; `SearchRow`'s resident card for both kinds, its recovery footer, its fallback body for both an errored search and a settled cardless result, its agreement with the summary row's run state, the replacement-title precedence, and the keyed registration under both `grep` and `glob` with one component; and the details panel's Output section for both kinds (with the recovery footer) against the non-search flattened form. `packages/client/ui-tool/src/*` sits on the coverage exclude list, so this file is written against no gate pressure. `packages/client/connection/src/client/fixture.ts` gains a `grep` turn emitting `kind: 'matches'` (three files, twelve rows over the row cap, `truncated` with a spill-recovery footer, so it exercises the head/tail cap and the recovery footer in the assembled snapshot) and a `glob` turn emitting `kind: 'paths'`, both driving the built-boot snapshot and the live `?fixture` server. `apps/web/tests/search-card.snapshot.ts` is the assembled-output check the repo contract asks for: it boots the real built `client.js` bundles through the keyless fixture transport, opens the fixture session, and pins the grep card's assembled shape — kind, truncation summary, the head/tail slice, and its expand control — under `apps/web/tests/snapshots/search-card/`, so a broken SearchRow registration or a dropped card fails a golden the built-boot smoke (boot-only by contract) cannot. +`packages/client/ui-tool/tests/search-card.client.spec.tsx` pins the wiring at every render site: `searchCardModel`'s derivation for both kinds, the truncation signal, the replacement title, the recovery text surfaced only when capped, each null arm (running, no views, generic, terminal, unknown card, an uncompiled `kind`, and a known kind with a missing/malformed shape); the chat row's expand-gated matches and paths bodies through `GenericToolCard` (with the recovery footer) against the non-search args-JSON body; `SearchRow`'s resident card for both kinds, its recovery footer, its fallback body for both an errored search and a settled cardless result, its agreement with the summary row's run state, the replacement-title precedence, and the keyed registration under both `grep` and `glob` with one component; and the details panel's Output section for both kinds (with the recovery footer) against the non-search flattened form. `packages/client/ui-tool/src/*` sits on the coverage exclude list, so this file is written against no gate pressure. `packages/client/connection/src/client/fixture.ts` gains a `grep` turn emitting `kind: 'matches'` (three files, twelve rows over the row cap, `truncated` with a spill-recovery footer, so it exercises the head/tail cap and the recovery footer in the assembled snapshot) and a `glob` turn emitting `kind: 'paths'`, both driving the built-boot snapshot and the live `?fixture` server. `apps/web/tests/search-card.snapshot.ts` is the assembled-output check the repo contract asks for: it boots the real built `client.js` bundles through the keyless fixture transport, opens the fixture session, and pins the grep card's assembled shape — kind, truncation summary, the head/tail slice, and its expand control — under `apps/web/tests/goldens/search-card/`, so a broken SearchRow registration or a dropped card fails a golden the built-boot smoke (boot-only by contract) cannot. ## Related diff --git a/.agents/notes/implemented/feature/2026-07-30-web-search-card.zh.md b/.agents/notes/implemented/feature/2026-07-30-web-search-card.zh.md index 7771097423..4fd653ef51 100644 --- a/.agents/notes/implemented/feature/2026-07-30-web-search-card.zh.md +++ b/.agents/notes/implemented/feature/2026-07-30-web-search-card.zh.md @@ -56,7 +56,7 @@ Status: implemented `packages/client/ui-primitives/tests/search-block.client.spec.tsx` 以 per-file 100% 覆盖固定组件:两种 kind、折入摘要的截断前总数、空结果分支、逐文件折叠/再展开且不影响邻居、一个文件头与匹配行一样,在高度上限中单独计为一行、切口落在文件中间时尾部切片恢复其所属文件头、跨两种形态的头/尾上限及其展开控件(含无尾与默认上限的边界),以及复制控件在接受与拒绝的剪贴板路径上写入整个结构化结果。 -`packages/client/ui-tool/tests/search-card.client.spec.tsx` 固定每个渲染点的接线:`searchCardModel` 对两种 kind 的推导、截断信号、替换标题、仅在截断时暴露的恢复文本,以及每个 null 分支(运行中、无视图、generic、terminal、未知卡片、本版本无法编译的 `kind`、以及一个形态缺失/错误的已知 kind);通过 `GenericToolCard` 的展开门控 matches 与 paths body(含恢复脚注),对照非搜索的 args-JSON body;`SearchRow` 对两种 kind 的常驻卡片、它的恢复脚注、它对出错搜索与已结算无卡片结果两者的 fallback body、它与摘要行运行状态的一致、替换标题优先级,以及一个组件在 `grep` 与 `glob` 两个键下的 keyed 注册;以及 details panel 的 Output 段对两种 kind(含恢复脚注),对照非搜索的压平形态。`packages/client/ui-tool/src/*` 在覆盖排除清单上,因此该文件不受 gate 压力。`packages/client/connection/src/client/fixture.ts` 新增一个发出 `kind: 'matches'` 的 `grep` turn(三个文件、十二行超过行内上限、`truncated` 且带溢出恢复脚注,因此在组装快照里同时演练头/尾上限与恢复脚注)与一个发出 `kind: 'paths'` 的 `glob` turn,两者都驱动 built-boot snapshot 与实时 `?fixture` 服务。`apps/web/tests/search-card.snapshot.ts` 是仓库约定要求的组装输出检查:它通过 keyless fixture 传输启动真实构建的 `client.js` bundle,打开 fixture 会话,并把 grep 卡片的组装形态——kind、截断摘要、头/尾切片及其展开控件——固定在 `apps/web/tests/snapshots/search-card/` 下,因此一个损坏的 SearchRow 注册或被丢弃的卡片会让一个 golden 失败,而 built-boot smoke(按约定只测启动)无法捕获它。 +`packages/client/ui-tool/tests/search-card.client.spec.tsx` 固定每个渲染点的接线:`searchCardModel` 对两种 kind 的推导、截断信号、替换标题、仅在截断时暴露的恢复文本,以及每个 null 分支(运行中、无视图、generic、terminal、未知卡片、本版本无法编译的 `kind`、以及一个形态缺失/错误的已知 kind);通过 `GenericToolCard` 的展开门控 matches 与 paths body(含恢复脚注),对照非搜索的 args-JSON body;`SearchRow` 对两种 kind 的常驻卡片、它的恢复脚注、它对出错搜索与已结算无卡片结果两者的 fallback body、它与摘要行运行状态的一致、替换标题优先级,以及一个组件在 `grep` 与 `glob` 两个键下的 keyed 注册;以及 details panel 的 Output 段对两种 kind(含恢复脚注),对照非搜索的压平形态。`packages/client/ui-tool/src/*` 在覆盖排除清单上,因此该文件不受 gate 压力。`packages/client/connection/src/client/fixture.ts` 新增一个发出 `kind: 'matches'` 的 `grep` turn(三个文件、十二行超过行内上限、`truncated` 且带溢出恢复脚注,因此在组装快照里同时演练头/尾上限与恢复脚注)与一个发出 `kind: 'paths'` 的 `glob` turn,两者都驱动 built-boot snapshot 与实时 `?fixture` 服务。`apps/web/tests/search-card.snapshot.ts` 是仓库约定要求的组装输出检查:它通过 keyless fixture 传输启动真实构建的 `client.js` bundle,打开 fixture 会话,并把 grep 卡片的组装形态——kind、截断摘要、头/尾切片及其展开控件——固定在 `apps/web/tests/goldens/search-card/` 下,因此一个损坏的 SearchRow 注册或被丢弃的卡片会让一个 golden 失败,而 built-boot smoke(按约定只测启动)无法捕获它。 ## Related diff --git a/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.i18n.yaml b/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.i18n.yaml index 635f0bfab6..dc0a40f23a 100644 --- a/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.md -2026-07-30-web-browser-snapshot-ci-gate.md: abb197f2a8e3488e2ae1edc7c2e77cbdcf919556 -2026-07-30-web-browser-snapshot-ci-gate.zh.md: 0239ae6062d2828b8b92683d4b0e7103205756fc +2026-07-30-web-browser-snapshot-ci-gate.md: e94141070ba283434f49108899f743fab6073ebc +2026-07-30-web-browser-snapshot-ci-gate.zh.md: 9976034bb0ff8ba0435be41fe9e6bd406267fadb diff --git a/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.md b/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.md index abb197f2a8..e94141070b 100644 --- a/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.md +++ b/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.md @@ -6,7 +6,7 @@ English | [中文](2026-07-30-web-browser-snapshot-ci-gate.zh.md) ## Problem -The [keyless web browser e2e lane](2026-07-24-web-gui-browser-e2e-lane.md) runs only under the local `pnpm run test:web` command, and PR CI does not compare `apps/web/tests/snapshots/**/*.expected.md`. A PR that changes user-visible web output can therefore remain green when its expected outputs are not refreshed; when any later branch explicitly runs `DSH_SNAPSHOT=refresh`, it backfills the earlier change and produces a diff unrelated to that branch. Ordinary local runs already default to read-only replay, so the gap is mandatory enforcement at the PR level, not a ban on writes in refresh mode. +The [keyless web browser e2e lane](2026-07-24-web-gui-browser-e2e-lane.md) runs only under the local `pnpm run test:web` command, and PR CI does not compare Web expectations under `snapshots/web/` or `apps/web/tests/goldens/`. A PR that changes user-visible web output can therefore remain green when its expected outputs are not refreshed; when any later branch explicitly runs `DSH_SNAPSHOT=refresh`, it backfills the earlier change and produces a diff unrelated to that branch. Ordinary local runs already default to read-only replay, so the gap is mandatory enforcement at the PR level, not a ban on writes in refresh mode. ## Decision diff --git a/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.zh.md b/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.zh.md index 0239ae6062..9976034bb0 100644 --- a/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.zh.md +++ b/.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.zh.md @@ -6,7 +6,7 @@ Status: implemented ## 问题 -[无密钥 Web 浏览器 e2e 车道](2026-07-24-web-gui-browser-e2e-lane.zh.md)只由本地 `pnpm run test:web` 运行,PR CI 不比较 `apps/web/tests/snapshots/**/*.expected.md`。因此,改变用户可见 Web 输出的 PR 可以在漏刷预期输出时保持绿色;后来任意分支显式运行 `DSH_SNAPSHOT=refresh`,都会替前序变更补账并产生与本分支无关的 diff。普通本地运行已经默认使用只读 replay,缺口是 PR 级的强制执行,而不是禁止 refresh 写入。 +[无密钥 Web 浏览器 e2e 车道](2026-07-24-web-gui-browser-e2e-lane.zh.md)只由本地 `pnpm run test:web` 运行,PR CI 不比较 `snapshots/web/` 或 `apps/web/tests/goldens/` 下的 Web 预期输出。因此,改变用户可见 Web 输出的 PR 可以在漏刷预期输出时保持绿色;后来任意分支显式运行 `DSH_SNAPSHOT=refresh`,都会替前序变更补账并产生与本分支无关的 diff。普通本地运行已经默认使用只读 replay,缺口是 PR 级的强制执行,而不是禁止 refresh 写入。 ## 决策 diff --git a/apps/web/tests/access-confirmation.e2e.ts b/apps/web/tests/access-confirmation.e2e.ts index a173f8399e..0c33b62d3b 100644 --- a/apps/web/tests/access-confirmation.e2e.ts +++ b/apps/web/tests/access-confirmation.e2e.ts @@ -13,7 +13,7 @@ import { } from './scaffold.ts' import { ZH_BROWSER_LOCALE, connectFreshWorkspaceZh, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/access-confirmation', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/access-confirmation', import.meta.url)) const UI_EXPECTED = join(SNAPSHOT_DIR, 'ui.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/agent-preset-authoring.e2e.ts b/apps/web/tests/agent-preset-authoring.e2e.ts index e2b9134ca3..04665819b4 100644 --- a/apps/web/tests/agent-preset-authoring.e2e.ts +++ b/apps/web/tests/agent-preset-authoring.e2e.ts @@ -22,7 +22,7 @@ import { } from './scaffold.ts' import { ZH_BROWSER_LOCALE, connectFreshWorkspaceZh, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/agent-preset-authoring', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/agent-preset-authoring', import.meta.url)) const SECTION_EXPECTED = join(SNAPSHOT_DIR, 'section.expected.md') const COPY_DIALOG_EXPECTED = join(SNAPSHOT_DIR, 'copy-dialog.expected.md') const CREATED_EXPECTED = join(SNAPSHOT_DIR, 'created.expected.md') diff --git a/apps/web/tests/agent-preset-selection.e2e.ts b/apps/web/tests/agent-preset-selection.e2e.ts index df6a2baa36..781823f19e 100644 --- a/apps/web/tests/agent-preset-selection.e2e.ts +++ b/apps/web/tests/agent-preset-selection.e2e.ts @@ -24,7 +24,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/agent-preset-selection', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/agent-preset-selection', import.meta.url)) const HERO_EXPECTED = join(SNAPSHOT_DIR, 'hero.expected.md') const MENU_EXPECTED = join(SNAPSHOT_DIR, 'menu.expected.md') const HEADER_EXPECTED = join(SNAPSHOT_DIR, 'header.expected.md') diff --git a/apps/web/tests/approval-composer.e2e.ts b/apps/web/tests/approval-composer.e2e.ts index 9739c13b07..9fb2c112d0 100644 --- a/apps/web/tests/approval-composer.e2e.ts +++ b/apps/web/tests/approval-composer.e2e.ts @@ -16,7 +16,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/approval-composer', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/approval-composer', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') // The golden covers the stable waiting panel; direct assertions cover its answer. const UI_EXPECTED = join(SNAPSHOT_DIR, 'ui.expected.md') diff --git a/apps/web/tests/background-job-list.e2e.ts b/apps/web/tests/background-job-list.e2e.ts index b0fdc62ddb..fcf02290fd 100644 --- a/apps/web/tests/background-job-list.e2e.ts +++ b/apps/web/tests/background-job-list.e2e.ts @@ -16,8 +16,8 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const FIXTURE = fileURLToPath(new URL('./snapshots/fresh-round-trip/session.jsonl', import.meta.url)) -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/background-job-list', import.meta.url)) +const FIXTURE = fileURLToPath(new URL('../../../snapshots/web/fresh-round-trip/session.jsonl', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/background-job-list', import.meta.url)) const RUNNING_EXPECTED = join(SNAPSHOT_DIR, 'running.expected.md') const SETTLED_EXPECTED = join(SNAPSHOT_DIR, 'settled.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/bash-abort-row.e2e.ts b/apps/web/tests/bash-abort-row.e2e.ts index 3e180e393d..dcd4f93cf9 100644 --- a/apps/web/tests/bash-abort-row.e2e.ts +++ b/apps/web/tests/bash-abort-row.e2e.ts @@ -14,7 +14,7 @@ import { import { newEnglishPage, saveFailureShot } from './support.ts' const FIXTURE = fileURLToPath(new URL('../../../snapshots/acp/cancel-tool-calls/session.jsonl', import.meta.url)) -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/bash-abort-row', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/bash-abort-row', import.meta.url)) const UI_EXPECTED = join(SNAPSHOT_DIR, 'ui.expected.md') const MODE = webSnapshotMode() const SEED_ID = 'bash-abort-row-web-e2e' diff --git a/apps/web/tests/code-mode-round.e2e.ts b/apps/web/tests/code-mode-round.e2e.ts index 342f9328e0..792ee3f283 100644 --- a/apps/web/tests/code-mode-round.e2e.ts +++ b/apps/web/tests/code-mode-round.e2e.ts @@ -13,8 +13,8 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const FIXTURE = fileURLToPath(new URL('./snapshots/code-mode-round/session.jsonl', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/code-mode-round/ui.expected.md', import.meta.url)) +const FIXTURE = fileURLToPath(new URL('../../../snapshots/web/code-mode-round/session.jsonl', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/code-mode-round/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() // Elicits the successful and failed sub-rows this scenario asserts. diff --git a/apps/web/tests/cold-blank-session.e2e.ts b/apps/web/tests/cold-blank-session.e2e.ts index dd79c4e8b1..5d914cf0df 100644 --- a/apps/web/tests/cold-blank-session.e2e.ts +++ b/apps/web/tests/cold-blank-session.e2e.ts @@ -12,7 +12,7 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/cold-blank-session', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/cold-blank-session', import.meta.url)) const SIDEBAR_EXPECTED = join(SNAPSHOT_DIR, 'sidebar.expected.md') const MODE = webSnapshotMode() const SESSION_ID = 'cold-blank-session-web-e2e' diff --git a/apps/web/tests/composer-draft-scroll.e2e.ts b/apps/web/tests/composer-draft-scroll.e2e.ts index b8fa9a6121..ddfc97990d 100644 --- a/apps/web/tests/composer-draft-scroll.e2e.ts +++ b/apps/web/tests/composer-draft-scroll.e2e.ts @@ -12,7 +12,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/composer-draft-scroll', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/composer-draft-scroll', import.meta.url)) /** Scroll geometry is absent from ARIA snapshots, so this scenario records it directly. */ const GEOMETRY_EXPECTED = join(SNAPSHOT_DIR, 'geometry.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/composer-tab-geometry.e2e.ts b/apps/web/tests/composer-tab-geometry.e2e.ts index 0399e665f8..2ca0b70439 100644 --- a/apps/web/tests/composer-tab-geometry.e2e.ts +++ b/apps/web/tests/composer-tab-geometry.e2e.ts @@ -13,7 +13,7 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/composer-tab-geometry', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/composer-tab-geometry', import.meta.url)) /** Records platform-neutral distances between the two tabs' card rectangles. */ const GEOMETRY_EXPECTED = join(SNAPSHOT_DIR, 'geometry.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/conversation-column-overflow.e2e.ts b/apps/web/tests/conversation-column-overflow.e2e.ts index fc51e0da34..e933759271 100644 --- a/apps/web/tests/conversation-column-overflow.e2e.ts +++ b/apps/web/tests/conversation-column-overflow.e2e.ts @@ -31,7 +31,7 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/conversation-column-overflow', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/conversation-column-overflow', import.meta.url)) /** * Committed golden of the one-axis relation at every stop. It records * relations and booleans, never absolute coordinates: the column width follows diff --git a/apps/web/tests/cordis-tool-round.e2e.ts b/apps/web/tests/cordis-tool-round.e2e.ts index 66d1a3b132..6ff81e2e5e 100644 --- a/apps/web/tests/cordis-tool-round.e2e.ts +++ b/apps/web/tests/cordis-tool-round.e2e.ts @@ -20,8 +20,8 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const FIXTURE = fileURLToPath(new URL('./snapshots/cordis-tool-round/session.jsonl', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/cordis-tool-round/ui.expected.md', import.meta.url)) +const FIXTURE = fileURLToPath(new URL('../../../snapshots/web/cordis-tool-round/session.jsonl', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/cordis-tool-round/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() const CORDIS_TOOLS = ['cordis_inspect_self', 'cordis_define', 'cordis_run', 'cordis_stop'] as const const PACKAGE_CODE = 'return { name: "snapshot-noop", apply(ctx) {} }' diff --git a/apps/web/tests/declared-reasoning.e2e.ts b/apps/web/tests/declared-reasoning.e2e.ts index f908511214..1ba84d655b 100644 --- a/apps/web/tests/declared-reasoning.e2e.ts +++ b/apps/web/tests/declared-reasoning.e2e.ts @@ -18,8 +18,8 @@ import { ZH_BROWSER_LOCALE, connectFreshWorkspaceZh, saveFailureShot } from './s /** Starts the shipped default on this scenario's declared reasoning model. */ const OVERLAY = fileURLToPath(new URL('./declared-reasoning.overlay.yml', import.meta.url)) -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/declared-reasoning', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/declared-reasoning/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/declared-reasoning', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./goldens/declared-reasoning/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() describe.skipIf(MODE === 'record')('web e2e: declared reasoning efforts reach the composer', () => { diff --git a/apps/web/tests/details-session-lifecycle.e2e.ts b/apps/web/tests/details-session-lifecycle.e2e.ts index 7f507c59d2..80f9750b57 100644 --- a/apps/web/tests/details-session-lifecycle.e2e.ts +++ b/apps/web/tests/details-session-lifecycle.e2e.ts @@ -14,10 +14,10 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/details-session-lifecycle', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/details-session-lifecycle', import.meta.url)) const HANDLES_EXPECTED = join(SNAPSHOT_DIR, 'handles.expected.md') -const FIXTURE = fileURLToPath(new URL('./snapshots/lifecycle-chrome/session.jsonl', import.meta.url)) -const SEED_FIXTURE = fileURLToPath(new URL('./snapshots/seeded-history/seed.jsonl', import.meta.url)) +const FIXTURE = fileURLToPath(new URL('../../../snapshots/web/lifecycle-chrome/session.jsonl', import.meta.url)) +const SEED_FIXTURE = fileURLToPath(new URL('../../../snapshots/web/seeded-history/seed.jsonl', import.meta.url)) const PROMPT = 'Reply with the single word LIGHTHOUSE and stop.' const MODE = webSnapshotMode() diff --git a/apps/web/tests/feedback-command.e2e.ts b/apps/web/tests/feedback-command.e2e.ts index 577e77a97a..aa384ab49c 100644 --- a/apps/web/tests/feedback-command.e2e.ts +++ b/apps/web/tests/feedback-command.e2e.ts @@ -20,7 +20,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/feedback-command', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/feedback-command', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') const ACK_EXPECTED = join(SNAPSHOT_DIR, 'ack.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/github-ready-review.e2e.ts b/apps/web/tests/github-ready-review.e2e.ts index 9e258620e7..20c6140a41 100644 --- a/apps/web/tests/github-ready-review.e2e.ts +++ b/apps/web/tests/github-ready-review.e2e.ts @@ -22,7 +22,7 @@ import { saveFailureShot } from './support.ts' const MODE = webSnapshotMode() const OVERLAY = fileURLToPath(new URL('../../../examples/web-github-review/cordis.yml', import.meta.url)) -const EXPECTED = fileURLToPath(new URL('./snapshots/github-ready-review/conversation.expected.md', import.meta.url)) +const EXPECTED = fileURLToPath(new URL('./goldens/github-ready-review/conversation.expected.md', import.meta.url)) const PROVIDER = 'github-webhook-review-test' const MODEL = 'reply' const SECRET = 'github-webhook-review-secret' diff --git a/apps/web/tests/goal-bar.e2e.ts b/apps/web/tests/goal-bar.e2e.ts index 00260a79ee..0fd212f545 100644 --- a/apps/web/tests/goal-bar.e2e.ts +++ b/apps/web/tests/goal-bar.e2e.ts @@ -14,7 +14,7 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/goal-bar', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/goal-bar', import.meta.url)) const ACTIVE_EXPECTED = join(SNAPSHOT_DIR, 'active.expected.md') const OVERLAY = fileURLToPath(new URL('./goal-bar.overlay.yml', import.meta.url)) const MODE = webSnapshotMode() diff --git a/apps/web/tests/goal-command-presentation.e2e.ts b/apps/web/tests/goal-command-presentation.e2e.ts index 6117fb8ace..8a976e6fab 100644 --- a/apps/web/tests/goal-command-presentation.e2e.ts +++ b/apps/web/tests/goal-command-presentation.e2e.ts @@ -14,9 +14,9 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/goal-command-presentation', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/goal-command-presentation', import.meta.url)) const UI_EXPECTED = fileURLToPath(new URL( - './snapshots/goal-command-presentation/ui.expected.md', import.meta.url, + './goldens/goal-command-presentation/ui.expected.md', import.meta.url, )) const MODE = webSnapshotMode() diff --git a/apps/web/tests/goal-multi-turn-actions.e2e.ts b/apps/web/tests/goal-multi-turn-actions.e2e.ts index 89082344a7..f73c100827 100644 --- a/apps/web/tests/goal-multi-turn-actions.e2e.ts +++ b/apps/web/tests/goal-multi-turn-actions.e2e.ts @@ -16,7 +16,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/goal-multi-turn-actions', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/goal-multi-turn-actions', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') const OVERRIDE = join(SNAPSHOT_DIR, 'replay.override.json') const UI_EXPECTED = join(SNAPSHOT_DIR, 'ui.expected.md') diff --git a/apps/web/tests/snapshots/access-confirmation/ui.expected.md b/apps/web/tests/goldens/access-confirmation/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/access-confirmation/ui.expected.md rename to apps/web/tests/goldens/access-confirmation/ui.expected.md diff --git a/apps/web/tests/snapshots/agent-preset-authoring/copy-dialog.expected.md b/apps/web/tests/goldens/agent-preset-authoring/copy-dialog.expected.md similarity index 100% rename from apps/web/tests/snapshots/agent-preset-authoring/copy-dialog.expected.md rename to apps/web/tests/goldens/agent-preset-authoring/copy-dialog.expected.md diff --git a/apps/web/tests/snapshots/agent-preset-authoring/created.expected.md b/apps/web/tests/goldens/agent-preset-authoring/created.expected.md similarity index 100% rename from apps/web/tests/snapshots/agent-preset-authoring/created.expected.md rename to apps/web/tests/goldens/agent-preset-authoring/created.expected.md diff --git a/apps/web/tests/snapshots/agent-preset-authoring/damaged.expected.md b/apps/web/tests/goldens/agent-preset-authoring/damaged.expected.md similarity index 100% rename from apps/web/tests/snapshots/agent-preset-authoring/damaged.expected.md rename to apps/web/tests/goldens/agent-preset-authoring/damaged.expected.md diff --git a/apps/web/tests/snapshots/agent-preset-authoring/section.expected.md b/apps/web/tests/goldens/agent-preset-authoring/section.expected.md similarity index 100% rename from apps/web/tests/snapshots/agent-preset-authoring/section.expected.md rename to apps/web/tests/goldens/agent-preset-authoring/section.expected.md diff --git a/apps/web/tests/snapshots/agent-preset-selection/header.expected.md b/apps/web/tests/goldens/agent-preset-selection/header.expected.md similarity index 100% rename from apps/web/tests/snapshots/agent-preset-selection/header.expected.md rename to apps/web/tests/goldens/agent-preset-selection/header.expected.md diff --git a/apps/web/tests/snapshots/agent-preset-selection/hero.expected.md b/apps/web/tests/goldens/agent-preset-selection/hero.expected.md similarity index 100% rename from apps/web/tests/snapshots/agent-preset-selection/hero.expected.md rename to apps/web/tests/goldens/agent-preset-selection/hero.expected.md diff --git a/apps/web/tests/snapshots/agent-preset-selection/menu.expected.md b/apps/web/tests/goldens/agent-preset-selection/menu.expected.md similarity index 100% rename from apps/web/tests/snapshots/agent-preset-selection/menu.expected.md rename to apps/web/tests/goldens/agent-preset-selection/menu.expected.md diff --git a/apps/web/tests/snapshots/cold-blank-session/sidebar.expected.md b/apps/web/tests/goldens/cold-blank-session/sidebar.expected.md similarity index 100% rename from apps/web/tests/snapshots/cold-blank-session/sidebar.expected.md rename to apps/web/tests/goldens/cold-blank-session/sidebar.expected.md diff --git a/apps/web/tests/snapshots/composer-draft-scroll/geometry.expected.md b/apps/web/tests/goldens/composer-draft-scroll/geometry.expected.md similarity index 100% rename from apps/web/tests/snapshots/composer-draft-scroll/geometry.expected.md rename to apps/web/tests/goldens/composer-draft-scroll/geometry.expected.md diff --git a/apps/web/tests/snapshots/composer-tab-geometry/geometry.expected.md b/apps/web/tests/goldens/composer-tab-geometry/geometry.expected.md similarity index 100% rename from apps/web/tests/snapshots/composer-tab-geometry/geometry.expected.md rename to apps/web/tests/goldens/composer-tab-geometry/geometry.expected.md diff --git a/apps/web/tests/snapshots/conversation-column-overflow/geometry.expected.md b/apps/web/tests/goldens/conversation-column-overflow/geometry.expected.md similarity index 100% rename from apps/web/tests/snapshots/conversation-column-overflow/geometry.expected.md rename to apps/web/tests/goldens/conversation-column-overflow/geometry.expected.md diff --git a/apps/web/tests/snapshots/declared-reasoning/ui.expected.md b/apps/web/tests/goldens/declared-reasoning/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/declared-reasoning/ui.expected.md rename to apps/web/tests/goldens/declared-reasoning/ui.expected.md diff --git a/apps/web/tests/snapshots/github-ready-review/conversation.expected.md b/apps/web/tests/goldens/github-ready-review/conversation.expected.md similarity index 100% rename from apps/web/tests/snapshots/github-ready-review/conversation.expected.md rename to apps/web/tests/goldens/github-ready-review/conversation.expected.md diff --git a/apps/web/tests/snapshots/goal-bar/active.expected.md b/apps/web/tests/goldens/goal-bar/active.expected.md similarity index 100% rename from apps/web/tests/snapshots/goal-bar/active.expected.md rename to apps/web/tests/goldens/goal-bar/active.expected.md diff --git a/apps/web/tests/snapshots/goal-command-presentation/ui.expected.md b/apps/web/tests/goldens/goal-command-presentation/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/goal-command-presentation/ui.expected.md rename to apps/web/tests/goldens/goal-command-presentation/ui.expected.md diff --git a/apps/web/tests/snapshots/home-path-tilde/workspace-hover.expected.txt b/apps/web/tests/goldens/home-path-tilde/workspace-hover.expected.txt similarity index 100% rename from apps/web/tests/snapshots/home-path-tilde/workspace-hover.expected.txt rename to apps/web/tests/goldens/home-path-tilde/workspace-hover.expected.txt diff --git a/apps/web/tests/snapshots/markdown-cjk-strong/ui.expected.md b/apps/web/tests/goldens/markdown-cjk-strong/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/markdown-cjk-strong/ui.expected.md rename to apps/web/tests/goldens/markdown-cjk-strong/ui.expected.md diff --git a/apps/web/tests/snapshots/markdown-images/ui.expected.md b/apps/web/tests/goldens/markdown-images/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/markdown-images/ui.expected.md rename to apps/web/tests/goldens/markdown-images/ui.expected.md diff --git a/apps/web/tests/snapshots/markdown-inline-code-links/ui.expected.md b/apps/web/tests/goldens/markdown-inline-code-links/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/markdown-inline-code-links/ui.expected.md rename to apps/web/tests/goldens/markdown-inline-code-links/ui.expected.md diff --git a/apps/web/tests/snapshots/markdown-wide-table/geometry.expected.md b/apps/web/tests/goldens/markdown-wide-table/geometry.expected.md similarity index 100% rename from apps/web/tests/snapshots/markdown-wide-table/geometry.expected.md rename to apps/web/tests/goldens/markdown-wide-table/geometry.expected.md diff --git a/apps/web/tests/snapshots/math-rendering/ui.expected.md b/apps/web/tests/goldens/math-rendering/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/math-rendering/ui.expected.md rename to apps/web/tests/goldens/math-rendering/ui.expected.md diff --git a/apps/web/tests/snapshots/max-tokens-notice/history-turn.expected.txt b/apps/web/tests/goldens/max-tokens-notice/history-turn.expected.txt similarity index 100% rename from apps/web/tests/snapshots/max-tokens-notice/history-turn.expected.txt rename to apps/web/tests/goldens/max-tokens-notice/history-turn.expected.txt diff --git a/apps/web/tests/snapshots/models-settings/configured.expected.md b/apps/web/tests/goldens/models-settings/configured.expected.md similarity index 100% rename from apps/web/tests/snapshots/models-settings/configured.expected.md rename to apps/web/tests/goldens/models-settings/configured.expected.md diff --git a/apps/web/tests/snapshots/models-settings/declared-edit.expected.md b/apps/web/tests/goldens/models-settings/declared-edit.expected.md similarity index 100% rename from apps/web/tests/snapshots/models-settings/declared-edit.expected.md rename to apps/web/tests/goldens/models-settings/declared-edit.expected.md diff --git a/apps/web/tests/snapshots/models-settings/declared.expected.md b/apps/web/tests/goldens/models-settings/declared.expected.md similarity index 100% rename from apps/web/tests/snapshots/models-settings/declared.expected.md rename to apps/web/tests/goldens/models-settings/declared.expected.md diff --git a/apps/web/tests/snapshots/models-settings/delete.expected.md b/apps/web/tests/goldens/models-settings/delete.expected.md similarity index 100% rename from apps/web/tests/snapshots/models-settings/delete.expected.md rename to apps/web/tests/goldens/models-settings/delete.expected.md diff --git a/apps/web/tests/snapshots/models-settings/empty.expected.md b/apps/web/tests/goldens/models-settings/empty.expected.md similarity index 100% rename from apps/web/tests/snapshots/models-settings/empty.expected.md rename to apps/web/tests/goldens/models-settings/empty.expected.md diff --git a/apps/web/tests/snapshots/models-settings/model-picker.expected.md b/apps/web/tests/goldens/models-settings/model-picker.expected.md similarity index 100% rename from apps/web/tests/snapshots/models-settings/model-picker.expected.md rename to apps/web/tests/goldens/models-settings/model-picker.expected.md diff --git a/apps/web/tests/snapshots/models-settings/native-delete.expected.md b/apps/web/tests/goldens/models-settings/native-delete.expected.md similarity index 100% rename from apps/web/tests/snapshots/models-settings/native-delete.expected.md rename to apps/web/tests/goldens/models-settings/native-delete.expected.md diff --git a/apps/web/tests/snapshots/onboarding-deepseek-config/missing.expected.md b/apps/web/tests/goldens/onboarding-deepseek-config/missing.expected.md similarity index 100% rename from apps/web/tests/snapshots/onboarding-deepseek-config/missing.expected.md rename to apps/web/tests/goldens/onboarding-deepseek-config/missing.expected.md diff --git a/apps/web/tests/snapshots/onboarding-deepseek-config/models.expected.md b/apps/web/tests/goldens/onboarding-deepseek-config/models.expected.md similarity index 100% rename from apps/web/tests/snapshots/onboarding-deepseek-config/models.expected.md rename to apps/web/tests/goldens/onboarding-deepseek-config/models.expected.md diff --git a/apps/web/tests/snapshots/onboarding-deepseek-config/welcome.expected.md b/apps/web/tests/goldens/onboarding-deepseek-config/welcome.expected.md similarity index 100% rename from apps/web/tests/snapshots/onboarding-deepseek-config/welcome.expected.md rename to apps/web/tests/goldens/onboarding-deepseek-config/welcome.expected.md diff --git a/apps/web/tests/snapshots/onboarding-usable-provider/dismissed.expected.md b/apps/web/tests/goldens/onboarding-usable-provider/dismissed.expected.md similarity index 100% rename from apps/web/tests/snapshots/onboarding-usable-provider/dismissed.expected.md rename to apps/web/tests/goldens/onboarding-usable-provider/dismissed.expected.md diff --git a/apps/web/tests/snapshots/plugin-config/section.expected.md b/apps/web/tests/goldens/plugin-config/section.expected.md similarity index 100% rename from apps/web/tests/snapshots/plugin-config/section.expected.md rename to apps/web/tests/goldens/plugin-config/section.expected.md diff --git a/apps/web/tests/snapshots/reference-composer/caret-edits.expected.md b/apps/web/tests/goldens/reference-composer/caret-edits.expected.md similarity index 100% rename from apps/web/tests/snapshots/reference-composer/caret-edits.expected.md rename to apps/web/tests/goldens/reference-composer/caret-edits.expected.md diff --git a/apps/web/tests/snapshots/reference-composer/menu.expected.md b/apps/web/tests/goldens/reference-composer/menu.expected.md similarity index 100% rename from apps/web/tests/snapshots/reference-composer/menu.expected.md rename to apps/web/tests/goldens/reference-composer/menu.expected.md diff --git a/apps/web/tests/snapshots/reference-composer/order.expected.md b/apps/web/tests/goldens/reference-composer/order.expected.md similarity index 100% rename from apps/web/tests/snapshots/reference-composer/order.expected.md rename to apps/web/tests/goldens/reference-composer/order.expected.md diff --git a/apps/web/tests/snapshots/schedule-after/at-conversation.expected.md b/apps/web/tests/goldens/schedule-after/at-conversation.expected.md similarity index 100% rename from apps/web/tests/snapshots/schedule-after/at-conversation.expected.md rename to apps/web/tests/goldens/schedule-after/at-conversation.expected.md diff --git a/apps/web/tests/snapshots/schedule-after/conversation.expected.md b/apps/web/tests/goldens/schedule-after/conversation.expected.md similarity index 100% rename from apps/web/tests/snapshots/schedule-after/conversation.expected.md rename to apps/web/tests/goldens/schedule-after/conversation.expected.md diff --git a/apps/web/tests/snapshots/schedule-after/every-conversation.expected.md b/apps/web/tests/goldens/schedule-after/every-conversation.expected.md similarity index 100% rename from apps/web/tests/snapshots/schedule-after/every-conversation.expected.md rename to apps/web/tests/goldens/schedule-after/every-conversation.expected.md diff --git a/apps/web/tests/snapshots/search-card/grep-card.expected.txt b/apps/web/tests/goldens/search-card/grep-card.expected.txt similarity index 100% rename from apps/web/tests/snapshots/search-card/grep-card.expected.txt rename to apps/web/tests/goldens/search-card/grep-card.expected.txt diff --git a/apps/web/tests/snapshots/settings-chrome/dialog-en.expected.md b/apps/web/tests/goldens/settings-chrome/dialog-en.expected.md similarity index 100% rename from apps/web/tests/snapshots/settings-chrome/dialog-en.expected.md rename to apps/web/tests/goldens/settings-chrome/dialog-en.expected.md diff --git a/apps/web/tests/snapshots/settings-chrome/dialog.expected.md b/apps/web/tests/goldens/settings-chrome/dialog.expected.md similarity index 100% rename from apps/web/tests/snapshots/settings-chrome/dialog.expected.md rename to apps/web/tests/goldens/settings-chrome/dialog.expected.md diff --git a/apps/web/tests/snapshots/settings-chrome/plugins.expected.md b/apps/web/tests/goldens/settings-chrome/plugins.expected.md similarity index 100% rename from apps/web/tests/snapshots/settings-chrome/plugins.expected.md rename to apps/web/tests/goldens/settings-chrome/plugins.expected.md diff --git a/apps/web/tests/snapshots/sidebar-subagent-activity/owner-running.expected.md b/apps/web/tests/goldens/sidebar-subagent-activity/owner-running.expected.md similarity index 100% rename from apps/web/tests/snapshots/sidebar-subagent-activity/owner-running.expected.md rename to apps/web/tests/goldens/sidebar-subagent-activity/owner-running.expected.md diff --git a/apps/web/tests/snapshots/skill-invocation-policy/menu.expected.md b/apps/web/tests/goldens/skill-invocation-policy/menu.expected.md similarity index 100% rename from apps/web/tests/snapshots/skill-invocation-policy/menu.expected.md rename to apps/web/tests/goldens/skill-invocation-policy/menu.expected.md diff --git a/apps/web/tests/snapshots/skill-user-invoke/ui.expected.md b/apps/web/tests/goldens/skill-user-invoke/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/skill-user-invoke/ui.expected.md rename to apps/web/tests/goldens/skill-user-invoke/ui.expected.md diff --git a/apps/web/tests/snapshots/stats-paged-history/ui.expected.md b/apps/web/tests/goldens/stats-paged-history/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/stats-paged-history/ui.expected.md rename to apps/web/tests/goldens/stats-paged-history/ui.expected.md diff --git a/apps/web/tests/snapshots/steer-all/mid-steer.expected.md b/apps/web/tests/goldens/steer-all/mid-steer.expected.md similarity index 100% rename from apps/web/tests/snapshots/steer-all/mid-steer.expected.md rename to apps/web/tests/goldens/steer-all/mid-steer.expected.md diff --git a/apps/web/tests/snapshots/steer-all/replay.override.json b/apps/web/tests/goldens/steer-all/replay.override.json similarity index 100% rename from apps/web/tests/snapshots/steer-all/replay.override.json rename to apps/web/tests/goldens/steer-all/replay.override.json diff --git a/apps/web/tests/snapshots/steer-all/settled.expected.md b/apps/web/tests/goldens/steer-all/settled.expected.md similarity index 100% rename from apps/web/tests/snapshots/steer-all/settled.expected.md rename to apps/web/tests/goldens/steer-all/settled.expected.md diff --git a/apps/web/tests/snapshots/todo-row/parallel-plan.expected.txt b/apps/web/tests/goldens/todo-row/parallel-plan.expected.txt similarity index 100% rename from apps/web/tests/snapshots/todo-row/parallel-plan.expected.txt rename to apps/web/tests/goldens/todo-row/parallel-plan.expected.txt diff --git a/apps/web/tests/snapshots/trajectory-virtualization/load-more.expected.md b/apps/web/tests/goldens/trajectory-virtualization/load-more.expected.md similarity index 100% rename from apps/web/tests/snapshots/trajectory-virtualization/load-more.expected.md rename to apps/web/tests/goldens/trajectory-virtualization/load-more.expected.md diff --git a/apps/web/tests/snapshots/web-runtime-context/file-reference-prompt.expected.md b/apps/web/tests/goldens/web-runtime-context/file-reference-prompt.expected.md similarity index 100% rename from apps/web/tests/snapshots/web-runtime-context/file-reference-prompt.expected.md rename to apps/web/tests/goldens/web-runtime-context/file-reference-prompt.expected.md diff --git a/apps/web/tests/snapshots/web-runtime-context/web-surface-prompt.expected.md b/apps/web/tests/goldens/web-runtime-context/web-surface-prompt.expected.md similarity index 100% rename from apps/web/tests/snapshots/web-runtime-context/web-surface-prompt.expected.md rename to apps/web/tests/goldens/web-runtime-context/web-surface-prompt.expected.md diff --git a/apps/web/tests/home-path-tilde.snapshot.ts b/apps/web/tests/home-path-tilde.snapshot.ts index 059a0ac003..348a2e7e7b 100644 --- a/apps/web/tests/home-path-tilde.snapshot.ts +++ b/apps/web/tests/home-path-tilde.snapshot.ts @@ -8,7 +8,7 @@ import { act, fireEvent, screen, waitFor, within } from '@testing-library/react' import { describe, expect, it } from 'vitest' import { installAssembledBootEnv, mountAssembledApp, REFRESHING_GOLDEN } from './assembled-boot.ts' -const EXPECTED = join(process.cwd(), 'apps/web/tests/snapshots/home-path-tilde/workspace-hover.expected.txt') +const EXPECTED = join(process.cwd(), 'apps/web/tests/goldens/home-path-tilde/workspace-hover.expected.txt') installAssembledBootEnv() diff --git a/apps/web/tests/lifecycle-chrome.e2e.ts b/apps/web/tests/lifecycle-chrome.e2e.ts index 3a814878da..45d710f35c 100644 --- a/apps/web/tests/lifecycle-chrome.e2e.ts +++ b/apps/web/tests/lifecycle-chrome.e2e.ts @@ -23,7 +23,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/lifecycle-chrome', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/lifecycle-chrome', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') const REPLAY_OVERRIDE = join(SNAPSHOT_DIR, 'replay.override.json') const HERO_EXPECTED = join(SNAPSHOT_DIR, 'hero.expected.md') diff --git a/apps/web/tests/live-interactions.e2e.ts b/apps/web/tests/live-interactions.e2e.ts index 0586a900c2..d39c6c3e0e 100644 --- a/apps/web/tests/live-interactions.e2e.ts +++ b/apps/web/tests/live-interactions.e2e.ts @@ -28,7 +28,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/live-interactions', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/live-interactions', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') // One golden pins the empty mid-turn loading state, one pins the sendable draft // state, and the other four capture what remains after cancel, after a diff --git a/apps/web/tests/markdown-cjk-strong.e2e.ts b/apps/web/tests/markdown-cjk-strong.e2e.ts index 0c57c513fe..102003333a 100644 --- a/apps/web/tests/markdown-cjk-strong.e2e.ts +++ b/apps/web/tests/markdown-cjk-strong.e2e.ts @@ -17,8 +17,8 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/markdown-cjk-strong', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/markdown-cjk-strong/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/markdown-cjk-strong', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./goldens/markdown-cjk-strong/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() const SEED_ID = 'markdown-cjk-strong-web-e2e' const DONE = 'CJK_STRONG_DONE' diff --git a/apps/web/tests/markdown-images.e2e.ts b/apps/web/tests/markdown-images.e2e.ts index 2763eb1837..769522311e 100644 --- a/apps/web/tests/markdown-images.e2e.ts +++ b/apps/web/tests/markdown-images.e2e.ts @@ -26,8 +26,8 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/markdown-images', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/markdown-images/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/markdown-images', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./goldens/markdown-images/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() const SEED_ID = 'markdown-images-web-e2e' const REMOTE_ALT = 'Remote test image' diff --git a/apps/web/tests/markdown-inline-code-links.e2e.ts b/apps/web/tests/markdown-inline-code-links.e2e.ts index 7b5c466298..d141c00d27 100644 --- a/apps/web/tests/markdown-inline-code-links.e2e.ts +++ b/apps/web/tests/markdown-inline-code-links.e2e.ts @@ -17,8 +17,8 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/markdown-inline-code-links', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/markdown-inline-code-links/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/markdown-inline-code-links', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./goldens/markdown-inline-code-links/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() const SEED_ID = 'markdown-inline-code-links-web-e2e' const DONE = 'INLINE_CODE_LINK_DONE' diff --git a/apps/web/tests/markdown-wide-table.e2e.ts b/apps/web/tests/markdown-wide-table.e2e.ts index bb897ea364..194f6da319 100644 --- a/apps/web/tests/markdown-wide-table.e2e.ts +++ b/apps/web/tests/markdown-wide-table.e2e.ts @@ -40,9 +40,9 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/markdown-wide-table', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/markdown-wide-table', import.meta.url)) const GEOMETRY_EXPECTED = fileURLToPath( - new URL('./snapshots/markdown-wide-table/geometry.expected.md', import.meta.url), + new URL('./goldens/markdown-wide-table/geometry.expected.md', import.meta.url), ) const MODE = webSnapshotMode() const SEED_ID = 'markdown-wide-table-web-e2e' diff --git a/apps/web/tests/math-rendering.e2e.ts b/apps/web/tests/math-rendering.e2e.ts index 67af32373c..129148a0c0 100644 --- a/apps/web/tests/math-rendering.e2e.ts +++ b/apps/web/tests/math-rendering.e2e.ts @@ -17,8 +17,8 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/math-rendering', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/math-rendering/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/math-rendering', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./goldens/math-rendering/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() const SEED_ID = 'math-rendering-web-e2e' const DONE = 'MATH_RENDERING_DONE' diff --git a/apps/web/tests/max-tokens-notice.snapshot.ts b/apps/web/tests/max-tokens-notice.snapshot.ts index 45432e702b..515aa7a699 100644 --- a/apps/web/tests/max-tokens-notice.snapshot.ts +++ b/apps/web/tests/max-tokens-notice.snapshot.ts @@ -15,7 +15,7 @@ import { fireEvent, screen, waitFor, within } from '@testing-library/react' import { describe, expect, it } from 'vitest' import { hasClass, installAssembledBootEnv, mountAssembledApp, REFRESHING_GOLDEN } from './assembled-boot.ts' -const EXPECTED = join(process.cwd(), 'apps/web/tests/snapshots/max-tokens-notice/history-turn.expected.txt') +const EXPECTED = join(process.cwd(), 'apps/web/tests/goldens/max-tokens-notice/history-turn.expected.txt') installAssembledBootEnv() diff --git a/apps/web/tests/message-actions.e2e.ts b/apps/web/tests/message-actions.e2e.ts index 72a7618fea..64b0f5154e 100644 --- a/apps/web/tests/message-actions.e2e.ts +++ b/apps/web/tests/message-actions.e2e.ts @@ -15,10 +15,10 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/message-actions', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/message-actions', import.meta.url)) // Borrowed read-only: this scenario needs any settled user+assistant pair, not // a new recording (workspace-management / sidebar-scrollbar pattern). -const SEED = fileURLToPath(new URL('./snapshots/seeded-history/seed.jsonl', import.meta.url)) +const SEED = fileURLToPath(new URL('../../../snapshots/web/seeded-history/seed.jsonl', import.meta.url)) const UI_EXPECTED = join(SNAPSHOT_DIR, 'ui.expected.md') const FORK_EXPECTED = join(SNAPSHOT_DIR, 'fork.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/message-feedback-layout.e2e.ts b/apps/web/tests/message-feedback-layout.e2e.ts index 89f20eee79..ad168d5a5e 100644 --- a/apps/web/tests/message-feedback-layout.e2e.ts +++ b/apps/web/tests/message-feedback-layout.e2e.ts @@ -33,7 +33,7 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/message-feedback-layout', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/message-feedback-layout', import.meta.url)) /** * Committed golden of the popover relations at every stop. Booleans and counts * only, never absolute coordinates. @@ -41,7 +41,7 @@ const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/message-feedback-layout' const GEOMETRY_EXPECTED = join(SNAPSHOT_DIR, 'geometry.expected.md') const MODE = webSnapshotMode() /** Borrowed read-only: this scenario needs any settled assistant message to rate. */ -const SEED = fileURLToPath(new URL('./snapshots/seeded-history/seed.jsonl', import.meta.url)) +const SEED = fileURLToPath(new URL('../../../snapshots/web/seeded-history/seed.jsonl', import.meta.url)) const SEED_ID = 'message-feedback-layout-e2e' /** Viewport widths from full-screen desktop down to a narrow window. */ const WIDTHS = [1680, 1280, 1024, 900, 700, 600] diff --git a/apps/web/tests/message-feedback-protocol.snapshot.ts b/apps/web/tests/message-feedback-protocol.snapshot.ts index 9fbc556f77..8ad9477ee5 100644 --- a/apps/web/tests/message-feedback-protocol.snapshot.ts +++ b/apps/web/tests/message-feedback-protocol.snapshot.ts @@ -10,7 +10,7 @@ import { type WebScaffold, } from './scaffold.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/message-feedback-protocol', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/message-feedback-protocol', import.meta.url)) const SESSION_FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') const PROTOCOL_EXPECTED = join(SNAPSHOT_DIR, 'protocol.expected.json') const SESSION_ID = 'message-feedback-protocol' diff --git a/apps/web/tests/message-feedback.e2e.ts b/apps/web/tests/message-feedback.e2e.ts index 69c5ad54bb..3169733f95 100644 --- a/apps/web/tests/message-feedback.e2e.ts +++ b/apps/web/tests/message-feedback.e2e.ts @@ -15,7 +15,7 @@ import { newEnglishPage, saveFailureShot } from './support.ts' // Borrowed read-only: this scenario needs any settled assistant message to // address, not a new recording (message-actions / sidebar-scrollbar pattern). -const SEED = fileURLToPath(new URL('./snapshots/seeded-history/seed.jsonl', import.meta.url)) +const SEED = fileURLToPath(new URL('../../../snapshots/web/seeded-history/seed.jsonl', import.meta.url)) const MODE = webSnapshotMode() const SEED_ID = 'message-feedback-web-e2e' const NOTE = 'Read both files before answering.' diff --git a/apps/web/tests/minimal-preset.snapshot.ts b/apps/web/tests/minimal-preset.snapshot.ts index 2975a0b500..8791f1760d 100644 --- a/apps/web/tests/minimal-preset.snapshot.ts +++ b/apps/web/tests/minimal-preset.snapshot.ts @@ -9,7 +9,7 @@ import type {} from '@deepseek-ai/dsh-agent-presets' import type {} from '@deepseek-ai/dsh-system-prompt' import { assertFixtureInventory, launchWebScaffold, type WebScaffold } from './scaffold.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/minimal-preset', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/minimal-preset', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') const PROMPT = 'Reply exactly MINIMAL_PRESET_REQUEST_OK and stop.' diff --git a/apps/web/tests/models-settings.e2e.ts b/apps/web/tests/models-settings.e2e.ts index bb84b2ec03..ee68aeb3a5 100644 --- a/apps/web/tests/models-settings.e2e.ts +++ b/apps/web/tests/models-settings.e2e.ts @@ -25,7 +25,7 @@ import { } from './scaffold.ts' import { ZH_BROWSER_LOCALE, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/models-settings', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/models-settings', import.meta.url)) const EMPTY_EXPECTED = join(SNAPSHOT_DIR, 'empty.expected.md') const CONFIGURED_EXPECTED = join(SNAPSHOT_DIR, 'configured.expected.md') const DECLARED_EXPECTED = join(SNAPSHOT_DIR, 'declared.expected.md') diff --git a/apps/web/tests/navigation-panes.e2e.ts b/apps/web/tests/navigation-panes.e2e.ts index 12ef148935..c694fe1be2 100644 --- a/apps/web/tests/navigation-panes.e2e.ts +++ b/apps/web/tests/navigation-panes.e2e.ts @@ -21,7 +21,7 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/navigation-panes', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/navigation-panes', import.meta.url)) const SEED = join(SNAPSHOT_DIR, 'seed.jsonl') const TRAJECTORY_EXPECTED = join(SNAPSHOT_DIR, 'trajectory.expected.md') const SEARCH_EXPECTED = join(SNAPSHOT_DIR, 'search-results.expected.md') diff --git a/apps/web/tests/onboarding-deepseek-config.e2e.ts b/apps/web/tests/onboarding-deepseek-config.e2e.ts index 82abde5777..dd2f1bde0a 100644 --- a/apps/web/tests/onboarding-deepseek-config.e2e.ts +++ b/apps/web/tests/onboarding-deepseek-config.e2e.ts @@ -18,7 +18,7 @@ import { } from './scaffold.ts' import { ZH_BROWSER_LOCALE, connectFreshWorkspaceZh, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/onboarding-deepseek-config', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/onboarding-deepseek-config', import.meta.url)) const WELCOME_EXPECTED = join(SNAPSHOT_DIR, 'welcome.expected.md') const MISSING_EXPECTED = join(SNAPSHOT_DIR, 'missing.expected.md') const MODELS_EXPECTED = join(SNAPSHOT_DIR, 'models.expected.md') diff --git a/apps/web/tests/onboarding-usable-provider.e2e.ts b/apps/web/tests/onboarding-usable-provider.e2e.ts index e2998b57ea..860b1d4274 100644 --- a/apps/web/tests/onboarding-usable-provider.e2e.ts +++ b/apps/web/tests/onboarding-usable-provider.e2e.ts @@ -16,7 +16,7 @@ import { } from './scaffold.ts' import { ZH_BROWSER_LOCALE, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/onboarding-usable-provider', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/onboarding-usable-provider', import.meta.url)) const DISMISSED_EXPECTED = join(SNAPSHOT_DIR, 'dismissed.expected.md') const MODE = webSnapshotMode() const CREDENTIAL_STEP = '添加一个 API Key 开始使用' diff --git a/apps/web/tests/permission-policy-context.e2e.ts b/apps/web/tests/permission-policy-context.e2e.ts index 867685678f..633eaaaaf5 100644 --- a/apps/web/tests/permission-policy-context.e2e.ts +++ b/apps/web/tests/permission-policy-context.e2e.ts @@ -17,8 +17,8 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/permission-policy-context', import.meta.url)) -const FIXTURE = fileURLToPath(new URL('./snapshots/permission-policy-context/session.jsonl', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/permission-policy-context', import.meta.url)) +const FIXTURE = fileURLToPath(new URL('../../../snapshots/web/permission-policy-context/session.jsonl', import.meta.url)) const MODE = webSnapshotMode() const PROMPTS = [ diff --git a/apps/web/tests/plan-control-row.e2e.ts b/apps/web/tests/plan-control-row.e2e.ts index 691c004c5c..49a3ce06dc 100644 --- a/apps/web/tests/plan-control-row.e2e.ts +++ b/apps/web/tests/plan-control-row.e2e.ts @@ -36,7 +36,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/plan-narrow-viewport', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/plan-narrow-viewport', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') const LAYOUT_EXPECTED = join(SNAPSHOT_DIR, 'layout.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/plan-review.e2e.ts b/apps/web/tests/plan-review.e2e.ts index 8c2462d7ee..a8b011887a 100644 --- a/apps/web/tests/plan-review.e2e.ts +++ b/apps/web/tests/plan-review.e2e.ts @@ -20,7 +20,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/plan-review', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/plan-review', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') // The waiting golden owns the decision card; the approved golden owns the // transcript the approval leaves behind — the state the card cannot see. diff --git a/apps/web/tests/plugin-config.e2e.ts b/apps/web/tests/plugin-config.e2e.ts index 3c97f4b414..cfc4837b91 100644 --- a/apps/web/tests/plugin-config.e2e.ts +++ b/apps/web/tests/plugin-config.e2e.ts @@ -16,7 +16,7 @@ import { } from './scaffold.ts' import { ZH_BROWSER_LOCALE, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/plugin-config', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/plugin-config', import.meta.url)) const SECTION_EXPECTED = join(SNAPSHOT_DIR, 'section.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/pwsh-terminal.e2e.ts b/apps/web/tests/pwsh-terminal.e2e.ts index 44912d9ca5..6da0e1cf90 100644 --- a/apps/web/tests/pwsh-terminal.e2e.ts +++ b/apps/web/tests/pwsh-terminal.e2e.ts @@ -24,7 +24,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/pwsh-terminal', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/pwsh-terminal', import.meta.url)) const SEED = join(SNAPSHOT_DIR, 'seed.jsonl') const TERMINAL_EXPECTED = join(SNAPSHOT_DIR, 'terminal-card.expected.md') const OVERLAY = fileURLToPath(new URL('./pwsh-terminal.overlay.yml', import.meta.url)) diff --git a/apps/web/tests/question-composer.e2e.ts b/apps/web/tests/question-composer.e2e.ts index 47219a30d7..37a4577685 100644 --- a/apps/web/tests/question-composer.e2e.ts +++ b/apps/web/tests/question-composer.e2e.ts @@ -21,7 +21,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/question-composer', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/question-composer', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') const UI_EXPECTED = join(SNAPSHOT_DIR, 'ui.expected.md') const SIDEBAR_EXPECTED = join(SNAPSHOT_DIR, 'sidebar.expected.md') diff --git a/apps/web/tests/queue-actions.e2e.ts b/apps/web/tests/queue-actions.e2e.ts index a10ca7188e..bfebbb2ba8 100644 --- a/apps/web/tests/queue-actions.e2e.ts +++ b/apps/web/tests/queue-actions.e2e.ts @@ -18,8 +18,8 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/queue-actions', import.meta.url)) -const FIXTURE = fileURLToPath(new URL('./snapshots/live-interactions/session.jsonl', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/queue-actions', import.meta.url)) +const FIXTURE = fileURLToPath(new URL('../../../snapshots/web/live-interactions/session.jsonl', import.meta.url)) const COLLAPSED_EXPECTED = join(SNAPSHOT_DIR, 'collapsed.expected.md') const EDITING_EXPECTED = join(SNAPSHOT_DIR, 'editing.expected.md') const LAYOUT_EXPECTED = join(SNAPSHOT_DIR, 'layout.expected.md') diff --git a/apps/web/tests/reference-composer.e2e.ts b/apps/web/tests/reference-composer.e2e.ts index a240af3c35..33f34ce1e0 100644 --- a/apps/web/tests/reference-composer.e2e.ts +++ b/apps/web/tests/reference-composer.e2e.ts @@ -27,7 +27,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/reference-composer', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/reference-composer', import.meta.url)) const MENU_EXPECTED = join(SNAPSHOT_DIR, 'menu.expected.md') const ORDER_EXPECTED = join(SNAPSHOT_DIR, 'order.expected.md') const CARET_EXPECTED = join(SNAPSHOT_DIR, 'caret-edits.expected.md') diff --git a/apps/web/tests/replay-round-trip.e2e.ts b/apps/web/tests/replay-round-trip.e2e.ts index 74e0a6df1d..c8fe57df70 100644 --- a/apps/web/tests/replay-round-trip.e2e.ts +++ b/apps/web/tests/replay-round-trip.e2e.ts @@ -22,10 +22,10 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, REPO_ROOT, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/fresh-round-trip', import.meta.url)) -const FIXTURE = fileURLToPath(new URL('./snapshots/fresh-round-trip/session.jsonl', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/fresh-round-trip/ui.expected.md', import.meta.url)) -const SYSTEM_PROMPT_EXPECTED = fileURLToPath(new URL('./snapshots/fresh-round-trip/system-prompt.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/fresh-round-trip', import.meta.url)) +const FIXTURE = fileURLToPath(new URL('../../../snapshots/web/fresh-round-trip/session.jsonl', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/fresh-round-trip/ui.expected.md', import.meta.url)) +const SYSTEM_PROMPT_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/fresh-round-trip/system-prompt.expected.md', import.meta.url)) const MODE = webSnapshotMode() // The scenario's one drive prompt. Record sends it; replay asserts the diff --git a/apps/web/tests/scaffold.ts b/apps/web/tests/scaffold.ts index 6981626167..1fef5a1a2e 100644 --- a/apps/web/tests/scaffold.ts +++ b/apps/web/tests/scaffold.ts @@ -25,7 +25,7 @@ import { existsSync, readFileSync } from 'node:fs' import { mkdir, mkdtemp, readFile, readdir, realpath, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' -import { join } from 'node:path' +import { join, resolve } from 'node:path' import { pathToFileURL } from 'node:url' import type { Page } from 'playwright' import { expect } from 'vitest' @@ -34,6 +34,7 @@ import Loader from '@deepseek-ai/cordis-plugin-loader' import Include, { type PatchOptions } from '@deepseek-ai/cordis-plugin-include' import Group from '@deepseek-ai/cordis-plugin-group' import { + parseSnapshotManifest, scrubRequestHeaders, scrubSessionSnapshot, stabilizeFixtureMessageIds, @@ -966,8 +967,23 @@ export async function compareOrRefreshGolden(goldenPath: string, actual: string, */ export async function assertFixtureInventory(dir: string, expected: string[]): Promise { const entries = (await readdir(dir)).sort() - expect(entries).toEqual([...expected].sort()) - for (const entry of entries.filter(name => name.endsWith('.jsonl'))) { + const ownsManifest = entries.includes('snapshot.yml') + const artifacts = entries.filter(name => name !== 'snapshot.yml') + expect(artifacts).toEqual([...expected].sort()) + if (ownsManifest) { + const manifestPath = join(dir, 'snapshot.yml') + const manifest = parseSnapshotManifest(await readFile(manifestPath, 'utf8'), manifestPath) + expect(manifest.profile).toBe('web') + if (manifest.session === undefined) { + expect( + artifacts.includes('session.jsonl') || artifacts.includes('seed.jsonl'), + `${dir}: session owner must carry session.jsonl or seed.jsonl`, + ).toBe(true) + } else { + expect(existsSync(resolve(dir, manifest.session.source)), `${dir}: session source`).toBe(true) + } + } + for (const entry of artifacts.filter(name => name.endsWith('.jsonl'))) { const content = await readFile(join(dir, entry), 'utf8') expect(scrubRequestHeaders(content), `${dir}/${entry} carries request-header bulk`).toBe(content) expect(content, `${dir}/${entry} carries a run-local rpcId`) diff --git a/apps/web/tests/schedule-after.e2e.ts b/apps/web/tests/schedule-after.e2e.ts index 70e79019ec..d9e1467139 100644 --- a/apps/web/tests/schedule-after.e2e.ts +++ b/apps/web/tests/schedule-after.e2e.ts @@ -29,7 +29,7 @@ import { connectFreshWorkspace, conversationContextKey, saveFailureShot } from ' const MODE = webSnapshotMode() const OVERLAY = fileURLToPath(new URL('../../../examples/web-schedule/cordis.yml', import.meta.url)) -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/schedule-after', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/schedule-after', import.meta.url)) const AFTER_EXPECTED = join(SNAPSHOT_DIR, 'conversation.expected.md') const AT_EXPECTED = join(SNAPSHOT_DIR, 'at-conversation.expected.md') const EVERY_EXPECTED = join(SNAPSHOT_DIR, 'every-conversation.expected.md') diff --git a/apps/web/tests/search-card.snapshot.ts b/apps/web/tests/search-card.snapshot.ts index 3e94faa16d..e4529b5d99 100644 --- a/apps/web/tests/search-card.snapshot.ts +++ b/apps/web/tests/search-card.snapshot.ts @@ -20,7 +20,7 @@ import { act, fireEvent, screen, waitFor, within } from '@testing-library/react' import { describe, expect, it } from 'vitest' import { hasClass, installAssembledBootEnv, mountAssembledApp, REFRESHING_GOLDEN } from './assembled-boot.ts' -const EXPECTED = join(process.cwd(), 'apps/web/tests/snapshots/search-card/grep-card.expected.txt') +const EXPECTED = join(process.cwd(), 'apps/web/tests/goldens/search-card/grep-card.expected.txt') installAssembledBootEnv() diff --git a/apps/web/tests/seeded-history.e2e.ts b/apps/web/tests/seeded-history.e2e.ts index de689175d9..d0c5cdb8bd 100644 --- a/apps/web/tests/seeded-history.e2e.ts +++ b/apps/web/tests/seeded-history.e2e.ts @@ -28,13 +28,13 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/seeded-history', import.meta.url)) -const SEED = fileURLToPath(new URL('./snapshots/seeded-history/seed.jsonl', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/seeded-history/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/seeded-history', import.meta.url)) +const SEED = fileURLToPath(new URL('../../../snapshots/web/seeded-history/seed.jsonl', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/seeded-history/ui.expected.md', import.meta.url)) // Command-row goldens over the same conversation after direct host commands. -const COMMAND_ROW_EXPECTED = fileURLToPath(new URL('./snapshots/seeded-history/command-row.expected.md', import.meta.url)) -const FEEDBACK_ROW_EXPECTED = fileURLToPath(new URL('./snapshots/seeded-history/feedback-row.expected.md', import.meta.url)) -const FILE_OPEN_FAILURE_EXPECTED = fileURLToPath(new URL('./snapshots/seeded-history/file-open-failure.expected.md', import.meta.url)) +const COMMAND_ROW_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/seeded-history/command-row.expected.md', import.meta.url)) +const FEEDBACK_ROW_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/seeded-history/feedback-row.expected.md', import.meta.url)) +const FILE_OPEN_FAILURE_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/seeded-history/file-open-failure.expected.md', import.meta.url)) const MODE = webSnapshotMode() const SEED_ID = 'seeded-history-web-e2e' diff --git a/apps/web/tests/settings-chrome.e2e.ts b/apps/web/tests/settings-chrome.e2e.ts index 562aff5dad..269a64f96c 100644 --- a/apps/web/tests/settings-chrome.e2e.ts +++ b/apps/web/tests/settings-chrome.e2e.ts @@ -21,7 +21,7 @@ import { } from './scaffold.ts' import { ZH_BROWSER_LOCALE, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/settings-chrome', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/settings-chrome', import.meta.url)) const DIALOG_EXPECTED = join(SNAPSHOT_DIR, 'dialog.expected.md') const PLUGINS_EXPECTED = join(SNAPSHOT_DIR, 'plugins.expected.md') // The English fallback surface: a browser naming no shipped language. diff --git a/apps/web/tests/shipped-composition.e2e.ts b/apps/web/tests/shipped-composition.e2e.ts index 295e861b95..0c4b27a131 100644 --- a/apps/web/tests/shipped-composition.e2e.ts +++ b/apps/web/tests/shipped-composition.e2e.ts @@ -22,7 +22,7 @@ import type {} from '@deepseek-ai/dsh-system-prompt' import { launchWebScaffold, type WebScaffold } from './scaffold.ts' const FILE_REFERENCE_PROMPT = fileURLToPath(new URL( - './snapshots/web-runtime-context/file-reference-prompt.expected.md', import.meta.url, + './goldens/web-runtime-context/file-reference-prompt.expected.md', import.meta.url, )) /** diff --git a/apps/web/tests/sidebar-scrollbar.e2e.ts b/apps/web/tests/sidebar-scrollbar.e2e.ts index 3500e09188..49813d6358 100644 --- a/apps/web/tests/sidebar-scrollbar.e2e.ts +++ b/apps/web/tests/sidebar-scrollbar.e2e.ts @@ -15,8 +15,8 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SEED = fileURLToPath(new URL('./snapshots/seeded-history/seed.jsonl', import.meta.url)) -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/sidebar-scrollbar', import.meta.url)) +const SEED = fileURLToPath(new URL('../../../snapshots/web/seeded-history/seed.jsonl', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/sidebar-scrollbar', import.meta.url)) /** Geometry and resolved style are absent from ARIA snapshots, so this scenario records them directly. */ const GEOMETRY_EXPECTED = join(SNAPSHOT_DIR, 'geometry.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/sidebar-subagent-activity.e2e.ts b/apps/web/tests/sidebar-subagent-activity.e2e.ts index c981d003b0..374db8b045 100644 --- a/apps/web/tests/sidebar-subagent-activity.e2e.ts +++ b/apps/web/tests/sidebar-subagent-activity.e2e.ts @@ -21,7 +21,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/sidebar-subagent-activity', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/sidebar-subagent-activity', import.meta.url)) const RUNNING_OWNER_EXPECTED = join(SNAPSHOT_DIR, 'owner-running.expected.md') const MODE = webSnapshotMode() const HOLD_PROVIDER = 'web-test-hold' diff --git a/apps/web/tests/skill-invocation-policy.e2e.ts b/apps/web/tests/skill-invocation-policy.e2e.ts index 54cd15bf94..56666aed8b 100644 --- a/apps/web/tests/skill-invocation-policy.e2e.ts +++ b/apps/web/tests/skill-invocation-policy.e2e.ts @@ -20,7 +20,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/skill-invocation-policy', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/skill-invocation-policy', import.meta.url)) const MENU_EXPECTED = join(SNAPSHOT_DIR, 'menu.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/skill-tool-row.e2e.ts b/apps/web/tests/skill-tool-row.e2e.ts index 91a92b89e9..8609af1212 100644 --- a/apps/web/tests/skill-tool-row.e2e.ts +++ b/apps/web/tests/skill-tool-row.e2e.ts @@ -13,8 +13,8 @@ import { import { newEnglishPage, saveFailureShot } from './support.ts' const FIXTURE = fileURLToPath(new URL('../../../snapshots/acp/skill-load/session.jsonl', import.meta.url)) -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/skill-tool-row', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/skill-tool-row/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/skill-tool-row', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/skill-tool-row/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() const SEED_ID = 'skill-tool-row-web-e2e' const PROMPT = 'Load the editing-cordis-compositions skill with the skill tool, then reply DONE.' diff --git a/apps/web/tests/skill-user-invoke.e2e.ts b/apps/web/tests/skill-user-invoke.e2e.ts index 8555ef7499..724c2ce5a9 100644 --- a/apps/web/tests/skill-user-invoke.e2e.ts +++ b/apps/web/tests/skill-user-invoke.e2e.ts @@ -23,7 +23,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/skill-user-invoke', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/skill-user-invoke', import.meta.url)) const UI_EXPECTED = join(SNAPSHOT_DIR, 'ui.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/smoke-real.e2e.ts b/apps/web/tests/smoke-real.e2e.ts index ff17f77507..084782c5f5 100644 --- a/apps/web/tests/smoke-real.e2e.ts +++ b/apps/web/tests/smoke-real.e2e.ts @@ -28,7 +28,7 @@ import { chromium } from 'playwright' import { afterAll, beforeAll, describe, expect, it, onTestFailed } from 'vitest' import { REPO_ROOT, connectFreshWorkspace, newEnglishPage, probeFreePort, requireDist, saveFailureShot } from './support.ts' -const WEB_SURFACE_PROMPT = fileURLToPath(new URL('./snapshots/web-runtime-context/web-surface-prompt.expected.md', import.meta.url)) +const WEB_SURFACE_PROMPT = fileURLToPath(new URL('./goldens/web-runtime-context/web-surface-prompt.expected.md', import.meta.url)) function waitForReadyLine(child: ChildProcess): Promise { return new Promise((resolveReady, reject) => { diff --git a/apps/web/tests/stats-paged-history.e2e.ts b/apps/web/tests/stats-paged-history.e2e.ts index e7ce2cdd06..4d282b0871 100644 --- a/apps/web/tests/stats-paged-history.e2e.ts +++ b/apps/web/tests/stats-paged-history.e2e.ts @@ -16,8 +16,8 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/stats-paged-history', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/stats-paged-history/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./goldens/stats-paged-history', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./goldens/stats-paged-history/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() const SEED_ID = 'stats-paged-history-web-e2e' diff --git a/apps/web/tests/steering.e2e.ts b/apps/web/tests/steering.e2e.ts index 8305771c4c..0b722a34aa 100644 --- a/apps/web/tests/steering.e2e.ts +++ b/apps/web/tests/steering.e2e.ts @@ -16,7 +16,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/steering', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/steering', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') // Two goldens pin the transient Host projection and its durable handoff: the // mid-turn state renders accepted steering from the Session control queue while the @@ -38,7 +38,7 @@ const STEER = 'Interjection: include the word BANANA in your final reply.' // replacement answers both model calls of a FRESH session (no recorded // session.jsonl exists — call 0 keeps the turn open with a question-tool // call, call 1 is the reply after both steerings drain). -const STEER_ALL_DIR = fileURLToPath(new URL('./snapshots/steer-all', import.meta.url)) +const STEER_ALL_DIR = fileURLToPath(new URL('./goldens/steer-all', import.meta.url)) const STEER_ALL_FIXTURE = join(STEER_ALL_DIR, 'session.jsonl') const STEER_ALL_OVERRIDE = join(STEER_ALL_DIR, 'replay.override.json') const STEER_ALL_MID = join(STEER_ALL_DIR, 'mid-steer.expected.md') diff --git a/apps/web/tests/subagent-conversation.e2e.ts b/apps/web/tests/subagent-conversation.e2e.ts index 193349fff5..649f90e7cd 100644 --- a/apps/web/tests/subagent-conversation.e2e.ts +++ b/apps/web/tests/subagent-conversation.e2e.ts @@ -17,14 +17,14 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const BASE_FIXTURE = fileURLToPath(new URL('./snapshots/live-interactions/session.jsonl', import.meta.url)) -const AVAILABLE_CHILD_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/ui.expected.md', import.meta.url)) -const TREE_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/tree.expected.md', import.meta.url)) -const BRANCHLESS_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/branchless.expected.md', import.meta.url)) -const STALE_CATALOG_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/stale-catalog.expected.md', import.meta.url)) -const SIDEBAR_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/sidebar.expected.md', import.meta.url)) -const UNAVAILABLE_GRANDCHILD_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/nested.expected.md', import.meta.url)) -const FORK_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/fork.expected.md', import.meta.url)) +const BASE_FIXTURE = fileURLToPath(new URL('../../../snapshots/web/live-interactions/session.jsonl', import.meta.url)) +const AVAILABLE_CHILD_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/ui.expected.md', import.meta.url)) +const TREE_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/tree.expected.md', import.meta.url)) +const BRANCHLESS_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/branchless.expected.md', import.meta.url)) +const STALE_CATALOG_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/stale-catalog.expected.md', import.meta.url)) +const SIDEBAR_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/sidebar.expected.md', import.meta.url)) +const UNAVAILABLE_GRANDCHILD_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/nested.expected.md', import.meta.url)) +const FORK_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/subagent-conversation/fork.expected.md', import.meta.url)) const MODE = webSnapshotMode() const LABEL = 'event-sourcing researcher' const ONE_SHOT_LABEL = 'event-sourcing reviewer' diff --git a/apps/web/tests/subagent-interrupt-ui.e2e.ts b/apps/web/tests/subagent-interrupt-ui.e2e.ts index 0eca3016fd..aa985f6601 100644 --- a/apps/web/tests/subagent-interrupt-ui.e2e.ts +++ b/apps/web/tests/subagent-interrupt-ui.e2e.ts @@ -26,9 +26,9 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const BASE_FIXTURE = fileURLToPath(new URL('./snapshots/live-interactions/session.jsonl', import.meta.url)) +const BASE_FIXTURE = fileURLToPath(new URL('../../../snapshots/web/live-interactions/session.jsonl', import.meta.url)) -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/subagent-interrupt', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/subagent-interrupt', import.meta.url)) const OFFLINE_COMPOSER_EXPECTED = join(SNAPSHOT_DIR, 'offline-composer.expected.md') const MODE = webSnapshotMode() const LABEL = 'event-sourcing researcher' diff --git a/apps/web/tests/todo-row.snapshot.ts b/apps/web/tests/todo-row.snapshot.ts index f39d1ba970..6501ce6cac 100644 --- a/apps/web/tests/todo-row.snapshot.ts +++ b/apps/web/tests/todo-row.snapshot.ts @@ -16,7 +16,7 @@ import { fireEvent, screen, waitFor, within } from '@testing-library/react' import { describe, expect, it } from 'vitest' import { hasClass, installAssembledBootEnv, mountAssembledApp, REFRESHING_GOLDEN } from './assembled-boot.ts' -const EXPECTED = join(process.cwd(), 'apps/web/tests/snapshots/todo-row/parallel-plan.expected.txt') +const EXPECTED = join(process.cwd(), 'apps/web/tests/goldens/todo-row/parallel-plan.expected.txt') installAssembledBootEnv() diff --git a/apps/web/tests/trajectory-virtualization.e2e.ts b/apps/web/tests/trajectory-virtualization.e2e.ts index d3f88d3a7f..f99475b0f8 100644 --- a/apps/web/tests/trajectory-virtualization.e2e.ts +++ b/apps/web/tests/trajectory-virtualization.e2e.ts @@ -24,7 +24,7 @@ import { newEnglishPage, saveFailureShot } from './support.ts' const MODE = webSnapshotMode() const LOAD_MORE_EXPECTED = fileURLToPath(new URL( - './snapshots/trajectory-virtualization/load-more.expected.md', + './goldens/trajectory-virtualization/load-more.expected.md', import.meta.url, )) const SESSION_ID = 'trajectory-virtualization-e2e' diff --git a/apps/web/tests/turn-tail-actions.e2e.ts b/apps/web/tests/turn-tail-actions.e2e.ts index 4822a254cd..d2f15fbccd 100644 --- a/apps/web/tests/turn-tail-actions.e2e.ts +++ b/apps/web/tests/turn-tail-actions.e2e.ts @@ -22,7 +22,7 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/turn-tail-actions', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/turn-tail-actions', import.meta.url)) const FIXTURE = join(SNAPSHOT_DIR, 'session.jsonl') // Two goldens for the same message: parked mid-turn, then settled. const RUNNING_EXPECTED = join(SNAPSHOT_DIR, 'running.expected.md') diff --git a/apps/web/tests/web-search-round.e2e.ts b/apps/web/tests/web-search-round.e2e.ts index 1975b0b937..505621b762 100644 --- a/apps/web/tests/web-search-round.e2e.ts +++ b/apps/web/tests/web-search-round.e2e.ts @@ -18,9 +18,9 @@ import { } from './scaffold.ts' import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/web-search-round', import.meta.url)) -const FIXTURE = fileURLToPath(new URL('./snapshots/web-search-round/session.jsonl', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./snapshots/web-search-round/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/web-search-round', import.meta.url)) +const FIXTURE = fileURLToPath(new URL('../../../snapshots/web/web-search-round/session.jsonl', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('../../../snapshots/web/web-search-round/ui.expected.md', import.meta.url)) const MODE = webSnapshotMode() const QUERIES = ['DeepSeek Harness snapshot search', 'DeepSeek Harness multi-query search'] as const const PROMPT = `Use web_search once with queries ${JSON.stringify(QUERIES)}. Then reply exactly SEARCH_DONE and stop.` diff --git a/apps/web/tests/workflow-run.e2e.ts b/apps/web/tests/workflow-run.e2e.ts index 3d2fb29c2f..b0e56cbf7e 100644 --- a/apps/web/tests/workflow-run.e2e.ts +++ b/apps/web/tests/workflow-run.e2e.ts @@ -19,7 +19,7 @@ import { } from './support.ts' const MODE = webSnapshotMode() -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/workflow-run', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/workflow-run', import.meta.url)) const UI_LIVE_EXPECTED = join(SNAPSHOT_DIR, 'ui-live.expected.md') const UI_EXPECTED = join(SNAPSHOT_DIR, 'ui.expected.md') const PARENT_FIXTURE = join(REPO_ROOT, 'snapshots/acp/workflow-run/session.jsonl') diff --git a/apps/web/tests/workspace-management.e2e.ts b/apps/web/tests/workspace-management.e2e.ts index 21913181bf..0233ff6725 100644 --- a/apps/web/tests/workspace-management.e2e.ts +++ b/apps/web/tests/workspace-management.e2e.ts @@ -24,10 +24,10 @@ import { } from './scaffold.ts' import { newEnglishPage, saveFailureShot } from './support.ts' -const SNAPSHOT_DIR = fileURLToPath(new URL('./snapshots/workspace-management', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('../../../snapshots/web/workspace-management', import.meta.url)) // The seed is another scenario's committed fixture, reused read-only: this // spec needs any one cold session row, not new recorded content. -const SEED = fileURLToPath(new URL('./snapshots/seeded-history/seed.jsonl', import.meta.url)) +const SEED = fileURLToPath(new URL('../../../snapshots/web/seeded-history/seed.jsonl', import.meta.url)) const MODE = webSnapshotMode() const BROWSER_EXPECTED = join(SNAPSHOT_DIR, 'directory-browser.expected.md') const SEED_ID = 'workspace-management-web-e2e' diff --git a/docs/testing.i18n.yaml b/docs/testing.i18n.yaml index 5d7bfda5d0..cb9b1e9463 100644 --- a/docs/testing.i18n.yaml +++ b/docs/testing.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/testing.md -testing.md: 5aaa32a5a067c57dee4f3054493cbea1a6e59042 -testing.zh.md: 15e17b08ea5836d925c7dd35e462978399474112 +testing.md: 9ca0188d04a64b462d68935ed1842827f06d874c +testing.zh.md: 89977da4434fd98b118fabf62a347e87c74b0db7 diff --git a/docs/testing.md b/docs/testing.md index 5aaa32a5a0..9ca0188d04 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -10,7 +10,7 @@ How this repo tests, tier by tier, and the rules that keep a green suite meaning - **Coverage gate** (`pnpm run test:coverage`): the gating run, per-file 100% on `packages/*/*/src`. An uncovered line is often dead code the gate is correctly flagging for deletion, not a missing test to bolt on. Line coverage is necessary, never sufficient — it proves lines ran, not that the feature works as shipped. Per-file 100% on `packages/shell/pwsh-local/src` needs a real `pwsh`: without one its executor suites self-skip and `vitest.config.ts` exempts the file so pwsh-less hosts stay green, while CI runners ship pwsh and enforce the full bar. - **Real-API e2e** (`pnpm run test:e2e`): with-key tests against live provider APIs — the DeepSeek model plus provider-specific smokes that gate on their own keys (`EXA_API_KEY`, `PERPLEXITY_API_KEY`, …); each suite self-skips without its key so keyless CI stays green ([real-API e2e Agent Note](../.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.md)). - **Snapshot** (`pnpm run test:snapshot`): keyless expected outputs cover external behavior — transport contracts and presentation, while persisted logs pin assembled backend behavior. ACP boots the real automation-server example, replays a recorded session, and diffs normalized JSON-RPC plus the re-persisted log ([ACP snapshot Agent Note](../.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.md)); headless backend scenarios boot their explicit example composition through an unexported JSONL test driver, while `apps/cli` separately owns product `dsh --profile headless` acceptance. Use `pnpm run test:snapshot:record` when a model transcript changes and `pnpm run test:snapshot:refresh` when replay input remains valid; review every JSONL and expected-output diff. One ACP scenario (`text-turn`) pins full system-prompt/tool-schema content; other fixtures tokenize it so an edit churns one line ([pinned-header Agent Note](../.agents/notes/archived/testing/2026-07-06-pin-request-header-content-in-one-scenario.md)). -- **Web browser snapshot** (`pnpm run test:web`; required Linux PR gate): Chromium compares replayed browser output with `apps/web/tests/snapshots/`. CI forces read-only `DSH_SNAPSHOT=replay`, never writing expected outputs; record/refresh stay local and every diff is reviewed ([web e2e lane](../.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.md), [CI gate decision](../.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.md)). `test:web` [builds first](../.agents/notes/implemented/bug-fix/2026-07-28-themed-scrollbars-and-reserved-gutter.md) for plugin CSS. +- **Web browser snapshot** (`pnpm run test:web`; required Linux PR gate): Chromium compares session-driven output under `snapshots/web/` and UI-only output under `apps/web/tests/goldens/`. CI forces read-only `DSH_SNAPSHOT=replay`, never writing expected outputs; record/refresh stay local and every diff is reviewed ([web e2e lane](../.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.md), [CI gate decision](../.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.md)). `test:web` [builds first](../.agents/notes/implemented/bug-fix/2026-07-28-themed-scrollbars-and-reserved-gutter.md) for plugin CSS. Session fixtures keep headers and payloads but omit body sequence/time envelopes. Replay synthesizes them; runtime persistence is unchanged. Fixtures use canonical packed rows; [the migrator](../scripts/migrate-packed-session-fixtures.ts) rewrites old layouts. diff --git a/docs/testing.zh.md b/docs/testing.zh.md index 15e17b08ea..89977da443 100644 --- a/docs/testing.zh.md +++ b/docs/testing.zh.md @@ -10,7 +10,7 @@ - **覆盖率门禁**(`pnpm run test:coverage`):门禁级运行,对 `packages/*/*/src` 按文件 100% 覆盖。未覆盖的行往往是门禁正确标记出的死代码(应删除),而非需要补写的测试。行覆盖率是必要条件,但永远不是充分条件:它证明行被执行过,不证明功能按交付预期工作。`packages/shell/pwsh-local/src` 的按文件 100% 覆盖需要真实的 `pwsh`:缺少它时其执行器套件会自动跳过,`vitest.config.ts` 会豁免该文件以使无 pwsh 的主机保持绿色,而 CI runner 自带 pwsh,仍按完整标准执行门禁。 - **真实 API e2e**(`pnpm run test:e2e`):带密钥测试调用真实提供方 API,包括 DeepSeek 模型以及各提供方特有的冒烟测试;这些测试各自由自己的密钥控制(`EXA_API_KEY`、`PERPLEXITY_API_KEY` 等),缺少密钥时套件会自动跳过,使 keyless CI 保持绿色([真实 API e2e Agent Note](../.agents/notes/implemented/testing/2026-06-19-real-api-e2e-ci.zh.md))。 - **快照**(`pnpm run test:snapshot`):无密钥预期输出覆盖对外行为(传输约定与呈现),持久化日志则固定组装后的后端行为。ACP 启动真实的自动化服务器示例、回放录制会话,并对归一化 JSON-RPC 与重新持久化的日志执行 diff([ACP 快照 Agent Note](../.agents/notes/implemented/testing/2026-06-19-acp-snapshot-tests.zh.md));headless 后端场景通过未导出的 JSONL 测试 driver 启动各自显式的示例组装,而 `apps/cli` 则单独负责产品 CLI(命令行界面)`dsh --profile headless` 的验收。当模型 transcript(文本记录)发生变化时使用 `pnpm run test:snapshot:record`,回放输入仍然有效时使用 `pnpm run test:snapshot:refresh`;请审查每一处 JSONL 与预期输出差异。一个 ACP 场景(`text-turn`)固定完整的系统提示词与工具 schema 内容;其他 fixture(测试前置数据)将其 token 化,因此修改只会扰动一行([pinned-header Agent Note](../.agents/notes/archived/testing/2026-07-06-pin-request-header-content-in-one-scenario.md))。 -- **Web 浏览器快照**(`pnpm run test:web`;必需的 Linux PR(Pull Request)门禁):Chromium 将回放后的浏览器输出与 `apps/web/tests/snapshots/` 比较。CI 强制只读的 `DSH_SNAPSHOT=replay`,绝不写入预期输出;record/refresh 留在本地,每处 diff 都须评审([web e2e 车道](../.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.zh.md)、[CI 门禁决策](../.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.zh.md))。`test:web` 会[先构建](../.agents/notes/implemented/bug-fix/2026-07-28-themed-scrollbars-and-reserved-gutter.zh.md)以交付插件 CSS。 +- **Web 浏览器快照**(`pnpm run test:web`;必需的 Linux PR(Pull Request)门禁):Chromium 比较 `snapshots/web/` 下由会话驱动的输出,以及 `apps/web/tests/goldens/` 下仅含 UI 的输出。CI 强制只读的 `DSH_SNAPSHOT=replay`,绝不写入预期输出;record/refresh 留在本地,每处 diff 都须评审([web e2e 车道](../.agents/notes/implemented/testing/2026-07-24-web-gui-browser-e2e-lane.zh.md)、[CI 门禁决策](../.agents/notes/implemented/testing/2026-07-30-web-browser-snapshot-ci-gate.zh.md))。`test:web` 会[先构建](../.agents/notes/implemented/bug-fix/2026-07-28-themed-scrollbars-and-reserved-gutter.zh.md)以交付插件 CSS。 会话 fixture 保留 header 与 payload,但省略正文序号/时间 envelope。回放会合成这些字段;运行时持久化不变。fixture 使用规范打包行;[迁移器](../scripts/migrate-packed-session-fixtures.ts)会改写旧布局。 diff --git a/apps/web/tests/snapshots/approval-composer/session.jsonl b/snapshots/web/approval-composer/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/approval-composer/session.jsonl rename to snapshots/web/approval-composer/session.jsonl diff --git a/snapshots/web/approval-composer/snapshot.yml b/snapshots/web/approval-composer/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/approval-composer/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/approval-composer/ui.expected.md b/snapshots/web/approval-composer/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/approval-composer/ui.expected.md rename to snapshots/web/approval-composer/ui.expected.md diff --git a/apps/web/tests/snapshots/background-job-list/running.expected.md b/snapshots/web/background-job-list/running.expected.md similarity index 100% rename from apps/web/tests/snapshots/background-job-list/running.expected.md rename to snapshots/web/background-job-list/running.expected.md diff --git a/apps/web/tests/snapshots/background-job-list/settled.expected.md b/snapshots/web/background-job-list/settled.expected.md similarity index 100% rename from apps/web/tests/snapshots/background-job-list/settled.expected.md rename to snapshots/web/background-job-list/settled.expected.md diff --git a/snapshots/web/background-job-list/snapshot.yml b/snapshots/web/background-job-list/snapshot.yml new file mode 100644 index 0000000000..45bd9372d1 --- /dev/null +++ b/snapshots/web/background-job-list/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../fresh-round-trip/session.jsonl diff --git a/snapshots/web/bash-abort-row/snapshot.yml b/snapshots/web/bash-abort-row/snapshot.yml new file mode 100644 index 0000000000..ea211fa553 --- /dev/null +++ b/snapshots/web/bash-abort-row/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../../acp/cancel-tool-calls/session.jsonl diff --git a/apps/web/tests/snapshots/bash-abort-row/ui.expected.md b/snapshots/web/bash-abort-row/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/bash-abort-row/ui.expected.md rename to snapshots/web/bash-abort-row/ui.expected.md diff --git a/apps/web/tests/snapshots/code-mode-round/session.jsonl b/snapshots/web/code-mode-round/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/code-mode-round/session.jsonl rename to snapshots/web/code-mode-round/session.jsonl diff --git a/snapshots/web/code-mode-round/snapshot.yml b/snapshots/web/code-mode-round/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/code-mode-round/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/code-mode-round/ui.expected.md b/snapshots/web/code-mode-round/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/code-mode-round/ui.expected.md rename to snapshots/web/code-mode-round/ui.expected.md diff --git a/apps/web/tests/snapshots/cordis-tool-round/session.jsonl b/snapshots/web/cordis-tool-round/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/cordis-tool-round/session.jsonl rename to snapshots/web/cordis-tool-round/session.jsonl diff --git a/snapshots/web/cordis-tool-round/snapshot.yml b/snapshots/web/cordis-tool-round/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/cordis-tool-round/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/cordis-tool-round/ui.expected.md b/snapshots/web/cordis-tool-round/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/cordis-tool-round/ui.expected.md rename to snapshots/web/cordis-tool-round/ui.expected.md diff --git a/apps/web/tests/snapshots/details-session-lifecycle/handles.expected.md b/snapshots/web/details-session-lifecycle/handles.expected.md similarity index 100% rename from apps/web/tests/snapshots/details-session-lifecycle/handles.expected.md rename to snapshots/web/details-session-lifecycle/handles.expected.md diff --git a/snapshots/web/details-session-lifecycle/snapshot.yml b/snapshots/web/details-session-lifecycle/snapshot.yml new file mode 100644 index 0000000000..9e6c1b428e --- /dev/null +++ b/snapshots/web/details-session-lifecycle/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../lifecycle-chrome/session.jsonl diff --git a/apps/web/tests/snapshots/feedback-command/ack.expected.md b/snapshots/web/feedback-command/ack.expected.md similarity index 100% rename from apps/web/tests/snapshots/feedback-command/ack.expected.md rename to snapshots/web/feedback-command/ack.expected.md diff --git a/apps/web/tests/snapshots/feedback-command/session.jsonl b/snapshots/web/feedback-command/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/feedback-command/session.jsonl rename to snapshots/web/feedback-command/session.jsonl diff --git a/snapshots/web/feedback-command/snapshot.yml b/snapshots/web/feedback-command/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/feedback-command/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/fresh-round-trip/session.jsonl b/snapshots/web/fresh-round-trip/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/fresh-round-trip/session.jsonl rename to snapshots/web/fresh-round-trip/session.jsonl diff --git a/snapshots/web/fresh-round-trip/snapshot.yml b/snapshots/web/fresh-round-trip/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/fresh-round-trip/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/fresh-round-trip/system-prompt.expected.md b/snapshots/web/fresh-round-trip/system-prompt.expected.md similarity index 100% rename from apps/web/tests/snapshots/fresh-round-trip/system-prompt.expected.md rename to snapshots/web/fresh-round-trip/system-prompt.expected.md diff --git a/apps/web/tests/snapshots/fresh-round-trip/ui.expected.md b/snapshots/web/fresh-round-trip/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/fresh-round-trip/ui.expected.md rename to snapshots/web/fresh-round-trip/ui.expected.md diff --git a/apps/web/tests/snapshots/goal-multi-turn-actions/replay.override.json b/snapshots/web/goal-multi-turn-actions/replay.override.json similarity index 100% rename from apps/web/tests/snapshots/goal-multi-turn-actions/replay.override.json rename to snapshots/web/goal-multi-turn-actions/replay.override.json diff --git a/apps/web/tests/snapshots/goal-multi-turn-actions/session.jsonl b/snapshots/web/goal-multi-turn-actions/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/goal-multi-turn-actions/session.jsonl rename to snapshots/web/goal-multi-turn-actions/session.jsonl diff --git a/snapshots/web/goal-multi-turn-actions/snapshot.yml b/snapshots/web/goal-multi-turn-actions/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/goal-multi-turn-actions/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/goal-multi-turn-actions/ui.expected.md b/snapshots/web/goal-multi-turn-actions/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/goal-multi-turn-actions/ui.expected.md rename to snapshots/web/goal-multi-turn-actions/ui.expected.md diff --git a/apps/web/tests/snapshots/lifecycle-chrome/command-menu-fuzzy.expected.md b/snapshots/web/lifecycle-chrome/command-menu-fuzzy.expected.md similarity index 100% rename from apps/web/tests/snapshots/lifecycle-chrome/command-menu-fuzzy.expected.md rename to snapshots/web/lifecycle-chrome/command-menu-fuzzy.expected.md diff --git a/apps/web/tests/snapshots/lifecycle-chrome/command-menu.expected.md b/snapshots/web/lifecycle-chrome/command-menu.expected.md similarity index 100% rename from apps/web/tests/snapshots/lifecycle-chrome/command-menu.expected.md rename to snapshots/web/lifecycle-chrome/command-menu.expected.md diff --git a/apps/web/tests/snapshots/lifecycle-chrome/hero.expected.md b/snapshots/web/lifecycle-chrome/hero.expected.md similarity index 100% rename from apps/web/tests/snapshots/lifecycle-chrome/hero.expected.md rename to snapshots/web/lifecycle-chrome/hero.expected.md diff --git a/apps/web/tests/snapshots/lifecycle-chrome/plan-active.expected.md b/snapshots/web/lifecycle-chrome/plan-active.expected.md similarity index 100% rename from apps/web/tests/snapshots/lifecycle-chrome/plan-active.expected.md rename to snapshots/web/lifecycle-chrome/plan-active.expected.md diff --git a/apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md b/snapshots/web/lifecycle-chrome/reloaded.expected.md similarity index 100% rename from apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md rename to snapshots/web/lifecycle-chrome/reloaded.expected.md diff --git a/apps/web/tests/snapshots/lifecycle-chrome/replay.override.json b/snapshots/web/lifecycle-chrome/replay.override.json similarity index 100% rename from apps/web/tests/snapshots/lifecycle-chrome/replay.override.json rename to snapshots/web/lifecycle-chrome/replay.override.json diff --git a/apps/web/tests/snapshots/lifecycle-chrome/session.jsonl b/snapshots/web/lifecycle-chrome/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/lifecycle-chrome/session.jsonl rename to snapshots/web/lifecycle-chrome/session.jsonl diff --git a/snapshots/web/lifecycle-chrome/snapshot.yml b/snapshots/web/lifecycle-chrome/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/lifecycle-chrome/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/live-interactions/cancel.expected.md b/snapshots/web/live-interactions/cancel.expected.md similarity index 100% rename from apps/web/tests/snapshots/live-interactions/cancel.expected.md rename to snapshots/web/live-interactions/cancel.expected.md diff --git a/apps/web/tests/snapshots/live-interactions/error-auth.expected.md b/snapshots/web/live-interactions/error-auth.expected.md similarity index 100% rename from apps/web/tests/snapshots/live-interactions/error-auth.expected.md rename to snapshots/web/live-interactions/error-auth.expected.md diff --git a/apps/web/tests/snapshots/live-interactions/loading.expected.md b/snapshots/web/live-interactions/loading.expected.md similarity index 100% rename from apps/web/tests/snapshots/live-interactions/loading.expected.md rename to snapshots/web/live-interactions/loading.expected.md diff --git a/apps/web/tests/snapshots/live-interactions/retry-exhausted.expected.md b/snapshots/web/live-interactions/retry-exhausted.expected.md similarity index 100% rename from apps/web/tests/snapshots/live-interactions/retry-exhausted.expected.md rename to snapshots/web/live-interactions/retry-exhausted.expected.md diff --git a/apps/web/tests/snapshots/live-interactions/retry.expected.md b/snapshots/web/live-interactions/retry.expected.md similarity index 100% rename from apps/web/tests/snapshots/live-interactions/retry.expected.md rename to snapshots/web/live-interactions/retry.expected.md diff --git a/apps/web/tests/snapshots/live-interactions/running-draft.expected.md b/snapshots/web/live-interactions/running-draft.expected.md similarity index 100% rename from apps/web/tests/snapshots/live-interactions/running-draft.expected.md rename to snapshots/web/live-interactions/running-draft.expected.md diff --git a/apps/web/tests/snapshots/live-interactions/session.jsonl b/snapshots/web/live-interactions/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/live-interactions/session.jsonl rename to snapshots/web/live-interactions/session.jsonl diff --git a/snapshots/web/live-interactions/snapshot.yml b/snapshots/web/live-interactions/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/live-interactions/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/message-actions/fork.expected.md b/snapshots/web/message-actions/fork.expected.md similarity index 100% rename from apps/web/tests/snapshots/message-actions/fork.expected.md rename to snapshots/web/message-actions/fork.expected.md diff --git a/snapshots/web/message-actions/snapshot.yml b/snapshots/web/message-actions/snapshot.yml new file mode 100644 index 0000000000..4b467e0555 --- /dev/null +++ b/snapshots/web/message-actions/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../seeded-history/seed.jsonl diff --git a/apps/web/tests/snapshots/message-actions/ui.expected.md b/snapshots/web/message-actions/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/message-actions/ui.expected.md rename to snapshots/web/message-actions/ui.expected.md diff --git a/apps/web/tests/snapshots/message-feedback-layout/geometry.expected.md b/snapshots/web/message-feedback-layout/geometry.expected.md similarity index 100% rename from apps/web/tests/snapshots/message-feedback-layout/geometry.expected.md rename to snapshots/web/message-feedback-layout/geometry.expected.md diff --git a/snapshots/web/message-feedback-layout/snapshot.yml b/snapshots/web/message-feedback-layout/snapshot.yml new file mode 100644 index 0000000000..4b467e0555 --- /dev/null +++ b/snapshots/web/message-feedback-layout/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../seeded-history/seed.jsonl diff --git a/apps/web/tests/snapshots/message-feedback-protocol/protocol.expected.json b/snapshots/web/message-feedback-protocol/protocol.expected.json similarity index 100% rename from apps/web/tests/snapshots/message-feedback-protocol/protocol.expected.json rename to snapshots/web/message-feedback-protocol/protocol.expected.json diff --git a/apps/web/tests/snapshots/message-feedback-protocol/session.jsonl b/snapshots/web/message-feedback-protocol/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/message-feedback-protocol/session.jsonl rename to snapshots/web/message-feedback-protocol/session.jsonl diff --git a/snapshots/web/message-feedback-protocol/snapshot.yml b/snapshots/web/message-feedback-protocol/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/message-feedback-protocol/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/minimal-preset/session.jsonl b/snapshots/web/minimal-preset/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/minimal-preset/session.jsonl rename to snapshots/web/minimal-preset/session.jsonl diff --git a/snapshots/web/minimal-preset/snapshot.yml b/snapshots/web/minimal-preset/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/minimal-preset/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/navigation-panes/search-results.expected.md b/snapshots/web/navigation-panes/search-results.expected.md similarity index 100% rename from apps/web/tests/snapshots/navigation-panes/search-results.expected.md rename to snapshots/web/navigation-panes/search-results.expected.md diff --git a/apps/web/tests/snapshots/navigation-panes/seed.jsonl b/snapshots/web/navigation-panes/seed.jsonl similarity index 100% rename from apps/web/tests/snapshots/navigation-panes/seed.jsonl rename to snapshots/web/navigation-panes/seed.jsonl diff --git a/snapshots/web/navigation-panes/snapshot.yml b/snapshots/web/navigation-panes/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/navigation-panes/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/navigation-panes/terminal-card.expected.md b/snapshots/web/navigation-panes/terminal-card.expected.md similarity index 100% rename from apps/web/tests/snapshots/navigation-panes/terminal-card.expected.md rename to snapshots/web/navigation-panes/terminal-card.expected.md diff --git a/apps/web/tests/snapshots/navigation-panes/trajectory.expected.md b/snapshots/web/navigation-panes/trajectory.expected.md similarity index 100% rename from apps/web/tests/snapshots/navigation-panes/trajectory.expected.md rename to snapshots/web/navigation-panes/trajectory.expected.md diff --git a/apps/web/tests/snapshots/permission-policy-context/session.jsonl b/snapshots/web/permission-policy-context/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/permission-policy-context/session.jsonl rename to snapshots/web/permission-policy-context/session.jsonl diff --git a/snapshots/web/permission-policy-context/snapshot.yml b/snapshots/web/permission-policy-context/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/permission-policy-context/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/plan-narrow-viewport/layout.expected.md b/snapshots/web/plan-narrow-viewport/layout.expected.md similarity index 100% rename from apps/web/tests/snapshots/plan-narrow-viewport/layout.expected.md rename to snapshots/web/plan-narrow-viewport/layout.expected.md diff --git a/apps/web/tests/snapshots/plan-narrow-viewport/session.jsonl b/snapshots/web/plan-narrow-viewport/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/plan-narrow-viewport/session.jsonl rename to snapshots/web/plan-narrow-viewport/session.jsonl diff --git a/snapshots/web/plan-narrow-viewport/snapshot.yml b/snapshots/web/plan-narrow-viewport/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/plan-narrow-viewport/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/plan-review/approved.expected.md b/snapshots/web/plan-review/approved.expected.md similarity index 100% rename from apps/web/tests/snapshots/plan-review/approved.expected.md rename to snapshots/web/plan-review/approved.expected.md diff --git a/apps/web/tests/snapshots/plan-review/review.expected.md b/snapshots/web/plan-review/review.expected.md similarity index 100% rename from apps/web/tests/snapshots/plan-review/review.expected.md rename to snapshots/web/plan-review/review.expected.md diff --git a/apps/web/tests/snapshots/plan-review/session.jsonl b/snapshots/web/plan-review/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/plan-review/session.jsonl rename to snapshots/web/plan-review/session.jsonl diff --git a/apps/web/tests/snapshots/plan-review/sidebar.expected.md b/snapshots/web/plan-review/sidebar.expected.md similarity index 100% rename from apps/web/tests/snapshots/plan-review/sidebar.expected.md rename to snapshots/web/plan-review/sidebar.expected.md diff --git a/snapshots/web/plan-review/snapshot.yml b/snapshots/web/plan-review/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/plan-review/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/pwsh-terminal/seed.jsonl b/snapshots/web/pwsh-terminal/seed.jsonl similarity index 100% rename from apps/web/tests/snapshots/pwsh-terminal/seed.jsonl rename to snapshots/web/pwsh-terminal/seed.jsonl diff --git a/snapshots/web/pwsh-terminal/snapshot.yml b/snapshots/web/pwsh-terminal/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/pwsh-terminal/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/pwsh-terminal/terminal-card.expected.md b/snapshots/web/pwsh-terminal/terminal-card.expected.md similarity index 100% rename from apps/web/tests/snapshots/pwsh-terminal/terminal-card.expected.md rename to snapshots/web/pwsh-terminal/terminal-card.expected.md diff --git a/apps/web/tests/snapshots/question-composer/answered.expected.md b/snapshots/web/question-composer/answered.expected.md similarity index 100% rename from apps/web/tests/snapshots/question-composer/answered.expected.md rename to snapshots/web/question-composer/answered.expected.md diff --git a/apps/web/tests/snapshots/question-composer/composed.expected.md b/snapshots/web/question-composer/composed.expected.md similarity index 100% rename from apps/web/tests/snapshots/question-composer/composed.expected.md rename to snapshots/web/question-composer/composed.expected.md diff --git a/apps/web/tests/snapshots/question-composer/session.jsonl b/snapshots/web/question-composer/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/question-composer/session.jsonl rename to snapshots/web/question-composer/session.jsonl diff --git a/apps/web/tests/snapshots/question-composer/sidebar.expected.md b/snapshots/web/question-composer/sidebar.expected.md similarity index 100% rename from apps/web/tests/snapshots/question-composer/sidebar.expected.md rename to snapshots/web/question-composer/sidebar.expected.md diff --git a/snapshots/web/question-composer/snapshot.yml b/snapshots/web/question-composer/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/question-composer/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/question-composer/ui.expected.md b/snapshots/web/question-composer/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/question-composer/ui.expected.md rename to snapshots/web/question-composer/ui.expected.md diff --git a/apps/web/tests/snapshots/queue-actions/collapsed.expected.md b/snapshots/web/queue-actions/collapsed.expected.md similarity index 100% rename from apps/web/tests/snapshots/queue-actions/collapsed.expected.md rename to snapshots/web/queue-actions/collapsed.expected.md diff --git a/apps/web/tests/snapshots/queue-actions/editing.expected.md b/snapshots/web/queue-actions/editing.expected.md similarity index 100% rename from apps/web/tests/snapshots/queue-actions/editing.expected.md rename to snapshots/web/queue-actions/editing.expected.md diff --git a/apps/web/tests/snapshots/queue-actions/layout.expected.md b/snapshots/web/queue-actions/layout.expected.md similarity index 100% rename from apps/web/tests/snapshots/queue-actions/layout.expected.md rename to snapshots/web/queue-actions/layout.expected.md diff --git a/apps/web/tests/snapshots/queue-actions/preserved.expected.md b/snapshots/web/queue-actions/preserved.expected.md similarity index 100% rename from apps/web/tests/snapshots/queue-actions/preserved.expected.md rename to snapshots/web/queue-actions/preserved.expected.md diff --git a/snapshots/web/queue-actions/snapshot.yml b/snapshots/web/queue-actions/snapshot.yml new file mode 100644 index 0000000000..6d57d2e451 --- /dev/null +++ b/snapshots/web/queue-actions/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../live-interactions/session.jsonl diff --git a/apps/web/tests/snapshots/queue-actions/ui.expected.md b/snapshots/web/queue-actions/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/queue-actions/ui.expected.md rename to snapshots/web/queue-actions/ui.expected.md diff --git a/apps/web/tests/snapshots/seeded-history/command-row.expected.md b/snapshots/web/seeded-history/command-row.expected.md similarity index 100% rename from apps/web/tests/snapshots/seeded-history/command-row.expected.md rename to snapshots/web/seeded-history/command-row.expected.md diff --git a/apps/web/tests/snapshots/seeded-history/feedback-row.expected.md b/snapshots/web/seeded-history/feedback-row.expected.md similarity index 100% rename from apps/web/tests/snapshots/seeded-history/feedback-row.expected.md rename to snapshots/web/seeded-history/feedback-row.expected.md diff --git a/apps/web/tests/snapshots/seeded-history/file-open-failure.expected.md b/snapshots/web/seeded-history/file-open-failure.expected.md similarity index 100% rename from apps/web/tests/snapshots/seeded-history/file-open-failure.expected.md rename to snapshots/web/seeded-history/file-open-failure.expected.md diff --git a/apps/web/tests/snapshots/seeded-history/seed.jsonl b/snapshots/web/seeded-history/seed.jsonl similarity index 100% rename from apps/web/tests/snapshots/seeded-history/seed.jsonl rename to snapshots/web/seeded-history/seed.jsonl diff --git a/snapshots/web/seeded-history/snapshot.yml b/snapshots/web/seeded-history/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/seeded-history/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/seeded-history/ui.expected.md b/snapshots/web/seeded-history/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/seeded-history/ui.expected.md rename to snapshots/web/seeded-history/ui.expected.md diff --git a/apps/web/tests/snapshots/sidebar-scrollbar/geometry.expected.md b/snapshots/web/sidebar-scrollbar/geometry.expected.md similarity index 100% rename from apps/web/tests/snapshots/sidebar-scrollbar/geometry.expected.md rename to snapshots/web/sidebar-scrollbar/geometry.expected.md diff --git a/snapshots/web/sidebar-scrollbar/snapshot.yml b/snapshots/web/sidebar-scrollbar/snapshot.yml new file mode 100644 index 0000000000..4b467e0555 --- /dev/null +++ b/snapshots/web/sidebar-scrollbar/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../seeded-history/seed.jsonl diff --git a/snapshots/web/skill-tool-row/snapshot.yml b/snapshots/web/skill-tool-row/snapshot.yml new file mode 100644 index 0000000000..fdba3b3d5d --- /dev/null +++ b/snapshots/web/skill-tool-row/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../../acp/skill-load/session.jsonl diff --git a/apps/web/tests/snapshots/skill-tool-row/ui.expected.md b/snapshots/web/skill-tool-row/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/skill-tool-row/ui.expected.md rename to snapshots/web/skill-tool-row/ui.expected.md diff --git a/apps/web/tests/snapshots/steering/mid-steer.expected.md b/snapshots/web/steering/mid-steer.expected.md similarity index 100% rename from apps/web/tests/snapshots/steering/mid-steer.expected.md rename to snapshots/web/steering/mid-steer.expected.md diff --git a/apps/web/tests/snapshots/steering/session.jsonl b/snapshots/web/steering/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/steering/session.jsonl rename to snapshots/web/steering/session.jsonl diff --git a/apps/web/tests/snapshots/steering/settled.expected.md b/snapshots/web/steering/settled.expected.md similarity index 100% rename from apps/web/tests/snapshots/steering/settled.expected.md rename to snapshots/web/steering/settled.expected.md diff --git a/snapshots/web/steering/snapshot.yml b/snapshots/web/steering/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/steering/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/subagent-conversation/branchless.expected.md b/snapshots/web/subagent-conversation/branchless.expected.md similarity index 100% rename from apps/web/tests/snapshots/subagent-conversation/branchless.expected.md rename to snapshots/web/subagent-conversation/branchless.expected.md diff --git a/apps/web/tests/snapshots/subagent-conversation/fork.expected.md b/snapshots/web/subagent-conversation/fork.expected.md similarity index 100% rename from apps/web/tests/snapshots/subagent-conversation/fork.expected.md rename to snapshots/web/subagent-conversation/fork.expected.md diff --git a/apps/web/tests/snapshots/subagent-conversation/nested.expected.md b/snapshots/web/subagent-conversation/nested.expected.md similarity index 100% rename from apps/web/tests/snapshots/subagent-conversation/nested.expected.md rename to snapshots/web/subagent-conversation/nested.expected.md diff --git a/apps/web/tests/snapshots/subagent-conversation/sidebar.expected.md b/snapshots/web/subagent-conversation/sidebar.expected.md similarity index 100% rename from apps/web/tests/snapshots/subagent-conversation/sidebar.expected.md rename to snapshots/web/subagent-conversation/sidebar.expected.md diff --git a/snapshots/web/subagent-conversation/snapshot.yml b/snapshots/web/subagent-conversation/snapshot.yml new file mode 100644 index 0000000000..6d57d2e451 --- /dev/null +++ b/snapshots/web/subagent-conversation/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../live-interactions/session.jsonl diff --git a/apps/web/tests/snapshots/subagent-conversation/stale-catalog.expected.md b/snapshots/web/subagent-conversation/stale-catalog.expected.md similarity index 100% rename from apps/web/tests/snapshots/subagent-conversation/stale-catalog.expected.md rename to snapshots/web/subagent-conversation/stale-catalog.expected.md diff --git a/apps/web/tests/snapshots/subagent-conversation/tree.expected.md b/snapshots/web/subagent-conversation/tree.expected.md similarity index 100% rename from apps/web/tests/snapshots/subagent-conversation/tree.expected.md rename to snapshots/web/subagent-conversation/tree.expected.md diff --git a/apps/web/tests/snapshots/subagent-conversation/ui.expected.md b/snapshots/web/subagent-conversation/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/subagent-conversation/ui.expected.md rename to snapshots/web/subagent-conversation/ui.expected.md diff --git a/apps/web/tests/snapshots/subagent-interrupt/offline-composer.expected.md b/snapshots/web/subagent-interrupt/offline-composer.expected.md similarity index 100% rename from apps/web/tests/snapshots/subagent-interrupt/offline-composer.expected.md rename to snapshots/web/subagent-interrupt/offline-composer.expected.md diff --git a/snapshots/web/subagent-interrupt/snapshot.yml b/snapshots/web/subagent-interrupt/snapshot.yml new file mode 100644 index 0000000000..6d57d2e451 --- /dev/null +++ b/snapshots/web/subagent-interrupt/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../live-interactions/session.jsonl diff --git a/apps/web/tests/snapshots/turn-tail-actions/running.expected.md b/snapshots/web/turn-tail-actions/running.expected.md similarity index 100% rename from apps/web/tests/snapshots/turn-tail-actions/running.expected.md rename to snapshots/web/turn-tail-actions/running.expected.md diff --git a/apps/web/tests/snapshots/turn-tail-actions/session.jsonl b/snapshots/web/turn-tail-actions/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/turn-tail-actions/session.jsonl rename to snapshots/web/turn-tail-actions/session.jsonl diff --git a/apps/web/tests/snapshots/turn-tail-actions/settled.expected.md b/snapshots/web/turn-tail-actions/settled.expected.md similarity index 100% rename from apps/web/tests/snapshots/turn-tail-actions/settled.expected.md rename to snapshots/web/turn-tail-actions/settled.expected.md diff --git a/snapshots/web/turn-tail-actions/snapshot.yml b/snapshots/web/turn-tail-actions/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/turn-tail-actions/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/web-search-round/session.jsonl b/snapshots/web/web-search-round/session.jsonl similarity index 100% rename from apps/web/tests/snapshots/web-search-round/session.jsonl rename to snapshots/web/web-search-round/session.jsonl diff --git a/snapshots/web/web-search-round/snapshot.yml b/snapshots/web/web-search-round/snapshot.yml new file mode 100644 index 0000000000..e52a61dbdc --- /dev/null +++ b/snapshots/web/web-search-round/snapshot.yml @@ -0,0 +1,2 @@ +version: 1 +profile: web diff --git a/apps/web/tests/snapshots/web-search-round/ui.expected.md b/snapshots/web/web-search-round/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/web-search-round/ui.expected.md rename to snapshots/web/web-search-round/ui.expected.md diff --git a/snapshots/web/workflow-run/snapshot.yml b/snapshots/web/workflow-run/snapshot.yml new file mode 100644 index 0000000000..41f21e9db5 --- /dev/null +++ b/snapshots/web/workflow-run/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../../acp/workflow-run/session.jsonl diff --git a/apps/web/tests/snapshots/workflow-run/ui-live.expected.md b/snapshots/web/workflow-run/ui-live.expected.md similarity index 100% rename from apps/web/tests/snapshots/workflow-run/ui-live.expected.md rename to snapshots/web/workflow-run/ui-live.expected.md diff --git a/apps/web/tests/snapshots/workflow-run/ui.expected.md b/snapshots/web/workflow-run/ui.expected.md similarity index 100% rename from apps/web/tests/snapshots/workflow-run/ui.expected.md rename to snapshots/web/workflow-run/ui.expected.md diff --git a/apps/web/tests/snapshots/workspace-management/.gitkeep b/snapshots/web/workspace-management/.gitkeep similarity index 100% rename from apps/web/tests/snapshots/workspace-management/.gitkeep rename to snapshots/web/workspace-management/.gitkeep diff --git a/apps/web/tests/snapshots/workspace-management/directory-browser.expected.md b/snapshots/web/workspace-management/directory-browser.expected.md similarity index 100% rename from apps/web/tests/snapshots/workspace-management/directory-browser.expected.md rename to snapshots/web/workspace-management/directory-browser.expected.md diff --git a/snapshots/web/workspace-management/snapshot.yml b/snapshots/web/workspace-management/snapshot.yml new file mode 100644 index 0000000000..4b467e0555 --- /dev/null +++ b/snapshots/web/workspace-management/snapshot.yml @@ -0,0 +1,4 @@ +version: 1 +profile: web +session: + source: ../seeded-history/seed.jsonl