Uh oh!
There was an error while loading. Please reload this page.
docs(spec): record the live read point of page:accordion items[].icon (#9881) - #9971
Conversation
…on (#9881) A `.describe()` naming the objectui consumer plus an accept-pin, so a liveness sweep stops re-deriving a false retirement candidate for a key that renders. Re-verified at the pin this repo builds against (`.objectui-sha` = 82a94170c): `containers.tsx:851-853` renders `{item.icon && <LazyIcon name={item.icon} …/>}` inside the AccordionTrigger, and `:898` publishes the key to the Studio block designer in the `items` input. Nothing about what parses changes — the key was already declared and optional.
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ✅ What this run could not seeCoarse fallback — 115 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin fa2d3221cefdddb5c536a48d34be416e53e10942 && git checkout fa2d3221cefdddb5c536a48d34be416e53e10942
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6aceca97143088c9c33e568c5dd49e5b7cfdf347 3ae2b5916ca0968e425f88e9fff69ab9f4b5feea && git checkout -B drift-repro 6aceca97143088c9c33e568c5dd49e5b7cfdf347 && git merge --no-ff 3ae2b5916ca0968e425f88e9fff69ab9f4b5feea
node scripts/docs-audit/affected-docs.mjs --json 6aceca97143088c9c33e568c5dd49e5b7cfdf347 |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#9881
PageAccordionProps.items[].iconparsed, rendered, and said nothing about itself. A liveness sweep therefore read it as declared-but-unenforced and opened a retirement candidate against it — which cost a full dispatch cycle before the cross-repo read point was found and the candidate was closed premise-overtaken. Nothing on the spec side recorded that liveness, so the next sweep would have derived the same false candidate from the same absence.This PR records it: a
.describe()naming the consumer, and an accept-pin that keeps it named.Premise re-verification — the read point is still live
Re-derived from the objectui pin this repo actually builds against rather than taken from the card.
.objectui-sha=82a94170c4058d451ce3ac179d99296d90554479, and the anchors were read at that ref (git show 82a94170c:…), not at the sibling checkout's HEAD, which has since moved to7260a1ed4:packages/components/src/renderers/layout/containers.tsx:851-853item.icon, renders aLazyIconelement whosenameprop isitem.icon(classesh-3.5 w-3.5 shrink-0 opacity-70,aria-hidden), inside theAccordionTriggercontainers.tsx:898ComponentRegistry.register('accordion', …)'sitemsinput, described as[{ label, icon?, collapsed?, children }]Both anchors in the card resolve exactly,
:898included. The vocabulary is Lucide, resolved through objectui'sLazyIcon(lib/lazy-icon.tsxnormalises kebab-case or PascalCase and falls back when the name is not a real Lucide icon).The describe
Placed in the file's house idiom rather than the card's literal wording. Nothing in
component.zod.tsputs acontainers.tsxfile:line inside a.describe()— every one of the ~35 describes that mentions a renderer does so behaviourally, and the file:line anchors live in the TSDoc block above the key (variant,recordChrome,showStar,showCopyIdall take that shape). So this follows the same split, withrecord:alert's owniconas the nearest sibling for the "this one IS read, contrast the one that isn't" construction:(In the source the final token is written the way the existing
valueprescription writes it —panel-followed by the word index in angle brackets. It is spelled out in words here, and only here, so the body sanitizer cannot swallow it; the committed string is the ordinary one.)The docblock above it carries the anchors, the pin, and why the key has a docblock at all. The item
valueprescribed against one line up is the deliberate contrast: same renderer, same item, but it overwrites that key with an index-derived panel id — a read point is precisely what separates the two verdicts, and the two now sit next to each other saying so.The accept-pin
Three assertions in
component.test.ts, beside the existingpage:accordion.variantblock, with the objectui consumer named in the block's prose:page:accordionitem and survives to the parsed output;iconName) on the same item is still refused withunrecognized_keys— without this the first assertion would be equally green on a schema that had stopped being strict, which is the vacuity an accept-pin exists to exclude;.describe()still names the consumer. Deleting the describe is what re-opens the false candidate, so it is pinned rather than left to review.Reverse-verified from the committed state, both legs, with the tree proven byte-identical to
HEADafterwards (git hash-object==git rev-parse HEAD:on the same path, porcelain empty). No rebuild was needed or performed for either leg, and that is a property of this pair rather than an omission: the test imports./component.zodrelative, inside its own package, so vitest resolves it tosrc/and never todist/— demonstrated by the pin passing on the very first run, which happened before any build existed in this worktree..describe()1 failed | 187 passed— only assertion 3iconkey entirely (what the sweep proposed)2 failed | 186 passed— assertions 1 and 3Regeneration
pnpm --filter @objectstack/spec build && check:generatedafter the change: all 13 generated artifacts already up to date, so there is no regen commit and none was hand-written.That is a measured result rather than a skipped step, and it is worth stating because the standing rule is that a
.describe()movescontent/docs/references/. It does — for top-level props. This key is one level down, and the docs generator renders a nested item object as a type signature in the parent row rather than as its own table:PageAccordionProps.itemsprints as{ label: …; icon?: string; collapsed: boolean; children: any[] }[]with an empty Description cell, while its siblingsallowMultipleandvariantcarry their describes. So the string genuinely reaches no checked-in artifact,check:docsis correctly green, and the describe's audience here is the source reader and the auditor, not the published reference.Verification
Gates re-derived on the actual diff with
node scripts/pm/dispatch-gates.mjs(no paths passed — it takes its own change set from the merge base), which placed 18 path-matched families plus 5 convention-triggered ones. The whole union was run at the final commit,3ae2b59, and every one is green:pnpm --filter @objectstack/spec test:Test Files 414 passed (414)/Tests 11022 passed (11022)tsc --noEmit+check:scripts-typecheck+check:test-typecheck; the new test file compiles undertsconfig.test.jsonwith the debt ledger held, not grown:55 file(s) / 263 error(s), noGREWverdictcheck:generated:All 13 generated artifacts are up to datecheck:liveness,check:empty-state,check:strictness-ledger,check:variant-docscheck:changeset-gate-self-tests,check:objectui-changeset,check-adr-0087-registration,check-changeset-no-major,check-empty-changesetcheck:cross-package-test-inputs,check:merge-driver,check:slot-lookup,check:spec-parsed-alias,check:type-source-resolution,check:dev-prereqs,check:doc-formula-expressions,check-affected-docs,check:nul-bytescheck:query-options-erasure,check:type-check-coverage,check:engine-double-contract,check:where-matcher, and the ratchet halfcheck:type-check-debt --re-measure:33 ledger entr(ies) re-measured in 205.4s, 1925 raw tsc error(s) total, none above its recorded numbercheck:react-declaration-parityis the one gate that cannot run here at all — it needs objectui'ssdui.manifest.json, which only a pin bump produces. Nothing in this diff moves the pin.Scope
No acceptance change. The key was already declared and already optional; nothing is widened, narrowed, retired or renamed. Clause ② does not apply.
Generated by Claude Code