mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
docs(notes): record how the notices tier learns what ships
A package a published browser artifact carries is a runtime disclosure whatever section declares it, and the build answers which ones those are. Record that clause, the dry run behind it, why a bundler's virtual module is not a shipped package, why a types-only package is not either, and the generator run cost the dry run adds.
This commit is contained in:
+2
-2
@@ -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-30-generated-third-party-notices.md
|
||||
2026-07-30-generated-third-party-notices.md: 9ca24c9634b0410f9b7cc255902344cd6014bb90
|
||||
2026-07-30-generated-third-party-notices.zh.md: b49e60565bbae62cf17026db17babc1ba7a408dc
|
||||
2026-07-30-generated-third-party-notices.md: 2128537b09f9d5d68cb1175b1ecb195fa50e1865
|
||||
2026-07-30-generated-third-party-notices.zh.md: 906f5ed5b9a11f3ddd68491686b460c5d9f4a682
|
||||
|
||||
@@ -26,6 +26,8 @@ The runtime tier deliberately covers **every mountable plugin**, not just what t
|
||||
|
||||
The manifest set is derived from the `packages:` members the root `pnpm-workspace.yaml` declares, including the Landlock workspace and its public packages, so a new member area is read the day it is declared rather than the day someone remembers to extend a list. License and repository metadata come from the root workspace's installed pnpm store and package-local link farms, so the generator requires an installed tree and fails loud when a package resolves to neither, rather than emitting an empty cell. `OVERRIDES` carries the packages whose published manifest cannot answer — Rust-built npm bins that omit `license`, and the `modelcontextprotocol/servers` packages whose repository is mid MIT→Apache-2.0 relicensing, so their effective terms are per-contribution. A runtime dependency whose license is not on the permissive list is a hard error: shipping copyleft is a distribution decision, not something a regenerated table may absorb silently. Vendored packages are cross-checked against `vendor/README.md` and rejected if any is not MIT, and `pnpm-workspace.yaml`'s `patchedDependencies` are listed under the runtime table because pnpm applies those patches at install time — shipped artifacts carry modified copies of `@earendil-works/pi-tui` and `node-pty`, and the patch files are the record of what changed.
|
||||
|
||||
**A package a published artifact carries is runtime whatever section declares it.** The browser side is built, not resolved: tsdown inlines every non-platform specifier into a plugin's `lib/client.js`, and Vite inlines the shell's imports into `@deepseek-ai/dsh-web-frontend`'s `dist`. Those packages are therefore declared as `devDependencies` — [the client build-time dependency note](../../proposed/process/2026-08-14-client-build-time-deps.md) owns that placement rule — while a copy of each is redistributed, so react, shiki, katex, and the markdown pipeline must stay in the runtime tier. [`scripts/browser-bundled-externals.ts`](../../../../scripts/browser-bundled-externals.ts) answers which ones those are from the build itself: it drives each client bundle through that package's own `tsdown.config.ts` and the shell through `apps/web`'s Vite config, with a recording plugin that resolves every bare specifier as external and notes it. The pass walks this repository's own source and stops at the package boundary, which costs about three seconds and yields exactly the direct-dependency granularity this file discloses. A specifier counts only once the host resolves it to a file inside a package, so a bundler's own virtual module is not mistaken for a shipped one: `vite/modulepreload-polyfill` is generated by a Vite plugin rather than published as a file, which makes the polyfill in the `dist` build glue of the same kind as an emitted TypeScript helper. Using the real configurations rather than a hand-kept list buys two properties no list has: an erased type import never appears, because the transform drops it before resolution, and a package stops being disclosed as shipped the moment its last browser import is gone. Workspace names are followed only on the Vite side, where the shell's aliases map them to source — that is how a browser-only library's own imports, `ui-primitives`' katex and shiki among them, become visible. A package that ships only type declarations is development-only however a shipped package names it: it contributes no redistributed code, and the dry run cannot see an erased type import anyway, because the transform drops it before resolution. `@types/mdast` and `micromark-util-types` moved to that tier for exactly this reason.
|
||||
|
||||
The project owner separately authorizes distribution of every official `@anthropic-ai/claude-agent-sdk` version and the official Claude Code CLI/platform payloads that version declares through `optionalDependencies`. The generator represents this as one exact direct-package identity exception, not as a permissive-license override: `SEE LICENSE IN README.md` and `SEE LICENSE IN LICENSE.md` remain non-permissive classifications, and every unrelated non-permissive runtime still fails closed. When the SDK is present, the generator reads its installed manifest, rejects optional identities outside the official SDK payload prefix, derives the current SDK, CLI, and payload versions, verifies the installed host payload's identity, version, and declared-license field, and renders the complete SDK-declared payload set in a separate notices section. Version, declared-license, and payload-set changes do not require new identity authorization, but they still require ordinary dependency, lockfile, compatibility, terms, and notices review.
|
||||
|
||||
## Testing
|
||||
@@ -52,7 +54,7 @@ The Claude distribution tests prove that only the exact direct SDK identity bypa
|
||||
|
||||
## Consequences
|
||||
|
||||
A dependency edit now carries a regenerated notices file into the same commit. Contributors pay one generator run — about a second — on commits that touch a manifest, and nothing on any other commit. Committing with hooks disabled defers the cost to a test-lane failure that names the command.
|
||||
A dependency edit now carries a regenerated notices file into the same commit. Contributors pay one generator run on commits that touch a manifest, and nothing on any other commit. It costs a few seconds rather than one, because learning what the browser artifacts carry drives the real client and shell bundlers; a broken client source therefore fails the hook, as the staged lint job already would. Committing with hooks disabled defers the cost to a test-lane failure that names the command.
|
||||
|
||||
The generator needs an installed tree, which makes it heavier than a pure-source generator, and a new package with unusable published metadata needs an `OVERRIDES` entry rather than silently rendering a blank license. Both failures are loud and name the remedy.
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ Status: implemented
|
||||
|
||||
manifest 集合由根 `pnpm-workspace.yaml` 声明的 `packages:` 成员派生,其中包括 Landlock 工作区及其公开包,因此新增成员区域在声明当天就会被读取,而不必等谁想起来去补一份列表。许可证与仓库地址取自根工作区已安装的 pnpm store 和包本地链接场;某个包两处都解析不到时直接失败,而不是留下空单元格。`OVERRIDES` 收录已发布 manifest 答不上来的包:用 Rust 构建、发布时省略 `license` 字段的 npm 可执行包,以及 `modelcontextprotocol/servers` 系列——该仓库正处在 MIT 向 Apache-2.0 的重新许可过程中,实际条款按贡献逐条而定。运行时依赖的许可证若不在宽松清单内即为硬失败:交付 copyleft 是一项分发决策,不该被一次重新生成悄悄吸收。被源码收编的包会与 `vendor/README.md` 交叉核对,出现非 MIT 即报错;`pnpm-workspace.yaml` 的 `patchedDependencies` 列入运行时表格,因为 pnpm 在安装期就会打上这些补丁——交付产物携带的是改动过的 `@earendil-works/pi-tui` 与 `node-pty`,补丁文件本身就是改动的完整记录。
|
||||
|
||||
**被已发布产物带上的包,无论由哪个区段声明都算 runtime。** 浏览器侧是构建出来的,不是解析出来的:tsdown 把每个非平台 specifier 内联进插件的 `lib/client.js`,Vite 把 shell 的 import 内联进 `@deepseek-ai/dsh-web-frontend` 的 `dist`。因此这些包声明在 `devDependencies`——落位规则归 [客户端构建期依赖那篇](../../proposed/process/2026-08-14-client-build-time-deps.md)——但它们各自都有一份副本被分发出去,所以 react、shiki、katex 与整条 markdown 管线必须留在 runtime 档。到底是哪些包,由 [`scripts/browser-bundled-externals.ts`](../../../../scripts/browser-bundled-externals.ts) 从构建本身取答案:它用各包自己的 `tsdown.config.ts` 驱动每个 client bundle,用 `apps/web` 的 Vite 配置驱动 shell,挂一个记录用插件把每个 bare specifier 解析成 external 并记下来。这一趟只走本仓自己的源码、到包边界即停,约三秒,且给出的正是本文件披露的「直接依赖」粒度。一个 specifier 只有在宿主把它解析到某个包内的文件之后才被计入,所以打包器自己的虚拟模块不会被误当成随产物分发的包:`vite/modulepreload-polyfill` 由 Vite 插件生成而非作为文件发布,因此 `dist` 里那段 polyfill 与 TypeScript 生成的辅助代码同类,属于构建胶水。用真配置而不是一张人工名单,白拿两个手写名单没有的性质:被擦除的类型 import 永远不会出现,因为 transform 在解析前就删了它;某个包最后一处浏览器 import 消失时,它也立刻不再被披露成随产物分发。workspace 名字只在 Vite 那侧继续走,因为 shell 的 alias 会把它们映射到源码——浏览器库包自己的 import,比如 `ui-primitives` 的 katex 与 shiki,正是这样才可见的。 只发布类型声明的包一律算 development-only,无论哪个已发布包具名了它:它不贡献任何被分发的代码,而 dry-run 本来也看不见被擦除的类型 import——transform 在解析前就删了它。`@types/mdast` 与 `micromark-util-types` 正是因此落到该档。
|
||||
|
||||
项目所有者另行授权分发每个官方 `@anthropic-ai/claude-agent-sdk` 版本,以及该版本通过 `optionalDependencies` 声明的官方 Claude Code CLI 与平台载荷。生成器将其表示为一项精确匹配直接包身份的例外,而非宽松许可证覆盖项:`SEE LICENSE IN README.md` 与 `SEE LICENSE IN LICENSE.md` 仍归类为非宽松,所有无关的非宽松运行时依赖仍以默认拒绝方式失败。存在该 SDK 时,生成器会读取其已安装 manifest,拒绝不符合官方 SDK 载荷前缀的可选包身份,推导当前 SDK、CLI 与载荷版本,核验已安装宿主载荷的身份、版本和声明许可证字段,并在单独的声明章节中渲染 SDK 声明的完整载荷集合。版本、声明许可证和载荷集合发生变化时无需新的身份授权,但仍须经过常规的依赖、锁文件、兼容性、条款和声明评审。
|
||||
|
||||
## 测试
|
||||
@@ -52,7 +54,7 @@ Claude 分发测试证明:只有精确匹配的直接 SDK 身份会绕过通
|
||||
|
||||
## 后果
|
||||
|
||||
此后改动依赖时,重新生成的披露文件会随同一个提交入库。触及 manifest 的提交多付一次生成器运行——约一秒;其余提交不受影响。若禁用钩子提交,代价推迟为一次测试 lane 失败,其报错会指明补救命令。
|
||||
此后改动依赖时,重新生成的披露文件会随同一个提交入库。触及 manifest 的提交多付一次生成器运行;其余提交不受影响。这次运行从约一秒变成几秒,因为要弄清浏览器产物带了什么就得驱动真实的 client 与 shell 打包器;因此客户端源码坏掉会让这个 hook 失败,而暂存区的 lint job 本来也会失败。若禁用钩子提交,代价推迟为一次测试 lane 失败,其报错会指明补救命令。
|
||||
|
||||
生成器需要已安装的依赖树,因此比纯源码生成器更重;发布元数据不可用的新包需要补一条 `OVERRIDES`,而不是默默渲染出空白许可证。这两类失败都会明确报错并指出补救方式。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user