You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
finding(tooling): ui:icon becomes a record-reading resolver in #5631, but its type is absent from the lucide gate's census — 96 authored glyph names go unjudged, three of them already retired spellings #6009
Found while implementing #5631 (the ui:icon glyph-key contract migration). Out of that card's scope — it is the wrong resolver table family, not the wrong schema key — so recorded here rather than folded in.
What happens
scripts/check-lucide-icon-record-names.mjs judges authored icon names by a hand-maintained census, RECORD_READING_TYPES, mapping a component type to the paths where its glyph names sit:
'icon' — the ui:icon node type itself — is not among them, and could not have been before #5631: that renderer named its glyph with name, and every census path is an icon path.
After #5631 lands, ui:icon resolves schema.icon through lucide's runtime icons record. It is now exactly the kind of resolver this gate exists for, and its authored names are still not judged.
How it was measured
The gate's own --report counter, run on the same tree before and after the corpus conversion (the conversion reverted in place under a restoring trap, then restored — the tree verified byte-identical to HEAD afterwards):
before conversion: authored icon names judged: 30 | declines to judge: 254
after conversion: authored icon names judged: 30 | declines to judge: 350
+96, and judged does not move. The delta is exactly the 96 non-.mdx icon nodes the migration converted from name to icon; they moved out of "invisible to the gate" and into "seen, and declined". The gate stays green either way, which is the property worth noting: this is not a gate that fails, it is a gate whose population quietly shrank relative to what now reaches a resolver.
Why it matters concretely
Three of those 96 are a retired lucide spelling today:
check-circle is absent from lucide's runtime icons record (the #5622 / #5586 mechanism: a retired spelling is dropped from the record while the deprecated named export survives). Those three rendered nothing before #5631 and render the visible placeholder after it — unchanged behaviour, no regression from that card — but they are precisely the population check-lucide-icon-record-names.mjs was built to catch, and it does not see them.
The fix is not mechanical, which is why this is filed rather than done
to the census turns the gate red on the three check-circle nodes. That is the correct outcome, but it makes the census entry and a retired-spelling repair land together — and the spelling family (#5622 / #5586) is deliberately kept separate from the key family. Whoever takes this decides whether the repair is circle-check in the fixtures or something the #5935 consolidation should absorb first.
Concentrated triage round: finding → pm:queue, Task; relabelled domain:ui → domain:devx (gate face — fix lands in scripts/check-lucide-icon-record-names.mjs's census). Upstream #5631 is closed completed, so ui:icon is now a record-reading resolver the gate does not judge: add the 'icon' census entry (path icon), and repair the three already-retired spellings the report surfaced — those three ship blank glyphs today. Coordinate with #5992 (same gate file) — fold-or-serial is a required answer at claim; the two cards look foldable (same file, same defect shape: census blind spots) and both are already graded, so a family dispatch is available to the seat under the five-gate check.
Fold-or-serial answer: serial, not folded.#5992 already landed as PR #6277 (merged into main at e3784607f), so there is nothing left to fold — that card rewrote scripts/check-lucide-icon-record-names.mjs (the descendants: true census flag for untyped child items, and a re-measured header container table). This branch points at post-e3784607fmain and re-derives every line reference and counter against the file as it now is; the card body predates that rewrite.
Scope: the 'icon' census entry plus the three retired-spelling fixture repairs in examples/schema-catalog/src/schemas/marketing/call-to-action.json, landing as one PR because the census entry alone turns the gate red on those three nodes.
{
"issue": 6009,
"status": "done",
"branch": "claude/issue-6009-icon-census-entry",
"pr": "https://github.com/objectstack-ai/objectui/pull/6290",
"premise_still_valid": true,
"summary": "Re-derived against post-#6277 main (branch point contains e3784607f, confirmed by git merge-base --is-ancestor). The card's central premise held exactly: adding 'icon' to RECORD_READING_TYPES moves 96 authored glyph names from declined to judged, and three of them are the retired spelling check-circle. Two corrections to the card/dispatch, both load-bearing. (1) The replacement is `circle-check-big`, NOT `circle-check`: probed against the installed lucide-react 1.31.0, CheckCircle === CircleCheckBig is true and CheckCircle === CircleCheck is false, so `circle-check` is a live key naming a DIFFERENT glyph and would have silently changed the rendered artwork while going green. The gate's own identity derivation prints `circle-check-big` unprompted. (2) The OK line's resolver count does NOT rise 8 -> 9: that number reads discovered.record.length (part 1's discovered MODULES), not the size of RECORD_READING_TYPES, so a part-2 entry cannot move it. RECORD_READING_TYPES goes 9 -> 10 entries, a count printed nowhere. Also added five pin tests plus a header note recording the re-taken container table. Only stale detail: check-circle sits at lines 54/70/86, not ~53/69/85.",
"tests": "All exit codes captured by redirect before any pipe; verdicts quoted from what each gate printed. FINAL UNION re-run on final commit 1443fcbf0 (git rev-parse --short HEAD), all green: `check:icon-record-names` EXIT=0 -> 'OK lucide icon names: 163 authored/declared names reaching 8 record-reading resolvers are live `icons` keys (record 1767 keys; dynamic surface 4 sites, 2025 names, not judged here).' | `type-check:scripts` EXIT=0 | `lint:root` UNNARROWED EXIT=0 -> '✖ 28 problems (0 errors, 28 warnings)' (all pre-existing no-explicit-any) | `check:control-bytes` EXIT=0 -> '✅ check-control-bytes: OK (scanned 5178 tracked text file(s); skipped 85 binary).' | `pnpm exec vitest run scripts/__tests__` EXIT=0 -> 'Test Files 77 passed (77) / Tests 2223 passed (2223)' | `check-changeset-presence` EXIT=0 -> '✅ No source of a released package changed in this range, so no changeset is owed.' NO NARROWING anywhere. GATE BOTH DIRECTIONS: with the census entry alone the gate went RED, EXIT=1, naming all three sites — examples/schema-catalog/src/schemas/marketing/call-to-action.json at $.children[0].children[3].children[{0,1,2}].children[0].icon, each '\"check-circle\" -> `CheckCircle` is not a key of the runtime `icons` record ... write `circle-check-big`', 'Resolved through: packages/components/src/renderers/basic/icon.tsx'; after the fixture repair EXIT=0. COUNTERS before/after: baseline at e3784607f judged 33 | declined 347 | anchored 34 | OK-line total 67 | resolvers 8; after census entry judged 129 | declined 251 | anchored 34 | resolvers 8; after repair judged 129 | declined 251 | anchored 34 | OK-line total 163 | resolvers 8. That is +96/-96, exactly the population the card measured, with anchoredJudged and the resolver count both holding still. SUITE: scripts/__tests__/check-lucide-icon-record-names.test.ts --reporter=verbose, 39 passed (39) — my 5 new tests collected by name ('the `ui:icon` node type > goes RED on a retired spelling, naming `icon.tsx` as the resolver' / '> goes GREEN on the live spelling — and the name was really judged' / '> declares NO descent — the renderer resolves one name and never walks children' / 'this repository > really judges the `ui:icon` nodes objectui#6009 opened up' / 'this repository > did NOT grow part 1 for `ui:icon` either — it was ALREADY a declared resolver'), and #6277's 9 tests all still pass. ABLATION (no build/dist involved — the gate runs from source and the suite imports it from source, so there is no stale-artifact leg to rebuild): deleting the 'icon' census entry, with the mutation CONFIRMED ON DISK by anchored grep on the exact line (count 1 -> 0, plus git diff --stat showing 1 deletion) rather than by the editor's exit code, and restored under a `trap ... EXIT INT TERM`. Result: 'Tests 4 failed | 35 passed (39)' — four of the five new tests go red. The fifth staying green is the correct reading, not a hole: it asserts icon.tsx was ALREADY a part-1 resolver, true independently of the part-2 entry. RESTORE LEG also confirmed on disk: anchored grep back to 1, git status clean against HEAD, gate re-run EXIT=0. type-check:scripts was non-vacuous over my own diff — it caught expect(RECORD_READING_TYPES.icon.descendants) as TS2339 (the key is absent from icon's inferred type since RECORD_READING_TYPES is a plain object literal); fixed at the ASSERTION using the file's own `'descendants' in ...` idiom, which also asserts the stronger fact, rather than widening the type to accommodate the test.",
"open_questions": [],
"out_of_scope_findings": []
}
Part-1 decision, with the import evidence
icon.tsx is a DIRECT record reader, and part 1 already knew it — no part-1 change was needed or made. The file carries import { icons, SquareDashed } from 'lucide-react'; and indexes it as (icons as any)[mappedIconName], which is exactly what discoverResolvers matches (named import of icons + an element access on the local binding). It has therefore been in DECLARED_RECORD_READERS since #5633's own discovery run, and appears in the discovered set on main before my change.
This is the asymmetry against dropdown-menu.tsx, which routes through resolveIcon and correctly stays out. Part 1 knowing a module and part 2 knowing which type sends names to it are two independent facts; this PR supplies only the second. Part 1's rediscovery did not flag icon.tsx as undeclared either before or after my edit, so there was nothing to reconcile — discovered.record stays at 8 across all three runs, now pinned by a test so a future change that moved the wrong part of the gate fails loudly.
descendants was decided by reading the renderer, not assumed: icon.tsx resolves one name and returns a single element (the resolved component, or the SquareDashed placeholder). It never walks children, so there is no untyped-child population for a descent to reach — and under the gate's own non-vacuity rule a descent that reaches nothing is an ERROR. No descendants, no min.
The header container table, re-measured
#6277 re-measured it at ef2a3bd8d as 61 untyped names across 7 containers. Re-taken at e3784607f: identical, per-container figures and all — tree-view 30, command 9, button-group 8, context-menu 4, timeline 4, breadcrumb 3, dropdown-menu 3.
It looks like this change should move it and it does not, which is the point worth recording: the table counts UNTYPED names, and a type: 'icon' node is typed, so the two populations are disjoint. No figure in it needed editing. Recorded in the header naming the commit, per the #6277/#6260 pattern, rather than left implicit — "the numbers did not move" is a measurement, and the next reader should not have to re-derive that it was taken.
Re-measuring did surface a scope caveat the count did not carry on its face, now also written into the header: the table is measured over examples/schema-catalog/, while the gate scanspackages/, apps/ and examples/. Over the full scan roots the same walk finds 76 untyped names across 9 containers — the extra 15 all in packages/types/examples/ (tree-view +6, timeline +3, plus list 3 and sidebar 3, two containers the table does not name at all). Both extra containers were read: data-display/list.tsx and navigation/sidebar.tsx never read icon, so those names reach no resolver and decline correctly. All 15 were additionally checked against the record and are live spellings, so nothing is hiding there — no finding filed, and the gap is closed in the header rather than left for a future reader to trip on.
Changeset
None, on the presence gate's own verdict rather than my reading of examples/: @object-ui/example-schema-catalog is private: trueand matches @object-ui/example-* in .changeset/config.json's ignore list. node scripts/check-changeset-presence.mjs EXIT=0 reports 3 file(s) changed, 0 of them published source of a package the release covers, 0 changeset(s) added. scripts/ needs none. No skip-changeset label created or applied.
PR #6290 is draft, base main, head 1443fcbf0, 3 files, +113/-3. Auto-merge NOT armed. CI convergence left to PM per the 2026-08-10 ruling.
Re-posted with a literal-text marker: on the previous comment (5407479522) the HTML-comment form of this marker was eaten by GitHub's body sanitizer after the write landed, which would have made that report invisible to a scan keyed on it. Same report, same run — the prose sections (part-1 import evidence, the re-measured header table, the changeset verdict) are in that comment and in the PR body; this one carries the machine-readable half.
{
"issue": 6009,
"status": "done",
"branch": "claude/issue-6009-icon-census-entry",
"pr": "https://github.com/objectstack-ai/objectui/pull/6290",
"premise_still_valid": true,
"summary": "Re-derived against post-#6277 main (branch point contains e3784607f, confirmed by git merge-base --is-ancestor). The card's central premise held exactly: adding 'icon' to RECORD_READING_TYPES moves 96 authored glyph names from declined to judged, and three of them are the retired spelling check-circle. Two corrections to the card/dispatch, both load-bearing. (1) The replacement is circle-check-big, NOT circle-check: probed against the installed lucide-react 1.31.0, CheckCircle === CircleCheckBig is true and CheckCircle === CircleCheck is false, so circle-check is a live key naming a DIFFERENT glyph and would have silently changed the rendered artwork while going green. The gate's own identity derivation prints circle-check-big unprompted. (2) The OK line's resolver count does NOT rise 8 to 9: that number reads discovered.record.length (part 1's discovered MODULES), not the size of RECORD_READING_TYPES, so a part-2 entry cannot move it; RECORD_READING_TYPES goes 9 to 10 entries, a count printed nowhere. Part 1 needed no change: icon.tsx imports the icons record DIRECTLY (import { icons, SquareDashed } from 'lucide-react' plus (icons as any)[mappedIconName]) and has been in DECLARED_RECORD_READERS since #5633's discovery run, so rediscovery never flagged it, before or after the edit — the asymmetry against dropdown-menu.tsx, which routes through resolveIcon and stays out. No descendants flag: the renderer resolves one name and returns a single element, never walking children. Added five pin tests plus a header note recording the re-taken container table (61 names / 7 containers at e3784607f — UNCHANGED, because the table counts UNTYPED names and a type:'icon' node is typed, so the populations are disjoint). Only stale detail in the card: check-circle sits at lines 54/70/86, not ~53/69/85.",
"tests": "All exit codes captured by redirect before any pipe; verdicts quoted from what each gate printed. FINAL UNION re-run on final commit 1443fcbf0 (git rev-parse --short HEAD), all green: check:icon-record-names EXIT=0 -> 'OK lucide icon names: 163 authored/declared names reaching 8 record-reading resolvers are live `icons` keys (record 1767 keys; dynamic surface 4 sites, 2025 names, not judged here).' | type-check:scripts EXIT=0 | lint:root UNNARROWED EXIT=0 -> '28 problems (0 errors, 28 warnings)' (all pre-existing no-explicit-any) | check:control-bytes EXIT=0 -> 'check-control-bytes: OK (scanned 5178 tracked text file(s); skipped 85 binary).' | pnpm exec vitest run scripts/__tests__ EXIT=0 -> 'Test Files 77 passed (77) / Tests 2223 passed (2223)' | check-changeset-presence EXIT=0 -> 'No source of a released package changed in this range, so no changeset is owed.' NO NARROWING anywhere. GATE BOTH DIRECTIONS: census entry alone went RED, EXIT=1, naming all three sites — examples/schema-catalog/src/schemas/marketing/call-to-action.json at $.children[0].children[3].children[0].children[0].icon, $.children[0].children[3].children[1].children[0].icon and $.children[0].children[3].children[2].children[0].icon, each 'check-circle -> CheckCircle is not a key of the runtime icons record ... write circle-check-big', 'Resolved through: packages/components/src/renderers/basic/icon.tsx'; after the fixture repair EXIT=0. COUNTERS before/after: baseline at e3784607f judged 33 | declined 347 | anchored 34 | OK-line total 67 | resolvers 8; after census entry judged 129 | declined 251 | anchored 34 | resolvers 8; after repair judged 129 | declined 251 | anchored 34 | OK-line total 163 | resolvers 8. That is +96/-96, exactly the population the card measured, with anchoredJudged and the resolver count both holding still. SUITE: scripts/__tests__/check-lucide-icon-record-names.test.ts --reporter=verbose, 39 passed (39) — 5 new tests collected by name ('the ui:icon node type > goes RED on a retired spelling, naming icon.tsx as the resolver' / '> goes GREEN on the live spelling — and the name was really judged' / '> declares NO descent — the renderer resolves one name and never walks children' / 'this repository > really judges the ui:icon nodes objectui#6009 opened up' / 'this repository > did NOT grow part 1 for ui:icon either — it was ALREADY a declared resolver'), and #6277's 9 tests all still pass. ABLATION (no build/dist leg exists here — the gate runs from source and the suite imports it from source, so there is no stale artifact to rebuild): deleted the 'icon' census entry with the mutation CONFIRMED ON DISK by anchored grep on the exact line (count 1 -> 0, plus git diff --stat showing 1 deletion) rather than by the editor's exit code, restored under a trap ... EXIT INT TERM. Result: 'Tests 4 failed | 35 passed (39)' — four of the five new tests go red. The fifth staying green is the correct reading, not a hole: it asserts icon.tsx was ALREADY a part-1 resolver, true independently of the part-2 entry. RESTORE LEG also confirmed on disk: anchored grep back to 1, git status clean against HEAD, gate re-run EXIT=0. type-check:scripts proved non-vacuous over my own diff — it caught expect(RECORD_READING_TYPES.icon.descendants) as TS2339 (the key is absent from icon's inferred type since RECORD_READING_TYPES is a plain object literal); fixed at the ASSERTION using the file's own \"'descendants' in ...\" idiom, which also asserts the stronger fact, rather than widening the type to accommodate the test.",
"open_questions": [],
"out_of_scope_findings": []
}
Activity
claude commentedon Aug 25, 2026
Concentrated triage round:
finding→pm:queue, Task; relabelleddomain:ui→domain:devx(gate face — fix lands inscripts/check-lucide-icon-record-names.mjs's census). Upstream #5631 is closed completed, soui:iconis now a record-reading resolver the gate does not judge: add the'icon'census entry (pathicon), and repair the three already-retired spellings the report surfaced — those three ship blank glyphs today. Coordinate with #5992 (same gate file) — fold-or-serial is a required answer at claim; the two cards look foldable (same file, same defect shape: census blind spots) and both are already graded, so a family dispatch is available to the seat under the five-gate check.Generated by Claude Code
yinlianghui-tw commentedon Aug 25, 2026
Claiming this card.
session_019b5UBNMtTzKbVtZZGvFuxeclaude/issue-6009-icon-census-entry../objectui-6009Fold-or-serial answer: serial, not folded. #5992 already landed as PR #6277 (merged into
mainate3784607f), so there is nothing left to fold — that card rewrotescripts/check-lucide-icon-record-names.mjs(thedescendants: truecensus flag for untyped child items, and a re-measured header container table). This branch points at post-e3784607fmainand re-derives every line reference and counter against the file as it now is; the card body predates that rewrite.Scope: the
'icon'census entry plus the three retired-spelling fixture repairs inexamples/schema-catalog/src/schemas/marketing/call-to-action.json, landing as one PR because the census entry alone turns the gate red on those three nodes.Generated by Claude Code
Generated by Claude Code
yinlianghui-tw commentedon Aug 25, 2026
{ "issue": 6009, "status": "done", "branch": "claude/issue-6009-icon-census-entry", "pr": "https://github.com/objectstack-ai/objectui/pull/6290", "premise_still_valid": true, "summary": "Re-derived against post-#6277 main (branch point contains e3784607f, confirmed by git merge-base --is-ancestor). The card's central premise held exactly: adding 'icon' to RECORD_READING_TYPES moves 96 authored glyph names from declined to judged, and three of them are the retired spelling check-circle. Two corrections to the card/dispatch, both load-bearing. (1) The replacement is `circle-check-big`, NOT `circle-check`: probed against the installed lucide-react 1.31.0, CheckCircle === CircleCheckBig is true and CheckCircle === CircleCheck is false, so `circle-check` is a live key naming a DIFFERENT glyph and would have silently changed the rendered artwork while going green. The gate's own identity derivation prints `circle-check-big` unprompted. (2) The OK line's resolver count does NOT rise 8 -> 9: that number reads discovered.record.length (part 1's discovered MODULES), not the size of RECORD_READING_TYPES, so a part-2 entry cannot move it. RECORD_READING_TYPES goes 9 -> 10 entries, a count printed nowhere. Also added five pin tests plus a header note recording the re-taken container table. Only stale detail: check-circle sits at lines 54/70/86, not ~53/69/85.", "tests": "All exit codes captured by redirect before any pipe; verdicts quoted from what each gate printed. FINAL UNION re-run on final commit 1443fcbf0 (git rev-parse --short HEAD), all green: `check:icon-record-names` EXIT=0 -> 'OK lucide icon names: 163 authored/declared names reaching 8 record-reading resolvers are live `icons` keys (record 1767 keys; dynamic surface 4 sites, 2025 names, not judged here).' | `type-check:scripts` EXIT=0 | `lint:root` UNNARROWED EXIT=0 -> '✖ 28 problems (0 errors, 28 warnings)' (all pre-existing no-explicit-any) | `check:control-bytes` EXIT=0 -> '✅ check-control-bytes: OK (scanned 5178 tracked text file(s); skipped 85 binary).' | `pnpm exec vitest run scripts/__tests__` EXIT=0 -> 'Test Files 77 passed (77) / Tests 2223 passed (2223)' | `check-changeset-presence` EXIT=0 -> '✅ No source of a released package changed in this range, so no changeset is owed.' NO NARROWING anywhere. GATE BOTH DIRECTIONS: with the census entry alone the gate went RED, EXIT=1, naming all three sites — examples/schema-catalog/src/schemas/marketing/call-to-action.json at $.children[0].children[3].children[{0,1,2}].children[0].icon, each '\"check-circle\" -> `CheckCircle` is not a key of the runtime `icons` record ... write `circle-check-big`', 'Resolved through: packages/components/src/renderers/basic/icon.tsx'; after the fixture repair EXIT=0. COUNTERS before/after: baseline at e3784607f judged 33 | declined 347 | anchored 34 | OK-line total 67 | resolvers 8; after census entry judged 129 | declined 251 | anchored 34 | resolvers 8; after repair judged 129 | declined 251 | anchored 34 | OK-line total 163 | resolvers 8. That is +96/-96, exactly the population the card measured, with anchoredJudged and the resolver count both holding still. SUITE: scripts/__tests__/check-lucide-icon-record-names.test.ts --reporter=verbose, 39 passed (39) — my 5 new tests collected by name ('the `ui:icon` node type > goes RED on a retired spelling, naming `icon.tsx` as the resolver' / '> goes GREEN on the live spelling — and the name was really judged' / '> declares NO descent — the renderer resolves one name and never walks children' / 'this repository > really judges the `ui:icon` nodes objectui#6009 opened up' / 'this repository > did NOT grow part 1 for `ui:icon` either — it was ALREADY a declared resolver'), and #6277's 9 tests all still pass. ABLATION (no build/dist involved — the gate runs from source and the suite imports it from source, so there is no stale-artifact leg to rebuild): deleting the 'icon' census entry, with the mutation CONFIRMED ON DISK by anchored grep on the exact line (count 1 -> 0, plus git diff --stat showing 1 deletion) rather than by the editor's exit code, and restored under a `trap ... EXIT INT TERM`. Result: 'Tests 4 failed | 35 passed (39)' — four of the five new tests go red. The fifth staying green is the correct reading, not a hole: it asserts icon.tsx was ALREADY a part-1 resolver, true independently of the part-2 entry. RESTORE LEG also confirmed on disk: anchored grep back to 1, git status clean against HEAD, gate re-run EXIT=0. type-check:scripts was non-vacuous over my own diff — it caught expect(RECORD_READING_TYPES.icon.descendants) as TS2339 (the key is absent from icon's inferred type since RECORD_READING_TYPES is a plain object literal); fixed at the ASSERTION using the file's own `'descendants' in ...` idiom, which also asserts the stronger fact, rather than widening the type to accommodate the test.", "open_questions": [], "out_of_scope_findings": [] }Part-1 decision, with the import evidence
icon.tsxis a DIRECT record reader, and part 1 already knew it — no part-1 change was needed or made. The file carriesimport { icons, SquareDashed } from 'lucide-react';and indexes it as(icons as any)[mappedIconName], which is exactly whatdiscoverResolversmatches (named import oficons+ an element access on the local binding). It has therefore been inDECLARED_RECORD_READERSsince #5633's own discovery run, and appears in the discovered set onmainbefore my change.This is the asymmetry against
dropdown-menu.tsx, which routes throughresolveIconand correctly stays out. Part 1 knowing a module and part 2 knowing whichtypesends names to it are two independent facts; this PR supplies only the second. Part 1's rediscovery did not flagicon.tsxas undeclared either before or after my edit, so there was nothing to reconcile —discovered.recordstays at 8 across all three runs, now pinned by a test so a future change that moved the wrong part of the gate fails loudly.descendantswas decided by reading the renderer, not assumed:icon.tsxresolves one name and returns a single element (the resolved component, or theSquareDashedplaceholder). It never walkschildren, so there is no untyped-child population for a descent to reach — and under the gate's own non-vacuity rule a descent that reaches nothing is an ERROR. Nodescendants, nomin.The header container table, re-measured
#6277 re-measured it at
ef2a3bd8das 61 untyped names across 7 containers. Re-taken ate3784607f: identical, per-container figures and all —tree-view30,command9,button-group8,context-menu4,timeline4,breadcrumb3,dropdown-menu3.It looks like this change should move it and it does not, which is the point worth recording: the table counts UNTYPED names, and a
type: 'icon'node is typed, so the two populations are disjoint. No figure in it needed editing. Recorded in the header naming the commit, per the #6277/#6260 pattern, rather than left implicit — "the numbers did not move" is a measurement, and the next reader should not have to re-derive that it was taken.Re-measuring did surface a scope caveat the count did not carry on its face, now also written into the header: the table is measured over
examples/schema-catalog/, while the gate scanspackages/,apps/andexamples/. Over the full scan roots the same walk finds 76 untyped names across 9 containers — the extra 15 all inpackages/types/examples/(tree-view+6,timeline+3, pluslist3 andsidebar3, two containers the table does not name at all). Both extra containers were read:data-display/list.tsxandnavigation/sidebar.tsxnever readicon, so those names reach no resolver and decline correctly. All 15 were additionally checked against the record and are live spellings, so nothing is hiding there — no finding filed, and the gap is closed in the header rather than left for a future reader to trip on.Changeset
None, on the presence gate's own verdict rather than my reading of
examples/:@object-ui/example-schema-catalogisprivate: trueand matches@object-ui/example-*in.changeset/config.json'signorelist.node scripts/check-changeset-presence.mjsEXIT=0 reports3 file(s) changed, 0 of them published source of a package the release covers, 0 changeset(s) added.scripts/needs none. Noskip-changesetlabel created or applied.PR #6290 is draft, base
main, head1443fcbf0, 3 files, +113/-3. Auto-merge NOT armed. CI convergence left to PM per the 2026-08-10 ruling.Generated by Claude Code
Generated by Claude Code
yinlianghui-tw commentedon Aug 25, 2026
os-dev-report
Re-posted with a literal-text marker: on the previous comment (5407479522) the HTML-comment form of this marker was eaten by GitHub's body sanitizer after the write landed, which would have made that report invisible to a scan keyed on it. Same report, same run — the prose sections (part-1 import evidence, the re-measured header table, the changeset verdict) are in that comment and in the PR body; this one carries the machine-readable half.
{ "issue": 6009, "status": "done", "branch": "claude/issue-6009-icon-census-entry", "pr": "https://github.com/objectstack-ai/objectui/pull/6290", "premise_still_valid": true, "summary": "Re-derived against post-#6277 main (branch point contains e3784607f, confirmed by git merge-base --is-ancestor). The card's central premise held exactly: adding 'icon' to RECORD_READING_TYPES moves 96 authored glyph names from declined to judged, and three of them are the retired spelling check-circle. Two corrections to the card/dispatch, both load-bearing. (1) The replacement is circle-check-big, NOT circle-check: probed against the installed lucide-react 1.31.0, CheckCircle === CircleCheckBig is true and CheckCircle === CircleCheck is false, so circle-check is a live key naming a DIFFERENT glyph and would have silently changed the rendered artwork while going green. The gate's own identity derivation prints circle-check-big unprompted. (2) The OK line's resolver count does NOT rise 8 to 9: that number reads discovered.record.length (part 1's discovered MODULES), not the size of RECORD_READING_TYPES, so a part-2 entry cannot move it; RECORD_READING_TYPES goes 9 to 10 entries, a count printed nowhere. Part 1 needed no change: icon.tsx imports the icons record DIRECTLY (import { icons, SquareDashed } from 'lucide-react' plus (icons as any)[mappedIconName]) and has been in DECLARED_RECORD_READERS since #5633's discovery run, so rediscovery never flagged it, before or after the edit — the asymmetry against dropdown-menu.tsx, which routes through resolveIcon and stays out. No descendants flag: the renderer resolves one name and returns a single element, never walking children. Added five pin tests plus a header note recording the re-taken container table (61 names / 7 containers at e3784607f — UNCHANGED, because the table counts UNTYPED names and a type:'icon' node is typed, so the populations are disjoint). Only stale detail in the card: check-circle sits at lines 54/70/86, not ~53/69/85.", "tests": "All exit codes captured by redirect before any pipe; verdicts quoted from what each gate printed. FINAL UNION re-run on final commit 1443fcbf0 (git rev-parse --short HEAD), all green: check:icon-record-names EXIT=0 -> 'OK lucide icon names: 163 authored/declared names reaching 8 record-reading resolvers are live `icons` keys (record 1767 keys; dynamic surface 4 sites, 2025 names, not judged here).' | type-check:scripts EXIT=0 | lint:root UNNARROWED EXIT=0 -> '28 problems (0 errors, 28 warnings)' (all pre-existing no-explicit-any) | check:control-bytes EXIT=0 -> 'check-control-bytes: OK (scanned 5178 tracked text file(s); skipped 85 binary).' | pnpm exec vitest run scripts/__tests__ EXIT=0 -> 'Test Files 77 passed (77) / Tests 2223 passed (2223)' | check-changeset-presence EXIT=0 -> 'No source of a released package changed in this range, so no changeset is owed.' NO NARROWING anywhere. GATE BOTH DIRECTIONS: census entry alone went RED, EXIT=1, naming all three sites — examples/schema-catalog/src/schemas/marketing/call-to-action.json at $.children[0].children[3].children[0].children[0].icon, $.children[0].children[3].children[1].children[0].icon and $.children[0].children[3].children[2].children[0].icon, each 'check-circle -> CheckCircle is not a key of the runtime icons record ... write circle-check-big', 'Resolved through: packages/components/src/renderers/basic/icon.tsx'; after the fixture repair EXIT=0. COUNTERS before/after: baseline at e3784607f judged 33 | declined 347 | anchored 34 | OK-line total 67 | resolvers 8; after census entry judged 129 | declined 251 | anchored 34 | resolvers 8; after repair judged 129 | declined 251 | anchored 34 | OK-line total 163 | resolvers 8. That is +96/-96, exactly the population the card measured, with anchoredJudged and the resolver count both holding still. SUITE: scripts/__tests__/check-lucide-icon-record-names.test.ts --reporter=verbose, 39 passed (39) — 5 new tests collected by name ('the ui:icon node type > goes RED on a retired spelling, naming icon.tsx as the resolver' / '> goes GREEN on the live spelling — and the name was really judged' / '> declares NO descent — the renderer resolves one name and never walks children' / 'this repository > really judges the ui:icon nodes objectui#6009 opened up' / 'this repository > did NOT grow part 1 for ui:icon either — it was ALREADY a declared resolver'), and #6277's 9 tests all still pass. ABLATION (no build/dist leg exists here — the gate runs from source and the suite imports it from source, so there is no stale artifact to rebuild): deleted the 'icon' census entry with the mutation CONFIRMED ON DISK by anchored grep on the exact line (count 1 -> 0, plus git diff --stat showing 1 deletion) rather than by the editor's exit code, restored under a trap ... EXIT INT TERM. Result: 'Tests 4 failed | 35 passed (39)' — four of the five new tests go red. The fifth staying green is the correct reading, not a hole: it asserts icon.tsx was ALREADY a part-1 resolver, true independently of the part-2 entry. RESTORE LEG also confirmed on disk: anchored grep back to 1, git status clean against HEAD, gate re-run EXIT=0. type-check:scripts proved non-vacuous over my own diff — it caught expect(RECORD_READING_TYPES.icon.descendants) as TS2339 (the key is absent from icon's inferred type since RECORD_READING_TYPES is a plain object literal); fixed at the ASSERTION using the file's own \"'descendants' in ...\" idiom, which also asserts the stronger fact, rather than widening the type to accommodate the test.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
Generated by Claude Code