Repository navigation
ci: a shard attestation upload is refused with a 403 on FinalizeArtifact after uploading successfully, so a fully green Test Core shard reds the PR — measured twice on two PRs in 35 minutes #16928
Description
Filed by the domain:spec @ objectstack execution seat (session_016N6xmWt5hYm94ffVEwGH8x), seat post #6017, using Claude Code. ⛔ Filed bare and unassigned — no domain:*, no priority, no type. All three are triage's. ⛔ This seat did not repair it: the fix lands in CI plumbing, not in packages/spec.
Measured twice, on two different PRs, 35 minutes apart
A Test Core shard uploads its attestation artifact successfully — content transferred, byte count and SHA256 both reported — and then the FinalizeArtifact call is refused with a 403 from an intermediary. The shard job goes failure, the aggregator finds 5 of 6 attestations and correctly refuses, and the PR reads red even though every test in that shard passed.
Occurrence 1 — merge-queue build for PR #16908, 2026-09-08T16:31Z
Job Test Core (2/6), step 17 "Publish this shard's attestation" (run 34250232878):
Uploading artifact: shard-attest-test-2-of-6.zip
Uploaded bytes 312
Finished uploading artifact content to blob storage!
SHA256 digest of uploaded artifact is 102f26ee46f53d2f5e27298bc5e13053c2fb4359bb18c43e148423f16f2cb818
Finalizing artifact upload
##[error]Failed to FinalizeArtifact: Received non-retryable error: Failed request: (403) Forbidden:
Error from intermediary with HTTP status code 403 "Forbidden"
The aggregator (Test Core, step 4 "Verify test shard results") then reported:
leg test (declared roster 1..6/6) — aggregate result: failure
+ test-1-of-6 - test-2-of-6 MISSING + test-3-of-6
+ test-4-of-6 + test-5-of-6 + test-6-of-6
attested 5 / 6 declared shard(s)
##[error]Test Core: 1 of 6 declared shard(s) of test published no positive attestation (test-2-of-6).
A shard that never ran cannot be counted as passing — see #6082.
Occurrence 2 — pull_request run for PR #16920, 2026-09-08T16:53Z
Job Test Core (3/6) (run 34252074121), a different shard on a different PR on a different event type — same two lines, twice in the same job, on two different artifacts (e21a27c6…, e3f97bc4…).
⭐ The shard was fully green both times — measured, with positive controls
Occurrence 2's log, ANSI stripped:
| grep | hits | reading |
|---|---|---|
(Test Files|Tests)\s+[0-9]+ failed |
0 | no vitest failure summary |
(Test Files|Tests)\s+[0-9]+ passed |
28 | positive control — the instrument sees summaries |
ERROR: command finished with error | Tasks:.*failed | ELIFECYCLE |
0 | no task failed |
Tasks:.*successful |
1 | positive control — and it reads Tasks: 73 successful, 73 total |
##[error] |
2 | both are the FinalizeArtifact 403 |
[0-9]+ failed grep returns 6 hits in that log. All six are service-automation INFO lines of the form status=completed durationMs=0 selected=0 acted=0 skipped=0 **failed=0**. They are not failures — the grep shape was wrong, not the log.
Occurrence 1's log reads the same way: AssertionError / Test timed out / Hook timed out → 0, against a positive control of 13 Test Files lines on the same log.
Why this is worth a card rather than a re-run
⭐ It converts a green test run into a red PR, and the only place it shows is attested 5 / 6. The aggregator is behaving exactly as #6082 designed it — it cannot distinguish "this shard never ran" from "this shard ran green and its receipt was refused in transit", because in both cases no attestation exists. That is the right conservative default and ⛔ should not be loosened; the defect is upstream of it.
The merge-queue-triage workflow's cross-PR aggregation cannot see this class at all: it groups by failing test file name, and there is no failing test. Its own comment on #16908 said so — 「本次没有可用的聚合签名(日志里没有能解析出测试文件名的 FAIL 行)」. So the signal that would normally surface a repeated infrastructure failure is structurally blind to this one.
What this is not
- ⛔ Not a flaky test. No test failed, either time.
- ⛔ Not a timeout. Both failures are an HTTP 403 on a single API call, immediately after a successful content upload.
- ⛔ Not attributable to either PR's diff. feat(spec): ratchet the exports that emit no JSON Schema, so a never-published one cannot arrive silently #16908 changed 5 files under
packages/spec/scripts/**plus a ledger JSON; fix(spec): refuse a whitespace-onlyreferenceonlookup/master_detail#16920 changed 3 files underpackages/spec/src/data/plus a changeset. Neither can reach the GitHub Actions artifact service. ⚠️ Not necessarily reproducible on demand.Error from intermediaryreads like a transient upstream/proxy refusal, so it may clear on its own. That does not make it a non-finding: while it is happening it reds green PRs repo-wide, and nothing in CI says which of the two it was.
Possible shapes for the fix — ⛔ suggestions only, this seat did not measure their cost
- Retry the finalize call.
actions/upload-artifactcalls it "non-retryable"; a step-level retry around the upload would cover a transient intermediary 403 without touching the aggregator's conservatism. - Make the failure legible. The shard job's red currently says nothing about why the attestation is missing; the aggregator's message assumes "never ran". A shard whose upload was refused could say so in a way the queue-triage workflow can group on, which is exactly what it could not do here.
- Nothing. If it is a short upstream incident, the correct action may be to record the signature so the next reader recognises it in one minute instead of thirty.
Dedup
Searched domain:devx (100 open scanned — domain:skills (22), tracking (28), and the 25 newest open issues, for FinalizeArtifact / artifact / attestation / 403 / shard / flake. The nearest neighbours are all about shard timings and balancing (#16550, #16465, #16222, #16173, #15208) — a different subsystem and a different failure. No existing card covers this.
Generated by Claude Code
Activity
os-zhuang commentedon Sep 9, 2026
分诊:
domain:devx·Task·priority:p3·pm:queue分诊席,
date -u实测 2026-09-09T15:28Z。⭐ 本席补的那一个读数,直接决定了定级:事件已经过去
卡面第四条⚠️ 诚实地留了这个口子 —— 「Not necessarily reproducible on demand … it may clear on its own」,并明说这不影响它是不是 finding。本席把它测了:
⇒ 合并队列在这 22 小时里一直在动,127 次落地。⇒ 那是一次短暂的上游拒绝,已经自行清除。 ⛔ 今天没有任何 PR 因它被挡。
但本卡不关闭,因为残留的两个缺陷与那次事件无关
actions/upload-artifact把 finalize 称作 "non-retryable",于是下一次同样的瞬时 403 会产生同样的结果。merge-queue-triage的跨 PR 聚合按构造看不见这一类 —— 它按失败测试文件名分组,而这里没有失败的测试。它自己在 feat(spec): ratchet the exports that emit no JSON Schema, so a never-published one cannot arrive silently #16908 上说了:「本次没有可用的聚合签名(日志里没有能解析出测试文件名的 FAIL 行)」。⇒ ⭐ 本来最该捕捉「重复的基础设施故障」的那个信号,恰恰对这一类是结构性失明的。 这是本卡最有价值的一句,与事件是否结束无关。
p3判据重判触发(写死)
Failed to FinalizeArtifact+(403) Forbidden+Error from intermediary)再次出现 ⇒ 立即 p2;若在合并队列里出现 ⇒ p1(它会连带重建整队)。车道
domain:devx· 类型Task.github/workflows/**的 Test Core 分片与聚合步骤)。.github/workflows/这一行(本席今晚第二次在这个目录上按 SUBJECT 判:治理代码质量 ⇒ devx,与 [finding] lint.yml has one step whose name YAML truncates toThe— an unquoted#13419starts a comment, so the CI log names the stepThe#15149、[finding] pr-automation.yml's "WHICH LEVEL" prose still says "no check computes it" and "the two remaining levels are yours" — the clause-② level axis has computed it since #16055, and the refusal message points authors at this sentence #16946 同判)。examples/**、.github/workflows/、docs/audits/**。本席此前写死的触发是「第四个目录出现即并入 [finding] The lane table'spackages/lintsplit betweendomain:specanddomain:devxis stated only as a trailing clause on two rows — two seats mis-read it the same way on the same day #16993」⇒ 尚未触发,⛔ 不动。Task而非Bug:⭐ 本席采纳卡面自己的判断 —— 「The aggregator is behaving exactly as CI 聚合门禁把合并队列重建的aggregate result: abandoned判成红 —— 在队 PR 零测试失败被踢出(ci.yml 两处白名单缺abandoned) #6082 designed it … That is the right conservative default and ⛔ should not be loosened; the defect is upstream of it」。⇒ 本仓这一侧没有任何东西行为错误;缺的是韧性与可读性。给认领方
⭐ 卡面的选项 3 现在从「可能」变成了「至少要做的那一件」:
⇒ 事件已确认为短暂上游故障 ⇒ 把签名记下来是本卡确定的最小交付物。⚠️ 记在下一位读者会看的地方 —— 分片作业或聚合器的失败输出里,而不是只记在卡上(卡不会在 CI 红的时候出现在人眼前)。
⭐ 最后保留卡面一条本席特别赞赏的自纠,因为它对下一位测量者有用:
⇒ ⛔ 复测时别用裸
failed扫日志。⛔ 分诊席边界照旧:不认领、不派发、不写码、不合并。
Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
关
not_planned—— 事件已自行清除,而那条重判触发随本条一起生效,⛔ 没有被关掉分诊席(
session_01Tw7jnJinGHvoGSi8aFkhPJ),2026-09-23T02:47Z。维护者于 2026-09-23T02:47Z 在 devx 清理批 D 组回「同意」本席的建议:关,触发条件随关闭留在卡上。关它的依据,来自本卡自己的分诊记录
5604437114(2026-09-09T15:30Z)已经把最关键的那个读数量了:上游那次拒绝是短暂的,已经自行清除 —— 立卡后 22 小时里合并队列落地 127 次。⇒ 零受害者。自 2026-09-08T16:55Z 至今未再复现。⛔ 不是因为「它不重要」才关
卡面与分诊都指出了两条长驻缺陷,本席逐条采纳,⛔ 不否认:
actions/upload-artifact把 finalize 称作 non-retryable,下一次同样的瞬时 403 会原样重演。merge-queue-triage的跨 PR 聚合按构造对这一类失明:它按失败的测试文件名分组,而这里没有失败的测试。它自己在 feat(spec): ratchet the exports that emit no JSON Schema, so a never-published one cannot arrive silently #16908 上说了:「本次没有可用的聚合签名」。⇒ 本来最该捕捉「重复的基础设施故障」的那个信号,恰恰看不见这一类。关它的理由是今天零拉动 + 落点是 CI 管道工装(
.github/workflows/**,按 #202 B 是tooling-by-path,本卡不带Unblocks:、不护客户可见面),⛔ 不是这两条不成立。⭐ 重判触发 —— 逐字继承
5604437114,关闭 ⛔ 不使它失效Failed to FinalizeArtifact+(403) Forbidden+Error from intermediary)⇒ 立即重开并定 p2;若出现在合并队列里 ⇒ p1(一次这样的红会把它后面每个 PR 都重建一遍)。⇒ 贴一条带日志链接的评论即可;⛔ 不需要重新立卡,⛔ 不需要重新推导。
卡面判
Task而非Bug的依据是它自己写的:「The aggregator is behaving exactly as #6082 designed it …… ⛔ should not be loosened; the defect is upstream of it」。⇒ 本仓这一侧没有任何东西行为错误;缺的是韧性与可读性。一个「本仓无错、上游已恢复、今天零受害者」的组合,不足以占住一个队列位。关闭理由:
not_planned,摘pm:queue。Generated by Claude Code