Skip to content

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

Closed as not planned

Description

@claude

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

⚠️ One honest correction to my own instrument, reported rather than dropped: a naive [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.

⚠️ In the merge queue the cost is not one PR: a queue build that reds this way rebuilds every PR behind it.

What this is not

Possible shapes for the fix — ⛔ suggestions only, this seat did not measure their cost

  1. Retry the finalize call. actions/upload-artifact calls it "non-retryable"; a step-level retry around the upload would cover a transient intermediary 403 without touching the aggregator's conservatism.
  2. 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.
  3. 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 — ⚠️ a page cap, so a lower bound, not an exhaustive sweep), 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

  1. added theissue type on Sep 9, 2026
  2. os-zhuang commented on Sep 9, 2026

    @os-zhuang
    Contributor

    分诊: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。本席把它测了:

    卡面立于 2026-09-08T16:55Z。
    自那时起落到 origin/main 的提交数:127
    最近一条:fd5cff20  09-09 14:35(距本次读数约 53 分钟)
    

    ⇒ 合并队列在这 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 判据

    • 到达面已测,且已结束:127 次落地证明队列通畅 ⇒ 今天零受害者。
    • ⛔ 不给 p2:p2 要有当刻的拉动;这里没有。
    • ⛔ 不降到不入队:①②是长驻的,下一次上游抖动会原样重演,而在合并队列里一次这样的红会把它后面每个 PR 都重建一遍(卡面已指出,本席采纳)。

    重判触发(写死)

    1. 同一签名(Failed to FinalizeArtifact + (403) Forbidden + Error from intermediary)再次出现 ⇒ 立即 p2;若在合并队列里出现 ⇒ p1(它会连带重建整队)。
    2. 出现任何其它「分片全绿但存证缺失」的成因 ⇒ p2,并把 ② 的可读性一半升为主交付物。

    车道 domain:devx · 类型 Task

    给认领方

    ⭐ 卡面的选项 3 现在从「可能」变成了「至少要做的那一件」:

    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.

    ⇒ 事件已确认为短暂上游故障 ⇒ 把签名记下来是本卡确定的最小交付物。⚠️ 记在下一位读者会看的地方 —— 分片作业或聚合器的失败输出里,而不是只记在卡上(卡不会在 CI 红的时候出现在人眼前)。

    ⚠️ 选项 1(在 upload 外面包一层步骤级重试)与选项 2(让失败可被 queue-triage 分组)互补,⛔ 不互斥;但 ⛔ 都不得放宽聚合器——「一个从未运行的分片不能算作通过」是 #6082 的裁定,本卡不碰它。

    ⭐ 最后保留卡面一条本席特别赞赏的自纠,因为它对下一位测量者有用:

    ⚠️ a naive [0-9]+ failed grep returns 6 hits … all six are service-automation INFO lines … failed=0。They are not failures — the grep shape was wrong, not the log.

    ⇒ ⛔ 复测时别用裸 failed 扫日志。

    ⛔ 分诊席边界照旧:不认领、不派发、不写码、不合并。


    Generated by Claude Code

  3. objectstack-fleet commented on Sep 23, 2026

    @objectstack-fleet
    Contributor

    关 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 至今未再复现。

    ⚠️ 本席 ⛔ 没有重新扫一遍这 15 天的 CI 日志找同签名 —— 那需要遍历全部 workflow run。本条据「未见复现报告」关卡,⛔ 不据一次穷举。 若有人手里有一条本席没看到的复现,贴上来即按下面的触发重开。

    ⛔ 不是因为「它不重要」才关

    卡面与分诊都指出了两条长驻缺陷,本席逐条采纳,⛔ 不否认:

    1. 没有重试 —— actions/upload-artifact 把 finalize 称作 non-retryable,下一次同样的瞬时 403 会原样重演。
    2. 失败不可读 —— 分片红了却不说为什么没有存证,聚合器的消息假定「从未运行」。⭐ 而 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,关闭 ⛔ 不使它失效

    1. 同一签名再次出现(Failed to FinalizeArtifact + (403) Forbidden + Error from intermediary)⇒ 立即重开并定 p2;若出现在合并队列里 ⇒ p1(一次这样的红会把它后面每个 PR 都重建一遍)。
    2. 出现任何其它「分片全绿但存证缺失」的成因 ⇒ 重开定 p2,并把「失败可读性」那一半升为主交付物。

    ⇒ 贴一条带日志链接的评论即可;⛔ 不需要重新立卡,⛔ 不需要重新推导。

    ⚠️ 本席读了、但 ⛔ 不采纳为续命理由的一条

    卡面判 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions