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 dd2137f023..9e2f0ab43b 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: 7b16c401a4cac45a218ba0b42743b38171f99d9e -2026-07-30-web-search-card.zh.md: 4fd653ef519d3ba1cb5e6e3e9c9275b3cc8127bb +2026-07-30-web-search-card.md: 55a91e2d2a9f35dd8897822442119edc88431e9b +2026-07-30-web-search-card.zh.md: eda7332848e513b52b04a944ca4fc1166027420b 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 7b16c401a4..55a91e2d2a 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/goldens/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.expected.e2e.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/expected/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 4fd653ef51..eda7332848 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/goldens/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.expected.e2e.ts` 是仓库约定要求的组装输出检查:它通过 keyless fixture 传输启动真实构建的 `client.js` bundle,打开 fixture 会话,并把 grep 卡片的组装形态——kind、截断摘要、头/尾切片及其展开控件——固定在 `apps/web/tests/expected/search-card/` 下,因此一个损坏的 SearchRow 注册或被丢弃的卡片会让一个 golden 失败,而 built-boot smoke(按约定只测启动)无法捕获它。 ## Related diff --git a/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.i18n.yaml b/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.i18n.yaml index bcfb80de6f..737b2dfb23 100644 --- a/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.i18n.yaml +++ b/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-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/process/2026-07-02-bilingual-docs-and-pairing-gate.md -2026-07-02-bilingual-docs-and-pairing-gate.md: f08b5b55b67007cb8c735525afffa5983b9b5863 -2026-07-02-bilingual-docs-and-pairing-gate.zh.md: f857f79f952b67adf50b1a18fb6daf85a5e3a404 +2026-07-02-bilingual-docs-and-pairing-gate.md: 62302f73120f40a9a1302ee839f266d382be7698 +2026-07-02-bilingual-docs-and-pairing-gate.zh.md: 8e9966de6f08a2f41157ebf2cae4bcd0312d62f2 diff --git a/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md b/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md index f08b5b55b6..62302f7312 100644 --- a/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md +++ b/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.md @@ -19,7 +19,7 @@ This repo's documentation corpus is read by people and agents inside and outside ## Verification -The verification contract covers each boundary independently. `verify-translation-pairing` pins pair completeness, hashes, switchers, and structure, while its discovery tests pin the named root policy documents and automatic README coverage; [`project-doc-site.spec.ts`](../../../../scripts/project-doc-site.spec.ts) pins locale-specific source selection for published pairs; [`cordis-config-files.spec.ts`](../../../../scripts/cordis-config-files.spec.ts) pins discovery of Loader YAML and exclusion of translation records; and the [translation-prompt runnable golden](../../../../scripts/translation-prompt.golden.spec.ts) pins the rendered system message, five reviewed example pairs, source request, and consumed response. Together these checks make pair drift, publication drift, configuration misclassification, and model-visible prompt drift review-visible. +The verification contract covers each boundary independently. `verify-translation-pairing` pins pair completeness, hashes, switchers, and structure, while its discovery tests pin the named root policy documents and automatic README coverage; [`project-doc-site.spec.ts`](../../../../scripts/project-doc-site.spec.ts) pins locale-specific source selection for published pairs; [`cordis-config-files.spec.ts`](../../../../scripts/cordis-config-files.spec.ts) pins discovery of Loader YAML and exclusion of translation records; and the [translation-prompt runnable expectation](../../../../scripts/translation-prompt.expected.spec.ts) pins the rendered system message, five reviewed example pairs, source request, and consumed response. Together these checks make pair drift, publication drift, configuration misclassification, and model-visible prompt drift review-visible. ## Alternatives considered diff --git a/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.zh.md b/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.zh.md index f857f79f95..8e9966de6f 100644 --- a/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.zh.md +++ b/.agents/notes/implemented/process/2026-07-02-bilingual-docs-and-pairing-gate.zh.md @@ -19,7 +19,7 @@ Status: implemented ## 验证 -验证约定分别覆盖每个边界。`verify-translation-pairing` 固定配对完整性、hash、语言切换行和结构,其发现测试则固定具名的根目录政策文档与自动 README 覆盖;[`project-doc-site.spec.ts`](../../../../scripts/project-doc-site.spec.ts) 固定已发布配对按 locale 选择对应源文件;[`cordis-config-files.spec.ts`](../../../../scripts/cordis-config-files.spec.ts) 固定 Loader YAML 的发现以及翻译记录的排除;[翻译提示词可运行 golden](../../../../scripts/translation-prompt.golden.spec.ts)则固定渲染后的系统消息、五对经评审的示例、源请求和所消费的响应。这些检查共同使配对漂移、发布漂移、配置误分类和模型可见提示词漂移都可在评审中看见。 +验证约定分别覆盖每个边界。`verify-translation-pairing` 固定配对完整性、hash、语言切换行和结构,其发现测试则固定具名的根目录政策文档与自动 README 覆盖;[`project-doc-site.spec.ts`](../../../../scripts/project-doc-site.spec.ts) 固定已发布配对按 locale 选择对应源文件;[`cordis-config-files.spec.ts`](../../../../scripts/cordis-config-files.spec.ts) 固定 Loader YAML 的发现以及翻译记录的排除;[翻译提示词可运行预期](../../../../scripts/translation-prompt.expected.spec.ts)则固定渲染后的系统消息、五对经评审的示例、源请求和所消费的响应。这些检查共同使配对漂移、发布漂移、配置误分类和模型可见提示词漂移都可在评审中看见。 ## 曾考虑的替代方案 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 dc0a40f23a..38d4fdee09 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: e94141070ba283434f49108899f743fab6073ebc -2026-07-30-web-browser-snapshot-ci-gate.zh.md: 9976034bb0ff8ba0435be41fe9e6bd406267fadb +2026-07-30-web-browser-snapshot-ci-gate.md: 8366c989f729878f362cfc51f13566c4768ef131 +2026-07-30-web-browser-snapshot-ci-gate.zh.md: 928a07aa2735832425efa759cce867165d54dde9 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 e94141070b..8366c989f7 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 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. +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/expected/`. 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 9976034bb0..928a07aa27 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 不比较 `snapshots/web/` 或 `apps/web/tests/goldens/` 下的 Web 预期输出。因此,改变用户可见 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/expected/` 下的 Web 预期输出。因此,改变用户可见 Web 输出的 PR 可以在漏刷预期输出时保持绿色;后来任意分支显式运行 `DSH_SNAPSHOT=refresh`,都会替前序变更补账并产生与本分支无关的 diff。普通本地运行已经默认使用只读 replay,缺口是 PR 级的强制执行,而不是禁止 refresh 写入。 ## 决策 diff --git a/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.i18n.yaml b/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.i18n.yaml index be5a8e8182..2210dc250e 100644 --- a/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.i18n.yaml +++ b/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.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-08-24-session-log-snapshot-corpus.md -2026-08-24-session-log-snapshot-corpus.md: 8706a0c431435319bd89ba5013853ebac60e4c50 -2026-08-24-session-log-snapshot-corpus.zh.md: fc64595267dd89b69a3097d552b858e3793eff46 +2026-08-24-session-log-snapshot-corpus.md: 30dad40098e5d1da08052384374425cad595a1ba +2026-08-24-session-log-snapshot-corpus.zh.md: 49edffc2a63486030ace8e76455e9bae209ee902 diff --git a/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.md b/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.md index 8706a0c431..30dad40098 100644 --- a/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.md +++ b/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.md @@ -16,7 +16,7 @@ Reserve the top-level `snapshots/` tree and `*.snapshot.ts` suffix for scenarios The recorded session remains the primary input and expected output. Human-originated messages drive the selected public interface, recorded assistant chunks drive deterministic model replay, and the normalized persisted result must equal the fixture. Parent and child sessions share one typed redaction map. Committed fixtures contain relationship-preserving identity tokens and replace request system prompts and tool schemas with tokens; each distinct header class retains one explicit sidecar owner. -Every existing ACP scenario receives a behavior-preserving destination. Ordinary one-shot behavior uses the headless profile, persistent machine control uses the SDK profile, and only ACP protocol behavior remains ACP-owned. Web scenarios driven by a recorded session join the corpus and retain their ARIA or geometry expected output as secondary evidence. Web and package tests without a recorded-session source remain owner-local goldens and stop using snapshot paths or filenames. +Every existing ACP scenario receives a behavior-preserving destination. Ordinary one-shot behavior uses the headless profile, persistent machine control uses the SDK profile, and only ACP protocol behavior remains ACP-owned. Web scenarios driven by a recorded session join the corpus and retain their ARIA or geometry expected output as secondary evidence. Web and package tests without a recorded-session source keep owner-local expected output and stop using snapshot paths or filenames. Workspace inputs remain scenario-local. A mutating scenario compares a complete expected final workspace that record and refresh never rewrite, so a model or tool self-report cannot satisfy the test. Existing intentional session reuse remains an explicit acyclic owner reference; the corpus adds no workspace inheritance or general fixture-merging mechanism. @@ -26,7 +26,7 @@ Workspace inputs remain scenario-local. A mutating scenario compares a complete **Move every scenario to a new headless test driver.** A private driver would reproduce the application-entrypoint problem and cannot express multi-turn, cancellation, or background lifecycle control available through the shipped SDK profile. -**Centralize every expected output under `snapshots/`.** ARIA, geometry, generator, and unit goldens do not use a recorded session as both input and result. Mixing them would keep the current ambiguous terminology and weaken package ownership. +**Centralize every expected output under `snapshots/`.** ARIA, geometry, generator, and unit expectations do not use a recorded session as both input and result. Mixing them would keep the current ambiguous terminology and weaken package ownership. **Create one declarative browser and terminal language.** Complex UI and PTY scenarios need interaction code. A shared snapshot core plus interface adapters removes application drivers without adding a second test framework. @@ -36,15 +36,15 @@ Workspace inputs remain scenario-local. A mutating scenario compares a complete - Every existing recorded-session scenario has one passing replacement before its old owner is removed. - Every process-level snapshot starts through `dsh`, and the application-entrypoint inventory no longer allows the retired snapshot drivers. -- Every top-level scenario owns or references session JSONL; non-session goldens remain owner-local. +- Every top-level scenario owns or references session JSONL; non-session expected output remains owner-local. - Committed session fixtures are redaction fixed points, contain no system-prompt or tool-schema bulk, and retain exactly one pin per header class. - Mutating scenarios verify their final workspace externally. -- Owner-local process goldens use `*.golden.e2e.ts` and a separate built-output gate. +- Owner-local process expectations use `*.expected.e2e.ts` and a separate built-output gate. - Source and built launch modes, browser replay, SDK projections, packaged Python runtime cases, documentation gates, and repository hygiene pass. ## Consequences -The corpus makes controller ownership visible: ordinary Agent behavior no longer inherits ACP protocol output, SDK and Web projections retain their interface-specific evidence, and only ACP cancellation and permission exchanges remain ACP-owned. Contributors review one normalized session diff plus the sidecars or UI goldens that add independent evidence. Adding a composition requires a manifest class pin; adding a volatile identity requires a typed relationship-preserving redaction rule rather than a broader text scrubber. +The corpus makes controller ownership visible: ordinary Agent behavior no longer inherits ACP protocol output, SDK and Web projections retain their interface-specific evidence, and only ACP cancellation and permission exchanges remain ACP-owned. Contributors review one normalized session diff plus the sidecars or UI expectations that add independent evidence. Adding a composition requires a manifest class pin; adding a volatile identity requires a typed relationship-preserving redaction rule rather than a broader text scrubber. ## Risks diff --git a/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.zh.md b/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.zh.md index fc64595267..49edffc2a6 100644 --- a/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.zh.md +++ b/.agents/notes/implemented/testing/2026-08-24-session-log-snapshot-corpus.zh.md @@ -16,7 +16,7 @@ Status: implemented 录制会话仍是主要输入和预期输出。来自用户的消息驱动所选公开接口,录制的 assistant chunk 驱动确定性模型回放,规范化后的持久化结果必须等于 fixture。父会话和子会话共享同一类型化脱敏映射。提交的 fixture 使用保留关系的身份 token,并将请求 system prompt 和工具 schema 替换为 token;每个不同 header 类仍保留一个显式 sidecar 所有者。 -每个现有 ACP 场景都获得一个保留行为的目标。普通单次行为使用 headless profile,需要持久机器控制的行为使用 SDK profile,只有 ACP 协议行为继续归 ACP 所有。由录制会话驱动的 Web 场景加入该语料,并保留其 ARIA 或几何预期输出作为辅助证据。没有录制会话来源的 Web 和包级测试继续使用归属方本地的 golden,并停止使用快照路径或文件名。 +每个现有 ACP 场景都获得一个保留行为的目标。普通单次行为使用 headless profile,需要持久机器控制的行为使用 SDK profile,只有 ACP 协议行为继续归 ACP 所有。由录制会话驱动的 Web 场景加入该语料,并保留其 ARIA 或几何预期输出作为辅助证据。没有录制会话来源的 Web 和包级测试保留归属方本地的预期输出,并停止使用快照路径或文件名。 Workspace 输入继续归各场景本地所有。变更文件的场景比较完整的预期最终 workspace,record 与 refresh 绝不改写该预期,因此模型或工具的自报结果无法满足测试。现有的有意会话复用继续使用显式、无环的所有者引用;语料不增加 workspace 继承或通用 fixture 合并机制。 @@ -26,7 +26,7 @@ Workspace 输入继续归各场景本地所有。变更文件的场景比较完 **将每个场景移动到新的 headless 测试驱动器。** 私有驱动器会重现应用入口问题,也无法表达随附 SDK profile 已提供的多轮、取消或后台生命周期控制。 -**将每种预期输出集中到 `snapshots/`。** ARIA、几何、生成器和单元测试 golden 不会把录制会话同时用作输入和结果。混合这些内容会保留当前含糊的术语,并削弱包所有权。 +**将每种预期输出集中到 `snapshots/`。** ARIA、几何、生成器和单元测试预期不会把录制会话同时用作输入和结果。混合这些内容会保留当前含糊的术语,并削弱包所有权。 **创建统一的声明式浏览器和终端语言。** 复杂 UI 和 PTY 场景需要交互代码。共享快照核心加接口适配器可以移除应用驱动器,而无需增加第二套测试框架。 @@ -36,15 +36,15 @@ Workspace 输入继续归各场景本地所有。变更文件的场景比较完 - 每个现有录制会话场景都在移除旧所有者之前拥有一个通过的替代场景。 - 每个进程级快照都通过 `dsh` 启动,应用入口清单不再允许已退休的快照驱动器。 -- 每个顶层场景都拥有或引用会话 JSONL;非会话 golden 继续归所有者本地所有。 +- 每个顶层场景都拥有或引用会话 JSONL;非会话预期输出继续归所有者本地所有。 - 提交的会话 fixture 是脱敏固定点,不含 system prompt 或工具 schema 正文,并为每个 header 类保留且仅保留一个 pin。 - 变更内容的场景从外部验证最终 workspace。 -- 所属位置的进程 golden 使用 `*.golden.e2e.ts`,并由单独的构建产物门禁运行。 +- 所属位置的进程预期使用 `*.expected.e2e.ts`,并由单独的构建产物门禁运行。 - 源码和构建启动模式、浏览器回放、SDK 投影、打包 Python 运行时场景、文档门禁和仓库卫生检查通过。 ## Consequences -该语料让控制器所有权可见:普通 Agent 行为不再继承 ACP 协议输出,SDK 和 Web 投影保留各自接口专有的证据,只有 ACP 取消与权限交换仍归 ACP 所有。贡献者审查一份规范化会话差异,以及提供独立证据的 sidecar 或 UI golden。新增组合必须提供 manifest 类别 pin;新增易变身份必须添加保留关系的带类型脱敏规则,而不是扩大文本清洗范围。 +该语料让控制器所有权可见:普通 Agent 行为不再继承 ACP 协议输出,SDK 和 Web 投影保留各自接口专有的证据,只有 ACP 取消与权限交换仍归 ACP 所有。贡献者审查一份规范化会话差异,以及提供独立证据的 sidecar 或 UI 预期。新增组合必须提供 manifest 类别 pin;新增易变身份必须添加保留关系的带类型脱敏规则,而不是扩大文本清洗范围。 ## Risks diff --git a/.agents/skills/dsh-pre-push-checks/SKILL.md b/.agents/skills/dsh-pre-push-checks/SKILL.md index f468745e7f..bce992e0c2 100644 --- a/.agents/skills/dsh-pre-push-checks/SKILL.md +++ b/.agents/skills/dsh-pre-push-checks/SKILL.md @@ -31,7 +31,7 @@ There is no universal local baseline beyond the hooks. Every behavior change nee - **Package or script behavior:** run the owning Vitest file or focused test name. Add adjacent package tests when a shared contract changes; leave repository-wide coverage to CI unless the change is genuinely cross-cutting or the user requests it. - **Documentation, Agent Notes, catalogs, or doc-linked comments:** run `pnpm run doc-sync`; run full lint when the documentation workflow requires it. - **Model-, editor-, CLI-, or terminal-visible output:** run the focused keyless snapshot or real runnable-example scenario that owns the output. -- **Expected-output placement:** a test whose recorded `session.jsonl` is replay input and expected persisted output belongs under top-level `snapshots/`, with `snapshot.yml` naming its shipped `dsh` profile and composition/header pin. ARIA, geometry, generator, CLI, and unit expectations without that session round trip stay beside their owning test under `tests/goldens/`; do not place them in `snapshots/` or give them a `*.snapshot.ts` owner. Use the owning `test:golden`, `test:web`, or `test` lane. +- **Expected-output placement:** a test whose recorded `session.jsonl` is replay input and expected persisted output belongs under top-level `snapshots/`, with `snapshot.yml` naming its shipped `dsh` profile and composition/header pin. ARIA, geometry, generator, CLI, and unit expectations without that session round trip stay beside their owning test under `tests/expected/`; do not place them in `snapshots/` or give them a `*.snapshot.ts` owner. Use the owning `test:expected`, `test:web`, or `test` lane. - **Package manifests, public exports, build configuration, worker/bin entries, or built runtime paths:** run `pnpm run build`, the relevant hygiene checks, and the owning built-artifact smoke. - **Real provider or agent behavior:** run the relevant `pnpm run test:e2e` target when credentials are available; never print secrets. diff --git a/AGENTS.md b/AGENTS.md index 12ae3be104..605c68e51a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -70,7 +70,7 @@ pnpm run clean # remove build outputs and safe residue from deleted pa pnpm run test # unit tests pnpm run test:coverage # CI coverage gate: per-file 100% on packages/*/*/src pnpm run test:e2e # real-API tests; self-skip without DEEPSEEK_API_KEY -pnpm run test:golden # owner-local process goldens +pnpm run test:expected # owner-local process expectations pnpm run test:snapshot # keyless recorded-session replay through shipped profiles; filter: -t pnpm run test:snapshot:record # re-record expected outputs (needs key) pnpm run typecheck diff --git a/apps/cli/tests/dsh-badge.golden.e2e.ts b/apps/cli/tests/dsh-badge.expected.e2e.ts similarity index 100% rename from apps/cli/tests/dsh-badge.golden.e2e.ts rename to apps/cli/tests/dsh-badge.expected.e2e.ts diff --git a/apps/cli/tests/web-browser-open.golden.e2e.ts b/apps/cli/tests/web-browser-open.expected.e2e.ts similarity index 100% rename from apps/cli/tests/web-browser-open.golden.e2e.ts rename to apps/cli/tests/web-browser-open.expected.e2e.ts diff --git a/apps/web/tests/access-confirmation.e2e.ts b/apps/web/tests/access-confirmation.e2e.ts index 0c33b62d3b..87578885ce 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('./goldens/access-confirmation', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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 04665819b4..d338b43b55 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('./goldens/agent-preset-authoring', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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 781823f19e..648a3f870e 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('./goldens/agent-preset-selection', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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/built-boot.golden.e2e.ts b/apps/web/tests/built-boot.expected.e2e.ts similarity index 100% rename from apps/web/tests/built-boot.golden.e2e.ts rename to apps/web/tests/built-boot.expected.e2e.ts diff --git a/apps/web/tests/cold-blank-session.e2e.ts b/apps/web/tests/cold-blank-session.e2e.ts index 5d914cf0df..87eaf848db 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('./goldens/cold-blank-session', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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/command-image-envelope.golden.e2e.ts b/apps/web/tests/command-image-envelope.expected.e2e.ts similarity index 100% rename from apps/web/tests/command-image-envelope.golden.e2e.ts rename to apps/web/tests/command-image-envelope.expected.e2e.ts diff --git a/apps/web/tests/composer-draft-scroll.e2e.ts b/apps/web/tests/composer-draft-scroll.e2e.ts index ddfc97990d..dd6ae8085e 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('./goldens/composer-draft-scroll', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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 2ca0b70439..99b746d97b 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('./goldens/composer-tab-geometry', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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 e933759271..c9805a4df8 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('./goldens/conversation-column-overflow', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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/declared-reasoning.e2e.ts b/apps/web/tests/declared-reasoning.e2e.ts index 1ba84d655b..8d35d0d1ea 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('./goldens/declared-reasoning', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./goldens/declared-reasoning/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/declared-reasoning', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./expected/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/goldens/access-confirmation/ui.expected.md b/apps/web/tests/expected/access-confirmation/ui.expected.md similarity index 100% rename from apps/web/tests/goldens/access-confirmation/ui.expected.md rename to apps/web/tests/expected/access-confirmation/ui.expected.md diff --git a/apps/web/tests/goldens/agent-preset-authoring/copy-dialog.expected.md b/apps/web/tests/expected/agent-preset-authoring/copy-dialog.expected.md similarity index 100% rename from apps/web/tests/goldens/agent-preset-authoring/copy-dialog.expected.md rename to apps/web/tests/expected/agent-preset-authoring/copy-dialog.expected.md diff --git a/apps/web/tests/goldens/agent-preset-authoring/created.expected.md b/apps/web/tests/expected/agent-preset-authoring/created.expected.md similarity index 100% rename from apps/web/tests/goldens/agent-preset-authoring/created.expected.md rename to apps/web/tests/expected/agent-preset-authoring/created.expected.md diff --git a/apps/web/tests/goldens/agent-preset-authoring/damaged.expected.md b/apps/web/tests/expected/agent-preset-authoring/damaged.expected.md similarity index 100% rename from apps/web/tests/goldens/agent-preset-authoring/damaged.expected.md rename to apps/web/tests/expected/agent-preset-authoring/damaged.expected.md diff --git a/apps/web/tests/goldens/agent-preset-authoring/section.expected.md b/apps/web/tests/expected/agent-preset-authoring/section.expected.md similarity index 100% rename from apps/web/tests/goldens/agent-preset-authoring/section.expected.md rename to apps/web/tests/expected/agent-preset-authoring/section.expected.md diff --git a/apps/web/tests/goldens/agent-preset-selection/header.expected.md b/apps/web/tests/expected/agent-preset-selection/header.expected.md similarity index 100% rename from apps/web/tests/goldens/agent-preset-selection/header.expected.md rename to apps/web/tests/expected/agent-preset-selection/header.expected.md diff --git a/apps/web/tests/goldens/agent-preset-selection/hero.expected.md b/apps/web/tests/expected/agent-preset-selection/hero.expected.md similarity index 100% rename from apps/web/tests/goldens/agent-preset-selection/hero.expected.md rename to apps/web/tests/expected/agent-preset-selection/hero.expected.md diff --git a/apps/web/tests/goldens/agent-preset-selection/menu.expected.md b/apps/web/tests/expected/agent-preset-selection/menu.expected.md similarity index 100% rename from apps/web/tests/goldens/agent-preset-selection/menu.expected.md rename to apps/web/tests/expected/agent-preset-selection/menu.expected.md diff --git a/apps/web/tests/goldens/cold-blank-session/sidebar.expected.md b/apps/web/tests/expected/cold-blank-session/sidebar.expected.md similarity index 100% rename from apps/web/tests/goldens/cold-blank-session/sidebar.expected.md rename to apps/web/tests/expected/cold-blank-session/sidebar.expected.md diff --git a/apps/web/tests/goldens/composer-draft-scroll/geometry.expected.md b/apps/web/tests/expected/composer-draft-scroll/geometry.expected.md similarity index 100% rename from apps/web/tests/goldens/composer-draft-scroll/geometry.expected.md rename to apps/web/tests/expected/composer-draft-scroll/geometry.expected.md diff --git a/apps/web/tests/goldens/composer-tab-geometry/geometry.expected.md b/apps/web/tests/expected/composer-tab-geometry/geometry.expected.md similarity index 100% rename from apps/web/tests/goldens/composer-tab-geometry/geometry.expected.md rename to apps/web/tests/expected/composer-tab-geometry/geometry.expected.md diff --git a/apps/web/tests/goldens/conversation-column-overflow/geometry.expected.md b/apps/web/tests/expected/conversation-column-overflow/geometry.expected.md similarity index 100% rename from apps/web/tests/goldens/conversation-column-overflow/geometry.expected.md rename to apps/web/tests/expected/conversation-column-overflow/geometry.expected.md diff --git a/apps/web/tests/goldens/declared-reasoning/ui.expected.md b/apps/web/tests/expected/declared-reasoning/ui.expected.md similarity index 100% rename from apps/web/tests/goldens/declared-reasoning/ui.expected.md rename to apps/web/tests/expected/declared-reasoning/ui.expected.md diff --git a/apps/web/tests/goldens/github-ready-review/conversation.expected.md b/apps/web/tests/expected/github-ready-review/conversation.expected.md similarity index 100% rename from apps/web/tests/goldens/github-ready-review/conversation.expected.md rename to apps/web/tests/expected/github-ready-review/conversation.expected.md diff --git a/apps/web/tests/goldens/goal-bar/active.expected.md b/apps/web/tests/expected/goal-bar/active.expected.md similarity index 100% rename from apps/web/tests/goldens/goal-bar/active.expected.md rename to apps/web/tests/expected/goal-bar/active.expected.md diff --git a/apps/web/tests/goldens/goal-command-presentation/ui.expected.md b/apps/web/tests/expected/goal-command-presentation/ui.expected.md similarity index 100% rename from apps/web/tests/goldens/goal-command-presentation/ui.expected.md rename to apps/web/tests/expected/goal-command-presentation/ui.expected.md diff --git a/apps/web/tests/goldens/home-path-tilde/workspace-hover.expected.txt b/apps/web/tests/expected/home-path-tilde/workspace-hover.expected.txt similarity index 100% rename from apps/web/tests/goldens/home-path-tilde/workspace-hover.expected.txt rename to apps/web/tests/expected/home-path-tilde/workspace-hover.expected.txt diff --git a/apps/web/tests/goldens/markdown-cjk-strong/ui.expected.md b/apps/web/tests/expected/markdown-cjk-strong/ui.expected.md similarity index 100% rename from apps/web/tests/goldens/markdown-cjk-strong/ui.expected.md rename to apps/web/tests/expected/markdown-cjk-strong/ui.expected.md diff --git a/apps/web/tests/goldens/markdown-images/ui.expected.md b/apps/web/tests/expected/markdown-images/ui.expected.md similarity index 100% rename from apps/web/tests/goldens/markdown-images/ui.expected.md rename to apps/web/tests/expected/markdown-images/ui.expected.md diff --git a/apps/web/tests/goldens/markdown-inline-code-links/ui.expected.md b/apps/web/tests/expected/markdown-inline-code-links/ui.expected.md similarity index 100% rename from apps/web/tests/goldens/markdown-inline-code-links/ui.expected.md rename to apps/web/tests/expected/markdown-inline-code-links/ui.expected.md diff --git a/apps/web/tests/goldens/markdown-wide-table/geometry.expected.md b/apps/web/tests/expected/markdown-wide-table/geometry.expected.md similarity index 100% rename from apps/web/tests/goldens/markdown-wide-table/geometry.expected.md rename to apps/web/tests/expected/markdown-wide-table/geometry.expected.md diff --git a/apps/web/tests/goldens/math-rendering/ui.expected.md b/apps/web/tests/expected/math-rendering/ui.expected.md similarity index 100% rename from apps/web/tests/goldens/math-rendering/ui.expected.md rename to apps/web/tests/expected/math-rendering/ui.expected.md diff --git a/apps/web/tests/goldens/max-tokens-notice/history-turn.expected.txt b/apps/web/tests/expected/max-tokens-notice/history-turn.expected.txt similarity index 100% rename from apps/web/tests/goldens/max-tokens-notice/history-turn.expected.txt rename to apps/web/tests/expected/max-tokens-notice/history-turn.expected.txt diff --git a/apps/web/tests/goldens/models-settings/configured.expected.md b/apps/web/tests/expected/models-settings/configured.expected.md similarity index 100% rename from apps/web/tests/goldens/models-settings/configured.expected.md rename to apps/web/tests/expected/models-settings/configured.expected.md diff --git a/apps/web/tests/goldens/models-settings/declared-edit.expected.md b/apps/web/tests/expected/models-settings/declared-edit.expected.md similarity index 100% rename from apps/web/tests/goldens/models-settings/declared-edit.expected.md rename to apps/web/tests/expected/models-settings/declared-edit.expected.md diff --git a/apps/web/tests/goldens/models-settings/declared.expected.md b/apps/web/tests/expected/models-settings/declared.expected.md similarity index 100% rename from apps/web/tests/goldens/models-settings/declared.expected.md rename to apps/web/tests/expected/models-settings/declared.expected.md diff --git a/apps/web/tests/goldens/models-settings/delete.expected.md b/apps/web/tests/expected/models-settings/delete.expected.md similarity index 100% rename from apps/web/tests/goldens/models-settings/delete.expected.md rename to apps/web/tests/expected/models-settings/delete.expected.md diff --git a/apps/web/tests/goldens/models-settings/empty.expected.md b/apps/web/tests/expected/models-settings/empty.expected.md similarity index 100% rename from apps/web/tests/goldens/models-settings/empty.expected.md rename to apps/web/tests/expected/models-settings/empty.expected.md diff --git a/apps/web/tests/goldens/models-settings/model-picker.expected.md b/apps/web/tests/expected/models-settings/model-picker.expected.md similarity index 100% rename from apps/web/tests/goldens/models-settings/model-picker.expected.md rename to apps/web/tests/expected/models-settings/model-picker.expected.md diff --git a/apps/web/tests/goldens/models-settings/native-delete.expected.md b/apps/web/tests/expected/models-settings/native-delete.expected.md similarity index 100% rename from apps/web/tests/goldens/models-settings/native-delete.expected.md rename to apps/web/tests/expected/models-settings/native-delete.expected.md diff --git a/apps/web/tests/goldens/onboarding-deepseek-config/missing.expected.md b/apps/web/tests/expected/onboarding-deepseek-config/missing.expected.md similarity index 100% rename from apps/web/tests/goldens/onboarding-deepseek-config/missing.expected.md rename to apps/web/tests/expected/onboarding-deepseek-config/missing.expected.md diff --git a/apps/web/tests/goldens/onboarding-deepseek-config/models.expected.md b/apps/web/tests/expected/onboarding-deepseek-config/models.expected.md similarity index 100% rename from apps/web/tests/goldens/onboarding-deepseek-config/models.expected.md rename to apps/web/tests/expected/onboarding-deepseek-config/models.expected.md diff --git a/apps/web/tests/goldens/onboarding-deepseek-config/welcome.expected.md b/apps/web/tests/expected/onboarding-deepseek-config/welcome.expected.md similarity index 100% rename from apps/web/tests/goldens/onboarding-deepseek-config/welcome.expected.md rename to apps/web/tests/expected/onboarding-deepseek-config/welcome.expected.md diff --git a/apps/web/tests/goldens/onboarding-usable-provider/dismissed.expected.md b/apps/web/tests/expected/onboarding-usable-provider/dismissed.expected.md similarity index 100% rename from apps/web/tests/goldens/onboarding-usable-provider/dismissed.expected.md rename to apps/web/tests/expected/onboarding-usable-provider/dismissed.expected.md diff --git a/apps/web/tests/goldens/plugin-config/section.expected.md b/apps/web/tests/expected/plugin-config/section.expected.md similarity index 100% rename from apps/web/tests/goldens/plugin-config/section.expected.md rename to apps/web/tests/expected/plugin-config/section.expected.md diff --git a/apps/web/tests/goldens/reference-composer/caret-edits.expected.md b/apps/web/tests/expected/reference-composer/caret-edits.expected.md similarity index 100% rename from apps/web/tests/goldens/reference-composer/caret-edits.expected.md rename to apps/web/tests/expected/reference-composer/caret-edits.expected.md diff --git a/apps/web/tests/goldens/reference-composer/menu.expected.md b/apps/web/tests/expected/reference-composer/menu.expected.md similarity index 100% rename from apps/web/tests/goldens/reference-composer/menu.expected.md rename to apps/web/tests/expected/reference-composer/menu.expected.md diff --git a/apps/web/tests/goldens/reference-composer/order.expected.md b/apps/web/tests/expected/reference-composer/order.expected.md similarity index 100% rename from apps/web/tests/goldens/reference-composer/order.expected.md rename to apps/web/tests/expected/reference-composer/order.expected.md diff --git a/apps/web/tests/goldens/schedule-after/at-conversation.expected.md b/apps/web/tests/expected/schedule-after/at-conversation.expected.md similarity index 100% rename from apps/web/tests/goldens/schedule-after/at-conversation.expected.md rename to apps/web/tests/expected/schedule-after/at-conversation.expected.md diff --git a/apps/web/tests/goldens/schedule-after/conversation.expected.md b/apps/web/tests/expected/schedule-after/conversation.expected.md similarity index 100% rename from apps/web/tests/goldens/schedule-after/conversation.expected.md rename to apps/web/tests/expected/schedule-after/conversation.expected.md diff --git a/apps/web/tests/goldens/schedule-after/every-conversation.expected.md b/apps/web/tests/expected/schedule-after/every-conversation.expected.md similarity index 100% rename from apps/web/tests/goldens/schedule-after/every-conversation.expected.md rename to apps/web/tests/expected/schedule-after/every-conversation.expected.md diff --git a/apps/web/tests/goldens/search-card/grep-card.expected.txt b/apps/web/tests/expected/search-card/grep-card.expected.txt similarity index 100% rename from apps/web/tests/goldens/search-card/grep-card.expected.txt rename to apps/web/tests/expected/search-card/grep-card.expected.txt diff --git a/apps/web/tests/goldens/settings-chrome/dialog-en.expected.md b/apps/web/tests/expected/settings-chrome/dialog-en.expected.md similarity index 100% rename from apps/web/tests/goldens/settings-chrome/dialog-en.expected.md rename to apps/web/tests/expected/settings-chrome/dialog-en.expected.md diff --git a/apps/web/tests/goldens/settings-chrome/dialog.expected.md b/apps/web/tests/expected/settings-chrome/dialog.expected.md similarity index 100% rename from apps/web/tests/goldens/settings-chrome/dialog.expected.md rename to apps/web/tests/expected/settings-chrome/dialog.expected.md diff --git a/apps/web/tests/goldens/settings-chrome/plugins.expected.md b/apps/web/tests/expected/settings-chrome/plugins.expected.md similarity index 100% rename from apps/web/tests/goldens/settings-chrome/plugins.expected.md rename to apps/web/tests/expected/settings-chrome/plugins.expected.md diff --git a/apps/web/tests/goldens/sidebar-subagent-activity/owner-running.expected.md b/apps/web/tests/expected/sidebar-subagent-activity/owner-running.expected.md similarity index 100% rename from apps/web/tests/goldens/sidebar-subagent-activity/owner-running.expected.md rename to apps/web/tests/expected/sidebar-subagent-activity/owner-running.expected.md diff --git a/apps/web/tests/goldens/skill-invocation-policy/menu.expected.md b/apps/web/tests/expected/skill-invocation-policy/menu.expected.md similarity index 100% rename from apps/web/tests/goldens/skill-invocation-policy/menu.expected.md rename to apps/web/tests/expected/skill-invocation-policy/menu.expected.md diff --git a/apps/web/tests/goldens/skill-user-invoke/ui.expected.md b/apps/web/tests/expected/skill-user-invoke/ui.expected.md similarity index 100% rename from apps/web/tests/goldens/skill-user-invoke/ui.expected.md rename to apps/web/tests/expected/skill-user-invoke/ui.expected.md diff --git a/apps/web/tests/goldens/stats-paged-history/ui.expected.md b/apps/web/tests/expected/stats-paged-history/ui.expected.md similarity index 100% rename from apps/web/tests/goldens/stats-paged-history/ui.expected.md rename to apps/web/tests/expected/stats-paged-history/ui.expected.md diff --git a/apps/web/tests/goldens/steer-all/mid-steer.expected.md b/apps/web/tests/expected/steer-all/mid-steer.expected.md similarity index 100% rename from apps/web/tests/goldens/steer-all/mid-steer.expected.md rename to apps/web/tests/expected/steer-all/mid-steer.expected.md diff --git a/apps/web/tests/goldens/steer-all/replay.override.json b/apps/web/tests/expected/steer-all/replay.override.json similarity index 100% rename from apps/web/tests/goldens/steer-all/replay.override.json rename to apps/web/tests/expected/steer-all/replay.override.json diff --git a/apps/web/tests/goldens/steer-all/settled.expected.md b/apps/web/tests/expected/steer-all/settled.expected.md similarity index 100% rename from apps/web/tests/goldens/steer-all/settled.expected.md rename to apps/web/tests/expected/steer-all/settled.expected.md diff --git a/apps/web/tests/goldens/todo-row/parallel-plan.expected.txt b/apps/web/tests/expected/todo-row/parallel-plan.expected.txt similarity index 100% rename from apps/web/tests/goldens/todo-row/parallel-plan.expected.txt rename to apps/web/tests/expected/todo-row/parallel-plan.expected.txt diff --git a/apps/web/tests/goldens/trajectory-virtualization/load-more.expected.md b/apps/web/tests/expected/trajectory-virtualization/load-more.expected.md similarity index 100% rename from apps/web/tests/goldens/trajectory-virtualization/load-more.expected.md rename to apps/web/tests/expected/trajectory-virtualization/load-more.expected.md diff --git a/apps/web/tests/goldens/web-runtime-context/file-reference-prompt.expected.md b/apps/web/tests/expected/web-runtime-context/file-reference-prompt.expected.md similarity index 100% rename from apps/web/tests/goldens/web-runtime-context/file-reference-prompt.expected.md rename to apps/web/tests/expected/web-runtime-context/file-reference-prompt.expected.md diff --git a/apps/web/tests/goldens/web-runtime-context/web-surface-prompt.expected.md b/apps/web/tests/expected/web-runtime-context/web-surface-prompt.expected.md similarity index 100% rename from apps/web/tests/goldens/web-runtime-context/web-surface-prompt.expected.md rename to apps/web/tests/expected/web-runtime-context/web-surface-prompt.expected.md diff --git a/apps/web/tests/github-ready-review.e2e.ts b/apps/web/tests/github-ready-review.e2e.ts index 20c6140a41..3a30ba3676 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('./goldens/github-ready-review/conversation.expected.md', import.meta.url)) +const EXPECTED = fileURLToPath(new URL('./expected/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 0fd212f545..a775143da6 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('./goldens/goal-bar', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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 8a976e6fab..537ab8095b 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('./goldens/goal-command-presentation', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/goal-command-presentation', import.meta.url)) const UI_EXPECTED = fileURLToPath(new URL( - './goldens/goal-command-presentation/ui.expected.md', import.meta.url, + './expected/goal-command-presentation/ui.expected.md', import.meta.url, )) const MODE = webSnapshotMode() diff --git a/apps/web/tests/home-path-tilde.golden.e2e.ts b/apps/web/tests/home-path-tilde.expected.e2e.ts similarity index 94% rename from apps/web/tests/home-path-tilde.golden.e2e.ts rename to apps/web/tests/home-path-tilde.expected.e2e.ts index 348a2e7e7b..9f30a560ad 100644 --- a/apps/web/tests/home-path-tilde.golden.e2e.ts +++ b/apps/web/tests/home-path-tilde.expected.e2e.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/goldens/home-path-tilde/workspace-hover.expected.txt') +const EXPECTED = join(process.cwd(), 'apps/web/tests/expected/home-path-tilde/workspace-hover.expected.txt') installAssembledBootEnv() diff --git a/apps/web/tests/image-display.golden.e2e.ts b/apps/web/tests/image-display.expected.e2e.ts similarity index 100% rename from apps/web/tests/image-display.golden.e2e.ts rename to apps/web/tests/image-display.expected.e2e.ts diff --git a/apps/web/tests/markdown-cjk-strong.e2e.ts b/apps/web/tests/markdown-cjk-strong.e2e.ts index 102003333a..83963ea36e 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('./goldens/markdown-cjk-strong', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./goldens/markdown-cjk-strong/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/markdown-cjk-strong', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./expected/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 769522311e..57e5910813 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('./goldens/markdown-images', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./goldens/markdown-images/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/markdown-images', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./expected/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 d141c00d27..e216e5b6d0 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('./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 SNAPSHOT_DIR = fileURLToPath(new URL('./expected/markdown-inline-code-links', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./expected/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 194f6da319..901a425f43 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('./goldens/markdown-wide-table', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/markdown-wide-table', import.meta.url)) const GEOMETRY_EXPECTED = fileURLToPath( - new URL('./goldens/markdown-wide-table/geometry.expected.md', import.meta.url), + new URL('./expected/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 129148a0c0..08f4ca2705 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('./goldens/math-rendering', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./goldens/math-rendering/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/math-rendering', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./expected/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.golden.e2e.ts b/apps/web/tests/max-tokens-notice.expected.e2e.ts similarity index 96% rename from apps/web/tests/max-tokens-notice.golden.e2e.ts rename to apps/web/tests/max-tokens-notice.expected.e2e.ts index 515aa7a699..3e35d13bb8 100644 --- a/apps/web/tests/max-tokens-notice.golden.e2e.ts +++ b/apps/web/tests/max-tokens-notice.expected.e2e.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/goldens/max-tokens-notice/history-turn.expected.txt') +const EXPECTED = join(process.cwd(), 'apps/web/tests/expected/max-tokens-notice/history-turn.expected.txt') installAssembledBootEnv() diff --git a/apps/web/tests/models-settings.e2e.ts b/apps/web/tests/models-settings.e2e.ts index ee68aeb3a5..f727c619f9 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('./goldens/models-settings', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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/onboarding-deepseek-config.e2e.ts b/apps/web/tests/onboarding-deepseek-config.e2e.ts index dd2f1bde0a..c84b600c9b 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('./goldens/onboarding-deepseek-config', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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 860b1d4274..a1d97993b7 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('./goldens/onboarding-usable-provider', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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/plugin-config.e2e.ts b/apps/web/tests/plugin-config.e2e.ts index cfc4837b91..1877d71e7c 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('./goldens/plugin-config', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/plugin-config', import.meta.url)) const SECTION_EXPECTED = join(SNAPSHOT_DIR, 'section.expected.md') const MODE = webSnapshotMode() diff --git a/apps/web/tests/reference-composer.e2e.ts b/apps/web/tests/reference-composer.e2e.ts index 33f34ce1e0..13f0468ef4 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('./goldens/reference-composer', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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/schedule-after.e2e.ts b/apps/web/tests/schedule-after.e2e.ts index d9e1467139..ea0bbf0118 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('./goldens/schedule-after', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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.golden.e2e.ts b/apps/web/tests/search-card.expected.e2e.ts similarity index 97% rename from apps/web/tests/search-card.golden.e2e.ts rename to apps/web/tests/search-card.expected.e2e.ts index e4529b5d99..ec8da8ff86 100644 --- a/apps/web/tests/search-card.golden.e2e.ts +++ b/apps/web/tests/search-card.expected.e2e.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/goldens/search-card/grep-card.expected.txt') +const EXPECTED = join(process.cwd(), 'apps/web/tests/expected/search-card/grep-card.expected.txt') installAssembledBootEnv() diff --git a/apps/web/tests/settings-chrome.e2e.ts b/apps/web/tests/settings-chrome.e2e.ts index 269a64f96c..291677f5e4 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('./goldens/settings-chrome', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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 0c4b27a131..d6c06c9ecd 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( - './goldens/web-runtime-context/file-reference-prompt.expected.md', import.meta.url, + './expected/web-runtime-context/file-reference-prompt.expected.md', import.meta.url, )) /** diff --git a/apps/web/tests/sidebar-subagent-activity.e2e.ts b/apps/web/tests/sidebar-subagent-activity.e2e.ts index 374db8b045..ed087f0b8f 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('./goldens/sidebar-subagent-activity', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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 56666aed8b..a938ed65d8 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('./goldens/skill-invocation-policy', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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-user-invoke.e2e.ts b/apps/web/tests/skill-user-invoke.e2e.ts index 724c2ce5a9..767146d2b9 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('./goldens/skill-user-invoke', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/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 084782c5f5..01c863f5b2 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('./goldens/web-runtime-context/web-surface-prompt.expected.md', import.meta.url)) +const WEB_SURFACE_PROMPT = fileURLToPath(new URL('./expected/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 4d282b0871..845b9a3593 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('./goldens/stats-paged-history', import.meta.url)) -const UI_EXPECTED = fileURLToPath(new URL('./goldens/stats-paged-history/ui.expected.md', import.meta.url)) +const SNAPSHOT_DIR = fileURLToPath(new URL('./expected/stats-paged-history', import.meta.url)) +const UI_EXPECTED = fileURLToPath(new URL('./expected/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 cf399fdd6e..a46bb851d6 100644 --- a/apps/web/tests/steering.e2e.ts +++ b/apps/web/tests/steering.e2e.ts @@ -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('./goldens/steer-all', import.meta.url)) +const STEER_ALL_DIR = fileURLToPath(new URL('./expected/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/todo-row.golden.e2e.ts b/apps/web/tests/todo-row.expected.e2e.ts similarity index 97% rename from apps/web/tests/todo-row.golden.e2e.ts rename to apps/web/tests/todo-row.expected.e2e.ts index 6501ce6cac..5672dd09a0 100644 --- a/apps/web/tests/todo-row.golden.e2e.ts +++ b/apps/web/tests/todo-row.expected.e2e.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/goldens/todo-row/parallel-plan.expected.txt') +const EXPECTED = join(process.cwd(), 'apps/web/tests/expected/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 f99475b0f8..6629bb0b5d 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( - './goldens/trajectory-virtualization/load-more.expected.md', + './expected/trajectory-virtualization/load-more.expected.md', import.meta.url, )) const SESSION_ID = 'trajectory-virtualization-e2e' diff --git a/docs/testing.i18n.yaml b/docs/testing.i18n.yaml index 91fcaf9bb3..7e4a544b2a 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: 8792d928798cabae0a4d2f12ff779248cf44d8ee -testing.zh.md: ea7d8a32f26d98656b977a8efeda698ff7382986 +testing.md: e243c027ac6c2efdcaa2feab6770c00dec1f6703 +testing.zh.md: 5bd0a488f2ea43470248697253317bd06841912d diff --git a/docs/testing.md b/docs/testing.md index 8792d92879..e243c027ac 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -9,9 +9,9 @@ How this repo tests, tier by tier, and the rules that keep a green suite meaning - **Unit** (`pnpm run test`): vitest over package and example specs under their `tests/**` directories plus repository script specs under `scripts/**/*.spec.ts`; tests stay with the code area they exercise. Every registry gets an HMR-safety test (dispose the contributing fiber, assert cleanup). Prefer edge cases, error paths, event ordering, concurrency races, and permanent tests for contract regressions (see `packages/core/agent-loop/tests/contract-regressions.spec.ts`). - **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)). -- **Owner-local golden** (`pnpm run test:golden`): keyless assembled CLI/process expectations without a recorded-session round trip. Drivers use `*.golden.e2e.ts` beside `tests/goldens/`; CI runs built exports. Package/script goldens use `test`, while browser goldens use `test:web`. +- **Owner-local expected output** (`pnpm run test:expected`): keyless assembled CLI/process expectations without a recorded-session round trip. Drivers use `*.expected.e2e.ts` beside `tests/expected/`; CI runs built exports. Package/script expectations use `test`, while browser expectations use `test:web`. - **Snapshot** (`pnpm run test:snapshot`): a top-level scenario's recorded `session.jsonl` supplies user input and model replay, then serves as the expected persisted result. Process scenarios start through `dsh`: headless owns one-shot behavior, the SDK owns persistent control, ACP owns automation-protocol behavior, and Web retains browser/ARIA evidence beside the same session. `snapshot.yml` declares the profile, composition/header class, recording policy, exceptional replay or input metadata, and workspace facts. Typed tokens preserve parent/child identity relationships; only header pins own prompt/schema sidecars. A mutating scenario independently compares the complete `workspace.expected/` tree, which record and refresh never rewrite. Use `test:snapshot:record` when a model transcript changes and `test:snapshot:refresh` when replay input remains valid; review every resulting diff. -- **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. +- **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/expected/`. 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. @@ -47,4 +47,4 @@ An e2e assertion re-runs the command or re-reads the file externally; a keyword ## When a snapshot test is required -Every non-trivial model-, protocol-, or human-visible change adds or updates a keyless recorded-session scenario in the same PR; package, e2e, mock-only, and rationale evidence does not replace the assembled transcript. Headless, SDK, ACP, and Web recordings live under `snapshots/session/`, `snapshots/sdk/`, `snapshots/acp/`, and `snapshots/web/`; a Web rendering may explicitly borrow another scenario's canonical session. Expected output that is not driven by a recorded session stays with its owning app, package, or script under `tests/goldens/` and does not use the `*.snapshot.ts` suffix. [`dsh-session-snapshot`](../packages/test-support/session-snapshot/README.md) owns the shared storage rules and profile adapters. Agent-loop, session-lifecycle, and `SessionEventMap` changes update both SDK projections: `snapshots/sdk/` owns TypeScript, while required Python-runtime CI owns `scripts/snapshots/python-sdk-single-exe/`. New capability seams and lifecycle or transcript variants name every required tier at plan time. +Every non-trivial model-, protocol-, or human-visible change adds or updates a keyless recorded-session scenario in the same PR; package, e2e, mock-only, and rationale evidence does not replace the assembled transcript. Headless, SDK, ACP, and Web recordings live under `snapshots/session/`, `snapshots/sdk/`, `snapshots/acp/`, and `snapshots/web/`; a Web rendering may explicitly borrow another scenario's canonical session. Expected output that is not driven by a recorded session stays with its owning app, package, or script under `tests/expected/` and does not use the `*.snapshot.ts` suffix. [`dsh-session-snapshot`](../packages/test-support/session-snapshot/README.md) owns the shared storage rules and profile adapters. Agent-loop, session-lifecycle, and `SessionEventMap` changes update both SDK projections: `snapshots/sdk/` owns TypeScript, while required Python-runtime CI owns `scripts/snapshots/python-sdk-single-exe/`. New capability seams and lifecycle or transcript variants name every required tier at plan time. diff --git a/docs/testing.zh.md b/docs/testing.zh.md index ea7d8a32f2..5bd0a488f2 100644 --- a/docs/testing.zh.md +++ b/docs/testing.zh.md @@ -9,9 +9,9 @@ - **单元测试**(`pnpm run test`):vitest 运行包和示例各自的 `tests/**` 目录下的测试,以及匹配 `scripts/**/*.spec.ts` 的仓库脚本测试;测试文件与其所覆盖的代码区域放在一起。每个注册表都有一个 HMR(热模块替换)安全测试(对向该注册表贡献内容的 fiber 执行 dispose(资源释放),并断言清理完成)。优先覆盖边界情况、错误路径、事件顺序、并发竞态,以及针对约定回归的永久测试(见 `packages/core/agent-loop/tests/contract-regressions.spec.ts`)。 - **覆盖率门禁**(`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))。 -- **所属位置的 golden**(`pnpm run test:golden`):无录制会话往返的无密钥组装 CLI/进程预期。驱动使用 `*.golden.e2e.ts`,并与 `tests/goldens/` 同属一处;CI 针对构建产物运行。包/脚本 golden 使用 `test`,浏览器 golden 使用 `test:web`。 +- **所属位置的预期输出**(`pnpm run test:expected`):无录制会话往返的无密钥组装 CLI/进程预期。驱动使用 `*.expected.e2e.ts`,并与 `tests/expected/` 同属一处;CI 针对构建产物运行。包/脚本预期使用 `test`,浏览器预期使用 `test:web`。 - **快照**(`pnpm run test:snapshot`):顶层场景的录制 `session.jsonl` 同时提供用户输入和模型回放,并作为持久化结果的预期值。进程级场景都通过 `dsh` 启动:headless 负责一次性行为,SDK 负责持久控制,ACP 负责自动化协议行为,Web 在同一会话旁保留浏览器与 ARIA 证据。`snapshot.yml` 声明 profile、组合与请求头类别、录制策略、例外回放或输入元数据以及工作区事实。带类型的 token 保留父子身份关系;只有请求头 pin 拥有提示词/schema sidecar。变更工作区的场景会独立比较完整的 `workspace.expected/` 目录,record 与 refresh 绝不改写该目录。当模型 transcript(文本记录)变化时使用 `test:snapshot:record`,回放输入仍有效时使用 `test:snapshot:refresh`;请审查所有结果差异。 -- **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。 +- **Web 浏览器快照**(`pnpm run test:web`;必需的 Linux PR(Pull Request)门禁):Chromium 比较 `snapshots/web/` 下由会话驱动的输出,以及 `apps/web/tests/expected/` 下仅含 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)会改写旧布局。 @@ -47,4 +47,4 @@ e2e 断言应重新运行命令或从外部重新读取文件;对 agent 自身 ## 何时需要快照测试 -每项非平凡的模型可见、协议可见或人类可见变更,都在同一 PR 中添加或更新无密钥录制会话场景;包级、e2e、仅 mock 和 PR 理由证据不能取代组装后的 transcript。Headless、SDK、ACP 和 Web 录制分别位于 `snapshots/session/`、`snapshots/sdk/`、`snapshots/acp/` 和 `snapshots/web/`;Web 渲染可以显式借用另一个场景的规范会话。不由录制会话驱动的预期输出保留在所属应用、包或脚本的 `tests/goldens/` 下,并且不使用 `*.snapshot.ts` 后缀。[`dsh-session-snapshot`](../packages/test-support/session-snapshot/README.zh.md) 拥有共享存储规则和 profile 适配器。Agent loop、会话生命周期和 `SessionEventMap` 变更应更新两个 SDK 投影:`snapshots/sdk/` 拥有 TypeScript,必需的 Python 运行时 CI 拥有 `scripts/snapshots/python-sdk-single-exe/`。新增 capability seam、生命周期或 transcript 变体应在计划阶段列出每个必需层级。 +每项非平凡的模型可见、协议可见或人类可见变更,都在同一 PR 中添加或更新无密钥录制会话场景;包级、e2e、仅 mock 和 PR 理由证据不能取代组装后的 transcript。Headless、SDK、ACP 和 Web 录制分别位于 `snapshots/session/`、`snapshots/sdk/`、`snapshots/acp/` 和 `snapshots/web/`;Web 渲染可以显式借用另一个场景的规范会话。不由录制会话驱动的预期输出保留在所属应用、包或脚本的 `tests/expected/` 下,并且不使用 `*.snapshot.ts` 后缀。[`dsh-session-snapshot`](../packages/test-support/session-snapshot/README.zh.md) 拥有共享存储规则和 profile 适配器。Agent loop、会话生命周期和 `SessionEventMap` 变更应更新两个 SDK 投影:`snapshots/sdk/` 拥有 TypeScript,必需的 Python 运行时 CI 拥有 `scripts/snapshots/python-sdk-single-exe/`。新增 capability seam、生命周期或 transcript 变体应在计划阶段列出每个必需层级。 diff --git a/examples/acp-agent/tests/goal-goldens/goal-round-driver/input.json b/examples/acp-agent/tests/goal-expected/goal-round-driver/input.json similarity index 100% rename from examples/acp-agent/tests/goal-goldens/goal-round-driver/input.json rename to examples/acp-agent/tests/goal-expected/goal-round-driver/input.json diff --git a/examples/acp-agent/tests/goal-goldens/goal-round-driver/replay.override.json b/examples/acp-agent/tests/goal-expected/goal-round-driver/replay.override.json similarity index 100% rename from examples/acp-agent/tests/goal-goldens/goal-round-driver/replay.override.json rename to examples/acp-agent/tests/goal-expected/goal-round-driver/replay.override.json diff --git a/examples/acp-agent/tests/goal-goldens/goal-round-driver/session.expected.jsonl b/examples/acp-agent/tests/goal-expected/goal-round-driver/session.expected.jsonl similarity index 100% rename from examples/acp-agent/tests/goal-goldens/goal-round-driver/session.expected.jsonl rename to examples/acp-agent/tests/goal-expected/goal-round-driver/session.expected.jsonl diff --git a/examples/acp-agent/tests/goal-goldens/goal-round-driver/session.jsonl b/examples/acp-agent/tests/goal-expected/goal-round-driver/session.jsonl similarity index 100% rename from examples/acp-agent/tests/goal-goldens/goal-round-driver/session.jsonl rename to examples/acp-agent/tests/goal-expected/goal-round-driver/session.jsonl diff --git a/examples/acp-agent/tests/goal-goldens/goal-round-driver/stdout.expected.jsonl b/examples/acp-agent/tests/goal-expected/goal-round-driver/stdout.expected.jsonl similarity index 100% rename from examples/acp-agent/tests/goal-goldens/goal-round-driver/stdout.expected.jsonl rename to examples/acp-agent/tests/goal-expected/goal-round-driver/stdout.expected.jsonl diff --git a/examples/acp-agent/tests/goal-goldens/goal-wrapup/input.json b/examples/acp-agent/tests/goal-expected/goal-wrapup/input.json similarity index 100% rename from examples/acp-agent/tests/goal-goldens/goal-wrapup/input.json rename to examples/acp-agent/tests/goal-expected/goal-wrapup/input.json diff --git a/examples/acp-agent/tests/goal-goldens/goal-wrapup/replay.override.json b/examples/acp-agent/tests/goal-expected/goal-wrapup/replay.override.json similarity index 100% rename from examples/acp-agent/tests/goal-goldens/goal-wrapup/replay.override.json rename to examples/acp-agent/tests/goal-expected/goal-wrapup/replay.override.json diff --git a/examples/acp-agent/tests/goal-goldens/goal-wrapup/session.expected.jsonl b/examples/acp-agent/tests/goal-expected/goal-wrapup/session.expected.jsonl similarity index 100% rename from examples/acp-agent/tests/goal-goldens/goal-wrapup/session.expected.jsonl rename to examples/acp-agent/tests/goal-expected/goal-wrapup/session.expected.jsonl diff --git a/examples/acp-agent/tests/goal-goldens/goal-wrapup/session.jsonl b/examples/acp-agent/tests/goal-expected/goal-wrapup/session.jsonl similarity index 100% rename from examples/acp-agent/tests/goal-goldens/goal-wrapup/session.jsonl rename to examples/acp-agent/tests/goal-expected/goal-wrapup/session.jsonl diff --git a/examples/acp-agent/tests/goal-goldens/goal-wrapup/stdout.expected.jsonl b/examples/acp-agent/tests/goal-expected/goal-wrapup/stdout.expected.jsonl similarity index 100% rename from examples/acp-agent/tests/goal-goldens/goal-wrapup/stdout.expected.jsonl rename to examples/acp-agent/tests/goal-expected/goal-wrapup/stdout.expected.jsonl diff --git a/examples/acp-agent/tests/goal.golden.e2e.ts b/examples/acp-agent/tests/goal.expected.e2e.ts similarity index 99% rename from examples/acp-agent/tests/goal.golden.e2e.ts rename to examples/acp-agent/tests/goal.expected.e2e.ts index 2e1494a01b..2f505a8fd9 100644 --- a/examples/acp-agent/tests/goal.golden.e2e.ts +++ b/examples/acp-agent/tests/goal.expected.e2e.ts @@ -15,12 +15,12 @@ import { describe, expect, it } from 'vitest' // This lifecycle proof has goal-specific timestamp normalization and semantic // assertions, so it owns a separate snapshot root from the generic suite. -const scenarioDir = join(dirname(fileURLToPath(import.meta.url)), 'goal-goldens/goal-round-driver') +const scenarioDir = join(dirname(fileURLToPath(import.meta.url)), 'goal-expected/goal-round-driver') const fixtureFile = join(scenarioDir, 'session.jsonl') const overrideFile = join(scenarioDir, 'replay.override.json') const stdoutExpected = join(scenarioDir, 'stdout.expected.jsonl') const sessionExpected = join(scenarioDir, 'session.expected.jsonl') -const wrapupDir = join(dirname(fileURLToPath(import.meta.url)), 'goal-goldens/goal-wrapup') +const wrapupDir = join(dirname(fileURLToPath(import.meta.url)), 'goal-expected/goal-wrapup') const refreshing = process.env.DSH_SNAPSHOT === 'refresh' const agent: AgentUnderTest = { diff --git a/examples/acp-agent/tests/image-offload.golden.e2e.ts b/examples/acp-agent/tests/image-offload.expected.e2e.ts similarity index 100% rename from examples/acp-agent/tests/image-offload.golden.e2e.ts rename to examples/acp-agent/tests/image-offload.expected.e2e.ts diff --git a/examples/headless-agent/tests/goldens/goal-tools/input.json b/examples/headless-agent/tests/expected/goal-tools/input.json similarity index 100% rename from examples/headless-agent/tests/goldens/goal-tools/input.json rename to examples/headless-agent/tests/expected/goal-tools/input.json diff --git a/examples/headless-agent/tests/goldens/goal-tools/replay.override.json b/examples/headless-agent/tests/expected/goal-tools/replay.override.json similarity index 100% rename from examples/headless-agent/tests/goldens/goal-tools/replay.override.json rename to examples/headless-agent/tests/expected/goal-tools/replay.override.json diff --git a/examples/headless-agent/tests/goldens/goal-tools/stream-json.expected.jsonl b/examples/headless-agent/tests/expected/goal-tools/stream-json.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/goal-tools/stream-json.expected.jsonl rename to examples/headless-agent/tests/expected/goal-tools/stream-json.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/headless-profile/session.expected.jsonl b/examples/headless-agent/tests/expected/headless-profile/session.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/headless-profile/session.expected.jsonl rename to examples/headless-agent/tests/expected/headless-profile/session.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/headless-profile/stderr.expected.txt b/examples/headless-agent/tests/expected/headless-profile/stderr.expected.txt similarity index 100% rename from examples/headless-agent/tests/goldens/headless-profile/stderr.expected.txt rename to examples/headless-agent/tests/expected/headless-profile/stderr.expected.txt diff --git a/examples/headless-agent/tests/goldens/invalid-credential/stream-json.expected.jsonl b/examples/headless-agent/tests/expected/invalid-credential/stream-json.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/invalid-credential/stream-json.expected.jsonl rename to examples/headless-agent/tests/expected/invalid-credential/stream-json.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/missing-credential/stream-json.expected.jsonl b/examples/headless-agent/tests/expected/missing-credential/stream-json.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/missing-credential/stream-json.expected.jsonl rename to examples/headless-agent/tests/expected/missing-credential/stream-json.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/provider-retry/input.json b/examples/headless-agent/tests/expected/provider-retry/input.json similarity index 100% rename from examples/headless-agent/tests/goldens/provider-retry/input.json rename to examples/headless-agent/tests/expected/provider-retry/input.json diff --git a/examples/headless-agent/tests/goldens/provider-retry/stream-json.expected.jsonl b/examples/headless-agent/tests/expected/provider-retry/stream-json.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/provider-retry/stream-json.expected.jsonl rename to examples/headless-agent/tests/expected/provider-retry/stream-json.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/semantic-checkpoint/replay.jsonl b/examples/headless-agent/tests/expected/semantic-checkpoint/replay.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/semantic-checkpoint/replay.jsonl rename to examples/headless-agent/tests/expected/semantic-checkpoint/replay.jsonl diff --git a/examples/headless-agent/tests/goldens/semantic-checkpoint/replay.override.json b/examples/headless-agent/tests/expected/semantic-checkpoint/replay.override.json similarity index 100% rename from examples/headless-agent/tests/goldens/semantic-checkpoint/replay.override.json rename to examples/headless-agent/tests/expected/semantic-checkpoint/replay.override.json diff --git a/examples/headless-agent/tests/goldens/semantic-checkpoint/session.expected.jsonl b/examples/headless-agent/tests/expected/semantic-checkpoint/session.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/semantic-checkpoint/session.expected.jsonl rename to examples/headless-agent/tests/expected/semantic-checkpoint/session.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/startup-activation-error/stderr.expected.txt b/examples/headless-agent/tests/expected/startup-activation-error/stderr.expected.txt similarity index 100% rename from examples/headless-agent/tests/goldens/startup-activation-error/stderr.expected.txt rename to examples/headless-agent/tests/expected/startup-activation-error/stderr.expected.txt diff --git a/examples/headless-agent/tests/goldens/subagent-diagnostic/parent.expected.jsonl b/examples/headless-agent/tests/expected/subagent-diagnostic/parent.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-diagnostic/parent.expected.jsonl rename to examples/headless-agent/tests/expected/subagent-diagnostic/parent.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/subagent-diagnostic/replay.override.json b/examples/headless-agent/tests/expected/subagent-diagnostic/replay.override.json similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-diagnostic/replay.override.json rename to examples/headless-agent/tests/expected/subagent-diagnostic/replay.override.json diff --git a/examples/headless-agent/tests/goldens/subagent-inheritance/child.expected.jsonl b/examples/headless-agent/tests/expected/subagent-inheritance/child.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-inheritance/child.expected.jsonl rename to examples/headless-agent/tests/expected/subagent-inheritance/child.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/subagent-inheritance/child.replay.jsonl b/examples/headless-agent/tests/expected/subagent-inheritance/child.replay.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-inheritance/child.replay.jsonl rename to examples/headless-agent/tests/expected/subagent-inheritance/child.replay.jsonl diff --git a/examples/headless-agent/tests/goldens/subagent-inheritance/parent.expected.jsonl b/examples/headless-agent/tests/expected/subagent-inheritance/parent.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-inheritance/parent.expected.jsonl rename to examples/headless-agent/tests/expected/subagent-inheritance/parent.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/subagent-inheritance/replay.override.json b/examples/headless-agent/tests/expected/subagent-inheritance/replay.override.json similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-inheritance/replay.override.json rename to examples/headless-agent/tests/expected/subagent-inheritance/replay.override.json diff --git a/examples/headless-agent/tests/goldens/subagent-settlement/child.expected.jsonl b/examples/headless-agent/tests/expected/subagent-settlement/child.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-settlement/child.expected.jsonl rename to examples/headless-agent/tests/expected/subagent-settlement/child.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/subagent-settlement/child.replay.jsonl b/examples/headless-agent/tests/expected/subagent-settlement/child.replay.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-settlement/child.replay.jsonl rename to examples/headless-agent/tests/expected/subagent-settlement/child.replay.jsonl diff --git a/examples/headless-agent/tests/goldens/subagent-settlement/parent.override.json b/examples/headless-agent/tests/expected/subagent-settlement/parent.override.json similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-settlement/parent.override.json rename to examples/headless-agent/tests/expected/subagent-settlement/parent.override.json diff --git a/examples/headless-agent/tests/goldens/subagent-settlement/parent.replay.jsonl b/examples/headless-agent/tests/expected/subagent-settlement/parent.replay.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-settlement/parent.replay.jsonl rename to examples/headless-agent/tests/expected/subagent-settlement/parent.replay.jsonl diff --git a/examples/headless-agent/tests/goldens/subagent-settlement/stream-json.expected.jsonl b/examples/headless-agent/tests/expected/subagent-settlement/stream-json.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/subagent-settlement/stream-json.expected.jsonl rename to examples/headless-agent/tests/expected/subagent-settlement/stream-json.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/workspace-context-resume/offline-edit/replay.jsonl b/examples/headless-agent/tests/expected/workspace-context-resume/offline-edit/replay.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/workspace-context-resume/offline-edit/replay.jsonl rename to examples/headless-agent/tests/expected/workspace-context-resume/offline-edit/replay.jsonl diff --git a/examples/headless-agent/tests/goldens/workspace-context-resume/offline-edit/replay.override.json b/examples/headless-agent/tests/expected/workspace-context-resume/offline-edit/replay.override.json similarity index 100% rename from examples/headless-agent/tests/goldens/workspace-context-resume/offline-edit/replay.override.json rename to examples/headless-agent/tests/expected/workspace-context-resume/offline-edit/replay.override.json diff --git a/examples/headless-agent/tests/goldens/workspace-context-resume/offline-edit/session.expected.jsonl b/examples/headless-agent/tests/expected/workspace-context-resume/offline-edit/session.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/workspace-context-resume/offline-edit/session.expected.jsonl rename to examples/headless-agent/tests/expected/workspace-context-resume/offline-edit/session.expected.jsonl diff --git a/examples/headless-agent/tests/goldens/workspace-context-resume/precedence-change/session.expected.jsonl b/examples/headless-agent/tests/expected/workspace-context-resume/precedence-change/session.expected.jsonl similarity index 100% rename from examples/headless-agent/tests/goldens/workspace-context-resume/precedence-change/session.expected.jsonl rename to examples/headless-agent/tests/expected/workspace-context-resume/precedence-change/session.expected.jsonl diff --git a/examples/headless-agent/tests/headless.golden.e2e.ts b/examples/headless-agent/tests/headless.expected.e2e.ts similarity index 99% rename from examples/headless-agent/tests/headless.golden.e2e.ts rename to examples/headless-agent/tests/headless.expected.e2e.ts index 9a473b66b3..c3ee295f02 100644 --- a/examples/headless-agent/tests/headless.golden.e2e.ts +++ b/examples/headless-agent/tests/headless.expected.e2e.ts @@ -17,7 +17,7 @@ import { } from '@deepseek-ai/dsh-session-persistence-jsonl/src/zstd.ts' import { describe, expect, it } from 'vitest' -const goldensDir = fileURLToPath(new URL('./goldens/', import.meta.url)) +const goldensDir = fileURLToPath(new URL('./expected/', import.meta.url)) const goalScenarioDir = join(goldensDir, 'goal-tools') const goalConfigPath = fileURLToPath(new URL('../goal.cordis.snapshot.yml', import.meta.url)) const retryScenarioDir = join(goldensDir, 'provider-retry') diff --git a/examples/headless-agent/tests/semantic-checkpoint.golden.e2e.ts b/examples/headless-agent/tests/semantic-checkpoint.expected.e2e.ts similarity index 99% rename from examples/headless-agent/tests/semantic-checkpoint.golden.e2e.ts rename to examples/headless-agent/tests/semantic-checkpoint.expected.e2e.ts index c1cc346b3d..119d3f5889 100644 --- a/examples/headless-agent/tests/semantic-checkpoint.golden.e2e.ts +++ b/examples/headless-agent/tests/semantic-checkpoint.expected.e2e.ts @@ -9,7 +9,7 @@ import SessionStore, { SESSION_FORMAT_VERSION, SessionId, type SessionEvent, typ import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' import { describe, expect, it } from 'vitest' -const fixtureDir = join(dirname(fileURLToPath(import.meta.url)), 'goldens/semantic-checkpoint') +const fixtureDir = join(dirname(fileURLToPath(import.meta.url)), 'expected/semantic-checkpoint') const replayFixture = join(fixtureDir, 'replay.jsonl') const replayOverride = join(fixtureDir, 'replay.override.json') const sessionExpected = join(fixtureDir, 'session.expected.jsonl') diff --git a/examples/headless-agent/tests/session-format-guard.golden.e2e.ts b/examples/headless-agent/tests/session-format-guard.expected.e2e.ts similarity index 98% rename from examples/headless-agent/tests/session-format-guard.golden.e2e.ts rename to examples/headless-agent/tests/session-format-guard.expected.e2e.ts index 902229c50b..899f0c821d 100644 --- a/examples/headless-agent/tests/session-format-guard.golden.e2e.ts +++ b/examples/headless-agent/tests/session-format-guard.expected.e2e.ts @@ -19,7 +19,7 @@ import SessionStore, { import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' import { describe, expect, it } from 'vitest' -const fixtureDir = join(dirname(fileURLToPath(import.meta.url)), 'goldens/workspace-context-resume/offline-edit') +const fixtureDir = join(dirname(fileURLToPath(import.meta.url)), 'expected/workspace-context-resume/offline-edit') const replayFixture = join(fixtureDir, 'replay.jsonl') const configPath = fileURLToPath(new URL('../workspace-context-resume.cordis.snapshot.yml', import.meta.url)) const binScript = fileURLToPath(new URL('./fixtures/headless-driver.ts', import.meta.url)) diff --git a/examples/headless-agent/tests/subagent-diagnostic.golden.e2e.ts b/examples/headless-agent/tests/subagent-diagnostic.expected.e2e.ts similarity index 98% rename from examples/headless-agent/tests/subagent-diagnostic.golden.e2e.ts rename to examples/headless-agent/tests/subagent-diagnostic.expected.e2e.ts index ca2d2e6418..63a26ef381 100644 --- a/examples/headless-agent/tests/subagent-diagnostic.golden.e2e.ts +++ b/examples/headless-agent/tests/subagent-diagnostic.expected.e2e.ts @@ -15,7 +15,7 @@ import SessionStore, { SESSION_FORMAT_VERSION, SessionId, type SessionEvent, typ import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' import { describe, expect, it } from 'vitest' -const fixtureDir = fileURLToPath(new URL('./goldens/subagent-diagnostic', import.meta.url)) +const fixtureDir = fileURLToPath(new URL('./expected/subagent-diagnostic', import.meta.url)) const replayOverride = join(fixtureDir, 'replay.override.json') const parentExpected = join(fixtureDir, 'parent.expected.jsonl') const configPath = fileURLToPath(new URL('../subagent-diagnostic.cordis.snapshot.yml', import.meta.url)) diff --git a/examples/headless-agent/tests/subagent-inheritance.golden.e2e.ts b/examples/headless-agent/tests/subagent-inheritance.expected.e2e.ts similarity index 98% rename from examples/headless-agent/tests/subagent-inheritance.golden.e2e.ts rename to examples/headless-agent/tests/subagent-inheritance.expected.e2e.ts index 9c07b36d1f..55a6b5c5ad 100644 --- a/examples/headless-agent/tests/subagent-inheritance.golden.e2e.ts +++ b/examples/headless-agent/tests/subagent-inheritance.expected.e2e.ts @@ -14,7 +14,7 @@ import SessionStore, { SESSION_FORMAT_VERSION, SessionId, type SessionEvent, typ import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl' import { describe, expect, it } from 'vitest' -const fixtureDir = fileURLToPath(new URL('./goldens/subagent-inheritance', import.meta.url)) +const fixtureDir = fileURLToPath(new URL('./expected/subagent-inheritance', import.meta.url)) const replayOverride = join(fixtureDir, 'replay.override.json') const childReplay = join(fixtureDir, 'child.replay.jsonl') const parentExpected = join(fixtureDir, 'parent.expected.jsonl') diff --git a/examples/headless-agent/tests/workspace-context-resume.golden.e2e.ts b/examples/headless-agent/tests/workspace-context-resume.expected.e2e.ts similarity index 99% rename from examples/headless-agent/tests/workspace-context-resume.golden.e2e.ts rename to examples/headless-agent/tests/workspace-context-resume.expected.e2e.ts index b7c965fa17..16d2e6beaf 100644 --- a/examples/headless-agent/tests/workspace-context-resume.golden.e2e.ts +++ b/examples/headless-agent/tests/workspace-context-resume.expected.e2e.ts @@ -22,7 +22,7 @@ import { renderWorkspaceContext } from '@deepseek-ai/dsh-agent-instructions' import { resolveConfig, workspaceBaselineIdentity } from '@deepseek-ai/dsh-agent-instructions/src/config.ts' import { describe, expect, it } from 'vitest' -const fixtureDir = join(dirname(fileURLToPath(import.meta.url)), 'goldens/workspace-context-resume/offline-edit') +const fixtureDir = join(dirname(fileURLToPath(import.meta.url)), 'expected/workspace-context-resume/offline-edit') const replayFixture = join(fixtureDir, 'replay.jsonl') const replayOverride = join(fixtureDir, 'replay.override.json') const sessionExpected = join(fixtureDir, 'session.expected.jsonl') diff --git a/package.json b/package.json index eeb41b35a2..64cf32a27e 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,8 @@ "test:coverage": "vitest run --coverage", "test:coverage:partitioned": "tsx scripts/run-coverage-partitions.ts", "test:e2e": "vitest run --config vitest.e2e.config.ts", - "test:golden": "vitest run --config vitest.golden.config.ts", - "test:golden:refresh": "DSH_SNAPSHOT=refresh vitest run --config vitest.golden.config.ts", + "test:expected": "vitest run --config vitest.expected.config.ts", + "test:expected:refresh": "DSH_SNAPSHOT=refresh vitest run --config vitest.expected.config.ts", "test:issue-management": "node .github/issue-management/policy.test.mjs", "test:snapshot": "vitest run --config vitest.snapshot.config.ts", "test:snapshot:record": "DSH_SNAPSHOT=record vitest run --config vitest.snapshot.config.ts --update", diff --git a/scripts/run-gates.spec.ts b/scripts/run-gates.spec.ts index a5fcffb72d..7a75841f21 100644 --- a/scripts/run-gates.spec.ts +++ b/scripts/run-gates.spec.ts @@ -397,7 +397,7 @@ describe('Node 24 lane ownership', () => { 'built-package-invariants', 'lint-and-duplication', 'snapshot', - 'golden', + 'expected-output', 'web-snapshot', 'doc-typecheck', 'node-next-types', @@ -414,7 +414,7 @@ describe('Node 24 lane ownership', () => { expect(subject.find(item => item.id === 'lint-and-duplication')?.needs).toEqual(['built-package-invariants']) for (const id of [ 'snapshot', - 'golden', + 'expected-output', 'web-snapshot', 'doc-typecheck', 'node-next-types', @@ -423,7 +423,7 @@ describe('Node 24 lane ownership', () => { expect(subject.find(item => item.id === id)?.needs).toEqual(['built-package-invariants']) } expect(subject.find(item => item.id === 'snapshot')?.env).toEqual({ DSH_EXAMPLE_MODE: 'lib' }) - expect(subject.find(item => item.id === 'golden')?.env).toEqual({ DSH_EXAMPLE_MODE: 'lib' }) + expect(subject.find(item => item.id === 'expected-output')?.env).toEqual({ DSH_EXAMPLE_MODE: 'lib' }) expect(subject.find(item => item.id === 'doc-typecheck')?.env).toEqual({ DSH_DOC_TYPECHECK_USE_BUILD_OUTPUT: '1', }) diff --git a/scripts/run-gates.ts b/scripts/run-gates.ts index 8da69710d8..a17df20b71 100644 --- a/scripts/run-gates.ts +++ b/scripts/run-gates.ts @@ -241,7 +241,7 @@ export function gatesForMode(selected: Mode): Gate[] { pnpmScript('issue-management', 'test:issue-management', { label: 'Issue management policy' }), pnpmScript('duplication', 'duplication'), snapshotGate(), - goldenGate(), + expectedOutputGate(), pnpmScript('build', 'build'), pnpmScript('build:web', 'build:web'), ...hygieneLeafGates({ artifactNeeds: ['build'] }), @@ -428,7 +428,7 @@ function ciConsumerGates(): Gate[] { needs: validatedBuild, }), snapshotGate(validatedBuild), - goldenGate(validatedBuild), + expectedOutputGate(validatedBuild), webSnapshotGate(validatedBuild), pnpmScript('doc-typecheck', 'doc-typecheck:contracts-ready', { needs: validatedBuild, @@ -596,10 +596,10 @@ function snapshotGate(needs: string[] = ['build']): Gate { }) } -// Owner-local process goldens consume built package exports without entering +// Owner-local process expectations consume built package exports without entering // the recorded-session corpus or the credentialed provider lane. -function goldenGate(needs: string[] = ['build']): Gate { - return pnpmScript('golden', 'test:golden', { +function expectedOutputGate(needs: string[] = ['build']): Gate { + return pnpmScript('expected-output', 'test:expected', { env: { DSH_EXAMPLE_MODE: 'lib' }, needs, }) diff --git a/scripts/translation-prompt.golden.spec.ts b/scripts/translation-prompt.expected.spec.ts similarity index 100% rename from scripts/translation-prompt.golden.spec.ts rename to scripts/translation-prompt.expected.spec.ts diff --git a/snapshots/AGENTS.md b/snapshots/AGENTS.md index 5bf49fe4e3..a778d2a19a 100644 --- a/snapshots/AGENTS.md +++ b/snapshots/AGENTS.md @@ -1,6 +1,6 @@ # AGENTS.md — Recorded-session snapshots -This tree contains only tests whose committed session JSONL is replay input and expected persisted output. Keep non-session ARIA, geometry, generator, CLI, and unit expected output with its owning app, script, or package as a golden; use `test:golden`, `test:web`, or `test` for its owning tier. +This tree contains only tests whose committed session JSONL is replay input and expected persisted output. Keep non-session ARIA, geometry, generator, CLI, and unit expected output with its owning app, script, or package; use `test:expected`, `test:web`, or `test` for its owning tier. Every process under test starts through the `dsh` CLI with a shipped profile and optional scenario patches. Test clients may drive a public protocol or browser interface; do not add another application entrypoint, hidden CLI mode, or executable scenario driver. diff --git a/vitest.e2e.config.ts b/vitest.e2e.config.ts index aa275d44e4..6ece35bdf4 100644 --- a/vitest.e2e.config.ts +++ b/vitest.e2e.config.ts @@ -43,7 +43,7 @@ export default defineConfig({ // apps/cli only, not apps/*: apps/web/tests/*.e2e.ts needs the built // frontend dist and runs under vitest.web.config.ts (the test:web job). include: ['packages/*/*/tests/**/*.e2e.ts', 'apps/cli/tests/**/*.e2e.ts', 'examples/*/tests/**/*.e2e.ts'], - exclude: ['**/*.golden.e2e.ts'], + exclude: ['**/*.expected.e2e.ts'], // Real model calls: generous timeouts, and retries for transient flakes // (the shared internal key hits concurrency quotas). No coverage — the // unit suites own the coverage gate. diff --git a/vitest.golden.config.ts b/vitest.expected.config.ts similarity index 87% rename from vitest.golden.config.ts rename to vitest.expected.config.ts index 64cb3b7694..51e6fec467 100644 --- a/vitest.golden.config.ts +++ b/vitest.expected.config.ts @@ -10,8 +10,8 @@ export default defineConfig({ execArgv: vitestExecArgv, setupFiles: ['./scripts/test-invariants.ts'], include: [ - 'apps/cli/tests/**/*.golden.e2e.ts', - 'examples/*/tests/**/*.golden.e2e.ts', + 'apps/cli/tests/**/*.expected.e2e.ts', + 'examples/*/tests/**/*.expected.e2e.ts', ], testTimeout: 120_000, hookTimeout: 30_000, diff --git a/vitest.snapshot.config.ts b/vitest.snapshot.config.ts index 8295960ca2..30e7aa2a63 100644 --- a/vitest.snapshot.config.ts +++ b/vitest.snapshot.config.ts @@ -58,7 +58,7 @@ export default defineConfig({ // (value 1 restores fully serial replay on constrained machines). Record // and refresh stay serial: record spends real API quota per scenario, and // refresh write-back harvests volatile values from fixtures already on - // disk, so concurrent writers would corrupt goldens. + // disk, so concurrent writers would corrupt expected outputs. testTimeout: 120_000, hookTimeout: 30_000, fileParallelism: (process.env.DSH_SNAPSHOT || 'replay') === 'replay' && snapshotMaxConcurrency > 1,