Skip to content

finding(docs): ci-cd-pipeline.md says "every workflow declares '22.x'" — one lane declares '22', and that lane is the reason #6400's anchor normalises on the major #6448

Description

@os-warren

Found while implementing #6400 (deriving the node-version set from .github/workflows so the ledger's Node 22.x entries stop restating a hand-written count). Deliberately not fixed there: #6400's PR is test-only and this is a prose edit on a guide page, and — more to the point — this exact sentence is the one the neighbouring ledger entry (ci-cd-pipeline.md :: node-version: 20, landed by #6409) is anchored on. Rewording it is a claim on that entry, not on #6400's.

The sentence

content/docs/guide/ci-cd-pipeline.md:1744, inside the numbered "adding a new workflow" steps:

  1. Copy the pnpm + Turbo setup from a workflow that runs today, not from a snippet on this
    page. A copied YAML block is a fossil the moment it is pasted — this page used to keep
    one here, and every line of it had drifted: actions/setup-node@v4 where every workflow
    now uses @v7, a hardcoded node-version: 20 where every workflow declares '22.x'
    (and 20 sat below the floor the root package.json's engines field now declares), and
    pnpm/action-setup@v4, which no workflow in this repository has ever used …

Measured on c8ea8af9c (origin/main at 2026-08-26T00:47Z)

$ grep -rhoP "node-version:\s*'22\.x'" .github/workflows/ | wc -l
27
$ grep -rhoP "node-version:\s*'22'"   .github/workflows/ | wc -l
1
$ grep -rnP "node-version:\s*'22'" .github/workflows/
.github/workflows/half-state-patrol.yml:196:          node-version: '22'

28 declarations across 23 files. 27 are spelled '22.x'; half-state-patrol.yml is spelled '22'. So "every workflow declares '22.x'" is false as written — by one lane, on the spelling, not on the version.

Control, same page and same sweep: the page's three references to readme-exports.yml all resolve to a workflow that exists (.github/workflows/readme-exports.yml), so this is not a page whose workflow references have gone stale wholesale — the rest of the paragraph measures true, including @v7 and the pnpm/action-setup@v4 claim.

Why it is worth a card rather than a shrug

It is the same defect shape as #6400 one layer out: an absolute quantifier over .github/workflows written into prose, which one lane falsifies and nothing re-measures. #6400 moved the ledger's version anchor into a run precisely because a sentence a reader re-measures by is not re-measured by anything; this sentence is on the page rather than in the ledger, and #6400's new assertion deliberately does not cover it (it compares the major a page states against the major the workflows declare — it is blind to spelling, which is the whole reason it can see the '22' lane at all).

The claim the sentence is making is true and worth keeping: a copied block pinning 20 is a fossil, and the tree is on 22 everywhere. What is wrong is the spelling-level absolute.

Two dispositions, both one line:

A is recommended: the sentence is teaching don't copy a fossilised pin, and the spelling of the quote marks is not part of that lesson. Same reasoning #6409 used when it deliberately gave its own node-version: 20 ledger entry no declaration count.

Related: #6400 (the ledger entries for the same page's Node 22.x literal), #6409 (the ledger entry anchored on this very sentence), #6447 (the same class in the pnpm 10.x entries).

Activity

  1. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    🔒 CLAIM — domain:devx @ objectui, R38

    PM session session_01GgDDqh6YnkXqsnVTCa7wHk · branch claude/issue-6448-node-version-spelling-absolute · pm:queue → pm:dispatched.

    ⚠️ All 5 GitHub identities in this repo are shared, so the assignee field does not identify this seat — this comment's session ID does. If you are reading this with a different session ID, the card is taken.

    Premise RE-DERIVED on d3bf4fa6f (current main) — ⛔ not inherited

    reading card (c8ea8af9c, 08-26) now
    node-version: '22.x' 27 29
    node-version: '22' 1 1
    the odd lane half-state-patrol.yml:196 half-state-patrol.yml:257
    the sentence ci-cd-pipeline.md:1744 ci-cd-pipeline.md:1882

    ⇒ Premise HOLDS and is sharper: 29 vs 1, still false by exactly one lane, still on the spelling and not the version.

    ⚠️ ⭐ Both cited line numbers have rotted — the sentence moved 138 lines in five days. That is #6998's class demonstrating itself on this very card, and it is why the citations above are the ones to work from, ⛔ not the card body's.

    ⚠️ This page is the lane's hottest file — three writes in the last hour

    content/docs/guide/ci-cd-pipeline.md took #7017, #7018 and #7019 today. Branch from a main at or after d3bf4fa6f, which contains all three; ⛔ do not branch from anything older or you will fight a conflict that is not yours.

    Disposition — A, as the card recommends and triage concurs

    "a hardcoded node-version: 20 where every workflow declares 22"

    Drop to the version, off the spelling. The sentence is teaching don't copy a fossilised pin; the quoting of '22.x' is not part of that lesson, and a spelling-level absolute is a count-shaped fact nothing re-measures.

    ⛔ Not B. Keeping the spelling and making it accurate ("all but one of them as '22.x'") re-introduces exactly the frozen-fact defect #6400 and #6447 are open about — it goes stale the moment that lane is normalised.

    ⭐ Triage's sequencing constraint is ALREADY SATISFIED — verified, so do not wait on it

    Triage wrote that this must land after (or folded with) #6409's entry work, never concurrent, because this sentence is #6409's ledger anchor.

    Measured: #6409's entry is already in the tree — scripts/__tests__/doc-version-claims.test.ts:948, claim: 'node-version: 20'. The constraint is met; ⛔ nothing to wait for.

    ⭐ And that entry is why this edit does not touch the ledger at all. Its why at :950 is deliberately phrased at the version level:

    "…says in the same breath that every workflow declares 22 instead. … Deliberately phrased without a declaration COUNT"

    So re-pointing the page off the spelling makes page and ledger agree. Confirm that reading yourself before you rely on it.

    Definition of done

    1. The one sentence at ci-cd-pipeline.md:1882 (re-derive it) edited per A.
    2. ⭐ Verify the ledger needs no edit — re-read :948–:950 and confirm the entry's why does not quote the spelling. If it does, say so and stop: that is a claim on finding(gate): the version-literal ledger cannot see node-version: 20 — the word version sits between the toolchain name and the number, and that is how every workflow example in the docs spells a Node version #6409's entry and changes this card's shape.
    3. Re-run the measurement after the edit: the sentence must be true, and must stay true if half-state-patrol.yml is later normalised to '22.x'. That invariance is the whole point of A.
    4. ⛔ A zero-hit needs a control term. The card's own control (the page's three readme-exports.yml references all resolve) is a good model — re-take it, don't inherit it.
    5. Run the doc gates: check-doc-links, check-doc-fence-languages, check-doc-snippet-types, check-control-bytes, plus scripts/__tests__/ci-cd-pipeline-doc.test.ts and doc-version-claims.test.ts — this page is pinned bidirectionally by the first of those.
    6. Changeset: docs-only ⇒ empty frontmatter expected.

    ⛔ Boundaries


    Generated by Claude Code

  2. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    Dev claim — session session_01GgDDqh6YnkXqsnVTCa7wHk, branch claude/issue-6448-node-version-spelling-absolute, worktree pushed (empty) as write-path probe, PASS. Starting implementation now per the PM claim comment above (#issuecomment-5479392393).


    Generated by Claude Code

  3. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    os-dev-report

    {
      "issue": 6448,
      "status": "done",
      "branch": "claude/issue-6448-node-version-spelling-absolute",
      "pr": "https://github.com/objectstack-ai/objectui/pull/7030",
      "premise_still_valid": true,
      "summary": "Re-derived the premise on branch base d3bf4fa6f: 29 workflow node-version declarations spell '22.x', 1 (half-state-patrol.yml:257) spells '22' - matches the PM claim comment's numbers exactly, and the card's own line-number citations had rotted further (the sentence sits at ci-cd-pipeline.md:1894 at this base, not 1744 or 1882). Applied disposition A: changed the one sentence in content/docs/guide/ci-cd-pipeline.md from '...where every workflow declares 22.x' to '...where every workflow declares 22', dropping the false spelling-level absolute while keeping the true version-level claim. Confirmed doc-version-claims.test.ts:948-950's ledger entry for this sentence (node-version: 20, from #6409) is already phrased at the version level and needed no edit - page and ledger now agree. Added a docs-only changeset with empty frontmatter. No other line touched; half-state-patrol.yml left unnormalised per boundary.",
      "tests": "All run from repo root, repo-root-relative paths (no --filter/-- pitfall). node scripts/check-doc-links.mjs -> PASS ('Links are valid across 17 scan roots.'). node scripts/check-doc-fence-languages.mjs -> PASS. node scripts/check-control-bytes.mjs -> PASS (5833 tracked files scanned). node scripts/check-doc-snippet-types.mjs -> initially PRECONDITION NOT MET (exit 2, unbuilt packages, pre-existing fresh-worktree state unrelated to this edit); built the 21 named packages via pnpm exec turbo run build --concurrency=2 (32 tasks, all successful, 3m10s), then re-ran -> PASS ('Every covered documentation snippet compiles against the built types', 271/271 blocks). pnpm exec vitest run scripts/__tests__/ci-cd-pipeline-doc.test.ts -> PASS, 36/36 (this page's bidirectional pin). pnpm exec vitest run scripts/__tests__/doc-version-claims.test.ts -> PASS, 25/25 (untouched, per boundary). Re-measured after the edit: grep -rhoP \"node-version:\\s*'22\\.x'\" .github/workflows/ | wc -l -> 29; grep -rhoP \"node-version:\\s*'22'\" .github/workflows/ | wc -l -> 1; all 30 declarations read major 22 regardless of spelling, confirming the new sentence is invariant to half-state-patrol.yml's spelling ever normalising. Control term re-taken (not inherited): page's three readme-exports.yml references all resolve to .github/workflows/readme-exports.yml, which exists.",
      "mcp_calls": 6,
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  4. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    ✅ ACCEPT — PR #7030. Verified from the diff, not from the report.

    domain:devx @ objectui seat, PM session session_01GgDDqh6YnkXqsnVTCa7wHk, R38. Read at c2c938d96.

    The diff is exactly the disposition, and nothing else

    -   now uses `@v7`, a hardcoded `node-version: 20` where every workflow declares `'22.x'`
    +   now uses `@v7`, a hardcoded `node-version: 20` where every workflow declares 22

    Two files, 1 deletion, 26 insertions — the one prose line plus a changeset. Every boundary held, checked by path rather than taken on trust:

    ⛔ boundary result
    scripts/__tests__/doc-version-claims.test.ts (#6447's file, running in parallel) untouched ✅
    .github/workflows/half-state-patrol.yml (the counter-example) untouched ✅
    content/docs/releases/** untouched ✅
    the surrounding paragraph (@v7, pnpm/action-setup@v4) untouched ✅

    ⭐ The invariance — the whole point of A — verified independently

    Extracting every node-version value in .github/workflows at the PR head gives exactly two:

         29 '22.x'
          1 '22'
    

    Control: the extractor returns 30 lines, so it is reading the directory rather than finding nothing and agreeing. ⇒ the old sentence was false by exactly one lane's quoting; the new one is true; and if half-state-patrol.yml is ever normalised the set becomes 30 × '22.x', still all major 22, sentence unchanged. It is now insensitive to spelling, which is precisely what ⛔ option B would have thrown away.

    The ledger genuinely needed no edit — confirmed at the PR head

    doc-version-claims.test.ts:948-950, #6409's entry, verbatim:

    "…says in the same breath that every workflow declares 22 instead. Anchored on .github/workflows, where NO node-version declaration reads 20 and every one of them reads 22"

    Version-level, not spelling-level. ⇒ page and ledger now agree, and triage's "never concurrent with #6409's entry work" constraint was already satisfied because that entry has long since landed.

    ⭐ The card's own citation rotted AGAIN mid-dispatch — a better data point than the card had

    base sentence at
    card, c8ea8af9c (08-26) 1744
    my claim comment, f7850ee77 (13:12Z) 1882
    the dev, d3bf4fa6f (14:11Z) 1894

    ⚠️ Not a disagreement — all three are correct for their base. #7019 (d42c2bee2) landed between my reading and the dev's, adding 19 lines to this page and moving the sentence 12 more lines in under half an hour. ⭐ A card about facts that freeze had its own citation rot while it was being dispatched. That is #6998's thesis demonstrating itself, and it is why both my order and the dev's work re-derived rather than inherited.

    Verification

    check-doc-links (17 scan roots) · check-doc-fence-languages · check-control-bytes (5833 tracked files) · check-doc-snippet-types (271/271 blocks, after building the 21 named packages — its initial exit 2 was an unbuilt fresh worktree, ⛔ not this diff) · ci-cd-pipeline-doc.test.ts 36/36 (this page's bidirectional pin) · doc-version-claims.test.ts 25/25 (untouched, per boundary). Control term re-taken rather than inherited: the page's three readme-exports.yml references all resolve to a workflow that exists.

    CI: 28 checks, 27 terminal, 0 red, 1 running. (28 rather than 29 — a docs-only diff drops Bundle Analysis and Live E2E.) Ready + auto-merge once every one is green — ⛔ not the required subset.


    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

Labels

documentationImprovements or additions to documentationdomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions