docs(skills): correct 25 false facts in the published objectui skill package - #7098
Merged
Merged
Conversation
…package Flight 12 of the published-skills factual sweep (objectstack#13658). Every claim in `skills/objectui/**` that names an operator, a key, an export or an asserted output was located in the IMPLEMENTING CODE and verified there -- never against another document -- and executed where behaviour-bearing. Dominant class, as the program predicted: an enumeration that stopped growing when the schema did. 30 formula functions documented as 16; DataSource's 32 optional members shown as 6 (two of them spellings that do not exist); ComponentMeta's "full reference" listing 10 of 16; QueryParams 6 of 9; the nav union 7 of 9; the plugin catalogue naming a package that was never built. Second class: phantom exports. `@object-ui/mobile` was documented with seven names it does not export, and `@object-ui/app-shell` with three `*Renderer` names that are either nowhere in the repo or belong to other packages. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Msg17tAHJ3jVTYFgHydCm2
os-zhuang
approved these changes
Sep 1, 2026
os-zhuang
marked this pull request as ready for review
September 1, 2026 06:36
This was referenced Sep 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7094
Part of objectstack-ai/objectstack#13658
Flight ⑫ of the published-skills factual sweep —
skills/objectui/**, the program's last package. 18 files, 5,729 markdown lines atorigin/main@2c3cd1b.Session, for durable attribution:
https://claude.ai/code/session_01Msg17tAHJ3jVTYFgHydCm2⛔ Governed surface — human merge, deliberately parked
skills/**is the published, customer-facing surface. This PR is a draft on purpose: not marked ready, auto-merge not armed, not enqueued, and the dispatching seat will not arm it. The repo's own guard agrees —node scripts/check-governed-queue-guard.mjs --testover this diff answers:Method
Per behavioural claim: locate the implementing code, verify there — never against another document — and execute it where the claim is behaviour-bearing. Verdicts are VERIFIED / FALSE / NOT MEASURABLE, none silently skipped. Split by file (the package-size allowance), reported in the dev report on #7094.
Two mechanical sweeps ran over the whole package rather than by eye, both reproducible from the base tree: every backticked API identifier and every
@object-ui/*import binding inside a fenced block, resolved against the real export surface of the package each names; and every in-repo path assertion. Deduplicated, that is 310 distinct (file, assertion) pairs. Both sweeps are what surfaced the phantom-export class below — neither would have been caught by reading, because in every case the surrounding prose is coherent and only the name is dead.False density: 25 false claims / 340 adjudicated — 7.4%, inside the program's 1.5–10% working range and at the top of it. The denominator is the 310 mechanical assertions plus the 30 enumerations probed against their schema's member set. A handful of the numerator (the coverage thresholds, the stale line range, the sibling count) are value claims that sit outside that mechanical substrate, so 7.4% is a ceiling on the density, not a point estimate.
The distribution is lopsided and worth naming: three guides carry 18 of the 25.
guides/mobile.mdalone documents an@object-ui/mobilethat does not exist — seven phantom exports across three consecutive code blocks — and theapp-shellsections of three more guides teach a*Renderernaming scheme the package never had.The corrections — 25 false facts, 34 landing sites
Class 1 — phantom exports (10 facts, 13 sites)
guides/mobile.md— gesture blockimport { useSwipe, useLongPress, usePinchZoom } from '@object-ui/mobile'useGesture(one hook,type+onGesture, returns a ref),usePullToRefresh;GestureType's ten values namedguides/mobile.md— overlay blockimport { BottomSheet, MobileNav }ResponsiveContainer(minBreakpoint/maxBreakpoint/showOn/hideOn/fallback) + the real overlays from@object-ui/components; mobile nav is app-shell'smobileNavModeguides/mobile.md— inputs blockimport { MobileSelect, MobileDatePicker }@object-ui/fields+useTouchTargetguides/mobile.md— offline blockconst { isOnline, queue, syncState } = useOffline()pendingCount—OfflineResulthas noqueueguides/mobile.md— sync statesidle → syncing → synced | error'idle' | 'syncing' | 'error' | 'offline'— there is no'synced'guides/page-builder.md,guides/project-setup.md,guides/architecture.md(3 sites)ObjectRenderer,PageRenderer,DashboardRendererfrom@object-ui/app-shellObjectView,RecordDetailView,PageView,DashboardView,ReportView, with a note on where the two real*Renderernames actually liveguides/architecture.mdPattern A// packages/core/src/registry.ts+registerComponent()/resolveComponent()packages/core/src/registry/Registry.ts, theComponentRegistryinstance,register(type, component, meta?)/get(type, namespace?)rules/composition.mdEmptytakingicon/title/descriptionpropsEmpty/EmptyMedia/EmptyTitle/EmptyDescriptioncomposition familyrules/composition.md(2 sites)data-icon="inline-start"rule, andSpinnercarrying that attributebuttonVariants' base already carriesgap-2 [&_svg]:size-4 [&_svg]:shrink-0rules/composition.mdButtontaking aniconprop (icon={CheckIcon})ButtonPropshas noiconprop —iconis the square-button size variantdata-iconoccurs zero times inpackages/,apps/,examples/,e2e/,scripts/,docs/andcontent/.ObjectRendereroccurs six times repo-wide, all six in one example README — filed as #7095.Class 2 — an enumeration that stopped growing when the schema did (11 facts, 16 sites)
guides/schema-expressions.md— Formula functionsMEDIANPERCENTILESTDEVVARIANCESWITCHTRIMLENLEFTRIGHTSUBSTRINGFINDREPLACEREGEXDATEDIFF, with the two non-obvious argument orders spelled outguides/schema-expressions.md— "Supported operators (full list)"typeof, no primaries!,-,+,typeof) + primaries row (array literals, single-param arrow)guides/schema-expressions.md— Security modelisDangerousas the source-level table and adds the fourBLOCKED_PROPSmembers it omitsguides/data-integration.md—DataSourcesaveView?andexecute?shown as memberscreateView/updateView/updateViewConfig/deleteView; the optional half is 32 members, not 6guides/data-integration.md—QueryParams$keys$search,$searchFields,$countguides/plugin-development.md— "ComponentMeta options (full reference)"tier,labelling,deprecated,examples,tags,descriptionguides/plugin-development.md—ComponentInputtypea single literal; 8 keysComponentInputControlType | ComponentInputControlType[](objectui#3832); 13 keys — addedinputType,min,max,step,placeholderguides/plugin-development.md—FieldWidgetComponentProps"and nothing else"dependsOnLabels,onUploadingChange,onSelectRecord,onCreateNew, and names the real intersection (FieldWidgetDomProps&AriaAttributes&data-${string})guides/app-composition.md— nav target tablecomponent(componentRef, colon-joined),separatorandactionREADME.md,guides/architecture.md,guides/page-builder.md,guides/project-setup.md(4 sites)plugin-workflow, omitsplugin-tree@object-ui/plugin-workflowdoes not exist;@object-ui/plugin-treedoes, registeringtreeandobject-tree. Count of 19 was right; one member was wrongguides/architecture.md— CLI listserveserveadded (.command('serve');devis described by the CLI as its alias)Class 3 — accept surface vs read surface (1 fact, 3 sites)
SKILL.md§6,rules/protocol.md,guides/mobile.mdcolumnstakes a breakpoint object keyedxs/sm/md/lg/xlBreakpointColumnMapSchemaaccepts six keys including2xl; thegridrenderer reads only five, so a2xlentry parses and is then silently droppedMeasured through a real
SchemaRendererrender, reading the emitted class:{xs:1, xl:5}→grid grid-cols-1 xl:grid-cols-5 gap-4;{xs:1, "2xl":6}→grid grid-cols-1 gap-4. The implementation half is filed as #7097 with both routes and the gate that generalizes.Class 4 — stale coordinates and self-description (3 facts, 6 sites)
guides/testing.md(3 sites)vitest.workspace.ts", split by package, setupvitest.setup.tsxunit/dom/dom-heavy) declared invitest.config.mts, split by file extension, each with its own setup file;vitest.setup.tsxis a legacy shim wired into no configguides/testing.md62 / 54 / 50 / 6140 / 33 / 30 / 40, the realcoverage.thresholdsguides/schema-expressions.md,guides/project-setup.md,README.mdSchemaRenderer.tsx"(lines 117-175)" (that range isresolveAriaProps); "its ten siblings" (there are 17); layout tree listing 10 of 12 guidesevaluatedSchemamemo by name; "sixteen siblings";architecture.md+app-composition.mdrestoredTwo test patterns in
guides/testing.mdwere rewritten because, as published, they cannot pass:new ExpressionEvaluator()thenevaluate(expr, context)puts the context whereEvaluationOptionsgoes, so every${…}resolves against an empty scope and the template part falls back to its own literal (measured —'Hello ${data.name}'comes back verbatim); andformatValidationErrors(result.errors)passes the errors array to a function whose parameter is the whole result. Both are counted inside F23–F25's file rows.Executed evidence
Three probe files, written and run against the real modules, then deleted — this PR adds no test files.
unitproject, 13/13 pass. The claims proven TRUE by execution (the non-vacuity control): the six safe globals resolve and evaluate; single-${}type preservation returns42/trueand"Count: 42"for the mixed template;${0 && "yes"}returns number0; a missing variable returnsundefinedwithout throwing. And all 13 patterns in the published "Blocked" list really throwPotentially dangerous expression detected: ….The FALSE ones, measured:
Every rewritten line re-executed: the 14 new formula calls with their real argument order (
FIND("@", s)→3,PERCENTILE(90, values)→8.6,SWITCH(…)→"silver",TRIM→"hi",DATEDIFF→7), and both rewritten test patterns pass 5/5 and 3/3.domproject, 8/8 + 3/3 pass. Export surfaces asserted against the real modules: the seven-partEmptyfamily andSpinnerpresent;buttonVariants()containsgap-2and[&_svg]:size-4; the ten real@object-ui/mobileexports present and all seven phantoms absent;BREAKPOINTSequals{xs:0, sm:640, md:768, lg:1024, xl:1280, '2xl':1536}; the thirteen realapp-shellnames present and all three*Renderernames absent;PageRendererabsent from@object-ui/components' public surface andDashboardRendererpresent on@object-ui/plugin-dashboard. Plus the2xlgrid measurements above.Budget — both readings, per the 2026-08-21 ruling
skills/objectui/**package lines (all 18.md)ceil(utf8 bytes / 4))guides/schema-expressions.mdguides/plugin-development.mdguides/testing.mdrules/composition.mdguides/architecture.mdNo token or line ratchet is in force in objectui — absence measured, not assumed. The only
skills/**-scoped gate isscripts/check-skills-paths.mjs, whose "ratchet" is its baseline exemption list, not a size budget; no script or workflow in the repo carries a skills token or line ceiling. So byte-neutral-or-shrinking does not bind here — which is stated so a reviewer can hold the growth to the ruling rather than to a gate.The +3.8% is disclosed for that judgement. It is dominated by enumerations that were incomplete: 14 formula-function names, 6
ComponentMetaoptions, 5ComponentInputkeys, 3QueryParamskeys, 3 nav-union rows. Every added line carries a fact that was missing or wrong; nuance that did not correct a falsehood was cut rather than kept (the security-model paragraph was trimmed from 8 lines to 4 on that rule), and two files shrink.Gates — derived from objectui's own tooling, run at head
a3dc965scripts/pm/dispatch-gates.mjslives only in objectstack and answers only about that tree, so the family was derived here from this repo's ownpackage.jsonscripts and.github/workflows/**— everycheck-*.mjswhose scan surface namesskills/, plus the unfiltered per-PR gates.Every exit code was captured before any pipe. Two gates are recorded honestly as NOT MEASURED rather than as passes:
node scripts/check-governed-queue-guard.mjs(no flag) exits 1 with "could not read GITHUB_EVENT_PATH" — by its own text it reads the workflow event payload and nothing else, so it is a PREREQUISITE NOT MET locally. Its--self-testhalf is green above and the real run happens in CI.pnpm check:readme-exportsexits 1 with 386 findings, every one of them "its type entry./dist/index.d.tsis not on disk — runpnpm buildfirst". Its population is the 43 READMEs underpackages/(its own census line: "0 outside any package"); zero of its findings touchskills/, and this diff changes none of its inputs.ESLint was not run repo-wide, and that narrowing is measured, not skipped. Its population, read from
eslint.config.jsitself, is**/*.{ts,tsx}(plus**/*.tsxand two test globs) — there is no markdown arm.npx eslint skills --format jsonreports 0 files linted, 0 messages. And the config declares noprojectService/project, so there is no cross-file type program through which a.md-only diff could move an untouched file's verdict in either direction.Changeset — none owed, and no label either
The repo's own gate decided it from the diff: "13 file(s) changed, 0 of them published source of a package the release covers … ✅ No source or published contract of a released package changed in this range, so no changeset is owed."
No
skip-changesetlabel is applied, deliberately. In this repo that label is a phantom:scripts/__tests__/ci-cd-pipeline-doc.test.tsfails if any file under.github/orscripts/so much as mentions it (objectui#4912). Nothing reads it, so applying it would be theatre.Filed, not fixed — out of scope by file surface
examples/byo-backend-console/README.mdteachesObjectRenderer, an export that exists nowhere in the repo #7095 —examples/byo-backend-console/README.mdteachesObjectRendererat six sites. Same phantom as F6, different file surface.pnpm test:integrationcannot run — it filters on a vitest project namedui, which does not exist #7096 — roottest:integrationrunsvitest run --project ui; there is no project namedui. Measured:Error: No projects matched the filter "ui", exit 1.columns: { "2xl": N }parses and is then silently dropped — the spec accepts six breakpoints, thegridrenderer reads five #7097 — the F22 implementation half:BreakpointColumnMapSchemaaccepts2xl, thegridrenderer drops it. Carries both routes and the gate that generalizes pastcolumnsto everyBreakpoint*Map.All three are unassigned, deduped against the 274 open issues in this repo before filing, and link back to #7094.
What is deliberately not here
guides/console-development.md,guides/auth-permissions.md,guides/i18n.md,rules/styling.mdandrules/no-touch-zones.mdare unchanged: every claim adjudicated in them came back VERIFIED.console-development.md's retired-names table is right in both directions — all 16 symbols it declares nonexistent return zero hits repo-wide.SKILL.mdcarries one added clause (F22) and nothing else.Generated by Claude Code
Generated by Claude Code