fix: 持久化 GitHub 到 Gitea 源码权威
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
# R1.1 调查报告
|
||||
|
||||
## 结论
|
||||
|
||||
- HWLAB `9c91ea0c5c37...` 的 GitHub push delivery 返回 `502`,bridge 日志没有对应新提交,Gitea branch 与 snapshot 均停在 `e76e4d2...`;没有证据表明该请求已被当前 bridge 持久接收。
|
||||
- GitHub [不会自动重送失败的 webhook delivery](https://docs.github.com/en/webhooks/using-webhooks/handling-failed-webhook-deliveries)。因此修复不能补送 #2492 的历史事件,也不得声称可以恢复;只能等待后续真实、非空且业务必要的 HWLAB source PR merge 产生新 push。
|
||||
- 当前 PK01 Caddy webhook route 没有有界 ingress retry。bridge 的 YAML retry 只覆盖收到请求后的 Git fetch/push,无法覆盖请求到达前的 FRP/Caddy 连接失败。
|
||||
- bridge 成功日志没有 `deliveryId`/payload `after`,status 只取 repo 最后一条日志;旧成功可遮蔽新 delivery 失败。
|
||||
- bridge 使用非原子的 `git push --force` 同时更新 branch 与 snapshot,不能证明两个 ref 全成或全败,也允许重写本应 immutable 的 snapshot。
|
||||
- mirror observer 在 branch 缺失时按 snapshot ref 字典序选“latest”,会把期望提交隐藏为任意旧 ref。
|
||||
- webhook status 仅在 delivery 为 `200/202` 时计算 stale,导致 HWLAB `MATCH=false`、delivery `502` 却显示 `STALE=false`,并输出违反自动交付边界的 `REPAIR` 手工同步提示。
|
||||
|
||||
## 冻结合同
|
||||
|
||||
- ingress 只在能够证明请求体可安全重放时做 YAML 有界 retry;4xx 与业务拒绝不重试。
|
||||
- bridge 按 `deliveryId/repo/after` 关联并隔离 repo 状态;重复 delivery 幂等。
|
||||
- branch 与 `snapshotPrefix/<commit>` 通过一次 `git push --atomic` 收敛;snapshot ref 不允许 force rewrite。
|
||||
- status 以 GitHub head 为期望提交精确判断 branch/snapshot;任一不匹配均为 stale,最新失败不得被旧成功覆盖。
|
||||
- 不提供 `REPAIR`、sync、flush、webhook-test、人工 PipelineRun 或轮询 fallback。
|
||||
@@ -0,0 +1,34 @@
|
||||
# R1.2 实现报告
|
||||
|
||||
## 交付
|
||||
|
||||
- Webhook HTTP 路径在验签、规范化字段校验后,仅把 `deliveryId/repo/ref/after/payloadSha` 等最小记录写入持久 inbox;文件 `fsync`、原子 rename 与目录 `fsync` 完成后才返回 `202`。
|
||||
- 首次投递的 `202` 表示持久接收为 `accepted`,并明确 `refsCommitted=false`。重复投递的 `202` 返回 journal 当前真实状态;相同 delivery 与相同正文幂等,相同 delivery 但正文或规范字段不同返回 `409`。
|
||||
- ingress 使用 YAML `responseBudgetMs=6500` 控制从请求进入到 body 读取、持久接收完成的绝对时限,与 worker 单次执行时限相互独立。时限耗尽返回 typed `503`,但不取消正在进行的持久写入;迟到的成功或失败会继续记录,重试仍按同一 delivery 幂等关联。
|
||||
- 重复 delivery 响应返回 journal 的真实状态。`accepted`、`processing` 与 `failed` 都保持 `refsCommitted=false`;只有 `committed` 才携带已持久化的 refs proof。
|
||||
- 持久 journal 采用严格 schema、不可变 identity、单调 sequence、崩溃恢复和每仓库 committed watermark。PVC 不可用、journal 损坏或容量耗尽时 readiness 失败并返回 `503`。
|
||||
- record 列举、worker 调度与 status 统一按不可变 `acceptedSequence` 排序;即使多笔接收记录具有相同毫秒时间戳,也不会回退到 delivery ID 或文件名顺序。
|
||||
- worker 每仓库串行、跨仓库并行;普通与 terminal backoff 都由 YAML 配置。terminal cycle 耗尽后仍自动进入下一 cycle,不要求人工重送。
|
||||
- executor 抛错以及返回 `undefined`、`null` 或缺少成功证明的 malformed terminal result,都会持久标记为 typed failure 并进入自动重试,不能被误判为成功。
|
||||
- Git 收敛先验证精确 `after`,再用一次 `git push --atomic` 更新带 lease 的 branch 与不可变 snapshot;乱序祖先只创建 snapshot,分叉 fail-closed,提交 journal 前重新读取远端 refs 证明结果。
|
||||
- SIGTERM/超时会中止活跃 Git 进程组;未完成 record 保留并在新进程恢复。
|
||||
|
||||
## 自动 desired delivery
|
||||
|
||||
- [UniDesk #1760](https://github.com/pikasTech/unidesk/issues/1760) 新增独立 `platform-infra-gitea-nc01` PaC PipelineRun。它由既有 `sentinel-nc01-v03` Repository CR 在真实 `master` push 上发现,不依赖 todo-note 镜像构建。
|
||||
- PipelineRun 使用既有 `default` ServiceAccount,从 immutable source snapshot 执行独立 publisher,不依赖本次 desired 才会创建的 bridge ServiceAccount。
|
||||
- publisher 以 CAS 向 `unidesk-host-gitops` 写入三项:现有 parent path 下的 child Argo Application、独立 platform-infra desired path、source release state。只 stage 自己的三个路径,保留并发 todo/sentinel 文件。
|
||||
- source state 只允许同提交幂等或祖先向前;同提交的 stored materialization hash 必须与 exact-source renderer 一致,否则 fail-closed。旧事件标记 superseded,分叉拒绝。push race 重新 clone 最新 head 后重试,成功后再 `ls-remote` 证明目标 ref。
|
||||
|
||||
## Ingress retry 边界
|
||||
|
||||
- Caddy 请求体安全重放、4xx 不重试、可重试 502/503/504、硬时限与 body cap 的 renderer 和真实 Caddy 测试已经具备。
|
||||
- PK01 host 尚无 PR-merge 自动 reconciler,因此 owning YAML 明确设置 `ingressRetry.enabled=false`,继续渲染现有无重试转发,不宣称该能力已上线。
|
||||
- 自动 host reconciliation 独立跟踪在 [UniDesk #1768](https://github.com/pikasTech/unidesk/issues/1768) 与 `docs/MDTODO/pk01-caddy-gitea-webhook-auto-reconciliation.md`;禁止手工 apply 补链。
|
||||
|
||||
## 测试证据
|
||||
|
||||
- durable bridge:21 个 Node 集成测试通过,覆盖入口绝对时限与迟到写入、重复投递各状态、同毫秒顺序、executor reject 与 malformed result。
|
||||
- independent publisher:首次发布/幂等、并发文件保留与 CAS fresh retry、乱序/分叉、同提交冲突 state 共 4 个测试通过。
|
||||
- desired bootstrap contract:既有 Repository、既有 ServiceAccount、child Application 与完整 bridge manifest 共 2 个测试通过。
|
||||
- Caddy renderer:单元测试通过;Caddy v2.11 真实重放集成测试另行在完整验收组运行。
|
||||
@@ -0,0 +1,27 @@
|
||||
# R1.3 状态权威报告
|
||||
|
||||
## 权威关联
|
||||
|
||||
- GitHub 最新 push delivery GUID 是状态关联起点;旧成功日志不能替代最新 delivery。
|
||||
- GUID 必须精确关联持久 inbox record;只有 `state=committed` 且 record result 证明 GitHub head,才视为 durable committed。
|
||||
- 重复 HTTP delivery 必须展示 journal 当前真实状态;只有 `committed` 可以返回 refs proof,不能把已接收、处理中或失败记录包装成已提交。
|
||||
- committed 后继续比较实时 Gitea branch 与 `snapshotPrefix/<GitHub head>`。任一不匹配均为 `MATCH=false`、`STALE=true`。
|
||||
- bridge logs 仅保留为辅助诊断;默认表格改为展示 durable state 和持久 refs proof。
|
||||
|
||||
## Bootstrap 时序
|
||||
|
||||
- #1760 自身 merge 必然先由旧 bridge 接收,再通过 PaC/GitOps 部署新 durable bridge,因此不能伪造它在新 journal 中存在 record。
|
||||
- journal 在 PVC 首建时持久保存 `createdAt`。只有 delivery 时间明确早于该时间、且 branch/snapshot 已经精确对齐,状态才标记 `pre-durable-bootstrap` 并允许 rollout 继续;字段 `durableInboxCommitted=false` 保持真实。
|
||||
- 新 durable contract 的首个端到端证据必须来自下一笔真实业务 PR merge,优先 #1764;禁止空提交、伪 webhook 或手工 redelivery。
|
||||
|
||||
## 手工补偿移除
|
||||
|
||||
- automatic source authority 开启时,`mirror sync --confirm` 在任何远端 capture 前 fail-closed。
|
||||
- synthetic webhook test 的远端伪 push/ping mutation 已删除;CLI tombstone 在任何 capture 前返回只读失败。
|
||||
- 默认顶层帮助、模块帮助、status next 与 repair hints 不再引导 sync/test/repair,只公开 Gitea authority 的只读 status、validate 与 webhook status 入口。
|
||||
|
||||
## 测试证据
|
||||
|
||||
- status evaluator:8 个场景通过,包括最新失败不被旧成功覆盖、repo 隔离、非 committed 状态、proof mismatch 与 `pre-durable-bootstrap`。
|
||||
- authority guard:4 个场景通过;manual sync 与 synthetic test 均证明 `mutation=false` 且没有 remote capture,顶层帮助只暴露四个只读 Gitea authority 命令。
|
||||
- YAML duplicate-key guard 在 Bun YAML 解析前拒绝同一 mapping scope 的重复键,避免静默覆盖配置权威。
|
||||
@@ -0,0 +1,25 @@
|
||||
# GitHub 到 Gitea 持久源码权威收敛
|
||||
|
||||
本任务修复 NC01 的 GitHub webhook、Gitea controlled mirror 与 immutable snapshot 自动收敛链。来源与边界:
|
||||
|
||||
- [UniDesk #1760](https://github.com/pikasTech/unidesk/issues/1760)
|
||||
- [UniDesk #1755](https://github.com/pikasTech/unidesk/issues/1755)
|
||||
- [HWLAB #2492](https://github.com/pikasTech/HWLAB/pull/2492)
|
||||
|
||||
唯一正式触发是 GitHub PR merge;本任务不得执行人工 mirror sync/flush、直接 Gitea push、webhook-test、人工 PipelineRun、branch-follower 或运行面 patch。
|
||||
|
||||
## R1 [in_progress]
|
||||
|
||||
在 [UniDesk #1760](https://github.com/pikasTech/unidesk/issues/1760) 下恢复 [UniDesk #1755](https://github.com/pikasTech/unidesk/issues/1755) 规定的 PR merge 自动交付,并覆盖 [HWLAB #2492](https://github.com/pikasTech/HWLAB/pull/2492) 暴露的 502/stale authority,完成任务后将详细报告写入[任务报告](./details/github-gitea-durable-source-authority/R1_Task_Report.md)。
|
||||
### R1.1 [completed]
|
||||
|
||||
调查 [UniDesk #1760](https://github.com/pikasTech/unidesk/issues/1760) 的 502、旧成功覆盖、ref observer 与 repo 隔离根因,冻结 delivery/head/ref 真值合同,完成任务后将详细报告写入[任务报告](./details/github-gitea-durable-source-authority/R1.1_Task_Report.md)。
|
||||
### R1.2 [completed]
|
||||
|
||||
由 YAML 声明 webhook ingress 与 bridge 有界 retry,按 deliveryId/repo/after 幂等排队并以 atomic branch+snapshot push 收敛,完成任务后将详细报告写入[任务报告](./details/github-gitea-durable-source-authority/R1.2_Task_Report.md)。
|
||||
### R1.3 [completed]
|
||||
|
||||
修正 mirror/webhook status:按 GitHub head 精确选择 snapshot,MATCH=false 必须 STALE=true,并移除全部 REPAIR/手工补偿 hint,完成任务后将详细报告写入[任务报告](./details/github-gitea-durable-source-authority/R1.3_Task_Report.md)。
|
||||
### R1.4 [in_progress]
|
||||
|
||||
覆盖重复 delivery、跨 repo、部分 ref 已存在、atomic failure、retry exhaustion 与 truthful status,提交 non-draft PR/preflight;运行面验收只由修复 PR merge 后新事件完成,完成任务后将详细报告写入[任务报告](./details/github-gitea-durable-source-authority/R1.4_Task_Report.md)。
|
||||
@@ -0,0 +1,15 @@
|
||||
# PK01 Caddy Gitea Webhook 自动协调
|
||||
|
||||
|
||||
## R1
|
||||
|
||||
调查现有 PK01 host/Caddy 自动协调入口并冻结 owning YAML 与 CAS 边界(https://github.com/pikasTech/unidesk/issues/1768),完成任务后将详细报告写入[任务报告](./details/pk01-caddy-gitea-webhook-auto-reconciliation/R1_Task_Report.md)。
|
||||
## R2
|
||||
|
||||
实现独立 PaC desired producer 与 PK01 幂等 reconciler,禁止手工 apply 补链(https://github.com/pikasTech/unidesk/issues/1768),完成任务后将详细报告写入[任务报告](./details/pk01-caddy-gitea-webhook-auto-reconciliation/R2_Task_Report.md)。
|
||||
## R3
|
||||
|
||||
增加配置并发保留、校验/reload 失败回滚和状态关联测试(https://github.com/pikasTech/unidesk/issues/1768),完成任务后将详细报告写入[任务报告](./details/pk01-caddy-gitea-webhook-auto-reconciliation/R3_Task_Report.md)。
|
||||
## R4
|
||||
|
||||
用真实业务 PR merge 验收自动 desired→PK01 observed,随后再启用 ingressRetry(https://github.com/pikasTech/unidesk/issues/1768),完成任务后将详细报告写入[任务报告](./details/pk01-caddy-gitea-webhook-auto-reconciliation/R4_Task_Report.md)。
|
||||
Reference in New Issue
Block a user