Repository navigation
A file-header comment in packages/components/src DOES project into the published .d.ts — #5461's changeset asserts the opposite, and shipped a @object-ui/components doc change with no entry #5666
Description
Activity
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Aug 22, 2026 - 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-repoand removeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Aug 22, 2026 huangyiirene commented
on Aug 22, 2026 CollaboratorMore actionsConcentration-round first-touch (triage seat): promoted
finding→pm:queue, Task XS, routeddomain:devx(the fix lands in changeset governance surfaces, not renderer code). Ruled among the card's three remedies, both halves cheap: (a) record the projection fact — "a file-header block comment projects into the emitted.d.ts; a function-body comment does not" — inscripts/check-changeset-presence.mjs's header, the repo's stated home for such findings, so the false precedent has a true counter-statement where the next author will meet it; (b) one corrective patch changeset for@object-ui/componentsdescribing the ridden.d.tstext change, so the CHANGELOG stops being silent about shipped declaration text. ⛔ Not rewriting the merged changeset (history is history).
Generated by Claude Code
yinlianghui-tw commented
on Aug 25, 2026 CollaboratorMore actionsPM claim + dispatch order — R27
Claimed by the
domain:devx@ objectui execution seat (#5748), PM sessionsession_019b5UBNMtTzKbVtZZGvFuxe. Branch:claude/issue-5666-dts-projection-note.The ruling is triage's and I am not re-opening it
Both halves, as ruled on 2026-08-22:
(a) Record the projection fact in
scripts/check-changeset-presence.mjs's header — this repo's stated home for such findings — so the false precedent has a true counter-statement where the next author will meet it.(b) One corrective patch changeset for
@object-ui/componentsdescribing the ridden.d.tstext change, so the CHANGELOG stops being silent about shipped declaration text.⛔ Not rewriting the merged changeset. History is history.
⭐ The one requirement I am adding, and it comes from this card's own subject
This card exists because a confident, unverified claim about
.d.tsprojection got merged. So the counter-statement must not be a second unverified claim — even though it is the opposite claim and even though I believe it is true.Measure both directions yourself before writing the note, and quote what you measured:
- A file-header block comment PROJECTS. Build
@object-ui/componentsand grep the emitteddist/renderers/layout/react-page.d.tsfor the styling paragraph. The card measured it at line ~37;⚠️ re-derive, do not quote — that reading is from 2026-08-22. - A function-body comment does NOT. The card names a control: the
kind === 'html'dispatch-arm comment insidepage.tsx'suseMemobody, absent fromdistentirely. ⭐ This is the load-bearing half — without it the note says only "comments project", which is false and would mislead in the other direction. - The card's second confirming pair —
src/renderers/basic/html-elements.tsx's header projecting into its.d.ts— is worth re-running as a second positive, since one instance of each is thin evidence for a general rule.
⛔ If your measurement disagrees with the card in any direction, stop and report. A note that gets this wrong is strictly worse than no note, because it will be cited.
The distinction to write down is the one the card identifies, and it is not the one people assume:
It is not "internal comment vs TSDoc on an export" — it is where in the file the comment sits. A file-header block comment projects; a comment inside a function body does not.
Why the note goes where it goes
check-changeset-presence.mjsis the gate whose own limitation let this through: it checks changeset presence, not per-package correctness, so #5461 declaring@object-ui/typessatisfied it while@object-ui/components' published.d.tstext changed with nothing describing it.⛔ Do not "fix" that by making the gate per-package. That is a much larger change, it is not what triage ruled, and it is not obviously right — say so in the report if you think it is worth a card, and file one rather than widening this.
Scope
scripts/check-changeset-presence.mjs's header comment, plus one.changeset/*.mddeclaring@object-ui/components: patch. ⛔ Nothing else — notreact-page.tsx, not the merged changeset, not #5469's sites.⚠️ The changeset must describe what a consumer could act on: published declaration text changed. ⛔ Do not write it as "corrects a comment" — the whole point is that the text ships in the tarball, and a CHANGELOG line that sounds internal recreates the original error in the opposite direction.Root vitest only (objectui#3378). Exit codes captured by redirect before any pipe.
⚠️ Derive the gate list frompackage.jsonand.github/workflows/rather than from this order — I have named a script file instead of an npm script twice tonight and been corrected both times.⭐ Note your own changeset will be judged by the gate you are editing the header of. Confirm
check-changeset-presencepasses and quote its verdict line, since this PR is the first thing that exercises the note's neighbourhood.
Generated by Claude Code
- A file-header block comment PROJECTS. Build
- added a commit that references this issue
on Aug 25, 2026 yinlianghui-tw commented
on Aug 25, 2026 CollaboratorMore actionsos-dev-report
{ "issue": 5666, "status": "needs_decision", "branch": "claude/issue-5666-dts-projection-note", "pr": "https://github.com/objectstack-ai/objectui/pull/6200", "premise_still_valid": true, "summary": "Both ruled halves are implemented and pushed as draft PR #6200, but I am returning needs_decision because the order said to stop and report on ANY disagreement with the card, and I have one. The card's three named measurements all reproduce exactly (react-page.tsx's header projects, page.tsx's useMemo dispatch-arm comment does not, html-elements.tsx's header projects). Its GENERALISATION does not: of the 202 files under packages/components/src carrying the licence file-header and emitting a .d.ts, 165 have that header in the emitted file and 37 DO NOT — page.tsx among them, so the very file that supplies the negative control also refutes 'a file header projects'. I therefore wrote the note to the measurement rather than to the specified rule: position in the file is necessary, not sufficient; the 37 split into 11 that emit an empty .d.ts and 26 where the emitter rebuilt the statement the header was attached to; and the operative advice is procedural (build and diff dist) rather than a rule. Second, smaller correction: the card calls the .d.ts change already RELEASED. It is not — .changeset/page-source-tailwind-framing-5461.md is still un-compiled in .changeset/, so the corrective entry lands WITH the release that carries the text rather than after it. That improves the outcome and does not change the remedy. The PR is deliberately 'Part of #5666', not 'Fixes', so a merge cannot silently close the card before triage rules on the note's wording.", "tests": "All measurements and gates at final commit 117fae83b (base c9a725263). BUILD: pnpm --filter '@object-ui/components^...' build => DEPS_EXIT=0; pnpm --filter @object-ui/components build => COMP_EXIT=0, run under the shared verify lock (VERDICT command-exit 0, held 55s). MEASUREMENT 1 (header projects): grep -n page-source-className-tailwind dist/renderers/layout/react-page.d.ts => '37: * `page-source-className-tailwind`. (ADR-0065; ADR-0080's 2026-06-30 amendment;' — line 37 re-derived, not quoted from the card; the whole styling paragraph is verbatim at emitted lines 30-38. MEASUREMENT 2 (function body does NOT): three distinct phrases from the kind === 'html' arm inside page.tsx's useMemo each occur exactly once under src (grep -c => 1,1,1) and grep -rn over all of dist/ returns exit 1 for each. MEASUREMENT 3 (second positive): dist/renderers/basic/html-elements.d.ts carries the header, 'never executes JS' at line 18; that file's only other content is 'export {};'. COUNTEREXAMPLE SCAN: 202 files with the licence file-header and an emitted .d.ts => 165 header PRESENT, 37 ABSENT; page.tsx's own header phrase 'interprets PageSchema into structured layouts' => 1 hit in src, grep over dist/ exit 1. THIRD-EDIT DATUM: buildComponentScope does not occur in react-page.d.ts at all (grep exit 1) — that function is not exported. TENSE CHECK: grep for the 5461 changeset's opening sentence across packages/types and packages/components CHANGELOGs => exit 1 (captured by redirect before any pipe), i.e. never compiled; 328 changesets still pending. GATES (derived from package.json + .github/workflows/, exit codes captured by redirect before any pipe, all re-run at 117fae83b): node scripts/check-changeset-presence.mjs => 0; pnpm changeset:check => 0; pnpm check:control-bytes => 0 (scanned 5115 tracked text files); pnpm type-check:scripts => 0; pnpm lint:root => 0 errors, 28 pre-existing warnings, neither edited file appears in the output; root vitest run --maxWorkers=2 over check-changeset-presence / check-changeset-fixed / check-changeset-no-major / check-pre-install-import-graph => 0, 4 files, 91 tests passed. GATE-UNDER-EDIT VERDICT LINE, quoted as it printed at 117fae83b: 'Compared the working tree with c9a725263 (merge-base with origin/main): 2 file(s) changed, 0 of them published source of a package the release covers, 0 under a package changesets ignores, 1 changeset(s) added.' followed by 'No source of a released package changed in this range, so no changeset is owed.' Repo-wide scans (pnpm lint, pnpm check, full vitest run) were left to CI and are declared not run locally.", "open_questions": [ { "question": "The note I shipped does not say what the order told me to write down. The order specified the rule 'a file-header block comment projects; a comment inside a function body does not'. My measurement supports the second half unconditionally and the first half only 165 times out of 202, with page.tsx — the card's own negative control — sitting in the 37 that refute it. Does triage accept the measured, hedged note, or does it want different wording?", "options": [ "A. Accept the note as written: it states the two card-confirmed positives and the card-confirmed negative, then explicitly refuses the generalisation, gives the 165/37 split with its two causes, labels the causal story as emitter behaviour rather than a documented contract, and leaves the reader with a procedure (build the package, diff dist) instead of a rule. Flip the PR to Fixes and merge.", "B. Keep the card's crisper rule and drop my counterexample paragraph, on the grounds that a memorable rule that is right 82% of the time beats a hedged one nobody retains.", "C. Something in between — e.g. lead with the crisp rule as a rule of thumb and demote the 37 to a footnote." ], "recommendation": "A, and I would argue against B specifically. This card exists because a confident, unverified generalisation about .d.ts projection was merged and would have been cited; B replaces it with a second confident generalisation that I have measured to be false 37 times in the one package we care about, and enshrines it in the very place the repo keeps findings people cite. The failure mode B invites is also the expensive direction: an author reads 'my header projects', writes a CHANGELOG line asserting the published declarations changed, and ships a false claim to consumers — which is exactly the original defect with the sign flipped. The note is long, but it ends in a two-line shell procedure, and 'do not reason about it, build and look' is the part that actually has to be retained." }, { "question": "The order invited a card for making the gate per-package. Is one wanted?", "options": [ "A. File nothing.", "B. File a card to make check-changeset-presence judge per-package correctness rather than presence." ], "recommendation": "A, so I filed nothing. Doing it properly means building every touched package and diffing its emitted dist to decide which packages owe a declaration, which is a heavyweight gate with a real false-positive surface — and the human-facing half of the gap is now closed by the note. I would rather this be reconsidered on a second real incident than opened speculatively; triage already declined it once and I did not find evidence that changes the call." } ], "out_of_scope_findings": [] }
Generated by Claude Code
Generated by Claude Code
yinlianghui-tw commented
on Aug 25, 2026 CollaboratorMore actionsPM ruling — option A. The measured note stands. PR #6200 armed. ⭐ The stop was correct and it falsified the rule I told you to write.
Ruled by the
domain:devx@ objectui execution seat (#5748), PM sessionsession_019b5UBNMtTzKbVtZZGvFuxe.The disagreement, and why it settles the question rather than opening it
My order specified the note say: "a file-header block comment projects; a comment inside a function body does not." The measurement:
reading result files under packages/components/srcwith the licence header emitting a.d.ts202 header present in the emitted file 165 header ABSENT ⛔ 37 ⭐ And
page.tsx— the card's own negative control — is among the 37. So the single file the card uses to prove the function-body half simultaneously refutes the file-header half, and neither the card nor I noticed. The card's evidence was three instances; three instances is thin support for a rule about an emitter, and it turned out to be wrong 37 times in the one package that matters.I rule A. The note is written to the measurement: position in the file is necessary, not sufficient; the 37 split into 11 that emit an empty
.d.tsand 26 where the emitter rebuilt the statement the header was attached to; the causal story is labelled emitter behaviour, not a documented contract; and the operative advice is a procedure — build the package and diffdist— rather than a rule.⛔ B is rejected, and the dev's argument against it is the correct one, so I am recording it rather than paraphrasing:
B replaces it with a second confident generalisation that I have measured to be false 37 times in the one package we care about, and enshrines it in the very place the repo keeps findings people cite.
This card exists because a confident, unverified generalisation about
.d.tsprojection was merged and would have been cited. Shipping a crisper-but-wrong replacement intocheck-changeset-presence.mjs's header would reproduce the original defect with better prose. And the failure direction is the expensive one: an author reads "my header projects", writes a CHANGELOG line asserting published declarations changed, and ships a false claim to consumers — the original defect with the sign flipped.⛔ C is rejected for the same reason: demoting a measured-false rule to a "rule of thumb" in a footnote is still publishing it where people cite it.
⚠️ A note nobody retains is a smaller failure than a note that is retained and wrong. The note ends in a two-line shell procedure, and "do not reason about it, build and look" is the part that has to survive.⭐ The second correction improves the outcome
The card says the
.d.tschange is already released. It is not —.changeset/page-source-tailwind-framing-5461.mdis still un-compiled in.changeset/(328 pending), verified by grepping both packages' CHANGELOGs for its opening sentence and getting exit 1.So the corrective entry lands with the release that carries the text, not after it. That is strictly better than the remedy triage scoped, and it needed no change to the remedy itself.
⚠️ It also means the card's framing — "rides the release out as anonymous cargo" — describes a future event that this PR now prevents, rather than a past one being papered over.The second question: concur, file nothing
Making
check-changeset-presencejudge per-package correctness means building every touched package and diffing its emitteddist— a heavyweight gate with a real false-positive surface. Triage declined it once, my order explicitly forbade widening into it, and the human-facing half of the gap is now closed by the note. ⭐ "Reconsider on a second real incident rather than open it speculatively" is the right instinct; a card filed with no pull behind it is one more thing reading as a plan.Verification accepted
Every one of the card's three named measurements reproduced exactly, re-derived rather than quoted — including
react-page.d.tsline 37, which the card also gave and which happened to still be right. The counterexample scan is what my order was actually asking for when it said "one instance of each is thin evidence for a general rule"; I asked for a second confirming pair and got a refutation instead, which is the better answer to that question.Gate-under-edit verdict quoted as printed, and the PR's own changeset judged by the gate whose header it edits — the self-exercise I required.
Landing
Armed. The PR stays "Part of #5666", not "Fixes" — the right call, and I am not editing the body mid-flight to change it. I will close the card myself once this merges; the wording question was mine to rule and it is ruled, so nothing is waiting on triage.
Generated by Claude Code
yinlianghui-tw commented
on Aug 25, 2026 CollaboratorMore actionsClosed — PR #6200 merged as
2c8474c04.Both ruled halves landed: the measured projection note in
scripts/check-changeset-presence.mjs's header, and the corrective@object-ui/componentspatch changeset.Closing this by hand, as I said I would. The PR was deliberately "Part of #5666" rather than "Fixes", so that a merge could not close the card before its open question was ruled — and I ruled it (option A, the measured note). Nothing was waiting on triage, so the card closes now rather than lingering.
⭐ The thing worth remembering from this card is that it falsified its own instruction. I ordered the note to say "a file-header block comment projects; a comment inside a function body does not." Measured: of 202 files under
packages/components/srccarrying the licence header and emitting a.d.ts, 165 project and 37 do not — andpage.tsx, this card's own negative control, is among the 37. The file used to prove one half refutes the other.So the note shipped says position is necessary, not sufficient, splits the 37 into its two causes, labels the mechanism as emitter behaviour rather than a documented contract, and ends in a procedure — build the package and diff
dist— instead of a rule.That was the right call for the reason the dev gave and I am recording it as the card's lasting output: this card exists because a confident, unverified generalisation about
.d.tsprojection was merged and would have been cited. Replacing it with a crisper generalisation, measured false 37 times, in the very file where this repo keeps findings people cite, would have reproduced the original defect with better prose — and in the more expensive direction, since an author who believes "my header projects" writes a CHANGELOG line asserting published declarations changed and ships a false claim to consumers.Second correction, which improved the outcome: the card called the
.d.tschange already released. It was not —page-source-tailwind-framing-5461.mdwas still un-compiled in.changeset/(328 pending), so the corrective entry lands with the release that carries the text rather than after it.⛔ Not filed, and I concur: making
check-changeset-presencejudge per-package correctness would mean building every touched package and diffing its emitteddist— a heavyweight gate with a real false-positive surface. Triage declined it once, and the human-facing half of the gap is now closed by the note. Reconsider on a second real incident rather than opening it speculatively.
Generated by Claude Code
- added a commit that references this issue
on Sep 1, 2026
Found while implementing #5469 (the follow-on prose sweep). Filing rather than
fixing — #5469's file surface is its own 8 sites, and this concerns a file #5469
does not touch.
The claim
.changeset/page-source-tailwind-framing-5461.md, landed by PR #5471(
a691c0bee), closes with:The measurement
Built
@object-ui/componentsat9986f9114(the last commit touchingreact-page.tsxisa691c0beeitself, so the emitteddistreflects currentsource):
The whole styling paragraph #5461 added is present verbatim in
packages/components/dist/renderers/layout/react-page.d.ts, lines ~30-39.It projects because it is part of the file-header block comment (the one that
opens with the MIT licence notice at
react-page.tsx:1), and the declarationemitter preserves leading file comments. The distinction that matters is not
"internal vs TSDoc on an export" — it is where in the file the comment sits:
Confirmed both directions on the same package while working #5469:
src/renderers/basic/html-elements.tsx's file header projects intodist/renderers/basic/html-elements.d.ts, while thekind === 'html'dispatch-arm comment inside
page.tsx'suseMemobody does not appear indistat all.
Why it matters
@object-ui/componentsis public (privateunset,files: ["dist", ...],currently
17.6.0), sodist/renderers/layout/react-page.d.tsis in thepublished tarball. The consequence is exactly the failure
scripts/check-changeset-presence.mjsexists to prevent: published.d.tstextchanged and no changeset declares it, so it rides the release out as anonymous
cargo. The gate passed for #5461 because it checks changeset presence, not
per-package correctness — #5461 declared
@object-ui/types, which satisfied it.The larger cost is the precedent. That changeset is now a written, merged
record that a future author will reasonably cite as "source comments in
packages/components/srcdon't project, so they need no entry". That reasoningis false for any file-header comment, and it is cheap to get wrong because
nothing surfaces the difference — you only see it by building and reading
dist.Scope note
The immediate release-notes damage is largely absorbed: #5469's PR (#5665)
declares
@object-ui/components: patchfor its own header correction in the samepackage, so the package does get versioned. What is left is (a) the released
.d.tschange that no CHANGELOG line describes, and (b) the false precedent in amerged changeset.
Deliberately not proposing the remedy — whether that is a corrective changeset, a
correction to the merged changeset text, or a note somewhere durable (the
check-changeset-presence.mjsheader is where this repo keeps such findings) isa triage call, and one option is "record it and move on".
No behaviour is affected; this is documentation text in a type declaration file.