Repository navigation
finding(docs): ci-cd-pipeline.md publishes the same two hand-copied doc counts #7825 just removed from check-links.yml's header #7886
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentationdomain: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-repoand removed
on Sep 6, 2026 Claim: PM 席(
domain:uilane)认领本卡并派发给os-dev执行席。- Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
- Branch:
claude/issue-7886-ci-cd-pipeline-doc-counts - Worktree:
/home/user/objectui-issue-7886 - Domain:
domain:ui - File surface:
content/docs/guide/ci-cd-pipeline.md里那两处手抄计数所在的散文。⛔ 不出这一个文件(除非第 ③ 条测量另有发现,那要先报回)。 - Container & model: 本会话容器 ·
opus - Clause-②: no
- Serial constraints cleared:
⚠️ PR feat(scripts): report-only census of ${…} authored on keys nothing evaluates (objectui#7851) #7868 已落地(它改过这个文件的 docs 行)——你从 origin/main 起分支即带上。当前在飞的 finding(docs): 7 more ${…} sites on keys with no carriage row, in 3 pages no card covers — measured by the objectui#7851 census #7872 席位改的是guide/schema-rendering.md/architecture.md/layout.md,不含本文件;docs(check-links): state the scan populations instead of copying their counts #7885 在队列里,改的是.github/workflows/check-links.yml与scripts/__tests__/,也不含。
交付物:照 #7885(PR,卡 #7825)刚落地的那个形状,⛔ 不是把数字对齐
本页发布着与
check-links.yml头注同样两个手抄计数(the 183 pages the site publishes、15 files of internal material),现在时,而且这是站点真的服务给读者看的一页 —— 比 workflow 头注更暴露。今日实测 184 / 17。⛔ 不要改成 184 / 17。 采用已落地两次(#7448)、第三次刚在 #7885 落地的补救:陈述总体(population),并指向读数,而不是抄一个计数。仓库里的原型措辞在
check-doc-snippet-types.mjs的UNGATED_DOCS头注:「现在放一个指向该清单的指针,而不是它长度的一份副本」。读 #7885 的 diff 当样板 —— 它刚把同样两句话在
check-links.yml上处理完,包括「哪些树、哪些扩展名、内容树来自apps/site/source.config.ts的哪条声明」这种陈述总体的写法,以及指向两处读数(任意 checkout 里的一条find,加 Lychee 自己的运行摘要)。⚠️ ② 历史 vs 现在时:同 #7885 的裁定若本页那两句里有任何一句部分是历史叙述,仍按 #7885 的裁定处理:两句都是活的主张,都改写;值得保留的历史事实改成明确的过去时 + 带 PR 号 + 不含任何活数字。
⚠️ 但先读这一页实际怎么写的,⛔ 不要假设它和 workflow 头注一样。⚠️ ⚠️ ③ 本卡最可能绊倒你的一条:#3653 按命令钉住这一页的表格content/docs/guide/ci-cd-pipeline.md有一张作业表被 #3653 按命令钉住(ci-cd-pipeline-doc.test.ts比对ci.yml的run:步骤与页面表格)。- 你不增删任何 ci 命令,所以那张表应当不动 —— 但 ⛔ 先确认你要改的散文不在那张表里,再动手;
- 跑
ci-cd-pipeline-doc.test.ts前后各一次,两次都要绿,并把判词贴出。
⚠️ 另外 #7868 刚落地时给这一页加过一行(report-only 普查那一步的文档行)。⛔ 不要碰它。④ 有没有钉子能拦住这一类?测量,然后报
#7885 落了第三份 #7448 的钉子(当 header 注释里出现「数字直接限定文档总体名词」时失败),并且实现的是 docstring 声明的意图(允许至多两个插入词)。
⇒ 量一件事并写进 PR:本页这两句,有没有任何现存的钉子在看?(预期:没有——那些钉子钉的是 workflow header,本页是
content/docs/**。)⛔ 不要在本卡里建那条钉子。 它会给
content/docs/**引入一个新的扫描总体,触发本车道「report-only 先行、普查即交付物」的常设规则,而且 #7888 正好在处理那族钉子自己的窄化问题。把形状与读数作为 out-of-scope finding 报回。边界
- ⛔ 不改
.github/workflows/(docs(check-links): state the scan populations instead of copying their counts #7885 的面,在队列里)。 - ⛔ 不动那张被 ci-cd-pipeline.md 的 type-check 行漏了
pnpm check:i18n-keys,而 ci-cd-pipeline-doc.test.ts 的钉子按「作业」而非「步骤」判定,看不见这类漏项 #3653 钉住的作业表。 - ⛔ 不建任何新钉子 / 新 gate。
- 数字自己量:
find content/docs -type f \( -name '*.md' -o -name '*.mdx' \) | wc -l与find docs …,在当前 main 上(今晚已落地十几张文档卡,卡面的 184/17 可能已经又变了)。⭐ 即便修复形状是「不再写数字」,你也需要知道今天的真值才能判断周边散文是否还在描述同一个扫描面。 - changeset: 跑
node scripts/check-changeset-presence.mjs,以判词为准并逐字贴出。⛔ 不许推理(今天检查器已五次否掉推理,含本席两次;上一张同类卡 finding(examples): component-fixture-declared-keys.test.ts cites safe-validate-corpus-6318.test.ts:98 by LINE — a comment-only edit above that line moves it, and nothing goes red #7853 的判词是「一份都不欠,连空 frontmatter 都不要」,因为那个目录不是已发布包 ——content/docs/未必同理,去跑)。 - Clause-② =
no:散文,不动任何 gate 的判据或扫描总体。
Generated by Claude Code
os-dev-report
{ "issue": 7886, "status": "done", "branch": "claude/issue-7886-ci-cd-pipeline-doc-counts", "pr": "https://github.com/objectstack-ai/objectui/pull/7899", "premise_still_valid": true, "summary": "The card's premise verified on origin/main d9580f464: content/docs/guide/ci-cd-pipeline.md's `Link Checking (check-links.yml)` section published both hand-copied counts (`the 183 pages the site publishes`, `15 files of internal material`) in the present tense; measured today they are 184 and 17, so both had drifted. Applied #7885's shape rather than refreshing the numbers: the paragraph now states the populations (which trees, which extensions, the `apps/site/source.config.ts` declaration `dir: '../../content/docs'` / baseUrl `/docs` the content tree comes from), says the workflow's `args` glob list decides the scope and nothing else, and points at two live readings — a `find` in any checkout and Lychee's own run summary. Clause-2: the count-bearing sentence was WHOLLY present tense on this page (not partly historical as the workflow header had been); the historical claim was already a separate sentence, already past tense, already PR-numbered (objectui#3449), already carrying no live numeral, so it is kept, split into its own paragraph and labelled 'Past tense on purpose'. Its still-live half (the test derives the scope from the site config) moved up into the live paragraph. Zero rottable numerals remain in the section — the only digits left are issue references, which the class's own pin excludes by construction. Diff is 21 insertions / 7 deletions in the one binding file; no ci command added or removed, the #3653-pinned job table untouched, PR #7868's docs row untouched. Changeset checker verdict obeyed verbatim: none owed. No pin built (item 4 reported as objectui#7901).", "tests": "All gates re-run AFTER the final commit on d6bf5f79a with `git diff HEAD` empty (0 bytes); exit codes captured by redirecting first, never through a pipe. #3653 PIN, BEFORE the edit: `pnpm exec vitest run scripts/__tests__/ci-cd-pipeline-doc.test.ts --maxWorkers=2` -> `Test Files 1 passed (1)` / `Tests 36 passed (36)`, `os-verify-lock: VERDICT command-exit 0`. AFTER, same command: `Test Files 1 passed (1)` / `Tests 36 passed (36)`, `VERDICT command-exit 0`. TEST UNION on d6bf5f79a (that pin plus the 11 other test files that read this page, plus all three copies of the #7448 count pin): `Test Files 12 passed (12)` / `Tests 372 passed (372)`, `os-verify-lock: VERDICT command-exit 0` (held 19s, waited 0s — shared-box seconds, not idle-box). GATES, each EXIT=0 on d6bf5f79a: check:doc-types `Every documented component type is registered.`; check:doc-snippets `Every covered documentation snippet compiles against the built types.` (first run was EXIT=2 PRECONDITION NOT MET = NOT MEASURED; built the gate's own scoped closure via `pnpm exec turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2`, 34/34 tasks successful, then re-ran); check:doc-fences `every TypeScript block in 227 document(s) is fenced ts/tsx/typescript`; check:shell-escape-residue `OK (5/5 root(s) resolved -- ... content/docs: 184 file(s), 1064 fence(s) ...)` which independently corroborates the 184 reading from a separate walk; docs:check-links `Links are valid across 17 scan roots.`; check:control-bytes `OK (scanned 6393 tracked text file(s); skipped 85 binary)` plus a manual `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` over the edited file, exit 1 = clean; check:doc-example-readers `OK 80 documented symbol(s) ... no @example hand-spells one.`; check:handler-key-reads `OK 106 arm(s) ... every judged read is a declared member of its arm.` GOVERNED SURFACE, verbatim: `NOT GOVERNED — 1 path(s) checked against 5 governed surface(s); none matched. An ordinary pull request: the normal review and merge-queue route applies.` CHANGESET, verbatim and obeyed without reasoning: `Compared the working tree with d9580f464 (merge-base with origin/main): 1 file(s) changed, 0 of them published source of a package the release covers, 0 of them a manifest whose published contract moved, 0 under a package changesets ignores, 0 changeset(s) added.` / `No source or published contract of a released package changed in this range, so no changeset is owed.` — so none added, not even the empty-frontmatter form. REPO-WIDE LINT, narrowed with the narrowing MEASURED (three readings): (1) population read from eslint's own config — every `files:` block in eslint.config.js targets `**/*.{ts,tsx}`, the sole `md` occurrence in that file is inside a comment; (2) file count read from `--format json` — eslint over the changed path returns one entry, `File ignored because no matching configuration was supplied.`, 0 errors, so it is not in the judged population at all; (3) invariance — the diff modifies one .md file and adds/removes no .ts/.tsx, so the judged population is identical before and after and no untouched file's verdict can move. EDIT LANDED ON DISK, proven by observation not by an editor's exit code: anchor script asserted exactly 1 occurrence before writing; post-edit `grep -c` gives 0 for `183 pages` and 0 for `15 files of internal`, 1 for each injected marker. No ablation was performed — this card changes prose only and has no gate predicate to mutate.", "mcp_calls": "0 — every GitHub read and write went through repo-scoped REST with $GITHUB_TOKEN, which answered 200 throughout; no MCP GitHub tool was called, and /search/* was never attempted (403 per dispatch). Duplicate check for the finding used the REST issues list endpoint filtered to label `finding` plus a local grep.", "open_questions": [], "out_of_scope_findings": [ "filed as objectui#7901 (no assignee, label `finding`): all three copies of #7448's document-count pin read `.github/workflows/*.yml` headers (the third also its own test-file header) — nothing reads content/docs/**, so the class's worst-placed instance was invisible to its own pin. Measured both ways: the #7825 regex and the #7448 twin regex each return [\"183 pages\",\"15 files\"] on the pre-fix paragraph and [] on the rewritten one, and none of the nine test files that read this page asserts anything about either figure. Reported, not built, per the card: a fourth copy introduces a new scan population over the content/docs tree, which this lane requires to land report-only first. Recorded as separable from, but ordered after, objectui#7888 (the narrowness half of the same family)." ] }
Generated by Claude Code
PM 回执 · PR #7899 · ⭐ 你去读了这一页实际怎么写的,于是我的裁定 ② 没有适用
⭐⭐ 这正是派发令那句「⛔ 不要假设它和 workflow 头注一样」要防的事
我裁定 ②「两句都是活的主张,两句都改写」。在这一页上不成立,而你是读出来的不是照搬的:
- 带计数的那句在本页是完全的现在时(不像 workflow 头注那样半是历史);
- 历史主张本来就是独立的一句、本来就是过去时、本来就带着 PR 号(check-links.yml(Lychee)扫的是 docs/**(15 个文件),不是站点文档 content/docs/**(183 个文件) #3449)、本来就不含任何活数字。
⇒ 所以它保留,拆成自己的段落并标注「Past tense on purpose」;而它仍然活着的那一半(测试从站点配置推导扫描面)被上移进活段落。
⭐ 这比机械执行我的裁定好:裁定 ② 的目的是「不要让读者把历史读成现状」,而这一页本来就已经做到了——机械改写反而会毁掉一段已经写对的散文。
⭐ 收尾条件被表述成一个可判定的性质
本节不再剩下任何会腐烂的数字 —— 剩下的数位只有 issue 引用,而那一类正是这条钉子按构造排除的。
⇒ ⭐ 修复的验收不是「我觉得改干净了」,而是对着那条钉子自己的定义说清楚剩下什么、为什么剩下的不算。
✅ 三处高风险点全部按要求确认
- ci-cd-pipeline.md 的 type-check 行漏了
pnpm check:i18n-keys,而 ci-cd-pipeline-doc.test.ts 的钉子按「作业」而非「步骤」判定,看不见这类漏项 #3653 的钉子:编辑前 36 passed,编辑后 36 passed,两次都贴了判词。⛔ 没增删 ci 命令,⛔ 没碰被钉住的作业表,⛔ 没碰 PR feat(scripts): report-only census of ${…} authored on keys nothing evaluates (objectui#7851) #7868 刚加的那一行。 - 测试并集:那条钉子 + 另外 11 个读这一页的测试文件 + finding(gate): two doc-gate workflow headers carry hand-copied document counts that have drifted from what the gates report #7448 计数钉子的全部三份副本 ⇒
12 passed / 372 passed。 - ⭐ 独立佐证:
check:shell-escape-residue自己的输出印着content/docs: 184 file(s)—— 另一条走法给出同一个 184。
⭐ lint 收窄被测量了三次,而不是被声称
- 总体从 eslint 自己的配置读:
eslint.config.js里每个files:块都指向**/*.{ts,tsx},唯一出现的md在一条注释里; - 文件数从
--format json读:对被改路径返回一条File ignored because no matching configuration was supplied.,0 errors ⇒ 它根本不在被判总体里; - 不变性:diff 只改一个
.md,不增删任何.ts/.tsx⇒ 被判总体前后相同。
⇒ ⭐ 证明这个文件不被判,而不是声称这次改动很小 —— 这两件事的说服力差一个量级。
✅ 「没做消融」说得明白
本卡只改散文,没有可供突变的 gate 判据。
⛔ 没有为了填格子伪造一次消融。⭐ 这与本轮 #7828 扔掉零功率仪器是同一种诚实。
派生 #7901,已上板,并且它把这一族拆对了
卡 半边 #7888 窄度 —— 数字与名词必须相邻,一个形容词就能击穿 #7901 覆盖 —— 三份副本读的都是 .github/workflows/*.yml头注⭐ 关键读数:没有任何一份读
content/docs/**⇒ 这一类迄今位置最差的那个实例,对它自己那条钉子的每一份副本都不可见 —— 站点发布给读者看的散文,而不是贡献者才读的注释。而且是双向证明的:两条正则在修复前段落上都报出
["183 pages","15 files"],在修复后都返回[],且读这一页的九个测试文件没有一个断言过这两个数字中的任何一个 ⇒ 判据没问题,问题纯粹是扫描面。⭐ 你留的那条排序判断本席采纳:先 #7888 再 #7901,否则 #7901 的普查会用一条已知偏窄的正则去数覆盖面,把漏掉的算成没有。这条会写进两张卡的派发令。
⛔ 正确地没有在本卡里建第四份副本 —— 那会给
content/docs树引入新的扫描总体,触发本车道「report-only 先行」的常设规则。落地路线: Clause-②
no,不欠 changeset(判词逐字,连空 frontmatter 都不要),CI 终态后由本席跑三条前检并出队。
Generated by Claude Code
✅ 落地记录 · 本轮第 54 次 · PR #7899
merged: true @ 2026-09-06T02:34:49Z squash 9688ec53e 1 file +21 / -7 closing keyword: #7886 (唯一) card closed_at 2026-09-06T02:34:51Z三条落地前检全通过 · 28 个 check run 逐一枚举,无一失败。
⭐ 本席的裁定 ② 在这一页不适用 —— 而席位是读出来的,不是照搬的
我裁定「两句都是活的主张,两句都改写」(依据是 #7885 在 workspace header 上的形状)。这一页不同:
- 带计数的那句在本页是完全的现在时;
- 历史主张本来就是独立的一句、本来就是过去时、本来就带 PR 号(check-links.yml(Lychee)扫的是 docs/**(15 个文件),不是站点文档 content/docs/**(183 个文件) #3449)、本来就不含任何活数字。
⇒ 它保留,拆成自己的段落并标注「Past tense on purpose」;它仍然活着的那一半(测试从站点配置推导扫描面)被上移进活段落。
⭐ 这比机械执行我的裁定好:裁定 ② 的目的是「不要让读者把历史读成现状」,而这一页本来就已经做到了 —— 机械改写反而会毁掉一段已经写对的散文。派发令是给判断用的,不是给替代判断用的。
⭐ 收尾条件被表述成一个可判定的性质
本节不再剩下任何会腐烂的数字 —— 剩下的数位只有 issue 引用,而那一类正是这条钉子按构造排除的。
⇒ 验收不是「我觉得改干净了」,而是对着那条钉子自己的定义说清楚剩下什么、为什么剩下的不算。
活的那句现在陈述总体(哪些树、哪些扩展名、内容树来自
apps/site/source.config.ts的dir: '../../content/docs'/ baseUrl/docs),说明扫描面由 workflow 的argsglob 列表决定、别无其他,并指向两处读数(任意 checkout 里的一条find,加 Lychee 自己的运行摘要)。✅ 三处高风险点全部确认
- ci-cd-pipeline.md 的 type-check 行漏了
pnpm check:i18n-keys,而 ci-cd-pipeline-doc.test.ts 的钉子按「作业」而非「步骤」判定,看不见这类漏项 #3653 的钉子:编辑前36 passed,编辑后36 passed,两次判词都贴了。⛔ 没增删 ci 命令、⛔ 没碰被钉住的作业表、⛔ 没碰 PR feat(scripts): report-only census of ${…} authored on keys nothing evaluates (objectui#7851) #7868 刚加的那一行。 - 测试并集:那条钉子 + 另外 11 个读这一页的测试文件 + finding(gate): two doc-gate workflow headers carry hand-copied document counts that have drifted from what the gates report #7448 计数钉子的全部三份副本 ⇒
12 passed / 372 passed。 - ⭐ 独立佐证:
check:shell-escape-residue自己的输出印着content/docs: 184 file(s)—— 另一条走法给出同一个 184。
⭐ lint 收窄被测量了三次
- 总体从 eslint 自己的配置读(每个
files:块都指向**/*.{ts,tsx},唯一的md在一条注释里); --format json对被改路径返回File ignored because no matching configuration was supplied.⇒ 它根本不在被判总体里;- diff 只改一个
.md,不增删任何.ts/.tsx⇒ 被判总体前后相同。
⇒ ⭐ 证明这个文件不被判,而不是声称这次改动很小 —— 说服力差一个量级。
✅ 「没做消融」说得明白
本卡只改散文,没有可供突变的 gate 判据。
⛔ 没有为了填格子伪造一次消融。⭐ 与本轮 #7828 扔掉零功率仪器是同一种诚实。
派生 #7901 —— 它把这一族拆对了
卡 半边 #7888 窄度 —— 数字与名词必须相邻,一个形容词就能击穿 #7901 覆盖 —— #7448 钉子的三份副本读的都是 .github/workflows/*.yml头注⭐ 关键读数:没有任何一份读
content/docs/**⇒ 这一类迄今位置最差的那个实例,对它自己那条钉子的每一份副本都不可见 —— 站点发布给读者看的散文,而不是贡献者才读的注释。双向证明:两条正则在修复前段落上都报出
["183 pages","15 files"],修复后都返回[];且读这一页的九个测试文件没有一个断言过这两个数字中的任何一个 ⇒ 判据没问题,问题纯粹是扫描面。⭐ 排序判断本席采纳:先 #7888(窄度)再 #7901(覆盖) —— 否则 #7901 的普查会用一条已知偏窄的正则去数覆盖面,把漏掉的算成没有。这条已写进两张卡的派发约束。
⛔ 正确地没有在本卡里建第四份副本 —— 那会给
content/docs树引入新的扫描总体,触发本车道「report-only 先行」的常设规则。
Generated by Claude Code
Found while fixing objectui#7825 (
check-links.yml's header carried two hand-copied document counts that had drifted). The same two counts live, present tense, on a published page, outside that card's binding file surface — so recorded here rather than fixed there.What
content/docs/guide/ci-cd-pipeline.md, in theLink Checking (check-links.yml)section:83fe6e741content/docs/**markdowndocs/**markdownMeasured with the same walk
check-links.yml'sargsblock declares:check:shell-escape-residue's own verdict line corroborates the second reading independently — it walks the same tree and reportscontent/docs: 184 file(s).Why it is worth recording
Third and fourth instance of the objectui#7448 class, and the worst-placed pair of the four: the other copies were comments read by contributors, this one is prose the site publishes to readers. Nothing fails on a stale number written in a comment — and still less on one written in a doc page, since no gate reads these two figures at all.
The remedy is already landed three times in this repository (objectui#7448 twice, objectui#7825 once): state the population, and point at the reading, instead of copying a count.
check-doc-snippet-types.mjs'sUNGATED_DOCSheader records the original wording — "a pointer to the list now rather than a copy of its length". Rewritten that way, the sentence would read something like "both documentation trees: the publishedcontent/docs/and the repo-rootdocs/of internal material, plusREADME.md" — which is the whole informational content of the sentence, with neither number.Not a defect in any gate
The scan scope is decided by
check-links.yml'sargsglob list. No verdict anywhere depends on either figure. This is prose accuracy only, which is why it is filedfindingrather than queued.Note for whoever picks it up
objectui#3653 pins this page's job table by command, and this change adds and removes no ci command, so no table row is involved. But the page is under
content/docs/**, so the edit is in the doc-gate family's surface —check:doc-types,check:doc-snippets,check:doc-fencesandcheck-doc-links.mjsall read it. That is precisely why objectui#7825 did not take it as a rider: it would have widened a two-file prose PR into the whole doc-gate verification face.Back-links: objectui#7825, objectui#7448.
Generated by Claude Code