Repository navigation
docs: two pages enumerate the label-resolving dimension class as select + lookup/master_detail, which #16390 makes short by two — and one of them is unreachable by the drift tool by construction #17483
Description
Activity
- addedbugSomething isn't workingSomething isn't working
on Sep 10, 2026 Triage: lands in
content/docs/**⇒domain:devx(the filing seat's suggested lane, confirmed against the table); typeBug,priority:p3,pm:queue— ⛔ NOTpm:blocked.⭐ The blocker cleared six minutes before I read this card
The card declares
Blocked-by: #16390and warns⚠️ 「Both sentences are TRUE onorigin/maintoday and become false only when PR #17470 merges. ⛔ Do not 'fix' them before then」. That was correct when filed at 16:34Z. Measured now:reading value PR #17470 merged 2026-09-10T17:15:02Z #16390 closed (#17470)ingit log --oneline -30 origin/main1 (control: 30 numbered commits in the window) LOOKUP_TYPESinpackages/services/service-analytics/0 — the private subset is gone referenceTargetOfin that package — lit controlpresent in src/dimension-labels.tsand its testcontent/docs/data-modeling/analytics.mdx:211still 「a lookup/master_detaildimension returns the related …」⇒ The sentences are false as of 17:15:02Z. The card is unblocked and the fence it set has expired — correcting them now is right, not premature.
pm:blockedis not applied and theBlocked-by:line in the body is spent.⭐ The filing seat's blocking discipline was exactly right and worth naming: it blocked on the issue (#16390, which closes via
Fixes), ⛔ not the PR, precisely so the wait would end at a readable moment. It did.Scope
packages/specdeclares one reference class —REFERENCE_VALUE_TYPES=lookup,master_detail,user,tree. Both pages enumerate two of the four. ⇒ Add the missing two; ⛔ do not restate the class by listing members if a name for it exists.⚠️ The second site is unreachable by the drift tool by construction — that is the card's own finding and the reason it is a card rather than a tool run. ⇒ Its absence from any drift output is structural, ⛔ not evidence it is fine.priority:p3: authored guidance that under-lists a class by two members. A reader who follows it does less than they could; nothing breaks, and no gate reddens.Triage seat ·
session_017VGfRocA8VjczSe84fgjY3· R+169 · 2026-09-10T17:22Z (timestamp taken in the same tool call that posts) · comment from the triage seat
Generated by Claude Code
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actionsClaim: PM loop round 9
Session:session_017ef78bLdybu3AffehKkhfk
Branch:claude/issue-17483-label-bearing-dimension-class
Worktree:objectstack-issue-17483
Domain:domain:devx
File surface:content/docs/data-modeling/analytics.mdx,content/docs/ui/dashboards.mdx— those two files and nothing else (stop on breach; explain in the report)
Container & model:S,mode:subagent,model: opus— this call's--tieron both paths printed "no path-derived mandate: the surface hits none of the 3 declared glob(s), derived here, not recalled", so the tier is the PM's judgment call and stays at the default.
Clause-②: no
Thread-read: 5622687438
Serial constraints cleared: none on these two files — board read at 2026-09-16T14:14Z, immediately before this claim; all 12 open PRs had their file lists read, two touchcontent/docs/**at all (#18420hotlong→automation/flows.mdx+ twodeployment/pages; #18319os-warren→ threereferences/pages) and zero touch either page on this surface.The blocker is spent, re-verified by this seat rather than inherited
The card carries a bolded
Blocked-by: #16390and an⚠️ fence: 「Both sentences are TRUE onorigin/maintoday and become false only when PR #17470 merges. ⛔ Do not "fix" them before then」. Triage (5622687438) already recorded that the blocker cleared six minutes after filing, and ⛔ deliberately did not applypm:blocked. Re-read here:reading (taken 2026-09-16T14:13Z) value #16390 closed / completedPR #17470 merged, 113050e2c2reading taken 2026-09-16T14:13Z, tree 8fe5cb8e5⇒ The fence has expired in the direction that makes the work correct: the two sentences are now false on
main, which is exactly when they must be fixed. ⭐ The filing seat blocked on the issue rather than the PR precisely so the wait would end at a readable moment — and it did.Both sites re-derived on
origin/main8fe5cb8e5, read 2026-09-16T14:13Zsite line still short? content/docs/data-modeling/analytics.mdx:211 — 「a lookup/master_detaildimension returns the related …」yes content/docs/ui/dashboards.mdx:146 — 「A sortBynaming a select or lookup dimension orders by the …」yes `user`anywhere in either page0 / 0 — `tree`anywhere in either page0 / 0 — reading taken 2026-09-16T14:13Z, tree 8fe5cb8e5⚠️ The spec-side truth, and the honest limit of how this seat read it:packages/spec/src/data/field-value.zod.ts:153-155declaresexport const REFERENCE_VALUE_TYPES: ReadonlySet<string> = new Set([ 'lookup', 'master_detail', 'user', 'tree', ] as const satisfies readonly FieldType[]);⛔ That is a source read of the declaration, not a module import — bare
nodewill not load the.tshere. It is theexport constitself and not a comment quoting it, but a dev with the build should confirm by importing.⚠️ This seat has already been burned once this shift by grepping a table instead of importing it (#17141), and says so rather than overstating this one.Fences carried into the dispatch
- ⭐ Triage's scope note, which is the sharpest constraint: 「Add the missing two; ⛔ do not restate the class by listing members if a name for it exists」. ⇒ Prefer naming the class the spec already names over growing a four-item enumeration in prose. ⛔ Do not simply append
user/treeto each list without asking whether the sentence should name the class instead. ⚠️ Site 2 is unreachable by the drift tool by construction — that is the card's own finding and the reason it is a card rather than a tool run. ⇒ ⛔ Its absence from any drift output is structural, ⛔ never evidence that it is fine.- ⭐ Site 1 is wrong in the direction that matters: a reader asking 「does a person axis render a name?」 reads that enumeration and concludes no — the exact belief analytics: 数据集维度只解析 lookup 字段,user 字段维度返回原始用户 id —— 以人为轴的图表/报表标签是一串 id #16390 was filed to correct. The repair must leave that question answered.
- ⛔ Docs only. ⛔ No
packages/**change rides along; if the prose needs a spec fact the spec does not state, stop and report rather than editing spec.
PM seat
domain:devx· sessionsession_017ef78bLdybu3AffehKkhfk· round 9 · 2026-09-16T14:15Z
Generated by Claude Code
- ⭐ Triage's scope note, which is the sharpest constraint: 「Add the missing two; ⛔ do not restate the class by listing members if a name for it exists」. ⇒ Prefer naming the class the spec already names over growing a four-item enumeration in prose. ⛔ Do not simply append
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actionsos-dev-report
{ "issue": 17483, "status": "done", "branch": "claude/issue-17483-label-bearing-dimension-class", "pr": "https://github.com/objectstack-ai/objectstack/pull/18474", "premise_still_valid": true, "summary": "Re-derived the card's premise on origin/main 8fe5cb8e5 and it holds: analytics.mdx:211 said 'a `lookup` / `master_detail` dimension returns the related record's display name' and dashboards.mdx:146 said 'A `sortBy` naming a select or lookup dimension orders by the display label', while REFERENCE_VALUE_TYPES has four members; 0 occurrences of `user` or `tree` in either page. Both sentences now NAME the class ('a **reference** dimension', defined as any field whose stored value is another record's id) instead of growing a two-item enumeration into a four-item copy of a const — the docs, the spec and the implementation all already carry that noun (`reference field` at data-api.mdx:199, `the reference class` at dimension-labels.ts:11, REFERENCE_VALUE_TYPES at field-value.zod.ts:153). `user` appears in each sentence as an open EXAMPLE, not as a list member, so the directional defect the card names (a reader concluding a person axis renders no name) is answered inside the paragraph while a future fifth member still cannot falsify the prose. Docs-only: 2 files, +7/-4, no packages/** change. assignee was os-try-charles (set by the PM) as expected.", "tests": "GATES — derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack content/docs/data-modeling/analytics.mdx content/docs/ui/dashboards.mdx` (exit 0): 39 families. Ran all 39; reconciled by feeding the exit codes back via `--ran` (exit 0, 14:38Z): '39 derived famil(ies) accounted for — 39 run, 0 NOT-MEASURED (a DERIVED zero — all 39 recorded an exit code and none of them is 3)'. 38 at exit 0. Four first returned exit 3 PREREQUISITE NOT MET in the unbuilt worktree (check:doc-formula-expressions, check:doc-security-posture, check:skill-examples, check:docs-transcript-drift) — neither pass nor finding; after `pnpm exec turbo run build --concurrency=2 --filter=@objectstack/formula --filter=@objectstack/lint --filter=@objectstack/client-react` all four re-ran at exit 0. ONE RED, NOT MINE: `pnpm check:cross-package-test-inputs` exit 1, 'FAIL: cross-package test inputs are not declared consistently … rooted in packages/cli/test/init-created-files-summary.e2e.test.ts / packages/spec/dist/ (no declared glob reaches inside it)'. That gate scans test sources and turbo.json; this diff has 0 files with a .ts/.mts/.mjs/.js/.json extension, so its inputs are byte-identical to the merge base. Re-run after the builds: same finding, same exit 1. LOCK — `bash scripts/pm/os-verify-lock.sh -c 'pnpm install --frozen-lockfile'` VERDICT command-exit 0 (held 10s, waited 0s); `... -c 'pnpm --filter @objectstack/spec build'` VERDICT command-exit 0 (held 174s); `... -c 'pnpm exec turbo run build --concurrency=2 --filter=@objectstack/formula --filter=@objectstack/lint --filter=@objectstack/client-react'` VERDICT command-exit 0 (held 418s), OS_VERIFY_LOCK_SLOT=issue-17483 throughout. SPEC FACT CONFIRMED BY IMPORT, not by grep: from the BUILT packages/spec, `import { REFERENCE_VALUE_TYPES, referenceTargetOf } from '@objectstack/spec/data'` printed MEMBERS=[\"lookup\",\"master_detail\",\"user\",\"tree\"], SIZE=4, has(user)=true, has(tree)=true, CONTROL has(select)=false, CONTROL has(text)=false, referenceTargetOf({type:user})=sys_user, referenceTargetOf({type:tree,reference:'dept'})=dept, CONTROL referenceTargetOf({type:select})=undefined. SIZE=4 reads the live Set so it counts members, not the four TSDoc comments in the same file that quote them. MDX PARSE — `pnpm exec fumadocs-mdx` in apps/docs, exit 0. REPO-WIDE LINT, narrowed and the narrowing MEASURED: (1) population read from eslint.config.mjs — every `files` entry is `**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}` or narrower, `.mdx` in none; (2) file count read from `--format json` — both touched paths return 'File ignored because no matching configuration was supplied.', errorCount 0, zero rules applied, so this diff contributes 0 files to the linted population; (3) invariance — no parserOptions.project and no typed @typescript-eslint rules anywhere (eslint.config.mjs:328 states it), so type-aware linting is off and an .mdx edit cannot move the verdict on any untouched file. NOT MEASURED: the 2 path-scheduled CI jobs (ci.yml 'Test Core (shard/6)' and 'Build Docs'), which dispatch-gates declares have no local invocation — declared to CI. ABLATION: none applies — this PR adds no gate and no test; it is prose in two bullets. Control-byte self-scan `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` over both edited files and over the PR body: exit 1 (clean); `pnpm check:nul-bytes` exit 0.", "mcp_calls": "0 — no MCP GitHub tool was called; every GitHub write went through the REST proxy with curl and GITHUB_TOKEN", "api_writes": "3 REST writes — POST /repos/objectstack-ai/objectstack/pulls (draft PR #18474); POST /repos/objectstack-ai/objectstack/issues/18474/labels (additive, skip-changeset); POST /repos/objectstack-ai/objectstack/issues/17483/comments (this report). Plus 2 git pushes: the mandated empty-branch routing probe (no 403) and the one commit 39528063a.", "open_questions": [], "out_of_scope_findings": [ "to file (3 classes, dedupe words: cross-package-test-inputs, init-created-files-summary.e2e, packages/spec/dist, declared glob, turbo test inputs): `pnpm check:cross-package-test-inputs` exits 1 on a tree whose only diff is two .mdx files — packages/cli/test/init-created-files-summary.e2e.test.ts descends packages/spec/dist/ and no declared glob reaches inside it, so a change there does not re-run the walk (the gate's own #7802 blind spot). Reproducible probe named; class (a). CAVEAT the filer must carry: packages/spec/dist/ exists here only because this seat built spec, so whether this is red on main in CI or only in a built local tree is UNVERIFIED by me — CI builds too, which argues it is red there as well, but I did not read a CI run.", "noted, not filed: both repaired sentences still spell the option-label arm as `select`, but the resolver does not key that arm on the type — dimension-labels.ts:203 and :387 both test `Array.isArray(meta.options) && meta.options.length > 0`, so a `radio` / `multiselect` / `checkboxes` dimension carrying options resolves its label the same way. Same shape as this card one class over (SINGLE_OPTION_TYPES / MULTI_OPTION_TYPES instead of REFERENCE_VALUE_TYPES), but a docs list short by a member is an incompleteness, not a copy-it-and-it-fails error, so it is not one of the three fileable classes. Successor named: these exact two bullets, analytics.mdx:210-216 and dashboards.mdx:146-152 — a card on the option class lands in the lines this PR just rewrote." ] }Attribution added in place by the owning seat (H64): this
os-dev-reportwas written by anos-devsubagent of sessionsession_017ef78bLdybu3AffehKkhfk, thedomain:devxseat, round 9, on card #17483 / PR #18474. ⛔ The JSON payload above is unchanged — only this line was appended, and the original stays as history.
Generated by Claude Code
os-try-charles commented
on Sep 16, 2026 CollaboratorMore actions落地 —— PR #18474 已合并,两读数确认
读数一 队列分支 队列已空,本 PR 的分支已消失 读数二 内容探针 origin/main tip 9c1897e52(重新 fetch 后取),落地前 85c6d76ec content/docs/data-modeling/analytics.mdx 243 → 244 行 前 后 "a **reference** dimension" 0 → 1 "`lookup` / `master_detail` dimension returns"(那句假话) 1 → 0 "person axis" 0 → 1 "`lookup`" 1 → 0 暗对照 zzq_nonexistent 0 → 0 content/docs/ui/dashboards.mdx 559 → 561 行 前 后 "**select** or **reference**" 0 → 1 "**select** or **lookup** dimension"(那句假话) 1 → 0 "person axis" 0 → 1 暗对照 zzq_nonexistent 0 → 0 squash 9c1897e52c 2026-09-16T15:13Z 父数 1⭐ 这次的探针串是从 diff 本身取的,⛔ 不是我编的。 每条恰好朝一个方向动,两个文件互为交叉对照 —— 上一张卡(#17141)我编了两个小写串读出假阴性,这次没有。
验收:卡自己写下的两处站点,逐条对照
卡的要求 结果 站点 1 analytics.mdx不再把类列成两项✅ 改为 a referencedimension(any field whose stored value is another record's id, auserperson axis included)站点 2 dashboards.mdx同✅ 改为 selectorreference,并补一句 Reference 是整个类,所以user人员轴也按名字排序⭐ 分诊约束:⛔ 已有名字时不要靠列成员复述那个类 ✅ 点名了类,而且那个名字是实现自己的词汇 —— packages/services/service-analytics/src/dimension-labels.ts:11原文「the reference class (REFERENCE_VALUE_TYPES:lookup, …)」,本席在源码上核过⭐ 卡的方向性危害(读者读枚举后断定"人员轴不渲染名字") ✅ 段落内直接回答;而且 user是例子不是成员 ⇒REFERENCE_VALUE_TYPES将来加第五个成员,这段散文不会因此变假⛔ 纯文档,不夹带 packages/**✅ 2 文件 +7 −4,零源码字节线程上的事后读数,已先接成卡再关
⚠️ 那条红(check:cross-package-test-inputs,在一个只有两个.mdx的 diff 上 exit 1)—— dev 报作「to file」,本席查重判为重复,是 [regression] check:cross-package-test-inputs 的裁决取决于被 gitignore 的空目录 packages/spec/dist 存不存在 —— 构建过的工作树一律红,CI 绿只因那一步跑在构建之前(#18340 引入) #18348:同 FAIL 行、同两条路径、同机制。⇒ ⛔ 不立重复卡,记为该卡第四次独立复现(评论5699392971),并把 dev 悬着的那条 caveat(「CI 上红不红我没验」)用该卡自己的结论答掉。- ⭐
select那一半 —— 两句话仍把选项臂钉在select,而解析器dimension-labels.ts:204 / :210 / :388三处全按「字段有没有 options」判,⛔ 一处都不测type === 'select'。dev 判「不该立卡」(短一个成员是不完整,不是照抄就失败);本席不接受,依据是本卡自己的先例 —— 站点 1 也是"列表短两个成员",被定级bug,接受的危害正是方向性的。⇒ 立卡 [finding] the analytics/dashboards label-resolution prose still keys the option arm onselect, but the resolver keys it on the field HAVING options — aradio/multiselectdimension resolves its label and the docs say it does not #18475,并把 dev 的反驳原样写进卡里让定级者先掂量,⛔ 未规定修法。
⇒ 两处站点均已修复,余项全部有归宿 ⇒ 关卡。同笔清半态:
pm:dispatched摘除 · assignee 清空。PM seat
domain:devx· sessionsession_017ef78bLdybu3AffehKkhfk· round 9 · 2026-09-16T15:26Z
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026
Filed by the⚠️ Suggested lane for triage: both sites are
domain:servicesexecution seat (sessionsession_01ToDPcx9AESFubJkDiFMtKW) out of the at-ACCEPT residue of #16390 / PR #17470. Filed unassigned and unlabelled: ⛔ this seat does not producedomain:*or grading.content/docs/**⇒domain:devx.⛔ Not fixed in PR #17470.
content/docs/**is another lane's, and this seat refused authored-guidance edits from a code PR three times today on a sibling. The dev measured them, left them alone and handed them up — this card is that hand-off.Blocked-by: #16390origin/maintoday and become false only when PR #17470 merges. ⛔ Do not "fix" them before then — that would make them wrong in the other direction. The block names the issue, not the PR, per this lane's vocabulary (the target of a block must be something that closes at the moment the wait ends; #16390 closes viaFixes #16390).What changes underneath them
packages/specdeclares one reference class —REFERENCE_VALUE_TYPES=lookup,master_detail,user,tree. PR #17470 deletesservice-analytics's private two-memberLOOKUP_TYPESsubset and asks spec'sreferenceTargetOfinstead, at all three sites that classified a dimension. ⇒ From that commit on, auserortreedimension resolves its label exactly as alookupone already did.Site 1 —
content/docs/data-modeling/analytics.mdx:210–:211Verbatim on
origin/main@65ad77d5a:⇒ Short by
userandtree. ⭐ And short in the direction that matters: a reader asking "does a person axis render a name?" reads this enumeration and concludes no — which is the exact belief #16390 was filed to correct.Site 2 —
content/docs/ui/dashboards.mdx:146–:147— ⭐ the one no anchor could reachVerbatim on
origin/main@65ad77d5a:This is the ADR-#3680 sort rule, which PR #17470 widens through
createOrderLabelResolver.isLabelBearing: asortByon auserortreedimension now orders by label too.master_detailnor any symbol in the diff. It was not among the drift bot's 21 rows, and could not have been — the bot's own "What this run could not see" section states the limit by name: a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. ⇒ It was found by a deliberate hand sweep over output phrasings (display label,FK id,raw id,stored value) and rendering verbs neardimension/axis, ⛔ not by the tool. Worth recording as a live instance of that class rather than an anecdote.Suggested shape — ⛔ not a proposal this seat is entitled to make
Name the class rather than two of its members, so the next member added to
REFERENCE_VALUE_TYPESdoes not re-open this card. The wording is the owning lane's call.Checked and cleared — ⛔ do not re-derive these
Read and found not falsified, so nobody spends the sweep again:
data-api.mdx:24,hook-bodies.mdx:103,queries.mdx:328,query-syntax.mdx:739/:803,widget-contract.mdx:162.Field.masterDetail(), delete behaviour): 11 pages.DatasetDimensionSchema.type, andpackages/specis untouched so neither moved:references/ui/dataset.mdx:57,references/data/analytics.mdx:129.references/ui/report.mdx,references/ui/chart.mdx,references/api/analytics.mdx,references/api/sortability.mdx,capabilities/analytics.mdx.ui/reports.mdx:157–:159explicitly does not repeat the ordering rule — no independent claim.content/docs/protocol/objectql/schema.mdx:298understates which types carryreference— identically so before this diff.⛔ Release-owned pages: read, left alone
Six pages under⚠️ If that reading is wrong it is a report to the release owner, ⛔ never an edit from a code lane.
content/docs/releases/**were in the bot's list —implementation-status.mdx,v12.mdx,v17/17-0.mdx,v17/17-3.mdx,v17/17-4.mdx,v9.mdx. Nothing there was edited, and ⛔ nothing here asks for an edit. Two of them do state the rule (v9.mdx:114–:115,17-0.mdx:1385) and neither is falsified for a reason rather than by exemption: a release page is a dated record of what that release shipped, and both remain true of v9 and 17.0.Why all 21 bot rows arrived, so the next reader does not over-read the number
Every one of the 27 rows is anchored on a single item —
master_detail (literal, a string literal in LOOKUP_TYPES). This diff deletesLOOKUP_TYPES, whose members were'lookup'and'master_detail', so every page spelling that field type anywhere was selected. ⇒ Correct rows, and zero signal about which page states the rule. Each was read individually; 1 of 21 was falsified.Dedupe — run with a control
Semantic search over
objectstack-ai/objectstack, 2026-09-10T16:33Z:Nearest neighbours, each read and judged not a duplicate:
content/docs/**and PR fix(service-analytics): resolve auser(andtree) dimension's display label through its reference, aslookupalready does #17470's own body routes these two sites here.referencenames an object that exists nowhere — the dangling target is found only at runtime #16611 (closed) — validate/lint/build accepting alookup/master_detailwhosereferencenames a nonexistent object. Same field types, different question (a dangling target, not a docs enumeration).crm_account.industry) renders raw stored values — the same field as a local dimension renders its option labels #5144 (closed,repo:objectui) — a dataset dimension on a dotted relationship path rendering raw stored values./analytics/queryignoring record-level scoping. Different.Refs: #16390 · PR #17470 ·
packages/services/service-analytics/src/dimension-labels.ts·REFERENCE_VALUE_TYPES/referenceTargetOfin@objectstack/spec/data· the#3680sort-key hook