Skip to content

fix(sync): 保护 addon 修改过的上游文件,并把静默跳过改为显式报告 - #5

Merged
C3H3-AI merged 3 commits into
masterfrom
fix/sync-protect-and-guard
Sep 15, 2026
Merged

C3H3-AI merged 3 commits into
masterfrom
fix/sync-protect-and-guard

Conversation

@C3H3-AI

@C3H3-AI C3H3-AI commented Sep 15, 2026

Copy link
Copy Markdown
Owner

Description / 变更描述

修复 sync_vendor.sh 的一个结构性缺陷:addon 对上游文件的改动会被静默覆盖
实测跑一次 sync 后项目直接编译失败

失败现象(实测)

internal/svc/svc.go:69:9: wbPool.SetLowCredits undefined
internal/svc/svc.go:69:27: cfg.LowCreditThreshold undefined
(traework / qoder 两处同样)

根因

sync_vendor.sh按文件覆盖的复制式同步。而现状是:

文件 在 PROTECT_FILES? 结果
internal/svc/svc.go(依赖扩展) ✅ 是 幸存 → 引用了不存在的符号
internal/pool/pool.go(提供扩展) ❌ 否 被覆盖 → SetLowCredits 消失
internal/config/config.go ❌ 否 被覆盖 → LowCreditThreshold 消失

保护了一半,反而制造出最坏的组合:独有代码引用了被覆盖掉的符号。

同时会丢失本轮新增的两个修复:

  • server/handler.go — TraeWork 预刷新窗口按平台区分
  • upstream/client.go — 流式请求改用无总时长上限的 client

为何这四处无法移到 addon 独有包(已逐项验证)

文件 阻碍
pool/pool.go 改了 Pick() / pickExcluding()内部实现。Go 不支持方法覆写(同名函数放同包新文件会编译冲突);所需状态 lowCredit / lowCredits私有字段,Go 规则下外部包无法访问
config/config.go LowCreditThresholdconfig.Config 的字段
server/handler.go chatCompletions 内部逻辑
upstream/client.go Client 结构体与方法

结论:这四个文件注定要被 addon 修改,只能 PROTECT。

改动

  1. PROTECT_FILES 分两类并扩充

    • A 类:addon 独有文件(原有)
    • B 类:addon 修改过的上游文件 → 新增 pool/pool.goconfig/config.go
      server/handler.goupstream/client.go,并逐条注明不可外移的原因
  2. 新增上游差异检查(核心)
    sync 结束时逐个比对 B 类文件,若上游自基线 BASELINE_COMMIT 后改动过,
    打印 [WARN] ... 需人工 merge 并汇总。

    目的:让 PROTECT 不成为黑洞 —— 上游的改动不会被永久静默忽略,
    而是当场告知。

  3. 比较时对上游 tr -d '\r'
    上游文件是 CRLF、addon 是 LF;不去掉会让全文件都显示为「有差异」而失去意义
    (这个坑已实测踩到,曾因此得出「traework 差异 199%」的错误结论)。

代价(已在 SYNC.md 载明)

这四个文件不再跟随上游自动更新,上游改了需人工 merge。

该代价目前为零:经核对,上游自基线 c62d0bc 起对
pool / config / server / upstream 的改动提交数为 0

验证(干净副本实测,未污染工作区)

sync_vendor.sh   exit=0
go build ./...   exit=0        ← 改造前此步失败
go test ./...    7 包通过 / 0 失败

sync 后六处改动全部幸存:TZ、TraeWork 预热、StreamHTTP、
is_custom_model、SetLowCredits、LowCreditThreshold。

[WARN] 路径亦实测:把基线改为 13e7b64 后正确输出
「pool.go 上游改动了 1 次 / handler.go 改动了 2 次」。

本 PR 同时解开了此前的一个死结:pool 治理能力移植(在途租约 / 成本账本 /
熔断退避)需要改 pool.go,而它此前不受保护、会被 sync 冲掉。
PROTECT 之后这个阻碍不存在了。

Type of change / 变更类型

  • bugfix: Bug fix / 问题修复
  • new feature: New feature / 新功能
  • refactor: Code refactoring and optimization / 重构与优化
  • breaking: Breaking change / 破坏性变更
  • docs: Documentation / 文档更新

Testing / 测试

  • HA Version / HA版本: 2024.1.0+
  • Add-on Version / 加载项版本: 1.1.0b13
  • Test Result / 测试结果: 干净副本跑完整链路(sync → build → test)全绿;
    WARN 路径亦构造场景实测

Checklist / 自检清单

  • Code follows project standards / 代码符合项目规范
  • No debug code or unrelated files / 无调试代码或无关文件

C3H3-AI added 3 commits September 15, 2026 13:42
Build Add-on Image 在合并后首次运行即失败:

  ##[error]Can't find 'action.yml', 'action.yaml' or 'Dockerfile'
  for action 'home-assistant/builder/actions/prepare-multi-arch-matrix@7.2.0'.

根因:home-assistant/builder 存在两条版本线。
- 7.x(7.0 / 7.1 / 7.2.0):旧版 builder,**仓库内没有 actions/ 目录**
- 2026.x(2026.09.0 等):新版,含 actions/{build-image,
  prepare-multi-arch-matrix,publish-multi-arch-manifest,cosign-verify}

实测对比(两个 tag 各自的 clone):
  tag 7.2.0      → azure-pipelines.yml builder.sh build.json Dockerfile ...
                   actions/ 不存在
  tag 2026.09.0  → actions/ action.yml ...(4 个子 action 齐全)

官方 README 示例中的 @[version] 指的是 releases 页面上的 tag,
即日历版本(2026.09.0),而非 7.x 那条线。此前取了 7.2.0 属实误判。
Build Add-on Image 第二次运行实际进入构建阶段,buildx 报错:

  ##[error]buildx failed with: ERROR: failed to build:
  invalid tag "ghcr.io/C3H3-AI/amd64-ai-proxy:1.1.0b13":
  repository name must be lowercase

根因:HA 官方 builder 的 prepare-multi-arch-matrix 与
publish-multi-arch-manifest 两个 action,其 registry-prefix 默认值均为
ghcr.io/${{ github.repository_owner }},而本仓库 owner 是 "C3H3-AI"(含大写)。
Docker/OCI 规范要求 repository name 必须全小写。

改动(3 处,统一为 ghcr.io/c3h3-ai):
- prepare-multi-arch-matrix: 显式传 registry-prefix
- publish-multi-arch-manifest: 显式传 registry-prefix
- verify job: 手写的 IMAGE 变量由 github.repository_owner 改为字面量

与 config.yaml 的 image: "ghcr.io/c3h3-ai/ai-proxy" 保持一致。

注:上一轮的 tag 引用修复(7.2.0 -> 2026.09.0)已生效——
本次 init job(Resolve version & matrix)全部步骤通过,
build job 也真正进入了 buildx 构建阶段,不再是 Set up job 失败。
## 问题

sync_vendor.sh 是「按文件」覆盖的复制式同步。addon 对上游文件做的改动会被
静默覆盖,实测跑一次 sync 后项目**直接编译失败**:

  internal/svc/svc.go:69: wbPool.SetLowCredits undefined
  internal/svc/svc.go:69: cfg.LowCreditThreshold undefined
  (traework / qoder 两处同样)

根因:`svc.go` 在 PROTECT_FILES 里(受保护),但它依赖的 `pool` /
`config` 扩展**不在**保护名单里 —— 保护了一半,反而制造出
「独有代码引用被覆盖掉的符号」这种最坏组合。

同时会丢失本次新增的修复:
  - server/handler.go   TraeWork 预刷新窗口按平台区分
  - upstream/client.go  流式请求改用无总时长上限的 client

## 为何这四处无法移到 addon 独有包(已逐项验证)

  - pool.go : 改了 Pick()/pickExcluding() 的**内部实现**。
              Go 不支持方法覆写 —— 同名函数放同包新文件会直接编译冲突;
              而所需状态 lowCredit/lowCredits 是**私有字段**,
              外部包(Go 语言规则)无法访问。
  - config.go        : LowCreditThreshold 是 config.Config 的字段,被 svc.go 引用。
  - server/handler.go: 改 chatCompletions 内部逻辑。
  - upstream/client.go: 改 Client 结构体与方法。

结论:这四个文件**注定要被 addon 修改**,只能 PROTECT。

## 改动

1. PROTECT_FILES 分为 A 类(addon 独有文件)/ B 类(addon 修改过的上游文件),
   B 类新增 pool/config/server/upstream 四个文件,并注明各自不可外移的原因。

2. 新增 B 类受保护文件的**上游差异检查**:sync 结束时逐个比对,
   若上游自基线(BASELINE_COMMIT)后改动过,打印 `[WARN] ... 需人工 merge`
   并汇总。目的是让 PROTECT **不成为黑洞** —— 上游的改动不会被永久静默忽略。

3. 比较时对上游做 `tr -d '\r'`:上游文件是 CRLF、addon 是 LF,
   不去掉会让全文件都显示为有差异而失去意义(这个坑已实测踩到)。

## 代价(已在 SYNC.md 载明)

这四个文件**不再跟随上游自动更新**,上游改了需人工 merge。
该代价**目前为零**:经核对,上游自基线 c62d0bc 起对
pool/config/server/upstream 的改动提交数为 0。

## 验证

完整链路实测(干净副本,未污染工作区):

  sync_vendor.sh  exit=0
  go build ./...  exit=0          ← 改造前此步失败
  go test ./...   7 包通过 / 0 失败

六处改动在 sync 后全部幸存:TZ、TraeWork 预热、StreamHTTP、
is_custom_model、SetLowCredits、LowCreditThreshold。

WARN 路径亦实测:把基线改为 13e7b64 后正确输出
「pool.go 上游改动了 1 次 / handler.go 改动了 2 次」。
@github-actions github-actions Bot added the 🐛 Bug Fix Bug fix / 问题修复 label Sep 15, 2026
@C3H3-AI
C3H3-AI merged commit e31342a into master Sep 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 Bug Fix Bug fix / 问题修复

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant