docs(analytics): correct four measured-false claims in the CubeRegistry docblocks - #15995
docs(analytics): correct four measured-false claims in the CubeRegistry docblocks#15995os-warren wants to merge 2 commits into
Conversation
…ry docblocks
The class docblock advertised "two sources: manifest definitions, and object
schema inference". Neither half held. Two live sources were missing — a
compiled dataset's Cube, registered under the dataset's name by queryDataset
(ADR-0021), and the ad-hoc Cube ensureCube/inferCubeFromQuery mints from the
members a query references. And object schema inference is inferFromObject,
which no path in this repository calls: its only in-tree caller is a unit test.
inferFromObject's own "heuristic rules" list was wrong in three of its five
bullets. Driving the BUILT package through its published entry:
- number/currency/percent fields mint one sum and one avg measure each. The
documented min and max measures do not exist.
- boolean fields become a boolean dimension and nothing else. The documented
"count measure (count where true)" is not minted.
- every field becomes a dimension; the documented "all non-computed fields"
implies an exclusion the code does not have, on a parameter carrying no
flag one could exclude on.
The two accurate bullets (a default count measure; date/datetime fields
becoming time dimensions granulated day/week/month/quarter/year) are kept and
stated in the form the run produced.
Comment-only: every changed line in the diff is a comment line. The corrected
text is what ships in dist/index.d.ts, where consumers read it, so this carries
a patch changeset rather than a skip-changeset claim.
This commit settles nothing about whether the published method is removed or
wired up as a real cube source. That measurement and its options go to the
maintainer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
…be-registry-infer-dead-code
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 9 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 967d4caab6e68b34cb6fe5ecc6c488b4d29c31ad && git checkout 967d4caab6e68b34cb6fe5ecc6c488b4d29c31ad
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin f7db8f4fd268a86a08c62ae4894cf7417720f8c9 02fdc7b056c97cb28128dbb7e6e0b664f51d630e && git checkout -B drift-repro f7db8f4fd268a86a08c62ae4894cf7417720f8c9 && git merge --no-ff 02fdc7b056c97cb28128dbb7e6e0b664f51d630e
node scripts/docs-audit/affected-docs.mjs --json f7db8f4fd268a86a08c62ae4894cf7417720f8c9 |
Part of #15019. Deliberately not a closing keyword: this PR ships only the half that needs no ruling. The card's actual question — delete the published method, or wire it up — is unresolved and goes to the maintainer, so the card must stay open.
Headline: the card's premise is refuted, by execution
The card says
CubeRegistry.inferFromObject"has no runtime caller" and that its three built-in default labels "are unreachable". The first half reproduces exactly. The second half does not.inferFromObjectis on the published surface of@objectstack/service-analytics@17.3.0(publishConfig.access: public,files: ["dist", ...]), and its output reaches the wire. Driven against the built package —dist/index.js, the artifact a consumer imports, notsrc, not the declared type:getMeta()maps every registered cube'smeasure.labelontoCubeMeta.measures[].title(analytics-service.ts:1495-1503), andinferFromObjectself-registers (this.register(cube)), so all three labels are one published call away from a real response. "No caller in this repository" and "unreachable" are different claims, and only the first one holds.The census, and what its anchor would miss
Whole tracked tree, no path restriction (the card and both triage comments scanned
-- packages apps examples):Controls, same command shape, same cwd — a zero-hit grep proves nothing without one:
registerAllinferCubeFromQueryinferMeasuregetAllcompileDatasetWhat the identifier anchor would miss, each scanned separately rather than assumed:
git grep -E "(cubeRegistry|registry)\s*\["returns 6 hits, all unrelated packages (cloud-connection,service-storage), none on aCubeRegistry. The scan is live and finds nothing here.getOwnPropertyNames/getPrototypeOf/Reflect.get/prototypeacrosspackages/services/service-analytics: 3 hits, allArray.prototype.sort/Object.prototype.hasOwnProperty/ a comment. No dispatch table.inferscan acrosspackages apps examples: every hit is a different identifier (inferDriverTypeFromUrl,inferExpressionType,inferCubeFromQuery,inferMeasure) or prose.objectuiat24e027e: 0 hits forinferFromObject, 0 forCubeRegistry, with the controlservice-analyticsfiring on 12 files, so that scan is live and objectui is a measured non-consumer.cloudis not checked out on this box — NOT MEASURED. The npm consumer population is NOT MEASURABLE from here at all.Every use of
cubeRegistryinanalytics-service.tsenumerated:registerAll(734),get(765, 935, 1492, 1563),size(818),register(1068, 1589, 1657),getAll(1493).inferFromObjectappears in none of them.The three labels are not one fact
label: 'Count'is minted unconditionally by the method.FIELDLABEL (Sum)/FIELDLABEL (Avg)are minted only fornumber/currency/percentfields, and each embeds the field's own label.They share one route (the method) but not one condition, and the composites are two per qualifying field, not one each. Separately: the string
Countis emphatically not unreachable —analytics-service.ts:2089and:2344mintlabel: 'Count'on live paths (inferCubeFromQuery,inferMeasure). Removing site 3 would take nothing off the wire that is on it today.What #14492's ruling site 3 actually says
The maintainer ruling of 2026-09-02 on #14492 lists
cube-registry.ts:80as one of five server-side built-in default sites to populate withbuiltinAggregate— i.e. the ruling was written on the assumption this code is live. The later disposition (PR #15017, merged) left the three Cube-metric sites alone on the ground that they never reachAnalyticsResult.fields[], and the epic PM's comment closing that card says in as many words that #15019 "stays with the maintainer".What this PR changes: four measured-false documentation claims
Comment-only. Every changed line in the diff is a comment line (
git diff -U0filtered to non-comment lines is empty).Class docblock. It said cubes reach the registry "from two sources: manifest definitions, and object schema inference". Neither half held. Two live sources were missing — a compiled dataset's Cube registered under the dataset's name by
queryDataset(analytics-service.ts:1068, ADR-0021), and the ad-hoc CubeensureCube/inferCubeFromQuerymints from the members a query references (:1589, gated byassertInferableCube, #3867). And "object schema inference" isinferFromObject, which nothing here calls. Note thatinferCubeFromQuerydoes not deliver it either: it infers from the QUERY's referenced members, never from the object's field schema — the object name is only checked for existence.Method docblock. Three of its five "heuristic rules" were false. Answered by the run above, not by reading:
numberfields tosum,avg,min,maxmeasuressumandavgonly.hours_min/hours_maxabsentbooleanfields to acountmeasure (count where true)activefieldsparameter carries no flag to exclude oncountmeasure is always addedcount, labelledCountdate/datetimeto time dimensions, standard granularitiestype=time,["day","week","month","quarter","year"]The method docblock now also records what the method is: published, uncalled in-repo, still callable by consumers, and wire-reaching through
getMeta().A patch changeset, not
skip-changeset. I assumed this was comment-only-therefore-invisible and measured it false. A/B on the emitted bytes, same tree, only this file's edit reverted and restored:The method docblock survives into the emitted bundle (
dist/index.js:66); the class docblock does not. So this edit does change published bytes in all three artifacts, and apatchis the honest disposition. Mutation proven on disk by marker counts (Three sources write to it0,Cubes can be registered from two sources1 under mutation); restore proven by blob equality against the HEAD blobd7ab4efe...plus an emptygit diff HEADon the path, under atrapon EXIT INT TERM with absolute paths.The open question, for the maintainer
Triage authorized option 1 (delete) as covered by "the enforce-or-remove precedent". Measured, that precedent does not reach this case: ADR-0049 is titled "Spec must not declare security properties the runtime does not enforce" and its trichotomy is about spec properties naming an access-control boundary; ADR-0078 extends it to metadata instances. Neither governs a TypeScript method on a published service class. And ADR-0059 concentrates the breadth gate on
packages/spec/api-surface.json— there is no surface ledger for@objectstack/service-analytics, confirmed: a recursive grep forinferFromObjectunderpackages/spec/api-surface/returns nothing. A removal here would be invisible to every gate in the repo except the changeset's own major declaration.Options, with their measured costs — no ranking on axes, because this dispatch carried no decision frame and I am not inventing one:
getMeta()exposure, and a decision on localizing composite defaults that embed a field label. Triage already routed this to a separate card at manual floor. It would also makecube-registry.ts:80live again, reopening analytics 契约:AnalyticsResult.fields[] 增加可选 builtinAggregate 鉴别字段,服务端内置聚合默认 label("Count" 等 5 处硬编码)不再以英文字面量出线(objectui#7258 裁 B 的生产者半边) #14492's conclusion for that site.cube.measures.countdefined,hours_sum/hours_avgdefined, four dimension types — and asserts none of the three labels. So the labels the card is about are unpinned published behaviour today, whichever way the ruling goes. Cost: pins make option 1 marginally more expensive later.Verification
Head for every run below:
02fdc7b05(the final commit on this branch).node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackwith no paths passed — 48 commands from the actual change set (2 paths, committed). The first derivation warned STALE TREE;origin/mainwas merged in (clean, nomerge=os-regenpath among the 10 files it brought) and the derivation re-run at02fdc7b05with no stale warning.pnpm check:dual-build-cjs-loadsfirst answered exit 3 PREREQUISITE NOT MET (unbuilt worktree). Prerequisite built (pnpm build --concurrency=2, 72/72 tasks) and re-run: exit 0, verdict "103 published require entry point(s) across 66 package(s) load; 619 emitted CommonJS file(s) parse".check:dts-closureandcheck:nul-bytesre-run on the built tree: exit 0 (164/164 declaration files; 7710 text files scanned, no control bytes).pnpm --filter @objectstack/service-analytics run typecheckexit 0;vitest run --maxWorkers=2— 92 test files, 2002 tests, all passed.node scripts/check-adr-0087-registration.mjs --base origin/mainexit 0 and--self-testexit 0. Not breaking, so no ADR-0087 marker is owed; the gate agrees.Heavy runs went through
scripts/pm/os-verify-lock.sh; verdict lines, not bare$?.🤖 Generated with Claude Code
https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
Generated by Claude Code