Skip to content

Commit 6ffccc5

Browse files
docs(cli): state the per-package dedup bound the CLI actually holds in #18677 / #18778 pending changesets (#19531)
Fixes #19245 Clause-②: no Two **pending, unreleased** changesets each asserted the sentence `packages/cli`'s own source now explicitly forbids restating, and each attributed it to that source. A changeset body ships verbatim into `packages/cli/CHANGELOG.md`, so this correction costs a diff today and a published falsehood after the release that consumes them. **Prose only** — two `.changeset/*.md` files, no code path changes, no export, no key, no accept set moved. **The two shas this diff is actually between:** merge base `eec56c37dfc89086658c1659bb2da869dfa08d4f` (the tip of `origin/main` at branch time *and* at every measurement below) → head `2babd1876786eb135509df70ab4fc2ee0113a7f3`. Verified with `git merge-base origin/main HEAD`, not assumed from the branch point. ## 1. The settled bound, read at the head this branch points at ⛔ No fourth phrasing was invented. Both replacement sentences are the tree's own, read from the two docblocks the card names: `packages/cli/src/commands/compile.ts:465-470` > `findingKey` now neutralises the top-level collection index, so what survives is the set of per-package findings no union finding already carried under the same rule, `where`, message and non-top-level position. ⛔ Do not re-inflate that to "exactly the set the union could not see" — `utils/artifact-packages.ts` states the bound and why it is narrower than that sentence. `packages/cli/src/utils/artifact-packages.ts:237-244` > What reaches the lists below is therefore the set of per-package findings whose `rule`, `where`, `message` and NON-top-level position no union finding already carried. ⚠️ That is the whole claim, and it is deliberately narrower than "exactly the set the union could not see" — ⛔ do not restate it as that sentence. Two entries rendering the same `where` still collapse (see `findingKey`) … Both halves are carried into both entries: the **bound**, and the **reason it is narrower** (two entries rendering the same `where` still collapse). An amended note that stated the bound and dropped the caveat would be the same defect one notch smaller, so neither entry drops it. ⚠️ Deliberately, **neither replacement reproduces the retired sentence verbatim**, not even as the "narrower than" contrast the source uses. The source can quote it because the source is the thing that prohibits it; a release note quoting it would put the sentence back into `CHANGELOG.md`, which is the entire cost this card exists to avoid — and it would leave the population sweep in §3 reading 3 again. ## 2. What each entry now says | file | before | after | |:--|:--|:--| | `.changeset/18677-validate-per-package-authoring-pass.md:7` | "By `compile.ts`' own description the survivors of that second pass are «exactly the set the union could not see», so that whole set was findings `os build` reported and `os validate` **structurally could not**." | "By `compile.ts`' own description the survivors of that second pass are the per-package findings no union finding already carried under the same rule, `where`, message and non-top-level position — deliberately narrower than everything the union run missed, because two entries rendering the same `where` still collapse. That whole set was findings `os build` reported and `os validate` **structurally could not**." | | `.changeset/18778-lint-per-package-authoring-pass.md:10-13` | "every finding that pass produces — «exactly the set the union could not see», in the build command's own words — was reported by the command that ships and invisible on the fastest of the three doors." | "every finding that pass produces — in the build command's own words, the per-package findings no union finding already carried under the same rule, `where`, message and non-top-level position — was reported by the command that ships and invisible on the fastest of the three doors. That bound is deliberately narrower than everything the union run missed: two entries rendering the same `where` still collapse." | Both attributions are now **accurate**: `compile.ts` does say the replacement, in those words. The downstream conclusion each entry draws is untouched and still holds — a survivor is by construction something the union run did not report, so it remains a finding `os build` reported and the other door structurally could not. Only the **size** claimed for that set moves, which is exactly the correction #18779 landed in the code and did not reach these two notes. ⭐ **One correction, not two.** The two entries needed the same substantive change; only the sentence surgery differed, because one file is unwrapped prose and the other is hard-wrapped at 80 columns. Each file's own wrapping convention is preserved. ⭐ **The `**BREAKING**` section PR #18867 just added to `18677-…md` is not touched.** The assertion sits at `:7`; that banner and its table occupy `:22-29`. `git diff` shows one changed line in that file. ## 3. The sweep over the whole `.changeset/` population, with lit controls ⚠️ **The first instrument was wrong and is reported rather than quietly replaced.** Its normaliser collapsed `\s+` only. That is enough for markdown, but inside a block comment the sentence's line wrap carries a `*` continuation marker, so a bare `\s+` bridge does **not** join `"exactly the` to `set the union could not see"`. On the tree scan in §4 it silently undercounted **13 → 11**. The corrected normaliser strips each line's comment-continuation prefix (`*`, `//`, `#`) *before* collapsing whitespace. Every number below is from the corrected instrument; both are kept in the report. Whole population, whitespace-normalised, case-insensitive, **every hit opened**: | run | population | lit control | needle | |:--|:--|:--|:--| | `.changeset/` @ `origin/main` `eec56c37df` (before) | **554** files | superset "the union could not see" → **3** occurrences, INSTRUMENT LIT | **3** | | `.changeset/` @ head `2babd18767` (after) | **554** files | superset → **1**, INSTRUMENT LIT | **1** | The three before, each opened, ⛔ not counted: 1. `18677-…md:7` — assertion, attributed to `compile.ts` → **corrected here** 2. `18778-…md:11` — assertion, attributed to the build command → **corrected here** 3. `18779-…md:52` — *"Also corrected: the sentence «…», **which was false** for as long as the key was positional"* → **quoted correction, untouched** The one after is row 3. ✅ **The only surviving hit in the whole population is `18779`'s quoted correction**, which is what the claim comment asked to be shown rather than trusted. ⚠️ A note on the population figure: the card recorded **482** changesets at `847e5773a`. At `eec56c37df` it is **554**. The tree moved; the count is re-measured here, ⛔ not inherited. The needle count is unchanged at 3, which is the number that matters. ⚠️ A second lit control was run on the before-sweep and is recorded because a zero is not a reading until a control hits: the distinctive string `position-insensitive, not collision-proof` returned exactly **1** file (`18779-…md`), confirming the loop was reading real bytes at real paths — the failure mode the card records (a loop that double-prefixed `.changeset/` and returned a wholly convincing `0`). ## 4. `.changeset/18779-…md` is untouched, and this PR makes its completeness claim true `18779-…md:55-56` claims the sentence *"is now stated at the bound the pass can actually hold, **in every file that carried it**"*. That claim was **false on `origin/main`**, falsified by the two rows above. It is true at this head. Measured over the **whole tree**, not just `.changeset/` — 9128 tracked text files at head, corrected normaliser, lit control 15 occurrences of the superset in 10 files: **13 occurrences in 10 files, every one opened and classified. Zero are assertions.** | site | class | |:--|:--| | `.changeset/18779-per-package-dedup-positional-key.md` | quoted correction | | `packages/cli/src/commands/compile.ts` ×2 | 1 quoted correction ("used to end … and that was FALSE"), 1 **prohibition** ("⛔ Do not re-inflate that to") | | `packages/cli/src/utils/artifact-packages.ts` ×3 | 1 "narrower than" contrast (`:101`), 1 historical account that names **#18677 and #18778 by number** as the two that quoted it, 1 **prohibition** ("⛔ do not restate it as that sentence") | | `packages/cli/src/commands/lint.ts` | quoted correction | | `packages/cli/src/commands/validate.ts` | quoted correction | | `packages/cli/test/{lint,validate}-per-package-authoring-{parity,seam}.test.ts` ×4 | quoted corrections | | `packages/cli/test/per-package-dedup-positional-echo.test.ts` | quoted correction | ⇒ Nothing in the tree still **asserts** the sentence. Editing `18779-…md` would be a no-op that spends a third file on the serial. ⛔ Left alone, exactly as ordered. ## 5. ⭐ The written confirmation `Check Changeset` route 0 asks for — and why that check stays red `node scripts/check-empty-changeset.mjs --base origin/main` exits **1** here, and that is **by design**, ⛔ not a defect and ⛔ not a finding about the gate. The route-0 discriminator `.github/workflows/pr-automation.yml` prescribes was run rather than reasoned about: ``` $ git merge-base origin/main HEAD eec56c3 $ git diff --name-status eec56c3 HEAD -- '.changeset/*.md' M .changeset/18677-validate-per-package-authoring-pass.md M .changeset/18778-lint-per-package-authoring-pass.md ``` Every row is `M`, none is `A` ⇒ the **DELIBERATE CORRECTION** class. The workflow's own instruction for it, verbatim: > -> do NOT apply 'skip-changeset'. Write the confirmation on the PR -- name the note and what changed under it, and get it confirmed there in writing -- and LEAVE THIS CHECK RED. > … Ruled on #18375 (ruling D, maintainer 2026-09-18): the 'skip-changeset' label is never applied to a PR that edits an existing changeset. **So, saying it, as the gate asks:** - **The notes:** `.changeset/18677-validate-per-package-authoring-pass.md` (PR #18769's, amended by PR #18867) and `.changeset/18778-lint-per-package-authoring-pass.md` (PR #18778's). Both pending, both unreleased. - **What changed under them:** ⛔ nothing in this PR's code — this PR contains none. What changed under them earlier is **#18779**, which neutralised the top-level collection index in `findingKey` and in the same stroke retired the sentence both notes quote. Both notes were written before that landed and were never revisited; the source they cite was, and now prohibits the sentence by name. - **What is asked:** confirmation that these two pending release notes may be corrected in place. ⛔ Restoring either from the base would republish a sentence the shipping code contradicts. This PR stays **draft** until that confirmation. ⚠️ **This PR carries no label, and the red is expected on CI.** Step 11 of `changeset-check` ("Require a changeset (or the skip-changeset label)") fails first — this PR adds no changeset of its own — which short-circuits the job, so the foreign-changeset refusal above never executes on CI at all. `Check Changeset` is not a required context, so its red blocks no merge and an approver merges over it. ⭐ Measured on the adjacent precedent rather than recalled: PR #18867's head `1056c00195` shows `Check Changeset` = **failure** on both runs, its final label set is `documentation, size/s, tooling` with **no `skip-changeset`**, and it merged. The route-0 block and ruling D are present in `pr-automation.yml` at #18867's own merge commit `03008c7e1a`, so that ruling is not newer than the precedent. ## 6. Verification All **19** commands derived for this surface, re-derived at this head — `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, which reported `--repo … checked against this checkout's 'origin' remote — it holds`, change set `2 path(s) vs merge base eec56c3`, and emitted **exactly the 19** the dispatch named. Exit codes captured by redirecting first (⛔ never through a pipe). | # | command | exit | |:--|:--|:--| | 1 | `node scripts/check-adr-0087-registration.mjs --base origin/main` | **0** | | 2 | `node scripts/check-adr-0087-registration.mjs --self-test` | **0** | | 3 | `node scripts/check-changeset-no-major.mjs --base origin/main` | **0** | | 4 | `node scripts/check-changeset-no-major.mjs --self-test` | **0** | | 5 | `node scripts/check-closing-keyword-parity.mjs` | **0** | | 6 | `node scripts/check-closing-keyword-parity.mjs --self-test` | **0** | | 7 | `node scripts/check-comment-mask-corpus.mjs` | **0** | | 8 | `node scripts/check-empty-changeset.mjs --base origin/main` | **1 — by design, §5** | | 9 | `node scripts/check-empty-changeset.mjs --self-test` | **0** | | 10 | `node scripts/pm/release-rehearsal-clone.mjs --self-test` | **0** | | 11 | `pnpm check:changeset-gate-self-tests` | **0** | | 12 | `pnpm check:driver-memory-census` | **0** | | 13 | `pnpm check:gitlink-declared` | **0** | | 14 | `pnpm check:nul-bytes` | **0** | | 15 | `pnpm check:objectui-changeset` | **0** | | 16 | `pnpm check:pm-changeset-deadline-census` | **0** | | 17 | `pnpm check:published-files` | **0** | | 18 | `pnpm check:refd-timer-probe` | **0** | | 19 | `pnpm check:watch-hint-literal` | **0** | Gate 8's refusal names both files and the DELIBERATE CORRECTION class; §5 is its remedy. Gate 1 reads `.changeset/18677-…md [BREAKING] not-required (no-migration-prescription)` — the disposition PR #18867 added survives this edit intact. Beyond the 19, run because the derivation refuses to call their silence a clearance: | what | result | |:--|:--| | `node scripts/check-changeset-fixed.mjs` — flagged ⛔ by the derivation, "roster under `.changeset`, which one of your paths is in" | **exit 0** — config `fixed` group in sync with 70 public packages | | `pnpm check:pm-governed-prose` | **exit 0** — and it names the 6 governed surfaces (`docs/adr/**` · `.claude/**` · `skills/**` · `AGENTS.md` · `CLAUDE.md` · `docs/NORTH-STAR.md`). `.changeset/**` is not among them, so no governed-surface obligations attach to this diff | | `pnpm lint` — whole repo, `eslint . --no-inline-config`, ⛔ **not narrowed**, so no narrowing argument is owed | **exit 0** at `2babd18767` | | control characters — `grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'` over both changed files | no hits (grep exit 1) | **No package test or typecheck is owed and none is claimed.** The diff touches no package source, no `exports`, no spec contract, no built artefact and no test. `turbo`'s affected set is empty of packages for a `.changeset/*.md` edit; that is stated as "not owed", ⛔ not as "green". **No changeset is owed for this PR.** It declares no release of its own — route 0 above is the discriminator, and it also forbids the `skip-changeset` label that would otherwise declare that in writing. **No label is written by this PR**, as ordered, and the order is independently correct: ruling D forbids `skip-changeset` on exactly this class. ## 7. Where this PR's reading differs from the dispatch order ⭐ Reported rather than silently accommodated, per the order's own instruction. - **`Clause-②: no` is declared above exactly as the seat declared it**, and this PR's reading of the finished diff **agrees**: prose in two unreleased notes, no export, no key, no member, no registration, no accept set moved in either direction. - ⚠️ **The order's label reasoning is right and its prediction is wrong.** "Write no labels" is correct — ruling D forbids `skip-changeset` here by name. But "⇒ your round needs no label to go green" does not hold: PR #18867, the precedent cited for it, went **red** on `Check Changeset` and was merged over, as measured in §5. This round will be red too, and ⛔ that red is not "a real finding about the gate" — it is the gate's documented behaviour for this class, and §5 is the prose-and-person remedy it prescribes. - **Nothing else in the order needed refusing.** The settled bound fits both sentences; `18677`'s `**BREAKING**` section is untouched; the two entries needed one correction, not two. ## Boundaries — what this PR deliberately does not do - ⛔ It does not touch `.changeset/18779-per-package-dedup-positional-key.md`. §4 shows why that would be a no-op. - ⛔ It does not touch `packages/cli/src/**`, any test, `content/docs/releases/`, or any `packages/*/CHANGELOG.md`. - ⛔ It does not add or change a `Clause-②:` line inside either changeset **body**. `18778-…md` carries `Clause-②: yes (narrowing)` at `:36`; that is a landed declaration about its own release and ⛔ not this card's to re-grade. - ⛔ It writes no label, and it did not route around that anywhere. ## Acceptance notes - **Noted, not filed:** `.changeset/18677-…md:9-16` pins a measurement to `origin/main 09e16a5` — `os build --json warnings: 4` against `os validate --json warnings: 3` — and #18779 has since moved that fixture's build count from 4 to 3. It is ⛔ not a defect: the reading is explicitly bound to a named sha, it was true there, and `18779-…md:19-24` publishes the 4→3 move in the same release, so a CHANGELOG reader gets both. Rewriting a correctly-dated historical measurement would be the larger error. **Carrier:** none — no PR is in flight on that file and none is predicted; recorded here because the "somebody will touch this anyway" fallback ⛔ does not hold for `.changeset/*`. - **Noted, not filed:** the first sweep instrument used for §4 undercounted the tree scan 13 → 11 by collapsing `\s+` without first stripping block-comment continuation markers. That is a fact about a throwaway script in this session, ⛔ not about any tracked file — no gate, helper or committed tool has the defect. It is written down because the card's own history records the opposite failure of the same instrument class (a convincing `0`), and the pair is the argument for the lit control. **Carrier:** none; nothing in the repo carries this code. --- _Generated by [Claude Code](https://claude.ai/code/session_01QCdUBjM47SxioST9z5Zwdf)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 744a0a3 commit 6ffccc5

2 files changed

Lines changed: 7 additions & 4 deletions

File tree

‎.changeset/18677-validate-per-package-authoring-pass.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
`os validate` runs the per-package author-time rule pass `os build` already ran — the false-clean residue #17069 left one layer down.
66

7-
`os build` runs the artifact's authoring rules **twice**: once over the union-folded stack, then a second `runAuthoringRules('build', …)` pass over each `artifactPackages(…)` entry with `packageBodyAsStack(…)` as resolution context, de-duplicated against the union run. `os validate` ran the union pass and stopped — it imported neither seam. By `compile.ts`' own description the survivors of that second pass are "exactly the set the union could not see", so that whole set was findings `os build` reported and `os validate` **structurally could not**. The direction is false-clean, and on the worse door: the fast pre-flight is what an author runs *before* shipping, so its clean bill of health is the strongest false assurance the three commands can give.
7+
`os build` runs the artifact's authoring rules **twice**: once over the union-folded stack, then a second `runAuthoringRules('build', …)` pass over each `artifactPackages(…)` entry with `packageBodyAsStack(…)` as resolution context, de-duplicated against the union run. `os validate` ran the union pass and stopped — it imported neither seam. By `compile.ts`' own description the survivors of that second pass are the per-package findings no union finding already carried under the same rule, `where`, message and non-top-level position — deliberately narrower than everything the union run missed, because two entries rendering the same `where` still collapse. That whole set was findings `os build` reported and `os validate` **structurally could not**. The direction is false-clean, and on the worse door: the fast pre-flight is what an author runs *before* shipping, so its clean bill of health is the strongest false assurance the three commands can give.
88

99
Measured on `origin/main` 09e16a574 over `examples/app-multi-package`, both commands exiting 0:
1010

‎.changeset/18778-lint-per-package-authoring-pass.md‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
`packages[]` entry with that package's body as the stack and the artifact's own
99
`packages[]` as resolution context, since #16611; `os validate` joined it in
1010
#18677. `os lint` ran the union fold and stopped, so every finding that pass
11-
produces — "exactly the set the union could not see", in the build command's own
12-
words — was reported by the command that ships and invisible on the fastest of
13-
the three doors. All three now call the one shared pass.
11+
produces — in the build command's own words, the per-package findings no union
12+
finding already carried under the same rule, `where`, message and non-top-level
13+
position — was reported by the command that ships and invisible on the fastest
14+
of the three doors. That bound is deliberately narrower than everything the
15+
union run missed: two entries rendering the same `where` still collapse. All
16+
three now call the one shared pass.
1417

1518
Measured on a two-package project whose union run is clean and whose per-package
1619
run is not (one package owns an object, a sibling package owns the view that

0 commit comments

Comments
 (0)