From 414c310324b7700f8e9e29251a3164ade385a94a Mon Sep 17 00:00:00 2001 From: Turtle Date: Mon, 3 Aug 2026 22:04:53 +0800 Subject: [PATCH] cleanup(cli): omit invariants from shipped configs --- ...-package-owned-invariant-service.i18n.yaml | 6 ++-- ...6-07-19-package-owned-invariant-service.md | 8 ++--- ...7-19-package-owned-invariant-service.zh.md | 8 ++--- ...t-invariants-from-shipped-config.i18n.yaml | 6 ++++ ...-03-omit-invariants-from-shipped-config.md | 30 +++++++++++++++++++ ...-omit-invariants-from-shipped-config.zh.md | 30 +++++++++++++++++++ apps/cli/config/tui.cordis.yml | 13 -------- apps/cli/package.json | 1 - apps/cli/tests/built-bin.e2e.ts | 4 +++ pnpm-lock.yaml | 3 -- 10 files changed, 81 insertions(+), 28 deletions(-) create mode 100644 .agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.i18n.yaml create mode 100644 .agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.md create mode 100644 .agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.zh.md diff --git a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml index a3e8c3ad8a..3c005a6deb 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml +++ b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml @@ -1,6 +1,6 @@ # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each # 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 -2026-07-19-package-owned-invariant-service.md: 2443a8f7d04b96f51bb798130078a7457f78b2a1 -2026-07-19-package-owned-invariant-service.zh.md: 3c71d3b7f99a507d4c0236b7ef6dc0794814cdc8 +# pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md +2026-07-19-package-owned-invariant-service.md: e32efe9f6b3ce6b782c61db56d928e87c160dc9a +2026-07-19-package-owned-invariant-service.zh.md: 60edaa3f6009acc516017683232ca0c07f64ec0d diff --git a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md index 2443a8f7d0..e32efe9f6b 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md +++ b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.md @@ -8,7 +8,7 @@ English | [中文](2026-07-19-package-owned-invariant-service.zh.md) Runtime invariant checks span session traces, agent state, scoped dispatch, and request reconstruction. Putting all checks in one diagnostics package makes that package import product vocabularies from unrelated domains, centralizes tests away from their owners, and requires the central package to change whenever a product package adds or removes a check. -Deployments also need more than presence or absence of one plugin. A standard composition should carry the known invariant contributions while permitting a global off switch and package-selective diagnostics. Selection must remain stable when a package loads later or reloads under HMR, and disabled contributions must not allow two plugins to claim the same package name silently. +Deployments that opt into diagnostics need more than presence or absence of one plugin. Such a composition carries the known invariant contributions while permitting a global off switch and package-selective diagnostics. Selection must remain stable when a package loads later or reloads under HMR, and disabled contributions must not allow two plugins to claim the same package name silently. Package ownership must also be exhaustive. Without a mechanical repository rule, a new package can omit the companion, dependency, or publication wiring and remain invisible to diagnostics until a maintainer notices the gap. @@ -72,9 +72,9 @@ These four owners supplied the initial stateful checks. The follow-up runtime-co The generated scoped-event subject resolver lives in `dsh-scope`, beside the contract and invariant that consume it. `gen-scoped-events` uses the root TypeScript Program to enumerate `this: Scoped` declarations, infer routing-key types from real `scopeTarget(base, key)` calls, and require one unambiguous payload subject or an explicit unsupported marker. The committed runtime map imports no event-owner package, so semantic completeness does not expand either the service or scope package's runtime closure. -### Standard composition and SDK output +### Example composition and SDK output -The standard agent spine mounts the service and all four stateful companion subpaths, forwarding `enabled`, `package_allowlist`, and `package_blocklist` to the service. Generated SDK Cordis composition emits the same entries. A subpath entry adds its installable root npm package rather than treating the subpath as a package name. +The example agent spine mounts the service and all four stateful companion subpaths, forwarding `enabled`, `package_allowlist`, and `package_blocklist` to the service. Generated SDK Cordis composition emits the same entries. A subpath entry adds its installable root npm package rather than treating the subpath as a package name. The shipped `dsh` TUI and Web config trees omit the service and companions under the [shipped-config decision](../simplification/2026-08-03-omit-invariants-from-shipped-config.md). Workspace constraints recognize the separate invariant bundle, and package exports, project references, build configuration, dependency declarations, and the lockfile describe the same publication surface. Generated config catalogs, module graphs, and API documentation derive from those sources. @@ -97,7 +97,7 @@ Every Vitest configuration loads a test host that mounts an explicitly enabled s - Product packages own and test their relational assertions while the service stays product-independent. - Every package pays the publication and dependency cost of a companion; only owners with a meaningful runtime relationship add listener or trace-state cost. -- Standard compositions can disable all checks or select package names without changing their plugin tree. +- Compositions that mount the diagnostics can disable all checks or select package names without changing their plugin tree. - Explicit companion entries make diagnostic cost and ownership visible in Cordis config and package exports. - One selected executable contribution adds one child fiber and its listener/state cost; a selected empty contribution has no listener or trace-state cost, while filtered registrations retain only name ownership. - Regex sources are deployment configuration and remain fixed until the service reloads. diff --git a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.zh.md b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.zh.md index 3c71d3b7f9..60edaa3f60 100644 --- a/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.zh.md +++ b/.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.zh.md @@ -8,7 +8,7 @@ Status: implemented 运行时不变式检查跨越会话轨迹、agent 状态、作用域 dispatch 和请求重建。如果所有检查都放在一个诊断包中,该包就必须导入彼此无关的产品领域词汇,测试也会离开真正的所有者;任何产品包新增或移除检查时,都要修改中央包。 -部署还需要比“是否加载一个插件”更细的控制。标准组合应携带已知的不变式贡献,同时允许全局关闭或按包选择诊断。包稍后加载或在 HMR 下重载时,选择结果必须保持稳定;被过滤的贡献也不能让两个插件静默占用同一个包名。 +选择启用诊断的部署还需要比“是否加载一个插件”更细的控制。这类组合会携带已知的不变式贡献,同时允许全局关闭或按包选择诊断。包稍后加载或在 HMR 下重载时,选择结果必须保持稳定;被过滤的贡献也不能让两个插件静默占用同一个包名。 包所有权还必须覆盖完整。若没有机械化的仓库规则,新包可能遗漏伴随插件、依赖或发布配置,并一直不会进入诊断范围,直到维护者发现这一缺口。 @@ -72,9 +72,9 @@ blocklist 匹配优先于 allowlist 匹配。每个条目都是区分大小写 生成的 scoped event 主体解析表位于 `dsh-scope`,与消费它的契约和不变式相邻。`gen-scoped-events` 使用根 TypeScript Program 枚举 `this: Scoped` 声明,从真实 `scopeTarget(base, key)` 调用推断路由键类型,并要求唯一、无歧义的 payload 主体或显式 unsupported 标记。提交的运行时映射不导入事件所有者包,因此语义完整性不会扩大服务包或 scope 包的运行时依赖闭包。 -### 标准组合与 SDK 输出 +### 示例组合与 SDK 输出 -标准 agent spine 会挂载服务和四个有状态伴随子路径,并把 `enabled`、`package_allowlist` 与 `package_blocklist` 转发给服务。生成的 SDK Cordis 组合输出相同条目。子路径条目添加可安装的根 npm 包,而不会把子路径误当成包名。 +示例 agent spine 会挂载服务和四个有状态伴随子路径,并把 `enabled`、`package_allowlist` 与 `package_blocklist` 转发给服务。生成的 SDK Cordis 组合输出相同条目。子路径条目添加可安装的根 npm 包,而不会把子路径误当成包名。根据[交付配置决策](../simplification/2026-08-03-omit-invariants-from-shipped-config.md),交付的 `dsh` TUI 与 Web 配置树会省略该服务及其伴随插件。 Workspace 约束识别独立的不变式 bundle;包 exports、项目引用、构建配置、依赖声明和 lockfile 描述同一发布表面。生成的配置目录、模块图和 API 文档都从这些源派生。 @@ -97,7 +97,7 @@ Workspace 约束识别独立的不变式 bundle;包 exports、项目引用、 - 产品包拥有并测试自己的关系断言,服务保持与产品无关。 - 每个包都承担 companion 的发布与依赖成本;只有具备有意义运行时关系的所有者才增加 listener 或 trace 状态成本。 -- 标准组合无需改变插件树即可关闭全部检查或按包名选择。 +- 挂载诊断的组合无需改变插件树即可关闭全部检查或按包名选择。 - 显式伴随条目让诊断成本和所有权在 Cordis 配置与包 export 中可见。 - 每个选中的可执行贡献增加一个子 fiber 及其 listener/状态成本;选中的空贡献不增加 listener 或 trace 状态成本,被过滤注册则只保留包名占用。 - 正则表达式源属于部署配置,在服务重载前保持固定。 diff --git a/.agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.i18n.yaml b/.agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.i18n.yaml new file mode 100644 index 0000000000..91b9e6a0c0 --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# 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/simplification/2026-08-03-omit-invariants-from-shipped-config.md +2026-08-03-omit-invariants-from-shipped-config.md: ff9a3b0ab2b4797ca4e96bea9e6b961b2e38501f +2026-08-03-omit-invariants-from-shipped-config.zh.md: 526ce0756e69b36b6f54b46b23e1814322d6a1fd diff --git a/.agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.md b/.agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.md new file mode 100644 index 0000000000..ff9a3b0ab2 --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.md @@ -0,0 +1,30 @@ +# Agent Note: Omit runtime invariants from shipped dsh config + +Status: implemented + +English | [中文](2026-08-03-omit-invariants-from-shipped-config.zh.md) + +## Problem + +`@deepseek-ai/dsh-invariants` and package-owned `./invariant` companions are optional development diagnostics. The shipped TUI mounted the service and four stateful companions while the shipped Web tree omitted them, so the two product surfaces had different diagnostic cost and failure behavior. A relational assertion failure could terminate an ordinary TUI run even though the always-on product boundary remained responsible for session validation and immutable history. + +## Decision + +The shipped `dsh` configuration trees under `apps/cli/config/` mount neither `@deepseek-ai/dsh-invariants` nor any package-owned `./invariant` companion. The CLI package therefore carries no direct dependency on the invariant service. + +Invariant support remains available for focused tests, example bundles, generated SDK compositions, and custom deployments that opt into diagnostics explicitly. Session validation, snapshotting, freezing, and provenance remain always on and do not depend on the optional service, as defined by the [source-owned immutability decision](../architecture/2026-06-11-dev-invariants-over-deep-readonly.md). + +The built CLI config-dump test checks both shipped surfaces and rejects either the service entry or any `@deepseek-ai/dsh-*/invariant` entry. + +## Alternatives considered + +- **Mount the service with `enabled: false`.** Rejected because the shipped tree and CLI dependency would still carry diagnostics that install no checks. +- **Keep the TUI-only mount.** Rejected because the shipped surfaces would retain different diagnostic and failure behavior. +- **Remove invariant support from the repository.** Rejected because package-owned checks remain useful in tests, examples, generated SDKs, and explicit development compositions; only the default product config is out of scope. + +## Consequences + +- Ordinary `dsh` TUI and Web runs install no invariant listeners or trace state and cannot fail through `InvariantError`. +- Development and custom compositions retain explicit access to the invariant service and companions. +- The shipped config absence is verified from the built CLI's composed output for both surfaces. +- Always-on session integrity remains unchanged. diff --git a/.agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.zh.md b/.agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.zh.md new file mode 100644 index 0000000000..526ce0756e --- /dev/null +++ b/.agents/notes/implemented/simplification/2026-08-03-omit-invariants-from-shipped-config.zh.md @@ -0,0 +1,30 @@ +# Agent Note: 从交付的 dsh 配置中省略运行时不变式 + +Status: implemented + +[English](2026-08-03-omit-invariants-from-shipped-config.md) | 中文 + +## 问题 + +`@deepseek-ai/dsh-invariants` 与各包(package)拥有的 `./invariant` 伴随插件是可选的开发诊断。交付的 TUI 挂载了该服务和四个有状态伴随插件,而交付的 Web 配置树省略了这些条目,导致两个产品 surface 的诊断成本和失败行为不同。即使始终启用的产品边界仍负责会话验证与不可变历史,关系断言失败也可能终止普通的 TUI 运行。 + +## 决策 + +`apps/cli/config/` 下交付的 `dsh` 配置树既不挂载 `@deepseek-ai/dsh-invariants`,也不挂载任何包拥有的 `./invariant` 伴随插件。因此,CLI 包不再直接依赖不变式服务。 + +不变式支持仍可供聚焦测试、示例组合包、生成的 SDK 组合,以及显式选择诊断的自定义部署使用。会话验证、快照、冻结和 provenance 始终启用,且不依赖可选服务,具体由[源端拥有的不可变性决策](../architecture/2026-06-11-dev-invariants-over-deep-readonly.md)规定。 + +构建后 CLI 的配置转储测试会检查两个交付的 surface,并拒绝服务条目或任何 `@deepseek-ai/dsh-*/invariant` 条目。 + +## 已考虑的替代方案 + +- **挂载服务并设置 `enabled: false`。** 不予采纳,因为交付的配置树和 CLI 依赖仍会携带不安装任何检查的诊断。 +- **保留仅由 TUI 挂载的方案。** 不予采纳,因为两个交付的 surface 仍会保留不同的诊断和失败行为。 +- **从仓库中移除不变式支持。** 不予采纳,因为包拥有的检查在测试、示例、生成的 SDK 及显式开发组合中仍然有用;只有默认产品配置不在其范围内。 + +## 后果 + +- 普通的 `dsh` TUI 与 Web 运行不安装不变式监听器或 trace 状态,也不会因 `InvariantError` 失败。 +- 开发和自定义组合仍可显式使用不变式服务及伴随插件。 +- 构建后 CLI 的组合输出会验证两个 surface 的交付配置中均不存在这些条目。 +- 始终启用的会话完整性保持不变。 diff --git a/apps/cli/config/tui.cordis.yml b/apps/cli/config/tui.cordis.yml index 02d8649447..68243bedce 100644 --- a/apps/cli/config/tui.cordis.yml +++ b/apps/cli/config/tui.cordis.yml @@ -58,19 +58,6 @@ # ── TUI-only rows ─────────────────────────────────────────────────────────── - insert: - # Relational runtime checks over the authoritative event streams; each - # companion registers the assertions its own package owns. - - id: invariants - name: '@deepseek-ai/dsh-invariants' - - id: session-invariant - name: '@deepseek-ai/dsh-session/invariant' - - id: agent-invariant - name: '@deepseek-ai/dsh-agent/invariant' - - id: scope-invariant - name: '@deepseek-ai/dsh-scope/invariant' - - id: agent-loop-invariant - name: '@deepseek-ai/dsh-agent-loop/invariant' - # The derived query index behind `/resume`. The launcher provides a unique # process-local path because this SQLite backend has one writer owner; the # project-local fallback applies when no launcher sets the typed slot. diff --git a/apps/cli/package.json b/apps/cli/package.json index 8c482ac3e2..9bba751b27 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -65,7 +65,6 @@ "@deepseek-ai/dsh-host-directory-picker-browse": "workspace:^", "@deepseek-ai/dsh-host-directory-picker-native": "workspace:^", "@deepseek-ai/dsh-host-webserver": "workspace:^", - "@deepseek-ai/dsh-invariants": "workspace:^", "@deepseek-ai/dsh-llm": "workspace:^", "@deepseek-ai/dsh-llm-deepseek": "workspace:^", "@deepseek-ai/dsh-llm-pi-ai": "workspace:^", diff --git a/apps/cli/tests/built-bin.e2e.ts b/apps/cli/tests/built-bin.e2e.ts index 3592d438dd..88f8178fba 100644 --- a/apps/cli/tests/built-bin.e2e.ts +++ b/apps/cli/tests/built-bin.e2e.ts @@ -94,6 +94,8 @@ describe.skipIf(!existsSync(dshBin))('dsh BUILT bin (node lib/bin.js, no tsx)', expect(stdout).toContain('model: deepseek-v4-pro') expect(stdout).toContain('cwd: !!js process.cwd()') expect(stdout).toContain("name: '@deepseek-ai/dsh-tui'") + expect(stdout).not.toMatch(/name: ['"]@deepseek-ai\/dsh-invariants['"]/) + expect(stdout).not.toMatch(/name: ['"]@deepseek-ai\/dsh-[^'"]+\/invariant['"]/) expect(stdout).toContain([ '- id: tool-web', " name: '@deepseek-ai/dsh-tool-web'", @@ -140,6 +142,8 @@ describe.skipIf(!existsSync(dshBin))('dsh BUILT bin (node lib/bin.js, no tsx)', expect(code).toBe(0) expect(stdout).toContain("name: '@deepseek-ai/dsh-host-webserver'") expect(stdout).not.toContain("name: '@deepseek-ai/dsh-tui'") + expect(stdout).not.toMatch(/name: ['"]@deepseek-ai\/dsh-invariants['"]/) + expect(stdout).not.toMatch(/name: ['"]@deepseek-ai\/dsh-[^'"]+\/invariant['"]/) }, 30_000) }) }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5e27760b0d..6b8b964f31 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -276,9 +276,6 @@ importers: '@deepseek-ai/dsh-host-webserver': specifier: workspace:^ version: link:../../packages/host/webserver - '@deepseek-ai/dsh-invariants': - specifier: workspace:^ - version: link:../../packages/support/invariants '@deepseek-ai/dsh-llm': specifier: workspace:^ version: link:../../packages/llm/llm