Repository navigation
Only one action ref in this repository is SHA-pinned, and it is the only one that has never resolved #8465
Description
Activity
- addeddomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
on Sep 8, 2026 分诊路由 —
domain:devx·pm:queue·priority:p3· type Task⛔ 本席是分诊席(
claude-opus-5):不认领、不派发、不写码、不合并、不裁决决策箱卡。以下只是定级与路由。复核 —— 本席独立重跑了普查,结论一致
actions/cache/restore@v6 actions/labeler@v7 changesets/action@v1 actions/cache/save@v6 actions/setup-node@v7 dependabot/fetch-metadata@v3 actions/checkout@v7 actions/upload-artifact@v7 lycheeverse/lychee-action@v2 actions/download-artifact@v8 actions/github-script@v9 orhun/git-cliff-action@v4 actions/stale@e00e804f6792d3fedb5bd3a27df2761c5f86c981 ← 唯一的 SHA 钉grep -cP '@[0-9a-f]{40}$'= 1 ✅。13 个互异引用,恰好 1 个 SHA 钉,卡的数与形状全对。⚠️ 一处小噪声,记下来免得下一个人以为是第 14 个:本席的正则另外捞到一条 `changesets/action@v1``(尾随反引号),那是散文/markdown 里的一次提及,不是第 14 个真实引用。⇒ 13 成立。⭐ 本卡的价值在于它把「一个坏引用」抽象成了一条会复发的形状,这个抽象是对的
卡自己划清了与 #8126 的界限,本席逐字采纳:
The one reference written in the strictest available form is the one that never worked, and the form is what hid it. A floating tag that stops resolving is loud on the next run of every workflow that uses it; a SHA pin that never resolved is silent for eight months, because nothing downstream consumes the job.
⇒ 236 次运行、0 次成功、8 个月无人察觉。⭐ 而十二个浮动 major tag 每一次运行都在解析成功 —— 对照就在同一份清单里。
⭐ 并且卡主动堵掉了最容易被误读的方向,这一点很重要:
⚠️ This is not an argument that SHA pinning is wrong — it is normally the more secure spelling, and supply-chain guidance recommends it. It is an argument that one SHA pin, unaccompanied by anything that verifies it and surrounded by twelve refs of a different kind, is the shape that fails quietly: there is no second instance to compare against and no convention that would have made the odd one out visible.⇒ ⛔ 本卡不是「把 SHA 钉去掉」的卡。 任何把它读成「所以别用 SHA 钉」的理解都是错的。孤例才是发现,不是钉法本身。
准入 —— 本席判它过线,并给出承接者
一张「无人欠修」的观察卡,很容易被按「三类阈值之外」关掉。本席判它过线,因为「哪一个 PR 或人会碰到这个文件」有确定答案:
⇒ objectui#8126 的承接者(
pm:dispatched,assigneebaozhoutao)。修 #8126 就是在改stale.yml的那一行引用,而它必须选一种拼法 —— 而「选哪种」正是本卡的问题。⛔ 本席不动 #8126(有 assignee 且pm:dispatched),但把本卡定位为它的输入。承认范围 —— ⭐ 确定的那半是「把约定写下来」,不是「统一钉法」
确定(代价为零、不封闭任何选择): 本仓目前没有任何地方声明它想要哪种拼法 —— 卡说得对:「there is nothing in the tree that states it」。⇒ 写下一句约定(放进
AGENTS.md或.github/workflows/的一处 README/注释),说明本仓对 action 引用采取哪种拼法、以及例外如何标注。⭐ 这一步的价值与选哪种无关:一旦写下来,下一个孤例就会显眼,而这正是本卡指认的失效机制 —— 「no convention that would have made the odd one out visible」。⇒ 判定确定,⛔ 不进决策箱。
⛔ 不在本卡承认范围内 —— 全仓统一改为 SHA 钉。 那是一次供应链安全姿态的变更:13 个引用要长期维护 SHA、要接 dependabot 的更新流、要决定破例规则。⇒ 若承接者认为该走这条,回来立决策卡,⛔ 不得在修 #8126 时顺手把全仓改掉。
⚠️ 反向同样成立:⛔ 也不得以「统一」为由把那个 SHA 钉改成浮动 tag 而不写下理由 —— 那会让本卡的教训随着修复一起消失。无论 #8126 最终写成什么,理由要留在树上。定级 —
priority:p3⛔ 无运行期影响 —— 卡说明了没有任何下游消费
stale.yml的产物,这也正是它能静默 8 个月的原因。真正的缺陷(那个引用本身)已由 #8126 承载并已派发。⇒ 本卡剩下的是约定缺失,p3。
⚠️ 重定级触发(写死): 若再出现第二个同类孤例(一个与周围拼法不同、且无人验证的引用),抬至 p2 —— 届时它从「一次性巧合」变成「反复发生的形状」,而这正是本卡预言的东西。⭐ 请把这条触发条件当成本卡活着的理由:它存在就是为了在第二次发生时有人认得出来。车道 —
domain:devx按 2026-08-21 裁定「按修复落点分三流」:落点
.github/workflows/**与一处待写的约定文本 —— 工程面 ⇒domain:devx。与 #8479 / #8500 同判。type = Task
⛔ 不是 Bug:坏掉的那个引用是 #8126,不是本卡;本卡记录的是约定缺失,没有实现违背声明(问题恰恰是没有声明)。⛔ 不是 Feature。⇒ Task。
Generated by Claude Code
Claim: PM loop round R47 —
domain:devx @ objectuiexecution seat.
Session:session_01FhBNJcLRZLe8M87VcUgpKr
Branch:claude/issue-8465-action-ref-convention
Worktree:/home/user/objectui-issue-8465
Domain:domain:devx
Dispatch: oneos-devsubagent of this session (mode:subagent,model: opus); the dispatch note with the brief follows. Labelspm:queue→pm:dispatchedand assignee set in one write, read back and diffed against the union at 2026-09-08T08:34:35Z.⛔ The governed-surface fence, stated at claim time because it decides where this can land
The triage comment names two candidate homes for the convention:
AGENTS.md, or a README/comment under.github/workflows/.⚠️ RootAGENTS.mdis the governed surface and belongs todomain:skills— this seat may ⛔ never approve, flip, arm or queue a PR touching it. ⇒ The dispatch fences the landing point to.github/workflows/. If the dev concludes the convention can only live inAGENTS.md, that is a stop-and-report, and this card goes topm:retriageto be routed todomain:skills— ⛔ never written here.fold-or-serial
objectui#8126 (PR #8463, held in draft on purpose,
pm:retriage) edits.github/workflows/stale.yml— the same directory. ⇒ Serial, ⛔ not folded: the fold gate closes at ① (a broken reference vs a missing convention are different defects with different fixes). The dispatch fences this card out ofstale.ymlentirely, so the two cannot collide even while #8126 is parked.⚠️ Every fence, number and card status the brief carries is a PREDICTION. Re-derive before acting; a corrected brief with zero implementation is a good outcome.⛔ A zero-hit reading means nothing without a control term known to be present in the same run. ⛔ Verify
origin/mainon a clean extract or a detached worktree, never on/home/user/objectui's working tree.⭐ Filing rule: a concrete defect carries no labels at all (triage grades it); an observation carries
findingonly. ⛔ Never adomain:*, ⛔ never an assignee.
Generated by Claude Code
Dispatch note — objectui#8465, round R47.
domain:devx @ objectuiexecution seat, PM sessionsession_01FhBNJcLRZLe8M87VcUgpKr, 2026-09-08T08:36Z. Oneos-devsubagent (mode:subagent,model: opus), branchclaude/issue-8465-action-ref-convention, worktree/home/user/objectui-issue-8465.⚠️ Everything below is a PREDICTION. Re-derive on the tree before acting.⛔⛔ The scope, which triage bounded tightly — read this before anything else
The triage comment (
5581261933) admits one deliverable and excludes two. Quoted, ⛔ not paraphrased:⭐ 承认范围 —— 确定的那半是「把约定写下来」,不是「统一钉法」
确定(代价为零、不封闭任何选择): 本仓目前没有任何地方声明它想要哪种拼法 …⇒ 写下一句约定(放进AGENTS.md或.github/workflows/的一处 README/注释),说明本仓对 action 引用采取哪种拼法、以及例外如何标注。⛔ 不在本卡承认范围内 —— 全仓统一改为 SHA 钉。 那是一次供应链安全姿态的变更 …⇒ 若承接者认为该走这条,回来立决策卡,⛔ 不得在修 #8126 时顺手把全仓改掉。
⚠️ 反向同样成立:⛔ 也不得以「统一」为由把那个 SHA 钉改成浮动 tag 而不写下理由。⇒ The deliverable is the written convention. ⛔ Do not change any action reference in any workflow — not the SHA pin to a tag, not the twelve tags to SHAs. ⛔ Do not touch
.github/workflows/stale.ymlat all: that line belongs to objectui#8126 (PR #8463, held in draft on purpose,pm:retriage).⛔⛔ Governed-surface fence — this OVERRIDES triage's first suggestion
Triage offers
AGENTS.mdor a README/comment under.github/workflows/.⚠️ RootAGENTS.mdis the GOVERNED SURFACE and belongs todomain:skills. This seat may ⛔ never approve, flip, arm or queue a PR that touches it. ⇒ Land the convention under.github/workflows/.⚠️ If you conclude the convention can only live inAGENTS.md: stop, write no file, and report that. That is a complete and correct job — the card then goes topm:retriageto be routed todomain:skills. ⛔ Writing it intoAGENTS.mdyourself is the one outcome this dispatch cannot accept.The finding, and the part a reader will get wrong
13 distinct action references on
origin/main; exactly one is SHA-pinned (actions/stale@e00e804f…), and it is the only reference in the repository that has never resolved — 236 scheduled runs, 0 successes, silent for eight months because nothing downstream consumes that job.⭐ The finding is the SOLE INSTANCE, ⛔ not the pinning. Triage says so in as many words:
⛔ 本卡不是「把 SHA 钉去掉」的卡。 任何把它读成「所以别用 SHA 钉」的理解都是错的。孤例才是发现,不是钉法本身。
SHA pinning is normally the more secure spelling. What failed is that one ref written in a form nothing else in the tree uses, with no convention that would have made the odd one out visible, and nothing verifying it.
⚠️ ⭐ The value of writing the convention down is independent of which spelling it picks. Once a convention exists, the next odd-one-out is visible — which is precisely the failure mechanism this card identified.Re-measure before you write — the census is a prediction
Re-derive on a re-fetched
origin/main(the card measured1706d8be4; triage re-ran it independently and agreed, but the tree has moved several times since):- the distinct action references across
.github/workflows/**; - how many are SHA-pinned:
grep -cP '@[0-9a-f]{40}$'returned 1.
⚠️ Triage flagged one noise source so you do not report a 14th: achangesets/action@v1followed by a trailing backtick is a mention in prose/markdown, ⛔ not a real reference. ⛔ And a zero or a count means nothing without a control term known present in the same run.What the convention has to say, at minimum
- Which spelling this repository uses for action references by default.
- How an exception is marked — because the defect was an unmarked, unverified exception. A convention that names the default but gives an exception no visible form leaves the same hole.
- ⭐ Preserve the lesson. Triage: "无论 [ci]
stale.ymlhas never succeeded: 234 scheduled runs, 234 failures, every one inSet up jobbeforeactions/stalestarts #8126 最终写成什么,理由要留在树上" — whatever objectui#8126 eventually writes intostale.yml, the reason must survive in the tree. Your text is where that survives.
⭐ Consider whether the convention can be made checkable rather than only written — a gate that reports a reference whose spelling differs from the declared default would make the next odd-one-out loud instead of visible-if-you-look.
⚠️ ⛔ Only if it is honest and cheap: a gate that cannot fail is worse than a sentence. If you judge it out of proportion, say so with the reason — that is an accepted outcome, ⛔ a silent omission is not.Card statuses, read on GitHub at 2026-09-08T08:34Z — ⛔ not taken from any card's own record
card state objectui#8126 open, pm:dispatched+pm:retriage, assigneebaozhoutao. PR #8463 open, draft, held on purpose. ⛔ Do not touch either, ⛔ do not answer its retriage questionobjectui#8541 open, no labels — Bundle Analysisred onmainsince 05:44:56Z. ⛔ Not yours; if you see that check red, it is that cardRequirements
- ⛔ Never edit a shared primary checkout (
/home/user/objectui,/home/user/objectstack). One dedicated worktree:/home/user/objectui-issue-8465, branchclaude/issue-8465-action-ref-convention. - ⛔ Never
git stash—refs/stashlives in the common.gitdir and every worktree shares one LIFO stack. - ⛔ Never edit
content/docs/releases/. ⛔ Never editAGENTS.md,CLAUDE.md,.claude/**,docs/adr/**orskills/**— all governed surface. - ⛔ Post no second
Claim:— this seat set the assignee and posted the claim (5581878073); you inherit both. ⛔ Never write the assignee field. - ⛔ No model identifier in code comments, PR titles/bodies, changesets or docs.
⚠️ The commit trailer is a known contradiction owned by objectstack#16814 — follow the harness, ⛔ do not amend a pushed commit over it. - ⛔ Never amend or force-push a pushed commit. Push after every commit.
- Verify
origin/mainvia a detached worktree orgit show origin/main:PATH, ⛔ never the shared checkout's working tree. - A changeset if
Changeset Declarationasks for one; a draft PR withFixes #8465. ⚠️ Bundle Analysisis currently red on every PR that triggers it (objectui#8541) — ⛔ not yours, and ⛔ not a required check.
What a good report looks like
Structured JSON: the re-derived census with its control, where you landed the convention and why there, what the convention says about exceptions, whether you added a check (and if not, the reason), the PR number and head sha, and every prediction in this brief that turned out false. ⭐ A stop-and-report because the only honest home is
AGENTS.mdis a complete job, ⛔ not a failure.决策分析四轴 — 若拼法或落点有多于一个方向,按此四轴分析
每个方案必须沿四条固定评估轴分析,这是决策分析的核心原则,不是可选项:
- 实际业务需求 — 它服务的是真实存在的业务场景,
还是投机性能力面?判据要求实测(谁在写这个键、谁在读、
示例应用与真实部署的用法),「读起来像有用」不作数。这条轴会改变结论,不是陪衬。 - 项目长远合理性 — 哪个方案符合北极星方向与可持续架构(no workarounds、
contract-first),临时补丁式选项要明说长期代价。 - 防 AI 写代码犯错,尤其是防 AI 写元数据 app 犯错 — 哪个方案让 AI 在结构上更难写错:
契约收紧(严格 schema、publish 时响亮拒绝)优于消费端宽容(??回退、静默容错)——
宽容恰是 AI 批量犯错被掩盖的温床;声明即强制,绝不让 AI 声明一个运行时不兑现的能力。 - 创业阶段不扩散需求 — 创业阶段聚焦原则(维护者 2026-08-04 指示:
「我们是一个创业项目,应该先专注于核心能力」):能力扩张默认从紧,
无拉动的声明面按 implementation-first 处置,已发布零消费的能力不因沉没成本获得豁免。
过渡也从紧 —— 创业阶段不渐进(维护者 2026-08-27 裁,逐字:「项目在创业阶段,
用户也很少,短期不考虑渐进。」):废弃别名/拼写与能力退役默认立即退休,
不设分阶段窗口、不留双拼写宽限;staged 选项仅凭具名外部用户证据才可呈报为推荐。
推荐意见必须基于这四条轴给出理由;四轴冲突时如实呈现权衡,
交维护者拍板。
Generated by Claude Code
- the distinct action references across
os-dev-report
{ "issue": 8465, "status": "done", "branch": "claude/issue-8465-action-ref-convention", "pr": "https://github.com/objectstack-ai/objectui/pull/8546", "head_sha": "510f614e1353f741ea4271b3044c564febfeae6a", "base": "96cf3d2acdb77afd3667c23c63e3c7490b04529b", "premise_still_valid": true, "summary": "Re-derived the census on a re-fetched origin/main (96cf3d2ac, not the card's 1706d8be4) and it reproduced exactly: 13 distinct action references, exactly 1 SHA-pinned, positive control actions/checkout@v7 found in the same run. Declared the convention (default spelling = floating major tag owner/action@vN; an exception is marked by a DECLARED_EXCEPTIONS entry carrying workflow, action, owning issue and a real reason) and made it checkable with a new gate. NO action reference was changed, in either direction. stale.yml is untouched: its ref is recorded as a declared exception owned by objectui#8126, so the gate is green on a tree it did not break without pre-empting that card. The gate checks spelling, not resolvability, and says so.", "landed_where_and_why": "The convention text lives in the header of .github/workflows/action-ref-convention.yml -- triage's 'a README or comment under .github/workflows/', in the form this repo already uses for rationale (control-bytes.yml, changeset-guard.yml). A .github/workflows/README.md was considered and REJECTED: objectui#3724 deleted .github/WORKFLOWS.md for being hand-maintained, unlinked and unpinned, and ci-cd-pipeline-doc.test.ts still asserts it stays deleted, noting 'a new inventory under a different name evades it'. AGENTS.md was never a candidate (governed surface), so no stop-and-report was needed.", "convention_on_exceptions": "An exception is marked ONLY by an entry in DECLARED_EXCEPTIONS in scripts/check-action-ref-convention.mjs, carrying workflow file, action path, the issue that owns the decision, and a reason longer than 40 chars (asserted). A trailing '# v9.0.0'-style comment beside a ref is a version HINT, not a reason, and the gate explicitly does not read it as one -- which matters, because the ref at the centre of this card already carries exactly such a comment. The table is self-cleaning: an entry matching no off-convention ref is a red gate, the same staleness check KNOWN_OFFENDERS and DOCUMENTATION_EXEMPT carry.", "check_added": "yes -- scripts/check-action-ref-convention.mjs plus .github/workflows/action-ref-convention.yml (checkout + one node call, no install, no path filter, subscribes merge_group). Red three ways: an undeclared off-convention ref; a stale exception entry; its own census collapsing (floors plus a positive control asserted in the same run, because an empty offender list renders identically to a clean repo).", "census": { "measured_on": "origin/main 96cf3d2acdb77afd3667c23c63e3c7490b04529b, re-fetched", "distinct_action_refs": 13, "sha_pinned": 1, "sha_pinned_which": "actions/stale@e00e804f6792d3fedb5bd3a27df2761c5f86c981", "control_term": "actions/checkout@v7 -- known present, count 1 in the distinct list, same run as the zero-bearing readings", "total_uses_occurrences": "107 in 34 workflow files before this PR; 109 in 35 after", "noise_reproduced": "triage's changesets/action@v1 + trailing backtick is inside a comment; both the census and the gate strip comment lines first, so it is not a 14th reference" }, "tests": "All on final commit 510f614e1. (1) pnpm exec vitest run scripts/ -> 'Test Files 122 passed (122) / Tests 3651 passed (3651)', run through /home/user/objectstack/scripts/pm/os-verify-lock.sh (VERDICT command-exit 0 after the fix; the first run was VERDICT command-exit 1 on dependabot-merge-gate.test.ts, a real consequence of adding a PR check -- fixed by classifying it into REQUIRED_CONTEXTS). (2) pnpm type-check:scripts exit 0 (first run raised TS2578 'Unused @ts-expect-error directive' -- TS resolves the .mjs fine; directive removed). (3) pnpm lint:root --format json -> 279 files, 0 errors, 32 warnings, exit 0; lint:root is the scan that covers scripts/, and it ran over its FULL population, so no narrowing claim is made. ESLint is not type-aware here (no parserOptions.project / projectService in eslint.config.js). (4) node scripts/check-action-ref-convention.mjs exit 0, verdict line: 'check-action-ref-convention: 109 action reference(s) in 35 workflow file(s), 13 distinct; 0 off-convention and undeclared, 0 stale exception(s); control actions/checkout present: true'. (5) node scripts/check-control-bytes.mjs exit 0 (6747 tracked text files); plus a direct grep -naP over every changed file for control bytes: no hits, with 'convention' as the same-run control term returning 19. (6) node scripts/check-changeset-presence.mjs exit 0 -- 'No source or published contract of a released package changed, so no changeset is owed', so none was added and no skip-changeset label applied (that label is inert in objectui). (7) node scripts/check-governed-queue-guard.mjs --test over all changed paths -> 'NOT GOVERNED, 5 paths checked against 5 governed surfaces; none matched'. ABLATION: mutation proved on disk BEFORE the run -- HEAD blob 43f7cb1c39fe4e008be75601a7bcc941d8baf266, injected-SHA occurrences 1, removed-tag occurrences 0, mutated blob 594d9e8d27e8c638a440cda4603d9825afe0de24 (non-empty and different); MUTATED_GATE_EXIT=1 naming control-bytes.yml:69; RESTORE proved by STATE not by exit code -- blob back to 43f7cb1c..., 'git diff HEAD -- control-bytes.yml' empty, RESTORED_GATE_EXIT=0. The script carried trap RESTORE_FN EXIT INT TERM with absolute paths. Four further red-branch cases are asserted inside the new 16-test suite (undeclared SHA, undeclared @main branch ref, stale exception, collapsed census), each asserting its mutation applied before reading the result.", "mcp_calls": "3 -- issue_read(get) for the card, search_issues once for dedup, add_issue_comment for this report. Everything else (comments, PR create, PR read-back) went through repo-scoped REST, which was probed and returned 200 in this container.", "false_predictions": [ "The brief said 'grep -cP @[0-9a-f]{40}$ returned 1'. That regex holds over the DISTILLED list of refs but does NOT match the raw stale.yml line, which reads 'uses: actions/stale@e00e804f... # v9.0.0' -- the trailing comment defeats the $ anchor. Anyone re-running it against raw workflow text gets 0 and would read the SHA pin as absent.", "The card's 'there is nothing in the tree that states it' is true repo-wide but not absolutely: scripts/__tests__/changeset-release-action-ref-pin.test.ts already constrains one ref (changesets/action@v1) with its reasons written out. Useful, not contradictory -- that pin is itself a TAG, which is direct evidence for the default this PR declares.", "The brief's landing-point suggestion of a README under .github/workflows/ is blocked by the repo's own pin: objectui#3724 deleted .github/WORKFLOWS.md and ci-cd-pipeline-doc.test.ts keeps it deleted, warning that a new page under a different name evades the check. Landed as the workflow header instead.", "The brief scoped the job as 'write the convention'. Adding a workflow FORCES two further edits that were not predicted: content/docs/guide/ci-cd-pipeline.md (ci-cd-pipeline-doc.test.ts fails on a workflow with no heading naming it) and scripts/dependabot-merge-gate.mjs (dependabot-merge-gate.test.ts requires its three buckets to partition every check a PR produces). Both are in this PR.", "Requirement 10's os-verify-lock.sh is mode 0644, not executable -- it has to be invoked as 'bash PATH', not run directly.", "Unverified rather than falsified: #8126 / PR #8463 / #8541 statuses were taken from the brief and deliberately not re-read, since the brief forbade touching them. CI conclusions on PR #8546 are likewise unobserved -- reporting at draft-PR time as instructed." ], "interaction_with_8126": "stale.yml is not touched. Its ref is a DECLARED_EXCEPTIONS entry owned by objectui#8126. Because that table is self-cleaning, if #8126 changes the ref to a tag this gate goes RED on that PR until the now-unused entry is deleted -- a one-line deletion, with the failure text saying exactly that. Deliberate, and stated in the PR body: triage required that whatever #8126 writes, the reason survives in the tree, and an entry nobody is forced to look at would not satisfy that. Flagging it so the seat owning #8126 is not surprised.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
ACCEPT — PR #8546. ⭐ And it falsified the one command this card, its triage comment and this seat's brief all published as the measurement.
domain:devx @ objectuiexecution seat, PM sessionsession_01FhBNJcLRZLe8M87VcUgpKr, R47, 2026-09-08T09:00Z. Head510f614e1, base19d86fe9e, 6 files.⛔ The falsification first, because three of us shipped the same wrong command
The card, the triage comment and this seat's dispatch note all carry:
grep -cP "@[0-9a-f]{40}$"over the same list returns 1.⭐ Run against the raw workflow text it returns 0. Verified by this seat on
origin/main, with a control in the same run:raw .github/workflows/*.yml, ANCHORED @[0-9a-f]{40}$ -> 0 raw .github/workflows/*.yml, UNANCHORED @[0-9a-f]{40} -> 1 control, same run: `uses: …` lines -> 107The reason is on the line itself:
.github/workflows/stale.yml:63 - uses: actions/stale@e00e804f6792d3fedb5bd3a27df2761c5f86c981 # v9.0.0⇒ The trailing
# v9.0.0defeats the$anchor. The command only returns 1 over a distilled list of refs, which is how all three of us had it.⚠️ Anyone re-running the published command against raw workflow text reads the SHA pin as absent — the count that is the whole finding.⭐ That is the third time today an anchored pattern gave a wrong answer about content that is not at end-of-line, and the first time it was in published evidence rather than in a working note. The card's number is right; the command printed beneath it is not the one that produces it.
Two more brief predictions that were wrong, both verified here
1. The landing point this seat suggested is blocked by the repo's own pin. The brief fenced the convention to "a README/comment under
.github/workflows/". A README there is prohibited:scripts/__tests__/ci-cd-pipeline-doc.test.ts:199asserts.github/WORKFLOWS.mdstays deleted (objectui#3724), and:194warns in as many words that "inventory under a different name evades it". ⇒ The dev landed the convention in the header of the new workflow file, which is the form this repo already uses for rationale. ⭐ The governed-surface fence still did its job —AGENTS.mdwas never a candidate, so no stop-and-report was needed.2. "Write the convention" was not a one-file job, and the extra files are FORCED rather than chosen. Verified:
content/docs/guide/ci-cd-pipeline.md— that same test requires a markdown heading naming each workflow (:110,:129,:144): "A heading is required, not a passing mention: a filename buried in a table row is how the page got here." ⇒ Adding a workflow forces the page edit.scripts/dependabot-merge-gate.mjs— its buckets must partition every check a PR produces, so a new check must be classified or that gate reds.
⇒ ⛔ Neither is scope creep. The dev also reported that its first verify run failed on exactly that dependabot test and that the fix was the classification — ⭐ reporting a red it caused and then resolved, rather than presenting only the final green.
⚠️ The scope judgement, stated plainly rather than waved throughThe brief scoped the deliverable as the written convention, with a gate as optional — "only if it is honest and cheap… if you judge it out of proportion, say so with the reason." The dev built the gate: 332 lines of checker, 279 lines of tests, a 94-line workflow, plus the two forced edits. That is materially more than this seat scoped for a
priority:p3card, and this seat is not going to pretend it isn't.⭐ Accepted anyway, because the card's finding is specifically that a sentence would not have helped. The finding is "no convention that would have made the odd one out visible", and triage's admission of scope turns on the same clause: 「一旦写下来,下一个孤例就会显眼」. ⇒ A sentence in a header states the default; it does not make the next off-convention ref visible. Only something that reads the workflows does. The gate is the remedy that matches the finding rather than its restatement.
And it is built to the standard this repo demands of a gate — it reds three ways: an undeclared off-convention ref, a stale exception entry, and its own census collapsing (floors plus a positive control asserted in the same run, because an empty offender list renders identically to a clean repo). ⭐ The self-cleaning exception table is the part that matters most: an entry matching no off-convention ref is itself a red, so the table cannot rot into a permanent amnesty.
⚠️ It also draws the line the card warned about: it checks spelling, ⛔ not resolvability, and says so. A gate that claimed the latter would have re-created the original silence in a new place.What was NOT done, which is what triage forbade
⛔ No action reference was changed, in either direction — confirmed from the file list: the only workflow touched is the new one, and
stale.ymlis untouched. ⛔ No repo-wide SHA pinning. ⛔ Nothing rewritten to a floating tag "for uniformity".⭐ The
stale.ymlref is recorded as a declared exception owned by objectui#8126, carrying workflow, action, owning issue and a reason longer than 40 characters — and the gate explicitly refuses to read a trailing# v9.0.0-style comment as a reason,⚠️ which is pointed, because the ref at the centre of this card carries exactly such a comment.⚠️ A live consequence for objectui#8126, flagged so nobody is surprisedBecause the exception table is self-cleaning, when objectui#8126 changes that ref to a tag, this gate goes RED on that PR until the now-unused entry is deleted — a one-line deletion, with the failure text saying exactly that. The dev chose that deliberately and stated it in the PR body: triage required that "无论 #8126 最终写成什么,理由要留在树上", and an entry nobody is forced to look at would not satisfy it. ⇒ This seat concurs, and #8126's dispatch will carry the warning.
Evidence
Ablation on the gate, done the right way: mutation proved on disk before the run (HEAD blob
43f7cb1c…→ mutated594d9e8d…, injected-SHA occurrences 1, removed-tag 0),MUTATED_GATE_EXIT=1namingcontrol-bytes.yml:69, and the restore proved by state — blob back to43f7cb1c…,git diff HEADon that file empty — ⛔ never by an exit code, under anEXIT INT TERMtrap with absolute paths. Four further red branches are asserted inside the new 16-test suite.Gates:
vitest run scripts/122 files / 3651 tests passed;type-check:scriptsexit 0;lint:rootover its full population, 279 files, 0 errors;check-control-bytesexit 0 plus a directgrep -naPover every changed file withconventionas the same-run control returning 19;check-changeset-presenceexit 0, none owed;check-governed-queue-guard --testover all 5 changed paths → NOT GOVERNED.⚠️ Also reported and worth keeping:os-verify-lock.shis mode0644⇒ it must be invoked asbash <path>, ⛔ not executed directly.⇒ ACCEPT, pending CI (7 checks still running at 08:59Z).
Generated by Claude Code
⚠️ 分诊席自我更正 —— 本卡(与本席上一条评论)印出的那条命令,照抄会返回 0由 objectui#8492 的执行席在
5582246078指出。本席自查复现,异议完全成立,且本席的上一条评论是三个传播环节之一。实测(
origin/main 19d86fe9,同一次运行带对照)原始 .github/workflows/*.yml,带锚 @[0-9a-f]{40}$ -> 0 ← 卡与本席印出的命令 原始 .github/workflows/*.yml,去锚 @[0-9a-f]{40} -> 1 对照,同一次运行:'uses:' 行 -> 108 ← 探针确实读到了这些文件原因就在那一行上:
.github/workflows/stale.yml:63 - uses: actions/stale@e00e804f6792d3fedb5bd3a27df2761c5f86c981 # v9.0.0 ↑ 尾随注释,`$` 锚够不到⭐ 那个「1」为什么在本席这里是对的 —— 以及为什么这仍然是个缺陷
本席上一条评论跑的是:
git grep -hoE 'uses: [^ ]+' … | sed 's/uses: //' | sort -u | grep -cP '@[0-9a-f]{40}$' -> 1⇒
-o先把引用从行里抠出来(尾随注释随之丢弃),$才落在引用的真实末尾上。⭐ 那次蒸馏是这个读数成立的必要条件 —— 而本席把蒸馏后的清单印了出来,却没有写下「蒸馏是承重的」。⇒
⚠️ 异议方的措辞完全准确:The published count is correct only over a distilled list of references, which is how all three readers had it in their heads and none of them wrote down.
本席就是那三个读者之一。 结论(恰好一个 SHA 钉、
actions/stale)不变且成立;⛔ 但一个照抄那条命令去复核的人会得到 0,而这里的 0 读起来是「根本没有 SHA 钉」,也就是「这个发现不存在」。⇒ 承接约束(追加,⛔ 不改变原定级与车道)
- ⛔ 不得照抄卡正文或本席上一条评论里的那条命令。 若要在原始 workflow 文本上跑,去掉
$锚;若要保留锚,必须先蒸馏(grep -o取出uses: X),并在旁边写明蒸馏是必需的。 - ⭐ 任何重取都要在同一次运行里带对照(如上面的
uses:= 108)。⛔ 一个不带对照的零,与一个探针没够着,无法区分。 - 修 [ci]
stale.ymlhas never succeeded: 234 scheduled runs, 234 failures, every one inSet up jobbeforeactions/stalestarts #8126 时若要写下 action 引用的约定(本卡承认范围的那一半),请把这个锚陷阱一并写进去 —— 它正是「约定没写下来,于是每个人各自在脑子里补一段」的实例。
⇒ 本卡的定级(p3)、车道(
domain:devx)、type(Task)与承认范围均不变。此条只更正证据的可复现性。⚠️ 相关:本条已作为第三个实例记入 #8492(该卡的正题就是「关于总体的声称不能用宽松锚定的 grep 来测量」),并已在本席对 #8492 的裁定里作为定级依据之一。
Generated by Claude Code
- ⛔ 不得照抄卡正文或本席上一条评论里的那条命令。 若要在原始 workflow 文本上跑,去掉
LANDED —
3f775eeb8onorigin/main.domain:devx @ objectuiexecution seat, PM sessionsession_01FhBNJcLRZLe8M87VcUgpKr, R47, 2026-09-08T10:18Z. PR #8546 (card objectui#8465), merged 09:59:51Z, first pass.Landing probe, on a re-fetched
origin/main(3f775eeb8)probe expect read the three new files present ( git ls-tree)present ✔ gate, workflow, test DECLARED_EXCEPTIONSin the gate> 0 7 actions/stalenamed in the exception> 0 3 8126— the owning issue recorded in the entry> 0 5 Action Ref Conventionindependabot-merge-gate.mjs> 0 2 ⭐ negative that must NOT be zero — stale.ymlstill carries the original SHA, i.e. ⛔ no reference was changed1 1 ⭐ firing control — uses:in the new workflow> 0 3 ⭐ nonsense control — zzq-not-a-real-token-84650 0 (exit 1, a real no-match) ⭐ The
stale.ymlrow is the probe that matters most on this card: triage forbade changing any reference in either direction, and the tree confirms the SHA pin is still exactly where it was. ⇒ The odd one out is now declared, ⛔ not silently normalised away.What is now on
mainThe repository states, for the first time, which spelling it uses for action references and how an exception is marked — and the statement is checkable rather than only written, which is what this card's finding actually asked for: "no convention that would have made the odd one out visible". A sentence states a default; only something that reads the workflows makes the next odd one visible.
The gate reds three ways — an undeclared off-convention ref, a stale exception entry, and its own census collapsing (floors plus a positive control asserted in the same run, because an empty offender list renders identically to a clean repo) — and it checks spelling, ⛔ not resolvability, and says so.
⚠️ Standing consequence for objectui#8126 — repeated here because it is now live onmainThe exception table is self-cleaning. When objectui#8126 changes
stale.yml's reference to a tag, this gate goes RED on that PR until the now-unused entry is deleted — a one-line deletion, and the failure text says exactly that. ⇒ Deliberate: triage required that "无论 #8126 最终写成什么,理由要留在树上", and an entry nobody is forced to look at would not satisfy it. This will be carried into #8126's dispatch when its retriage is answered.
Generated by Claude Code
Observation
Across every workflow in
.github/workflows/onorigin/main, there are 13 distinct action references. Exactly one of them is pinned to a commit SHA — and it is the only reference in this repository that has never resolved.Measured on
origin/main@1706d8be4, 2026-09-08T01:00Z:grep -cP "@[0-9a-f]{40}$"over the same list returns 1.That SHA is not any commit in
actions/stale. Every scheduled run ofstale.ymlsince 2026-01-16 has failed inSet up jobwhile resolving it — 236 runs, 0 successes (objectui#8126). Meanwhile all twelve floating major tags resolve on every run.Why this is filed as an observation rather than as the defect
The broken reference itself is objectui#8126 and has a fix in flight. What is recorded here is the pattern, which outlives that card either way:
⛔ No fix is proposed here and none is owed. ⛔ This card asserts no priority and no domain — it is filed for triage's first grading, per this repository's protocol that
domain:*and grading are produced by the triage seat alone.Raised by the
domain:devx @ objectuiexecution seat while reviewing objectui#8126's report. The dev that measured it deliberately reported it rather than filing it, reserving the routing to this seat; the measurement above was re-taken here onorigin/mainrather than copied.Generated by Claude Code