chore: work the tracker items that need no cluster #19

Merged
FLYEMOJ1 merged 10 commits from chore/issue-sweep into main 2026-07-29 01:52:15 +09:00
FLYEMOJ1 commented 2026-07-28 18:07:48 +09:00 (Migrated from github.com)

十条 commit,全部取自 tracker 里不需要集群、不需要 harness、也不碰 panel/ 的条目。每条 commit 自己的正文写清了改了什么、为什么、以及验证方式;这里只讲它对应哪条 issue,以及哪几条只做了一半——那几条用 Refs 而不是 Closes,不靠合并把它们静默关掉。

随合并关闭

commit issue
4177694 + 584d31f + 503240d #7 push/PR CI(go vet / go test / panel vitest / typecheck,外加一个 shell 作业)
afdbfac #18 docs/deferred-seams.md,把 34 处 INTEGRATION-ONLY / KNOWN-LIMITATION 按「待接 / 有意不做 / 已完成」分桶

Closes #7
Closes #18

#7 的验收条件是「开一个 PR,能看到 Go 测试和 panel 测试各自跑起来并报状态」——本 PR 自身就是那次演示,下面的 checks 就是证据。

503240d 是这条自己的返工:ci.yml 开头写着「不重复 release.yml,因为私有仓要为一个答案付两次钱」,而它交付的触发器 branches: ['**'] 加 pull_request 正好做了这件事。并发组的键是 github.ref,refs/heads/chore/issue-sweep 和 refs/pull/19/merge 不是同一个,所以互相不取消。证据就在这个 PR 前几次的 checks 里:go 3m14s 和 go 3m3s、shell 7s 和 7s、panel 25s 和 24s。改成 branches: [main] 后,合并前有 PR 这道闸、合并后有 main 那道闸,掉的只有重复的那份;唯一失去覆盖的情形是「推了分支但还没开 PR」,那时候还没有人问这个问题。

已关闭 issue 的代码落地

这三条在 2026-07-28 已经按「sha + 验收实测」的评论关掉了,代码到这个 PR 才上远端:

commit issue
71e1664 #5 .gitattributes 钉 LF;bootstrap_asset.go 是逐字 embed 再 bash -s 管进目标机的,带 CR 的 shebang 和 heredoc 终止符在 Linux 上直接坏
3af5cc3 #6 runbook §11/§12 把四个有人读的字段写成 INERT,其中 §11 把一个配置问题误诊成未实现的功能
82a1275 #14 插件表声称产出三个 loader mod jar,一次安装实际一个都没有

只做了一半,不当结题

Refs #15 — 4f5014d 把 legacy-forwarding 后端列表从写死的 "legacy18" 变成 FELIS_LEGACY_FORWARDING_SERVERS。但 #15 的验收是「给 CR 打标记后列表自动收敛」,这条没做:转发判定在 fork 对 Velocity core 的 patch 里,不在 Felis 插件里,core 要读插件持有的动态后端注册表,那座桥不存在。它是一个 JVM system property,进程启动时读一次,改了仍要重启。

Refs #10 — 23792d6 选了「移除」而不是「实现」。字段过 CRD 校验、随 CRD 发布、零 controller 读取;设 true 描述的是本来就会发生的事,设 false 读起来像「请删掉这个世界」却被静默忽略。但这偏离了冻结的 Felis-Spec-V4.1.md §5(那里要求 finalizer + 按 retainOnDelete 处理 PVC)。偏离记在 docs/troubleshooting.md §13,冻结文档没动。要恢复 spec 那条,就得加一个 finalizer——它列出的另外三件事 ownerReference GC 已经在做,唯一新增的动作是删世界,而且不经过 reaper 的「先证明有备份」检查。这条需要你拍板,所以没有用 Closes。

附带修正:#10 的正文原先误贴了 #9(per-credential UV)的内容,标题一直是对的。已经在这个 PR 之外单独改正。

Refs #16 — 4e5a809 的方向和 issue 相反。issue 说「env seam 已就位,加个 flag 接出来即可」,这个前提是错的:Go 里没有任何地方读写 FELIS_INSTALL_MODE,那是 bootstrap.sh 自己消费的 shell 变量。felis setup 不做选择性安装,它是跑完整 bootstrap TUI 重装主机。所以 --nano 只能是两种东西之一——重跑安装器(等于现在就有的),或把整机拆成 nano(那是卸载,不是 flag)。commit 删掉了 nano.go 里那句不成立的承诺并写明为什么不加。建议关成 wontfix,但那是你的决定。

Refs MliroLirrorsIngenuity/Felis-Legacy#19 — 584d31f 建了 FELIS_VELOCITY_FORK_JAR 的摘要闸门。这个变量装的是所有玩家连接经过的那个代理,之前唯一的检查是路径指向可读文件。现在没有 FELIS_VELOCITY_FORK_JAR_SHA256 就拒装,对不上也拒装。issue 的另一半——摘要来自一次在第二台机器上复现出来的构建——没有交付,脚本里因此不写死任何常量:fork 只在一台机器上构建过,写死等于钉住那台机器的输出。同时删掉了原注释里那句 "is not byte-reproducible",因为证据不支持这么确定的说法(三个 fl004 jar 的条目时间戳全是 Gradle 的常量 1980-02-01,jar 不可复现最常见的来源已经不存在),但没有反过来断言它可复现。

交付前抓到的两个假绿

摘要大小写。 闸门的测试原先只把 sha256sum 自己的输出喂回去,永远发现不了操作者实际会敲什么。同一个文件实测:sha256sum → f5f8eeae…,Get-FileHash → F5F8EEAE…,certutil → f5f8eeae…。同一个哈希,原来的比较会拒绝正确的 jar 并把它报成 checksum mismatch。fork 的构建机通常就是 Windows。现在比较前归一化大小写和空格,测试补了这两格。

CI 的 sh -n。 本机 sh 就是 bash,一刀切 sh -n 五个脚本全过。runner 的 sh 是 dash。没有用近似——直接在 ubuntu:24.04(/bin/sh -> /usr/bin/dash)里跑真的:

--- shebang 分派(本 PR 的写法)---
ok bash  deploy/bootstrap.sh          ok sh    deploy/lobby/entrypoint.sh
ok bash  deploy/demo-up.sh            ok sh    deploy/paper/entrypoint.sh
ok sh    deploy/limbo/entrypoint.sh   ok sh    deploy/bootstrap_test.sh

--- 反例:一刀切 sh -n ---
deploy/bootstrap.sh: 191: Syntax error: "(" unexpected

deploy/bootstrap_test.sh 在真 dash 下 7 条全 PASS。它用 awk 从 bootstrap.sh 里抽取被测块再跑,而不是抄一份——抄的那份在原文被改之后会永远绿。抽取加了长度上限:awk 的结束模式不匹配就一路跑到 EOF,会把 bootstrap.sh 剩下的部分喂给被测 shell。

一条范围外的发现,已立 #20

不设 FELIS_VELOCITY_FORK_JAR 时(也就是默认安装路径),install_velocity 直接 curl -fsSL 下 stock Velocity,零校验。而摘要就在手里:Fill v3 返回 checksums.sha256,下载 URL 本身就是按这个值内容寻址的(实测 fill-data.papermc.io/v1/objects/b4e3164d…/velocity-3.5.1-615.jar,摘要在响应里出现两次),papermc_latest_jar grep 出 URL 之后把它丢了。合并后会变成「opt-in 路径有校验、默认路径没有」。

写 issue 时才发现比这更大:papermc_latest_jar 有两个调用者,Paper 那条(resolve_game_jars:1224 → deploy/lobby/Dockerfile:63、deploy/paper/Dockerfile:39)同样把摘要丢掉。不在 #19 范围内所以没动,立成 #20。

验证

  • go vet ./... / go test ./... — 24 个包,0 失败(Linux)
  • npm test(8 文件 111 断言)/ npm run typecheck
  • deploy/bootstrap_test.sh 在真 dash 下 ALL PASS
  • git ls-files --eol — 三个改动文件全部 i/lf w/lf
  • .github/workflows/ci.yml 用仓库自己的 sigs.k8s.io/yaml 解析验证:触发器是 {"pull_request":null,"push":{"branches":["main"]}},三个作业 go / panel / shell 都在。留个坑给下一个解析 workflow 的人:YAML 1.1 把裸键 on 读成布尔 true,转 JSON 之后键名就是字符串 "true",写 json:"on" 的 struct tag 会静默匹配不上——第一次检查就是这么返回空的。GitHub 自己的解析器没这个问题,本地检查有
  • 所有 commit 均已签名——git log origin/main..HEAD --format='%h %G? %s' 十条全是 G,不是抽查一条

合并方式:请用 merge commit,不要 squash

这个分支上有 11 条 issue 是按「sha + 验收实测」的评论关掉的,评论里直接写着 71e1664、479cba4、2842af6、00673cb 这些短 sha。squash 和 rebase 都会重写它们,重写之后 git log main 找不到任何一条,当初开这些 issue 要的可追溯性正好断在合并按钮上。两个仓都开着 merge commit,选它就行。

panel/ 一个字节没动。

十条 commit,全部取自 tracker 里**不需要集群、不需要 harness、也不碰 `panel/`** 的条目。每条 commit 自己的正文写清了改了什么、为什么、以及验证方式;这里只讲它对应哪条 issue,以及**哪几条只做了一半**——那几条用 `Refs` 而不是 `Closes`,不靠合并把它们静默关掉。 ## 随合并关闭 | commit | issue | |---|---| | `4177694` + `584d31f` + `503240d` | **#7** push/PR CI(`go vet` / `go test` / panel vitest / typecheck,外加一个 shell 作业) | | `afdbfac` | **#18** `docs/deferred-seams.md`,把 34 处 `INTEGRATION-ONLY` / `KNOWN-LIMITATION` 按「待接 / 有意不做 / 已完成」分桶 | Closes #7 Closes #18 #7 的验收条件是「开一个 PR,能看到 Go 测试和 panel 测试各自跑起来并报状态」——本 PR 自身就是那次演示,下面的 checks 就是证据。 `503240d` 是这条自己的返工:`ci.yml` 开头写着「不重复 release.yml,因为私有仓要为一个答案付两次钱」,而它交付的触发器 `branches: ['**']` 加 `pull_request` 正好做了这件事。并发组的键是 `github.ref`,`refs/heads/chore/issue-sweep` 和 `refs/pull/19/merge` 不是同一个,所以互相不取消。证据就在这个 PR 前几次的 checks 里:`go 3m14s` 和 `go 3m3s`、`shell 7s` 和 `7s`、`panel 25s` 和 `24s`。改成 `branches: [main]` 后,合并前有 PR 这道闸、合并后有 main 那道闸,掉的只有重复的那份;唯一失去覆盖的情形是「推了分支但还没开 PR」,那时候还没有人问这个问题。 ## 已关闭 issue 的代码落地 这三条在 2026-07-28 已经按「sha + 验收实测」的评论关掉了,代码到这个 PR 才上远端: | commit | issue | |---|---| | `71e1664` | #5 `.gitattributes` 钉 LF;`bootstrap_asset.go` 是逐字 embed 再 `bash -s` 管进目标机的,带 CR 的 shebang 和 heredoc 终止符在 Linux 上直接坏 | | `3af5cc3` | #6 runbook §11/§12 把四个**有人读**的字段写成 INERT,其中 §11 把一个配置问题误诊成未实现的功能 | | `82a1275` | #14 插件表声称产出三个 loader mod jar,一次安装实际一个都没有 | ## 只做了一半,不当结题 **Refs #15** — `4f5014d` 把 legacy-forwarding 后端列表从写死的 `"legacy18"` 变成 `FELIS_LEGACY_FORWARDING_SERVERS`。但 #15 的验收是「给 CR 打标记后列表自动收敛」,这条没做:转发判定在 fork 对 Velocity core 的 patch 里,不在 Felis 插件里,core 要读插件持有的动态后端注册表,那座桥不存在。它是一个 JVM system property,进程启动时读一次,改了仍要重启。 **Refs #10** — `23792d6` 选了「移除」而不是「实现」。字段过 CRD 校验、随 CRD 发布、零 controller 读取;设 `true` 描述的是本来就会发生的事,设 `false` 读起来像「请删掉这个世界」却被静默忽略。**但这偏离了冻结的 `Felis-Spec-V4.1.md §5`**(那里要求 finalizer + 按 retainOnDelete 处理 PVC)。偏离记在 `docs/troubleshooting.md` §13,冻结文档没动。要恢复 spec 那条,就得加一个 finalizer——它列出的另外三件事 ownerReference GC 已经在做,唯一新增的动作是删世界,而且不经过 reaper 的「先证明有备份」检查。**这条需要你拍板,所以没有用 `Closes`。** > 附带修正:#10 的正文原先误贴了 #9(per-credential UV)的内容,标题一直是对的。已经在这个 PR 之外单独改正。 **Refs #16** — `4e5a809` 的方向和 issue 相反。issue 说「env seam 已就位,加个 flag 接出来即可」,**这个前提是错的**:Go 里没有任何地方读写 `FELIS_INSTALL_MODE`,那是 `bootstrap.sh` 自己消费的 shell 变量。`felis setup` 不做选择性安装,它是跑完整 bootstrap TUI 重装主机。所以 `--nano` 只能是两种东西之一——重跑安装器(等于现在就有的),或把整机拆成 nano(那是卸载,不是 flag)。commit 删掉了 `nano.go` 里那句不成立的承诺并写明为什么不加。**建议关成 wontfix,但那是你的决定。** **Refs MliroLirrorsIngenuity/Felis-Legacy#19** — `584d31f` 建了 `FELIS_VELOCITY_FORK_JAR` 的摘要闸门。这个变量装的是**所有玩家连接经过的那个代理**,之前唯一的检查是路径指向可读文件。现在没有 `FELIS_VELOCITY_FORK_JAR_SHA256` 就拒装,对不上也拒装。**issue 的另一半——摘要来自一次在第二台机器上复现出来的构建——没有交付**,脚本里因此不写死任何常量:fork 只在一台机器上构建过,写死等于钉住那台机器的输出。同时删掉了原注释里那句 "is not byte-reproducible",因为证据不支持这么确定的说法(三个 fl004 jar 的条目时间戳全是 Gradle 的常量 `1980-02-01`,jar 不可复现最常见的来源已经不存在),但没有反过来断言它可复现。 ## 交付前抓到的两个假绿 **摘要大小写。** 闸门的测试原先只把 `sha256sum` 自己的输出喂回去,永远发现不了操作者实际会敲什么。同一个文件实测:`sha256sum` → `f5f8eeae…`,`Get-FileHash` → `F5F8EEAE…`,`certutil` → `f5f8eeae…`。同一个哈希,原来的比较会拒绝正确的 jar 并把它报成 checksum mismatch。fork 的构建机通常就是 Windows。现在比较前归一化大小写和空格,测试补了这两格。 **CI 的 `sh -n`。** 本机 `sh` 就是 bash,一刀切 `sh -n` 五个脚本全过。runner 的 `sh` 是 dash。没有用近似——直接在 `ubuntu:24.04`(`/bin/sh -> /usr/bin/dash`)里跑真的: ``` --- shebang 分派(本 PR 的写法)--- ok bash deploy/bootstrap.sh ok sh deploy/lobby/entrypoint.sh ok bash deploy/demo-up.sh ok sh deploy/paper/entrypoint.sh ok sh deploy/limbo/entrypoint.sh ok sh deploy/bootstrap_test.sh --- 反例:一刀切 sh -n --- deploy/bootstrap.sh: 191: Syntax error: "(" unexpected ``` `deploy/bootstrap_test.sh` 在真 dash 下 7 条全 PASS。它用 awk 从 `bootstrap.sh` 里**抽取**被测块再跑,而不是抄一份——抄的那份在原文被改之后会永远绿。抽取加了长度上限:awk 的结束模式不匹配就一路跑到 EOF,会把 `bootstrap.sh` 剩下的部分喂给被测 shell。 ## 一条范围外的发现,已立 #20 不设 `FELIS_VELOCITY_FORK_JAR` 时(也就是默认安装路径),`install_velocity` 直接 `curl -fsSL` 下 stock Velocity,**零校验**。而摘要就在手里:Fill v3 返回 `checksums.sha256`,下载 URL 本身就是按这个值内容寻址的(实测 `fill-data.papermc.io/v1/objects/b4e3164d…/velocity-3.5.1-615.jar`,摘要在响应里出现两次),`papermc_latest_jar` grep 出 URL 之后把它丢了。合并后会变成「opt-in 路径有校验、默认路径没有」。 写 issue 时才发现比这更大:`papermc_latest_jar` 有**两个**调用者,Paper 那条(`resolve_game_jars:1224` → `deploy/lobby/Dockerfile:63`、`deploy/paper/Dockerfile:39`)同样把摘要丢掉。不在 #19 范围内所以没动,立成 **#20**。 ## 验证 - `go vet ./...` / `go test ./...` — 24 个包,0 失败(Linux) - `npm test`(8 文件 111 断言)/ `npm run typecheck` - `deploy/bootstrap_test.sh` 在真 dash 下 ALL PASS - `git ls-files --eol` — 三个改动文件全部 `i/lf w/lf` - `.github/workflows/ci.yml` 用仓库自己的 `sigs.k8s.io/yaml` 解析验证:触发器是 `{"pull_request":null,"push":{"branches":["main"]}}`,三个作业 `go` / `panel` / `shell` 都在。**留个坑给下一个解析 workflow 的人**:YAML 1.1 把裸键 `on` 读成布尔 `true`,转 JSON 之后键名就是字符串 `"true"`,写 `json:"on"` 的 struct tag 会静默匹配不上——第一次检查就是这么返回空的。GitHub 自己的解析器没这个问题,本地检查有 - 所有 commit 均已签名——`git log origin/main..HEAD --format='%h %G? %s'` 十条全是 `G`,不是抽查一条 ## 合并方式:请用 merge commit,不要 squash 这个分支上有 11 条 issue 是按「sha + 验收实测」的评论关掉的,评论里直接写着 `71e1664`、`479cba4`、`2842af6`、`00673cb` 这些短 sha。**squash 和 rebase 都会重写它们**,重写之后 `git log main` 找不到任何一条,当初开这些 issue 要的可追溯性正好断在合并按钮上。两个仓都开着 merge commit,选它就行。 `panel/` 一个字节没动。
Sign in to join this conversation.