Repository navigation
runtime /packages domain 持久化不对称:enable/disable/uninstall 直写 in-memory registry,install/update 却走 protocol service 落 sys_packages #5047
Description
Activity
xuyushun441-sys commented
on Aug 4, 2026 CollaboratorAuthorMore actions核实完成 —— 原前提不成立,但挖出一个更窄的真 bug;本单改定性并收窄派发
只读核实(全部证据带 file:line,以 origin/main 为准)推翻了正文的"enable/disable 只写内存":
持久化存在,且是刻意设计:
packages/runtime/src/package-state-store.ts:70-77把 disabled 集合写进<OS_HOME>/package-state/<environmentId>.json,文件头 rationale 明写"intentionally a flat file rather than a sys_* object: package lifecycle state is runtime/operational state, not project metadata"。boot 回灌路径也存在且时序自洽:app-plugin.ts:226-248在 init(Phase 1)seed disabled 集合 →service-package/index.ts:200-253在 start(Phase 2)从sys_packages重放时,registry.installPackage消费它(registry.ts:1602-1608)把包装成 disabled。原文那种"直写内存、重启即失"的定性不成立,不按原文修。真 bug(本单收窄为它):empty-env 早退跳过 disabled seed
app-plugin.ts:196-201—— bundle 无 app 载荷时init提前 return,而 disabled seed 块(:226-248)在早退之后。empty env 恰恰是"包只来自 sys_packages / HTTP 安装"的场景(hydration 自己的注释就是这么写的)。后果:纯 DB 驱动的环境里,管理员禁用的包每次重启都复活。修法低风险:把 seed 块提到早退之前 —— 同一函数里
installDefaultHookBodyRunner/wireAuthoredTranslationSync已因同样理由被提前(:177-195 有注释先例)。测试盲区是它没被发现的原因:全仓零测试覆盖package-state-store/setInitialDisabledPackageIds,修复必须补上(含 empty-env 场景的回归测试)。记录为债、本单不修
- 状态跨两种介质(disabled 在 OS_HOME 文件,包在 DB),容器/多副本/临时文件系统下会漂移 —— 那是
package-state-store.tsrationale 的 ADR 级取舍,要改先改 ADR; DELETE /packages/:id双写清理sys_packages(protocol.ts:8429-8440,"so the package cannot resurrect at boot")但不清理 disabled 条目 → 同 id 重装会静默以 disabled 回来;sys_packages无 lifecycle 列(raw-SQL 表,无 spec 定义),统一到 DB 需 schema 变更。
认领(PM 分派,收窄后)
- session:
session_018iARDqtrhQgz6fVHDeDkbQ - 分支:
claude/issue-5047-empty-env-disabled-seed - 车道:cli(落点
packages/runtime/src/app-plugin.ts+ 新测试)
Generated by Claude Code
- 状态跨两种介质(disabled 在 OS_HOME 文件,包在 DB),容器/多副本/临时文件系统下会漂移 —— 那是
- addedbugSomething isn't workingSomething isn't working
on Aug 4, 2026 xuyushun441-sys commented
on Aug 4, 2026 CollaboratorAuthorMore actions审核通过 — PR #5117 已取消草稿并挂上 auto-merge(SQUASH)
修复是最小行序调整,验证是全真件的。 seed 提到 empty-env 早退之前,抽成带文档注释的私有方法,注释对齐同函数两个先例。要害在测试的成色:
- 回归测试跑在真 LiteKernel + 真 ObjectQLPlugin + 真状态文件上,不是 mock 拼装;hydration 断言更进一步 —— 把 empty-env boot 出来的真 registry 交给真的
PackageServicePlugin.start()重放 sys_packages,为此按 service-job 先例加了 devDependency + vitest alias,宁可引真件也不重实现被测对象 —— 重实现的 hydration 验证不了任何事。 - 反向验证钉在正确的钉眼上:行序改回后恰好两条 empty-env 用例红(
enabled: true / status: installed对false / disabled),非 empty 用例保持绿,store 单测独立于行序 —— 红的形状证明测试测的就是这个 bug,不是别的。 - 盲区补齐:
package-state-store从零覆盖到 12 例,含环境 id 路径消毒(../../etc/evil逃不出目录)与坏 JSON 降级为空集 —— 核实报告点名的"为什么没被发现"被正面回答。 - 新增的
getService('objectql')触点在无引擎 kernel 下仍能 boot(case 7 钉住)—— 行序调整没有引入新的启动依赖。
runtime 全量 1150 测试绿(含 #5045 刚接的 typecheck),六道 check 门禁绿。lockfile 仅 devDependency 3 行,OSV 修复已在 main,无红。
三条一致性债照核实结论留档不扩面。dev 另纠了资源纪律文档里的一处错误:
--concurrency应为--workspace-concurrency且置于--filter前 —— 这个坑本会话已有四个 agent 踩过,值得进 skill 修订素材。
Generated by Claude Code
- 回归测试跑在真 LiteKernel + 真 ObjectQLPlugin + 真状态文件上,不是 mock 拼装;hydration 断言更进一步 —— 把 empty-env boot 出来的真 registry 交给真的
- added a commit that references this issue
on Aug 4, 2026 - added a commit that references this issue
on Sep 28, 2026
未认领,待核实定性。 #4311 runtime 片(PR #5045)实施中的观察,修复需改运行时行为、超出该片边界,按 PD#10 立案。
观察(来自
packages/runtime/src/domains/packages.ts的实读)install/updatePackageManifest:优先走 protocol service 持久化到sys_packages,服务缺席时才回落 in-memory;enable/disable/get/uninstall:直接读写 in-memory registry,不经持久化路径。若属实,后果是:enable/disable/uninstall 的状态变更重启即失 —— 管理员禁用一个包,进程重启后它复活。这与 install 路径的语义不一致,像是持久化通道接了一半。
待核实
sys_packages的行里有没有 enabled 字段可承接。核实第 1 条成立即标
bug入队(维护者当前规则:只派 bug)。关联