Browse Source

fix(boot): limit required IDs to application endpoints

turtle1999 1 month ago
parent
commit
7fd41b833b

+ 2 - 2
.agents/notes/implemented/architecture/2026-09-09-consumer-owned-startup-strictness.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/architecture/2026-09-09-consumer-owned-startup-strictness.md
-2026-09-09-consumer-owned-startup-strictness.md: eab57329bc33c6a341d1073275deb4fd2355f041
-2026-09-09-consumer-owned-startup-strictness.zh.md: 687017533d114cd1e13205b50373fc415eb99c2a
+2026-09-09-consumer-owned-startup-strictness.md: dd93e3867452e4456e2d7e1853e01aff66deb881
+2026-09-09-consumer-owned-startup-strictness.zh.md: dfb84c803ead167807897fe18d39f19d00eecac4

+ 1 - 1
.agents/notes/implemented/architecture/2026-09-09-consumer-owned-startup-strictness.md

@@ -12,7 +12,7 @@ Best-effort Loader reconciliation preserves usable plugins, but applications sti
 
 DSH owns startup strictness outside vendored Cordis. App-boot audits the settled initial tree against one global list of stable entry ids. A listed entry that is present, enabled, and not active rejects startup and disposes the application. A listed id that is absent or disabled has no effect. The bootstrap Include is required by entry identity because a missing or invalid root configuration prevents application assembly. Other inactive entries produce one warning and leave successful siblings running.
 
-The required ids are `agent-loop`, `webserver`, `modules`, `connection`, `headless-runner`, `acp`, and `sdk-jsonrpc-server`. They represent shared Agent execution and the endpoints of the shipped Web, headless, ACP, and SDK applications. Their injected providers do not need separate list entries: a missing provider leaves the listed endpoint pending or failed.
+The required ids are `agent-loop`, `webserver`, `headless-runner`, `acp`, and `sdk-jsonrpc-server`. They represent shared Agent execution and the endpoints of the shipped Web, headless, ACP, and SDK applications. Their injected providers do not need separate list entries: a missing provider leaves the listed endpoint pending or failed.
 
 The audit runs only during initial application boot. Later config HMR remains best effort and keeps the failed candidate visible for repair.
 

+ 1 - 1
.agents/notes/implemented/architecture/2026-09-09-consumer-owned-startup-strictness.zh.md

@@ -12,7 +12,7 @@ Best-effort Loader reconcile 会保留可用 plugin,但应用仍需一组最
 
 DSH 在 vendored Cordis 之外持有启动严格语义。App-boot 用一份全局稳定 entry id list 审计已结算的初始 tree。List 中存在、启用且未 active 的 entry 会使启动 reject,并拆卸应用。List 中缺失或禁用的 id 不产生影响。Bootstrap Include 按 entry 身份被视为 required,因为根配置缺失或无效会阻止应用组装。其他 inactive entry 输出一次 warning,并让成功 sibling 继续运行。
 
-Required id 为 `agent-loop`、`webserver`、`modules`、`connection`、`headless-runner`、`acp` 和 `sdk-jsonrpc-server`。它们分别代表共享 Agent 执行,以及随附 Web、headless、ACP 和 SDK 应用的 endpoint。其 injected provider 不需要单列:provider 缺失会让已列出的 endpoint 保持 pending 或失败。
+Required id 为 `agent-loop`、`webserver`、`headless-runner`、`acp` 和 `sdk-jsonrpc-server`。它们分别代表共享 Agent 执行,以及随附 Web、headless、ACP 和 SDK 应用的 endpoint。其 injected provider 不需要单列:provider 缺失会让已列出的 endpoint 保持 pending 或失败。
 
 该审计只在应用首次启动时运行。之后的 config HMR 仍采用 best effort,并保留 failed candidate 供后续修复。
 

+ 2 - 2
packages/boot/app-boot/README.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 packages/boot/app-boot/README.md
-README.md: 28d6cfd622947378367da59b1e6a897c8f9f2664
-README.zh.md: 593e3105bf50a3a04cf70a0df97e8f347081701b
+README.md: 55689d496dcd1610ba45c0fc6140296968652410
+README.zh.md: 7d320a045d16571576340e5238a1372f4ec6f4ba

+ 1 - 1
packages/boot/app-boot/README.md

@@ -40,7 +40,7 @@ installFailLoud('dsh')
 const ctx = await boot('dsh', resolveConfigPath(argv[2], process.env.DSH_SNAPSHOT))
 ```
 
-With that entry point, startup keeps every plugin that can activate. An enabled failed plugin produces a labelled warning. A failed required entry makes startup dispose the whole app and exit nonzero; required ids absent from a profile and disabled required entries do not affect startup. The global required list covers shared Agent execution and each application's endpoint: `agent-loop`, `webserver`, `modules`, `connection`, `headless-runner`, `acp`, and `sdk-jsonrpc-server`.
+With that entry point, startup keeps every plugin that can activate. An enabled failed plugin produces a labelled warning. A failed required entry makes startup dispose the whole app and exit nonzero; required ids absent from a profile and disabled required entries do not affect startup. The global required list covers shared Agent execution and each application's endpoint: `agent-loop`, `webserver`, `headless-runner`, `acp`, and `sdk-jsonrpc-server`.
 
 <a id="profiles"></a>
 ### Profiles

+ 1 - 1
packages/boot/app-boot/README.zh.md

@@ -40,7 +40,7 @@ installFailLoud('dsh')
 const ctx = await boot('dsh', resolveConfigPath(argv[2], process.env.DSH_SNAPSHOT))
 ```
 
-有了这个入口,启动会保留所有能够激活的插件。启用但失败的插件会产生带标签的警告。required entry 失败时,启动会拆卸整个应用并以非零码退出;profile 中不存在的 required id 和已禁用的 required entry 不影响启动。全局 required list 覆盖共享 Agent 执行与各应用的 endpoint:`agent-loop`、`webserver`、`modules`、`connection`、`headless-runner`、`acp` 和 `sdk-jsonrpc-server`。
+有了这个入口,启动会保留所有能够激活的插件。启用但失败的插件会产生带标签的警告。required entry 失败时,启动会拆卸整个应用并以非零码退出;profile 中不存在的 required id 和已禁用的 required entry 不影响启动。全局 required list 覆盖共享 Agent 执行与各应用的 endpoint:`agent-loop`、`webserver`、`headless-runner`、`acp` 和 `sdk-jsonrpc-server`。
 
 <a id="profiles"></a>
 ### Profile

+ 0 - 2
packages/boot/app-boot/src/index.ts

@@ -703,8 +703,6 @@ const FIBER_FAILED = 3 as FiberState.FAILED
 export const REQUIRED_STARTUP_ENTRY_IDS: readonly string[] = Object.freeze([
   'agent-loop',
   'webserver',
-  'modules',
-  'connection',
   'headless-runner',
   'acp',
   'sdk-jsonrpc-server',

+ 3 - 5
packages/boot/app-boot/tests/app-boot.spec.ts

@@ -537,8 +537,6 @@ describe('auditStartupEntries', () => {
     expect(REQUIRED_STARTUP_ENTRY_IDS).toEqual([
       'agent-loop',
       'webserver',
-      'modules',
-      'connection',
       'headless-runner',
       'acp',
       'sdk-jsonrpc-server',
@@ -667,10 +665,10 @@ describe('auditStartupEntries', () => {
 
   it('rejects a required entry pending on an injected service', async () => {
     await expect(auditStartupEntries(ctxWith([{
-      fiber: fiber(0, undefined, { webRuntime: {} }),
-      options: { id: 'connection', name: '@deepseek-ai/dsh-client-connection' },
+      fiber: fiber(0, undefined, { headlessStartup: {} }),
+      options: { id: 'headless-runner', name: '@deepseek-ai/dsh-headless' },
     }]), NAME, vi.fn())).rejects.toThrow(
-      'connection (@deepseek-ai/dsh-client-connection): pending (waiting for service: webRuntime)',
+      'headless-runner (@deepseek-ai/dsh-headless): pending (waiting for service: headlessStartup)',
     )
   })
 })