fix(review): 按独立 review 结论修正 PR C 的注释、文档与用例保真度
独立 review(对照606339f/4099700静态复核 + 日志逐行核对)提出的问题,逐条修正: 1. **补回被我自己抹掉的源码注释**:上次验证「未修复代码上 4/4 红」时用了 `git checkout606339f-- src/client/native/index.ts`,随后 `git checkout HEAD -- <同一文件>` 把**尚未提交**的 `disposeSafely` 注释一起还原掉了 —— PR 描述里承诺的 「说明释放失败为何只走 console.error」因此在 diff 里根本不存在。已重新落盘。 2. **事故文档三处事实修正**:同一毫秒的 `already registered` 是 **7 条**(.339 一条 + .340 六条,合计 burst 9 条),不是 6;验证段的「114 files / 1136 passed」是修复分支 (base 早于 #781)的数字,补上口径并给出合入 main 后的 122/1292;`index.ts:353` 标注 为 v0.22.0 行号(main 上因 #777 顺移)。 3. **撤回一处措辞过头**:「部分回滚分支从未被执行」→ 回收集合虽然进了、但 disposer 列表恒为空(释放动作未执行),改后能真正覆盖。 4. **e2e 门不再可能静默通过**:`test.skip(CLIENT_JS === undefined, …)` 改成硬失败—— 这个门的价值就在于 harness 以后不再导出 DSH_HOME 时必须报错而不是变成 skip。 同时把「无 `[data-sidebar-right-unavailable]`」移到文件渲染断言**之后**(前者在空 pane 上恒真,不是真空但也没重量)。 5. **测试替身补齐保真度**:假注册表的 disposer 改为幂等(真宿主的 disposer 是幂等的 ——cordis effect 二次释放返回同一个 task),避免「二次 release 又被记一笔」这种与 真实宿主不一致的行为被后续用例当成事实。 6. **AGENTS §2 的 HMR 机制加版本限定**:`mtime/ctime/size` 的 sha1 rev 是**钉住的宿主 0.1.7-rc.1** 的行为;DSH 源码树新版本改成只比 `mtime+size` 并对内容取 sha1,pin 上调 时该触发器必须同步复核(否则会红在替换断言上,而不是静默失效)。 验证:typecheck / lint 通过;pnpm test 122 files / 1292 passed / 9 skipped(重启前机器上有 两个 scratch dsh 服务时的 fs-watch 超时是负载抖动,单独跑 5/5 绿、清空负载后全量绿)。
This commit is contained in:
@@ -65,7 +65,11 @@ test.afterAll(async () => {
|
||||
})
|
||||
|
||||
test('the native tab types survive an in-page client entry replacement', async ({ page }) => {
|
||||
test.skip(CLIENT_JS === undefined, 'set DSH_HOME or DSH_E2E_PLUGIN_CLIENT_JS to locate the installed bundle')
|
||||
// A hard failure, not a skip: this gate's whole value is that it cannot
|
||||
// pass quietly when the harness stops telling us where the bundle lives.
|
||||
if (CLIENT_JS === undefined) {
|
||||
throw new Error('DSH_HOME (or DSH_E2E_PLUGIN_CLIENT_JS) must point at the profile running this server')
|
||||
}
|
||||
const consoleErrors: string[] = []
|
||||
page.on('console', (message) => {
|
||||
if (message.type() === 'error') consoleErrors.push(message.text())
|
||||
@@ -145,6 +149,12 @@ test('the native tab types survive an in-page client entry replacement', async (
|
||||
const filesEntry = page.locator('[data-sidebar-right-guide-entry="files"]')
|
||||
await expect(filesEntry, 'the Files guide row must be offered again').toHaveCount(1, { timeout: 30_000 })
|
||||
await filesEntry.click()
|
||||
await expect(pane.locator('[data-sidebar-right-unavailable]')).toHaveCount(0)
|
||||
// The explorer must really render again — assert the CONTENT first (a bare
|
||||
// "no unavailable marker" check passes on an empty pane), then the host's
|
||||
// "a kind with no registrant" fallback must be absent.
|
||||
await expect(pane.locator(`[role="button"][title$="${SEEDED_FILE}"]:visible`)).toHaveCount(1, { timeout: 30_000 })
|
||||
await expect(
|
||||
pane.locator('[data-sidebar-right-unavailable]'),
|
||||
'the host must not fall back to its "nothing can view this kind" face',
|
||||
).toHaveCount(0)
|
||||
})
|
||||
|
||||
@@ -51,8 +51,14 @@ function createRegistry() {
|
||||
throw new Error(`sidebarRight: tab type id "${definition.id}" is already registered`)
|
||||
}
|
||||
events.push(`register ${definition.id}`)
|
||||
// The host's disposer is IDEMPOTENT (a cordis effect disposer returns
|
||||
// the same task on a second call), so a repeated release must neither
|
||||
// log again nor pretend to free something twice.
|
||||
let released = false
|
||||
const dispose = (): void => {
|
||||
if (released) return
|
||||
if (failReleaseOf === definition.id) throw new Error(`cannot release ${definition.id}`)
|
||||
released = true
|
||||
registered.delete(definition.id)
|
||||
events.push(`release ${definition.id}`)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user