Repository navigation
spec 的 #4650 删除闸门在「按 SHA 钉住的消费者构建」里无法锚定 origin/main,硬失败 —— cloud 的镜像构建与 pin bump 全线卡死 #5235
Description
Activity
订正影响面:坏的是「在 buildx 阶段构建 framework」的那条路,不是所有钉住检出
正文里我按「三个 workflow 的 checkout 形状相同」推断三条都会红。再等了 ~50 分钟看实际结果,这个推断只对了三分之一,据实更正:
cloud CI job framework 检出 结果 verify-objectos-ee-image(buildx 里构建 framework)actions/checkout+COPY objectstack/进 Docker红,闸门 fatal(2.5 分钟内) build-and-test(runner 上直接构建)同样的 actions/checkout@v4 + ref: <SHA>跑过了 spec 构建阶段(50 分钟仍在后续步骤) console-boots/ pin-smoke(runner 上直接构建)同上 同样跑过了 spec 构建阶段 差别不在 checkout,而在闸门的自愈 fetch 能不能成功:
let tipProbe = git('rev-parse', '--verify', '--quiet', 'origin/main^{commit}'); if (tipProbe.status !== 0) { git('fetch', '--quiet', '--depth=1', 'origin', '+refs/heads/main:refs/remotes/origin/main'); tipProbe = git('rev-parse', '--verify', '--quiet', 'origin/main^{commit}'); }
在 runner 上这条 fetch 成功(有网、有 checkout 留下的凭据),所以闸门自愈、构建通过——正文引的那句注释「CI's typecheck job checks out shallow with no branch refs, so fetch the one ref this check needs」写的就是这个场景,它是有效的。
在 buildx 构建阶段里这条 fetch 没成功,于是 fatal。我没有进一步把「无网 / 无凭据 / 私有仓」区分开——这需要在 Docker 里插桩复现,属于修复者该做的一步,我只报实测到的事实。
对结论的影响
- 不是「任何钉住检出都构建不了 spec」,收窄成:任何在无法访问 GitHub 的构建环境里构建 framework 的下游都会 fatal。cloud 的镜像构建(
verify-objectos-ee-image、release-objectos-ee、deploy-*都在 buildx 里构建 framework)全在此列。 - 「离线 / 气隙 / fork 构建会被打断」这一条仍然成立,而且现在有了实测证据——cloud 的镜像构建就是一个真实存在的、构建期不便联网的环境。
- 建议方向不变,第 2 条(把基线锚点固化成树内产物)依然是对下游最友好的:它让闸门不再依赖构建期网络,同时保留 authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 的防旁路性质。
Generated by Claude Code
- 不是「任何钉住检出都构建不了 spec」,收窄成:任何在无法访问 GitHub 的构建环境里构建 framework 的下游都会 fatal。cloud 的镜像构建(
- addedbugSomething isn't workingSomething isn't workingand removed
on Aug 4, 2026 认领:PM 循环第 2 批(spec 车道,维护者已核准 batch:5;本单列 A1 —— 正在阻断 cloud 发布链)
会话:session_01ErbEDVAg1No9gdg1pgDAGB
分支:claude/issue-5235-offline-surface-anchor
Worktree:objectstack-issue-5235
域:domain:spec(spec 构建工具面)
文件面:packages/spec/scripts/build-schemas.ts(resolveSurfaceBase一段)、树内基线锚点新产物(形如packages/spec/authorable-surface.base.json,命名以实现为准)、packages/spec/package.json(若需纳入发布 files)、配套测试。⛔ 不动 schema 源与其它生成物语义。执行依据:维护者指示按方向 2(基线锚点固化为树内产物)执行,保留 #4650 的防旁路性质;PM 已核实 origin/main 上闸门 fatal 路径仍在、树内无锚点产物,前提成立。落地后 cloud pin bump(cloud#1012 / PR cloud#1091)解锁。
Generated by Claude Code
- added a commit that references this issue
on Aug 4, 2026 验收:ACCEPT(PM 复核毕,PR #5304,第二轮 CI 24/24 全绿)
复核依据(GitHub 实据):
- 方向 2 落地完整:树内锚点
authorable-surface.base.json(8045 keys)+ 双重真实性校验(祖先 + keys 逐行);写入侧只准 git 解析基线、且在删除闸门判定之后才写(顺序承重:被拒的删除永远推不进锚点);两种锚点都缺时仍 exit 1,无环境变量旁路 —— authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650 防旁路性质完好; - CI 红自愈质量高:首轮 CI 的浅检出假阳性(
88b9b2d明明是祖先、浅仓判不了)被 dev 在我落返工简报的同窗内自行诊断修复(e80df68:非浅仓才判祖先,浅仓验 keys 半边),并加了用$GIT_DIR/shallow忠实截断的两条 pin —— 与 PM 返工方向完全一致,返工轮未消耗;「生产环境替你跑了反向验证」这条记录进 PR 正文,诚实; - 7 文件对账吻合(含
.gitattributes+regen-artifacts.mjs的驱动登记,注明「陈旧合法」与邻居的差异),check:merge-driver双向自检过,changeset patch 档合理;20/20 测试(12 存量 + 8 新增); - RED→GREEN 逐字节复刻 cloud 现场报错,反篡改两式(削行、指本地 commit)均红。
后续:本 PR 与 #5289/#5293/#5300 同批四单全绿,按生成物纪律串行入队(每落地一单,下一单先 merge-main + 整体重生成再入队)。落地后:cloud pin bump(cloud#1012 / PR #1091)解锁;cloud 的
.git-入上下文绕法(cloud#1098 / PR #1106,~20 分钟冷构建/次)可撤,缓存买回(cloud#1102)—— 已在 PR 正文记录,cloud 车道见 Blocked-by 解除自会跟进,验收时不另开单。
Generated by Claude Code
- 方向 2 落地完整:树内锚点
- added a commit that references this issue
on Aug 4, 2026 - added a commit that references this issue
on Aug 5, 2026 - added 3 commits that reference this issue
on Aug 6, 2026 - added a commit that references this issue
on Aug 8, 2026
这条挡住了 cloud 的所有 framework pin bump(实测:objectstack-ai/cloud#1091,把 pin 从
ad047d2e挪到586d6f70后,verify-objectos-ee-image立刻红)。现象
cloud 的 EE 镜像构建里,framework 的
@objectstack/specbuild 直接失败:归因(已逐条核过,不是推断)
ad047d2e上存在吗git grep零命中)586d6f70上呢packages/spec/scripts/build-schemas.tsorigin/main远程引用的 framework worktree 里构建586d6f70也就是说:闸门是本区间新增的,且只在「没有
origin/main远程引用」的构建环境里触发。为什么消费者构建必然踩到
resolveSurfaceBase()先git rev-parse origin/main^{commit},失败则自愈式git fetch --depth=1 origin +refs/heads/main:refs/remotes/origin/main,再失败就 fatal。cloud(以及任何按 SHA 消费 framework 的下游)拿到的 framework 树来自
actions/checkout@v4+ref: <pinned SHA>(默认fetch-depth: 1):只有那一个 commit,没有refs/remotes/origin/main。cloud 三个 workflow 全是这个形状:.github/workflows/verify-objectos-ee-image.yml(已实测红).github/workflows/pin-smoke.yml.github/workflows/test.yml镜像那条更硬:framework 是被
COPY objectstack/ /repo/objectstack/抄进 buildx 构建阶段再构建的,自愈 fetch 在那里也没成功。为什么这不只是「cloud 自己加个 fetch」就完事
可以让 cloud 三处 checkout 都
fetch-depth: 0(或显式 fetch main)绕过去,但那给这个开源产物加了一条很难看的性质:「构建一个按 SHA 钉死的
@objectstack/spec发布树,必须能联网访问它自己 main 分支的当前状态。」这会打断离线 / 气隙构建、fork 构建、以及任何按 tag 复现历史版本的构建——而在这些场景里闸门要防的事根本不存在:树是不可变的、已经合并过的,没有「我这个 PR 相对 main 删了什么」这个问题可问。闸门在消费者构建里既问不出答案,也没有要防的对象。
同时也不该简单加个
SKIP=1环境变量——那正是 #4650 要堵的旁路。建议方向(留给维护者定)
authorable-surface.json相对已提交状态有改动、或存在多于一个 commit / 存在分支引用。消费者构建里没有可删的基线,就没有要证明的删除。authorable-surface.base.json),让闸门比对树内文件而不是远程分支——保持「PR 改不动的基线」这个性质,同时不依赖网络。两条都保留 #4650 的防旁路性质;第 2 条对下游最友好。
影响面
.objectstack-sha今天无法往前挪到任何含该闸门的 SHA,pin 会一直停在ad047d2e(现已落后 main 119+ commit),连带 staging 部署与所有等 pin 的 issue(如 cloud#1012)。release-objectos-ee.yml与deploy-*系列(都在 pin 住的 framework 检出上构建镜像)。出处
cloud#1012 的 pin bump(PR objectstack-ai/cloud#1091,会话
session_015W6nhsDrz6zWQc8je12a1t)。失败 run:https://github.com/objectstack-ai/cloud/actions/runs/30905564626 。未指派,按 Prime Directive #10 归档。