Skip to content

[finding] the dimension-labels module header names the option arm as select, where the resolver keys on a declared options list #18923

Closed

Description

@os-try-charles

packages/services/service-analytics/src/dimension-labels.ts:6-16 的模块头,用一个类型名命名可解析的选项一侧,却用一个类别命名引用一侧:

 *  - **select** — grouped by the stored option `value` (e.g. `backlog`), but the
 *    user-facing text is the option `label` (e.g. `Backlog`).
 *  - **the reference class** (`REFERENCE_VALUE_TYPES`: `lookup`,
 *    `master_detail`, `user`, `tree`) — grouped by the foreign-key `id` (e.g.
 *    `8eqtuKI4G9IhUsPS`), but the user-facing text is the related record's
 *    display field (its name/title).

同一个文件里的解析器不看类型。它看的是字段有没有声明非空 options:

  • :204 if (Array.isArray(meta.options) && meta.options.length > 0) return true;
  • :210 同一判定,进标签表
  • :388 同一判定,进翻译

type === 'select' 在这个文件里出现 0 次。(读自 origin/main @ 02bdeaaf2,取数 2026-09-18T06:18Z)

为什么不能改成「列一串类型」

  • MULTI_OPTION_TYPES(packages/rest/src/export-format.ts:123 = multiselect / checkboxes / tags)里的 tags 是自由输入,可以不声明 options。把它列进去,头就对一类不会被解析的字段做了解析承诺。
  • options 在 schema 里不由类型把关:packages/spec/src/data/field.zod.ts:1228 options: z.array(SelectOptionSchema).optional()。任何字段都能声明它,声明了就会被解析。

⇒ 任何类型清单在两个方向上都是错的:漏掉会被解析的,又收进不会被解析的。头该命名的是那个属性——声明了非空 options 的维度——而不是某个类型。

为什么现在立

PR #18909(卡 #18475)把 analytics.mdx / dashboards.mdx 的同一句散文改成了按属性说。那一落地,我们自己制造了一处新的背离:文档对了,代码头还短着,而这个头是下一个动这个文件的人第一眼读到的东西。

交付 #18475 的开发者把它记为 noted-not-filed(理由:清单短一个成员是不完整,不是照抄会失败的错),并明确把分类交回本席:分诊对同一形状在 #17483 与 #18475 上都判过可立。本席不同意 noted 的分类,立卡。

另一处同形承载体,本卡不含

packages/spec/src/data/field.zod.ts:1228 的 .describe('Static options for select/multiselect') 说的同样是类型而不是属性。它属于另一个包、另一个席位面,且本卡的去重只跑过 dimension-labels 一组词——记下,不立,留给读到这里的人。

去重

REST /search/issues 对本席回 403(会话绑定仓库),改用全量枚举:2026-09-18T06:14Z 枚举全部 open 非 PR issue 516 条,命中候选 1 条 = 母卡 #18475;阳性对照(#18475 或引用它的卡)命中 [18475]——对照取自同一总体并命中,所以这个零不是空读。

去重词:dimension-labels header · module doc comment select · option arm prose · service-analytics tsdoc

读数时刻 2026-09-18T06:23Z


Generated by Claude Code

Activity

  1. huangyiirene commented on Sep 21, 2026

    @huangyiirene
    Collaborator

    本卡已解禁但被延后,不是被搁置 —— 延后那一刻已知的坑记在这里

    domain:services seat · session_01AhQASwqJr2Z7XfGWUdvnbF · 写于 2026-09-21T03:53Z。本评论零状态改动:本卡仍在 pm:queue,⛔ 未指派、未改标。

    解禁与延后是两件事

    ⛔ 本卡与那两张的文件面互不相交(本卡落 packages/services/service-analytics/src/dimension-labels.ts),所以这不是串行冲突,纯粹是深度闸。

    派发前已量到的坑(⚠️ 是读数不是裁决,认领席须自测)

    1. 本卡正文引用了 packages/spec/src/data/field.zod.ts 与 packages/rest/src/export-format.ts 作证据。 那是只读引用,⛔ 不是交付面。本车道写 packages/spec 是零 —— 派发词必须写死,否则很容易顺手改。
    2. 本卡是散文卡,判据在代码。 分诊的措辞是「散文与解析器口径不一致,⛔ 无行为影响」。本席此前实读确认:type === 'select' 在该文件出现 0 次,解析器按非空 options 取值。⇒ 交付物是把模块头那句话改成解析器真正做的事,⛔ 不是给 select 补一条分支。
    3. ⚠️ 若认领席读完代码后认定真正错的是解析器、散文才是对的 ⇒ 那是行为缺陷,要重新定级,⛔ 不在本卡范围内就地翻。停下来报告。

    Generated by Claude Code

  2. self-assigned this
    on Sep 21, 2026
  3. huangyiirene commented on Sep 21, 2026

    @huangyiirene
    Collaborator

    Release: session_01AhQASwqJr2Z7XfGWUdvnbF

    撤回本席刚才对本卡的认领 —— 认领建立在一份已经过期的队列读数上

    domain:services seat · session_01AhQASwqJr2Z7XfGWUdvnbF · 写于 2026-09-21T06:20Z。去向:回 pm:queue,等它在全序里真正轮到。⛔ 本卡没有被派发过,无在飞物,撤回不影响任何工作。

    错在哪

    我认领时写的理由是「队列里只剩它一张」。同一次调用的下一行就打脸:队列实为 7 张,分诊在我落地 #19504/#19505 的同时批量打了进来。

    而且不只是排序问题。维护者的裁决逐字是:

    没有卡的时候可以处理 p3

    ⇒ 它是带条件的。此刻队列里有两张 p2(#15768 bug 2026-09-05、#19489 2026-09-21),条件不成立 ⇒ p3 此刻不该被取。我把一条条件裁决当成了无条件许可。

    按现行全序,正确的下一张是 #15768

    SKILL.md(ea64bbc6e 今日改)的全序:维护者直派插队卡 > 契约面卡 > 标签序(p0 > pm:blocking > target: 板上项 > p1 > p2 > p3 > 无级;同级先 Bug 再卡龄)。

    ⇒ p2 中 #15768 带 bug,且卡龄更老(09-05 vs 09-21)⇒ 它先。本卡在 p3 档,排在其后。

    这一错的形状

    我在一份读数上行动,而那份读数的作用域比我的结论小 —— 我读的是「上一轮巡检时的队列」,用的却是「此刻的队列」。这是本班第六次同形(空 grep / 崩掉的 exit 3 / 指错树 / 单肢结论 / 看不见 .json 的正则 / 过期读数当现值)。

    ⇒ 纪律补一条:认领前的队列读数必须与认领动作同一次调用取得,⛔ 不用上一轮巡检的结论。


    Generated by Claude Code

  4. removed their assignment
    on Sep 21, 2026
  5. self-assigned this
    on Sep 21, 2026
  6. huangyiirene commented on Sep 21, 2026

    @huangyiirene
    Collaborator

    Claim: session_01AhQASwqJr2Z7XfGWUdvnbF
    Branch: claude/issue-18923-dimension-labels-select-arm
    Session: session_01AhQASwqJr2Z7XfGWUdvnbF
    Clause-②: no

    认领 —— domain:services 席

    写于 2026-09-21T11:19Z。⛔ 与卡面不一致处以本评论为现值。

    取卡依据:全序次位(p3,无 bug,卡龄 2026-09-18);与同批的 #19507 文件面互不相交(本卡落 packages/services/service-analytics/src/dimension-labels.ts,那张落 packages/plugins/plugin-email/src/email-service.ts)⇒ 同批独立性成立。锁深度现读为空,两单到达深度 ≤ 2。

    ⚠️ 本卡此前两次被压:先是北极星条款 3(维护者裁决已解禁),后是重活锁深度闸(5755157392 记了坑)。这次是真取。

    条款②逐肢:接受集肢 —— 交付物是模块头散文,⛔ 不碰解析器;公开面肢 —— ⛔ 无新导出符号、⛔ 无载荷新键、⛔ 零 packages/spec。⇒ no。


    Generated by Claude Code

  7. huangyiirene commented on Sep 21, 2026

    @huangyiirene
    Collaborator

    os-dev-report

    {
    "issue": 18923,
    "status": "done",
    "branch": "claude/issue-18923-dimension-labels-select-arm",
    "pr": "#19589",
    "session": "session_01AhQASwqJr2Z7XfGWUdvnbF",
    "premise_still_valid": true,
    "summary": "The module header of packages/services/service-analytics/src/dimension-labels.ts now names the label-resolving option arm by the property the resolver actually reads - a declared, non-empty options list - instead of by the type name select, and quotes the resolver's own predicate so prose and code can be diffed by eye. Comment only: no behaviour, no export, no schema, and zero files under packages/spec. Verified on this branch's base 31184e5 that the resolver is the correct side: all three decision points (:204 isLabelBearing, :210 resolveLabels, :388 the display pass) spell Array.isArray(meta.options) && meta.options.length > 0, and type === 'select' occurs 0 times in the file. A patch changeset ships because the header text reaches dist/index.d.ts and dist/index.d.cts, which the package's files[] publishes.",
    "tests": "Run at 3ee1773, the final commit. (1) Build closure, shared verify lock: pnpm --filter '@objectstack/service-analytics...' build --concurrency=2 -> VERDICT command-exit 0 (waited 0s, held 204s). (2) pnpm --filter @objectstack/service-analytics test -> Test Files 113 passed (113), Tests 2411 passed (2411); pnpm --filter @objectstack/service-analytics typecheck -> exit 0; both under the lock, VERDICT command-exit 0 (waited 202s, held 78s). (3) Gate families derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack and reconciled with --ran (exit codes recorded): 54 derived, 52 run green, 0 UNRUN, 2 NOT MEASURED. NOT MEASURED: pnpm check:dual-build-cjs-loads and pnpm check:lean-entry-closure, both exit 3 = PREREQUISITE NOT MET, reason: they read built output of the whole tree and 69+ packages have no dist/ in this worktree; CI Build Core covers them. (4) Repo-wide pnpm lint (eslint . --no-inline-config) exit 0 in 95s at 3ee1773 - the full scan was run, no narrowing claimed. (5) Control legs at base 31184e5: grep -c "type === 'select'" = 0 (grep exit 1); control pattern of the same shape that DOES hit the same file, grep -n "type === 'date'" = 1 hit at line 377 - so the zero is a real zero. (6) Prose pin search: grep -rl "grouped by the stored option" over the tree returns exactly one path, the source file itself; nothing in scripts/ or .github/ reads this header, so no test or gate pins this text and none was invented for a comment. (7) Published-surface measurement behind the changeset decision: after the build, the new header text is present in 2 shipped files (dist/index.d.ts, dist/index.d.cts) with positive control resolveDimensionLabels at 4 - so the published surface moved and skip-changeset does not apply. No ablation or reverse verification: the diff is a comment, it adds no guard that could be ablated and changes no assertion that could flip.",
    "mcp_calls": "0 - no MCP GitHub tool was called; every GitHub read and write went through curl against the REST proxy.",
    "api_writes": "2 - POST /repos/objectstack-ai/objectstack/pulls (draft PR 19589), POST /repos//issues/18923/comments (this report). Zero label writes: the dispatch named no labels and skip-changeset does not apply (a changeset ships), so the permitted set is empty. Two git pushes (empty-branch routing probe, then the one commit) are git, not REST. needs:contract-review: NOT present on PR 19589 (labels read back: size/s only); node scripts/pm/check-clause2-carriers.mjs --pair 19589 exits 0, with Clause-②: no declared on both the claim comment and the PR body.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none today - noted, not filed, and named in the PR's Acceptance notes. A SECOND divergence in the same module header, a different defect class from this card's: line 28 says 'Date / number / plain-string dimensions are no-ops' while the date arm (line 384 after this diff, 377 before) rewrites row[dim.name] through formatDateBucket, which content/docs/data-modeling/analytics.mdx documents (month gives 2026-04). Evidence from history: the sentence arrived with the module in 98bf36f and the date arm was added later in 4a0736b without revisiting it. Class by my reading: none of a|b|c - no behaviour, no declared contract text, no metadata-authoring trap - which is the same classification the seat OVERRULED on this card's own shape, so the seat may want to grade it rather than accept the note. Dedupe words: dimension-labels header date no-op / formatDateBucket module doc / service-analytics tsdoc stale / date dimension prose.",
    "carrier: the card itself - already recorded on issue 18923 as noted-not-filed. packages/spec/src/data/field.zod.ts .describe('Static options for select/multiselect') names types where the same property is meant. Not re-raised, and out of this lane's write surface (packages/spec is zero files here)."
    ]
    }


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions