Files
HomeAgent/internal/kernelmod/all
JianFeeeee 8cc8bca380 test(kernel): 架构防腐判据 + 修 migrateEntry 的并发缺陷
## 判据(internal/kernelmod/all/layering_test.go)

六条,全部经变异验证:

  TestCoreDoesNotImportKernelboot        core 不依赖装配引擎
  TestPluginDoesNotImportKernelboot      plugin 不依赖装配引擎
  TestSdkDoesNotImportKernelboot         sdk 不依赖装配引擎
  TestSecurityDoesNotImportKernelboot    security 不依赖装配引擎
  TestKstateDoesNotDependOnCore          kstate 不依赖 core("core 能读挂载点"的另一面)
  TestSecuritySingletonGuardStillExists  单例判据文件不得被删
  TestAgentHasNoPromptSectionsField      Agent 不得再持有提示词段字段
  TestPluginSettersAreInjection          防过度收敛:plugin 不得读 kstate
  TestPromptSectionsOnlyFromKstate       内核只从挂载点读插件段

用 `go list -deps` 而不是源码扫描:传递依赖能抓到间接环。

## 为什么需要"防过度收敛"这一条

kernelplan v1 曾主张把 plugin 的 12 个 SetXxx 改成"读 kstate"。实测做不到:

    kstate.State.PluginRegistry 的类型是 *plugin.Registry
    ⇒ kstate 依赖 plugin
    ⇒ plugin import kstate 就是 import cycle(已用探针实证)

更重要的是——它们**本来就不是缺陷**:每个 Setter 只有一个调用点,
调用方持有 ks、显式传参;少了任何一个插件拿 nil 立刻报错,
不存在"静默降级"(那才是包级单例的病症)。

TestPluginSettersAreInjection 防的是后来者看到一堆 Setter 就想合并成
全局注册表,那会把"显式注入"退化成"隐式全局"。

## 顺带修一个真缺陷

migrateEntry 在**解锁之后**调 saveLocked()。而 saveLocked 遍历 s.data
序列化 —— 解锁后再调就是在读一个可能被并发改写的 map:

  · data race(-race 可复现)
  · 可能写出半更新的快照(部分条目是新密文、部分是旧密文)

函数名里的 Locked 就是要求"调用方已持锁"。改为持锁期内调用。
判据:go test ./internal/security/ -race 全绿。

## 验证

  go build ./...              PASS
  go vet ./...                PASS
  gofmt -l                    干净
  go test ./... -count=1      63 包全过,0 FAIL
  go test ./internal/security/ -race   PASS
  干净检出(git worktree)     build + 判据全绿

## kernelplan.md 同步

T5 标记为"计划错误,已撤销",并记录实测依据 —— 避免下次又有人
想"顺手收敛掉"这十几个 Setter。
2026-11-04 12:28:43 +08:00
..