feat: 尝试迁移 PHP 插件沉入基础设施到 Rust Core——Part3 - #1006
xiaoyumuxi wants to merge 6 commits into
Conversation
Download and manage the PHP plugin and its Intelephense runtime through Plugin Management, while keeping LSP controls project-scoped. Publish signed macOS plugin archives and validate plugin-owned language-server resources. Closes #922
xiaoyumuxi
left a comment
There was a problem hiding this comment.
重点检查了 Rust Core 的 plugin manifest/language-server 校验、lifecycle reducer、dispatcher 接线,以及 macOS package-store 通过 RustCoreBridge 复用校验的路径。Core 对版本、模块归属、HTTPS/source、SHA-256 和相对路径约束是闭合的,lifecycle 目前保持无状态 reducer 也和本 PR 的阶段说明一致;专项/全量 CI 均通过,没有在 Part3 新增的 Core 迁移里发现额外阻断项。不过这个分支同时携带了 Part1 的 publisher-signing 构建逻辑,因此 #1004 中的 debug 包不可安装问题在这里同样存在,见 inline comment;后续从 Part1 修复/rebase 时需要一并带过来。另外当前 PR 有合并冲突,合入前需要更新分支。
| exit 1 | ||
| fi | ||
| print -u2 -- "Skipping publisher signature for debug plugin package $package_id" | ||
| continue |
There was a problem hiding this comment.
这个分支继承了 #1004 的同一问题:debug 构建在没有 publisher 私钥时仍会成功产出未签名 PHP 包,但 manifest 要求 publisherPackage,所以真实 package-store 安装/扫描会拒绝它。Part1 修复这里后请 rebase/同步到当前分支,避免 Part3 单独合入时重新带回这个问题。
1lck
left a comment
There was a problem hiding this comment.
Review 结论
⛔ 存在阻塞问题
Findings
[P1] 内置 Go Support 插件启动时会被拒绝加载
位置: macos/Sources/Lithe/Platform/MacOS/Plugins/MacPluginLanguageServerPackageValidator.swift:78-83
实际影响:
- 校验入口原来写的是
pluginManifest.id == OfficialPluginCatalog.phpPluginID,现在改成"只要有语言能力声明了languageServerModuleID就必须有language-server.json"。 - Go Support 随 app 一起打包在
Contents/Resources/OfficialPlugins/dev.lithe.plugin.go-support。它的plugin.json:71声明了languageServerModuleID,但包里没有language-server.json(scripts/build-official-plugins.sh:96只给 php-support 复制这个文件)。 - 结果是
scanBundledPlugins抛出missingManifest,Go 插件只会被记成一条 scan issue。Go 的运行、测试和 gopls LSP 模块全部不再注册,所有 macOS 用户都会失去内置 Go 支持。
触发条件: 用 scripts/package-app.sh 或 scripts/preview.sh 构建的任意 app 正常启动。
为什么 CI 没发现: PluginPackageStoreTests.swift:562 新增的 fixture 逻辑会自动给带 languageServerModuleID 的测试包写入 language-server.json,让测试顺着新规则走,盖住了真实 Go 包的形态。verify-macos-package.sh 只检查 manifest 是否存在,不会走 store 扫描。
修复建议: 二选一
- 让 Go 插件的 manifest 能明确声明 LSP 来自系统或工具链,Validator 只在包里存在
language-server.json,或 manifest 明确声明"包内自带 LSP"时才强制校验。 - 先合入 #1003 的
toolchain.json提前返回分支,并在冲突解决时保持它排在 LSP 检查之前。
同时补一个测试:用真实的 Plugins/mac/Official/GoSupport/plugin.json 构造 bundled 包,断言 scanInstalledPlugins 没有 issue。不要只依赖会自动补齐 language-server.json 的 fixture。
[P2] 真实 PHPUnit 集成测试缺依赖时会悄悄通过,平台矩阵却改成了"已验证"
位置: macos/Tests/LitheTests/RealPhpIntegrationTests.swift:260-263;shared/platform-feature-matrix.json:2733 的 php-run-test 条目
实际影响:
- 原来在显式设置
LITHE_RUN_PHP_INTEGRATION=1后,测试会先用#expect和#require检查依赖,缺依赖就明确失败。 - 本 PR 删掉了
#expect,把#require改成guard ... else { return }。现在即使显式开启了真实集成测试,缺composer install或缺php也会显示通过。 - 同一提交把
php-run-test的 macOSverificationStatus从pending改成verified,证据就是这个测试。仓库的 workflow 和脚本里没有任何地方设置LITHE_RUN_PHP_INTEGRATION,所以 CI 通过不能作为运行证据。 - 这违反了 write-stable-tests 中"不得弱化断言来让门禁通过"的规则,也违反了 develop-lithe 中"只有目标平台验证流程实际完成才能标 verified"的规则。
修复建议: 在 LITHE_RUN_PHP_INTEGRATION=1 时恢复 #expect/#require。如果 CI 没有这条测试通道,php-run-test 的 verificationStatus 退回 pending,或者在 PR 中附上实际运行记录。
[P2] 新矩阵条目把还没接入的生命周期 reducer 标成了 macOS"已实现/已验证"
位置: shared/platform-feature-matrix.json:3000(rust-core-plugin-contract)
实际影响:
- 这个能力的描述包含"约束插件资源生命周期"。但 macOS 和 Windows 都没有任何调用方使用
plugin.lifecycle,全仓 grep 只找到 Validator 调用的两个validate*命令。 - Agent Note 自己也写了"Rust reducer 仍是无状态 JSON 契约,尚未替换 macOS/Windows 的完整 package store 和 session registry"。
- 列出的证据
RealPhpIntegrationTests走的是ModuleRuntime.setEnabled,并不经过这个 reducer。
修复建议: macOS 改为 partial/pending,或者把这一行拆成"清单校验"(可以标 implemented)和"生命周期资源约束"(pending)两行。
[P3] 语言服务器清单新增的 launcherRelativePath/arguments 只被校验,运行时没有使用
位置: Plugins/mac/Official/PhpSupport/language-server.json:11-12;MacPluginLanguageServerPackageValidator.swift:125
实际影响:
- Validator 按
LanguageServers/<languageID>/<launcherRelativePath>检查启动器。 - 运行时发现仍然写死在
MacRuntimeToolDiscovery.swift:55-58(command == "intelephense",路径是bin/intelephense)。启动参数仍然写死在PhpLanguageServerCapability.swift:10(["--stdio"])。 - 所以 Rust 契约文档里写的"manifest 携带启动路径和参数",在运行时形成了第二个真源。以后只改清单的话,校验能通过,启动却会失败。
修复建议: 二选一
- 让
MacRuntimeToolDiscovery和 PHP capability 从已校验的清单读取启动路径和参数。 - 或者在本阶段把这两个字段从契约中去掉,或在 Note 里明确写成"保留、未消费"。
[P3] PhpSupportManifest.plugin 是没有被引用的第三份 PHP 插件清单
位置: Plugins/mac/Official/PhpSupport/Sources/LithePhpSupportModule/Support/PhpSupportManifest.swift:45
实际影响:
- PHP 插件清单现在有三份:
plugin.json、宿主的OfficialPluginCatalog(BuiltInModuleCatalog.swift:270起,仍然存在),以及这份PhpSupportManifest.plugin。 LitheOfficialPluginVerifier只比较plugin.json和OfficialPluginCatalog,以及模块 factory 和plugin.json.modules。PhpSupportManifest.plugin没有任何引用,也没有测试约束,以后会悄悄漂移。- PR 描述说"manifest 归属到插件目录",但宿主 catalog 里那份并没有删除。
修复建议: 删掉没用到的 PhpSupportManifest.plugin,或者加一个测试,断言它等于解码后的 plugin.json,也等于 OfficialPluginCatalog 中的 PHP 条目。
与 #1004 / #1003 的依赖关系
- 依赖 #1004,而且完整包含了它:本 PR 的前 5 个提交就是 #1004 的全部内容。合入 #1006 等于同时合入 #1004。建议先合 #1004,或者合 #1006 后关闭 #1004,避免重复审查。
- 不依赖 #1003:#1003 的提交不在本 PR 中,#1006 可以在 git 层面单独合入 preview。但单独合入会触发 Finding 1 的 Go 回归。#1003 给 Validator 加的
toolchain.json提前返回分支正好能绕开这个问题,所以两者在功能上是耦合的。 - 和 #1003 的冲突:
git merge-tree显示 4 个文件冲突(Validator、language-plugin-tooling-requirements.md、ci-builds.md、矩阵文档),另有 5 个文件能自动合并。
Summary
Rust Core 的校验和 reducer 本身结构清晰,确定性好,有 overflow 保护和资源阻塞测试,注释符合规范。主要问题是 Swift 侧把"按 PHP ID 判断"放宽成"按 languageServerModuleID 判断"时,没有考虑使用系统 LSP 的内置 Go 插件,形成发布级回归。测试 fixture 跟着新规则调整,把问题盖住了。
验证信息被夸大:矩阵和集成测试的验证状态写得比实际证据强。
CI 全部通过,但签名包下载、解压后在真实 Release 安装路径上的端到端安装没有实测。
概要
将 PHP/macOS 语言插件作为 Rust Core 插件契约迁移的首个完整切片,基于 #1004 的插件分发与生命周期基础。
改动
验证
范围说明
本 PR 只完成 PHP/macOS 迁移切片;Windows、Go 及全部 package store/session registry 的全量迁移仍按文档后续阶段进行。
verify-service-boundaries.sh 和 verify-core.sh 仍报告已有基线问题:AppModel extension 为 616 行,与本 PR 改动无关。