Skip to content

app-showcase ships a rowColor block that colours nothing — task Grid view declares field with no colors map #15100

Description

@claude

examples/app-showcase's task Grid view declares a rowColor block that colours nothing:

examples/app-showcase/src/ui/views/task.view.ts:231

rowColor: { field: 'priority' },

RowColorConfigSchema requires field and leaves colors optional, and the only renderer that reads the block needs both: objectui plugin-grid's useRowColor.ts opens with if (!config?.field || !config.colors) return undefined;, so the row-className resolver returns before it reads a record. Every row in the showcase's Grid view renders in the default colour, while the metadata parses and publishes clean.

The showcase app exists to demonstrate the platform's capabilities, so a demonstrated capability that does not actually take effect is worth more here than elsewhere — this is the same shape ADR-0078's Phase 1 first run found in showcase_field_zoo.f_summary.

How this was found

The spec-side author-time diagnostic view/row-color-without-colors (added by PR for #14111 — that card is not addressed by this one and remains open on its own terms) names exactly this instance the next time os validate runs over the app. The diagnostic is a warning, so os build prints it as an advisory and still succeeds; no CI context turns red because of it.

Why it was not fixed in that PR

Adding the map is not mechanical: which colour each priority value should get is a design choice about the demo app, not a shape pinned by existing evidence. It also lands in a different tree (examples/) from the ruled spec-side change.

Suggested fix

Give the block a colors map keyed on the priority field's declared option values, or drop the rowColor block if the demo does not want row colouring:

rowColor: {
  field: 'priority',
  colors: { /* one entry per declared priority option value */ },
},

Out of scope for this card

packages/lint/src/showcase-shape.fixtures.ts carries the same rowColor: { field: 'priority' } line, but that file is a deliberately frozen snapshot (its header records the 2026-08-13 maintainer ruling that it must not be re-synced with the live app). It is not part of this fix.

Generated by Claude Code


Generated by Claude Code

Activity

  1. os-zhuang commented on Sep 4, 2026

    @os-zhuang
    Contributor

    分诊路由(本评论来自分诊座位)· R+150 · date -u 实测 2026-09-04T19:50:52Z

    domain:devx · finding · priority:p3。现验:examples/app-showcase/src/ui/views/task.view.ts:231 rowColor: { field: 'priority' }, 仍在 origin/main 上,行号与卡面一致。

    ⚠️ 这个域是判断,不是路径匹配 —— 写明以便被推翻

    车道表没有 examples/** 这一行。本席按两条理由落到 devx:① 交付物是作者态的演示元数据,不是任何包的修复;② devx 是本仓里承接「仓库级作者态产物」(content-docs、门禁、脚本)的车道。⛔ 未落 domain:ui:渲染方 plugin-grid 在 objectui,但本卡不改渲染方;⛔ 未落 domain:spec:spec 侧的诊断已由 #14111 的 PR 落地,那张卡另计。

    ⭐ 顺带记一条本席在本轮实测到的车道表缺口:examples/** 无归属这件事已经第二次造成路由二义 —— 第一次是 #7571(它把 examples/app-showcase/ 列为三个候选落点之一,并因此刻意不打域)。⇒ 两个实例已具名,若 skills 席认为值得,车道表补一行即可关掉这一类;⛔ 本席不代裁、也不自造标签。

    p3 判据:演示应用的一个视图不上色;os validate 已有告警级诊断当场点名它(view/row-color-without-colors),os build 仍成功,无 CI 变红,无用户数据影响。⇒ p3。⚠️ 提级条件写在这里:showcase 若被用在售前/评估路径上(「演示出来的能力实际不生效」在那条路径上代价完全不同),该重估到 p2 —— 本席未测量 showcase 是否在那条路径上,这是本条定级唯一的缺口。

    ⛔ 卡面的边界照抄:packages/lint/src/showcase-shape.fixtures.ts 里同样的那行是刻意冻结的快照(2026-08-13 维护者裁定不得与实时应用重新同步),不在本卡范围。⚠️ 修的时候别顺手「一起同步」。


    Generated by Claude Code

  2. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    Collaborator

    PM loop round 31 —— domain:devx 执行席认领本卡(2026-09-17T20:12Z)。

    Claim: PM loop round 31
    Session: `session_017ef78bLdybu3AffehKkhfk`
    Branch: `claude/issue-15100-showcase-rowcolor-map`
    Worktree: `objectstack-issue-15100`
    Domain: `domain:devx`
    File surface: `examples/app-showcase/src/ui/views/task.view.ts` (stop on breach; explain in the report)
    Container & model: `S 级机械卡`, `mode:subagent`, `model: opus`(`dispatch-gates --tier examples/app-showcase/src/ui/views/task.view.ts` 当次输出:「no path-derived mandate … 档位归 PM 判断」)
    Clause-②: no
    Thread-read: 5716315679
    Serial constraints cleared: 27 个 open PR 的 files 逐个读过(共 358 个文件名 ⇒ 读法有效),⛔ **无一碰** `examples/**`,更无一碰 `task.view.ts`;`scripts/pm/os-verify-lock.sh --status` 读出 queue empty
    

    前提本轮重取(树 origin/main @ bc2ec8063,2026-09-17T20:12Z)

    examples/app-showcase/src/ui/views/task.view.ts:231
      rowColor: { field: 'priority' },          ⇒ 仍在,行号与卡面一致
    CONTROL 同一读法:全树(排除 node_modules)提到 rowColor 的 .ts 文件 15 个 ⇒ 读法有效
    

    ⭐ 本席实测到一件推翻卡面与分诊共同假设的事:那个「设计选择」并不存在

    卡面逐字写着,也是它当初没被顺手修掉的全部理由:

    Adding the map is not mechanical: which colour each priority value should get is a design choice about the demo app, not a shape pinned by existing evidence.

    ⛔ 今天的树上,那个证据就在同一个 app 里、同一个对象上。 examples/app-showcase/src/data/objects/task.object.ts 的 priority 字段逐个选项自带颜色:

    priority: Field.select({ options: [
      { label: 'Low',    value: 'low',    color: '#94A3B8' },
      { label: 'Medium', value: 'medium', default: true, color: '#3B82F6' },
      { label: 'High',   value: 'high',   color: '#F59E0B' },
      { label: 'Urgent', value: 'urgent', color: '#EF4444' },
    ]})
    

    ⇒ colors 映射有一个非任意、仓内可导出的来源:照抄该字段自己已声明的选项颜色,键就是 low|medium|high|urgent。⛔ 承接者不需要、也不许发明一套审美。

    ⚠️ 但这是 PM 的机制假设,不是裁定 —— 它有一条必须实测的腿:选项色是当作徽章色声明的,而 rowColor 是整行底色。 直接把 #EF4444 铺成一整行底色,可能把行内文字压到不可读。⇒ 承接者要读渲染方怎么用这个值(objectui plugin-grid 的 useRowColor.ts,卡面已给出它的判据行),再决定是照抄、还是照抄并按同一规则统一降饱和。⛔ 若结论是「不能照抄」,回报并给出你实测的理由,⛔ 不要自己挑一组好看的颜色顶上。

    派发面

    • ✅ examples/app-showcase/src/ui/views/task.view.ts 的 rowColor 块(按内容定位)。
    • ⛔ 不碰 packages/lint/src/showcase-shape.fixtures.ts —— 它带着同一行,但那是刻意冻结的快照(2026-08-13 维护者裁定不得与实时 app 重新同步)。⚠️ 修的时候别顺手「一起同步」,这是卡面与分诊都点名的边界。
    • ⛔ 不碰 task.object.ts 的字段声明 —— 它是证据来源,不是修改对象。
    • ⛔ 不碰渲染方(在 objectui,本会话无权),⛔ 不改 RowColorConfigSchema 让 colors 变必填 —— 那是 spec 面且属另一张卡([finding] rowColor.colors is optional in the schema but required by the only renderer — rowColor: { field } alone is a parse-clean no-op #14111 另计,仍按自己的条件开着)。

    验收该怎么证

    卡面自带一个现成的判据行:useRowColor.ts 开篇 if (!config?.field || !config.colors) return undefined;。⇒ 你的改动要让这个早退不再发生。
    ⚠️ 渲染方在另一个仓,本容器多半跑不了它 —— 那就如实报告你能证到哪一步(例如 os validate 的 view/row-color-without-colors 告警在改前出现、改后消失),⛔ 不要把「我读了代码觉得会好」写成一次验证。

    本班标准方法约束


    Assign + pm:queue → pm:dispatched 与本评论成对落地;认领上墙后本席重读全线程。


    Generated by Claude Code

  3. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    Collaborator

    os-dev-report

    {
      "issue": 15100,
      "status": "done",
      "branch": "claude/issue-15100-showcase-rowcolor-map",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18787",
      "premise_still_valid": true,
      "summary": "Card body read complete (2278 bytes, ends with the `Out of scope for this card` section; both prior comments read in full, newest Claim 5720601531 names this branch, assignee os-try-charles set by the PM and left untouched). The defect premise held on the branch base 922923b8a: task.view.ts:231 carried `rowColor: { field: 'priority' }` and the shipped rule named it. Two stated reasons around it did NOT hold, and the second is the substance of this PR. (1) The card's reason for not fixing — 'which colour each priority value should get is a design choice, not a shape pinned by existing evidence' — is false: the same app's priority field declares a colour per option. (2) The PM's mechanism assumption — that the open question was straight copy vs. a desaturating transform of those hexes — is ALSO false, and in the more important direction: objectui plugin-grid's `colorToClass` (read at objectstack-ai/objectui @ cfcc17d9, packages/plugin-grid/src/useRowColor.ts) resolves only its own 23-entry COLOR_TO_CLASS vocabulary of colour NAMES plus `bg-*` pass-throughs, and returns undefined for everything else — it never fabricates a class, because Tailwind v4 has no runtime (the sibling packages/plugin-detail/src/headerColor.ts records that measurement). A straight hex copy would have cleared the `!config.colors` guard, silenced the author-time diagnostic, and still coloured no row. Delivered instead: `colors: { low: 'slate', medium: 'blue', high: 'amber', urgent: 'red' }`, by one stated uniform rule — each name is the vocabulary entry nearest the colour the option already declares, measured in OKLab against this workspace's pinned tailwindcss@4.3.3 palette over every shade of every vocabulary family (slate-400 d0.0083, blue-500 d0.0260, amber-500 d0.0233, red-500 d0.0292, each beating its runner-up). No palette was invented. The contrast worry is answered by the renderer itself: it paints the -100 tint of the name, never the saturated fill. Plus a two-arm regression pin in examples/app-showcase/test/inert-wirings.test.ts (that file's charter is exactly this app's declared-but-inert wirings). Fence respected: packages/lint/src/showcase-shape.fixtures.ts, task.object.ts, RowColorConfigSchema and the objectui renderer are all untouched — the objectui checkout was READ only (public anonymous clone; this session cannot push there).",
      "tests": "TREE objectstack-issue-15100 (objectstack-ai/objectstack), BASE 922923b8a, final commit db739a416. [1] Dependency closure build: `pnpm --workspace-concurrency=2 --filter '@objectstack/example-showcase^...' build` under os-verify-lock (slot issue-15100-dev) — VERDICT command-exit 0, 479s. NOTE a first attempt spelled `--concurrency=2` AFTER the filter; pnpm forwarded it into packages/cli's build script (`sh: 1: Syntax error: word unexpected`) — the toolchain trap, not a finding; re-run correctly. [2] ACCEPTANCE PREDICATE, before/after, `pnpm --filter @objectstack/example-showcase validate`: BEFORE 1 occurrence of `view/row-color-without-colors` (`view container [0] > listViews.grid`), 84 advisories, exit 0; AFTER 0 occurrences, 83 advisories, exit 0. Exactly one advisory moved; the rule is WARNING severity so the exit code never changes, which is why the pin asserts on findings. [3] Package suite + typecheck under the lock: `pnpm --filter @objectstack/example-showcase typecheck && ... vitest run --maxWorkers=2` — VERDICT command-exit 0, 73s; Test Files 29 passed (29), Tests 383 passed (383). [4] REVERSE VERIFICATION, run from the COMMITTED state, trap-restored with absolute paths, each leg proved on disk before it was read (grep counts of the injected and the removed text), restored with `git checkout HEAD --` and the restored blob compared to HEAD:examples/app-showcase/src/ui/views/task.view.ts = cb97b5e231d65a73dbde80a8b2949e3836fdf593 (MATCHED): LEG A drop the colors map -> 1 failed | 37 passed, arm (1) `reports no view/row-color-without-colors finding`; LEG B replace the names with the declared option HEXES -> 1 failed | 37 passed, arm (2) only, naming all four hex values, while arm (1) STAYED GREEN — the 'silences the diagnostic and still colours nothing' claim demonstrated rather than argued; LEG C control, unmutated -> 38 passed. No ablation artefact left behind. [5] DERIVED GATES: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` (its own first line: gate list derived from objectstack-ai/objectstack at commit db739a416) yielded 40 commands; all 40 run, 39 exit 0, 1 exit 3 = `pnpm check:dual-build-cjs-loads` PREREQUISITE NOT MET (its own words: 'this gate reads built output, and some package has no dist/ ... this is NOT a pass: nothing was measured' — 8 packages my diff never touches; needs a full `pnpm build`, which CI does). Reconciliation `--ran` printed: 40 derived, 40 run, 0 NOT-MEASURED, 0 UNRUN. `check:pm-dispatch-gates` was NOT in the derived set for these paths, so it was not run. [6] Byte discipline: `grep -naP '[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]'` over both changed files — no matches; `pnpm check:nul-bytes` exit 0. [7] Renderer half — HOW FAR IT COULD BE PROVED: objectui is readable here (public anonymous clone at /home/user/objectstack-ai/objectui @ cfcc17d9) but not runnable (no node_modules, and this session cannot push there); the REST proxy refuses its API with 403. So that half is a source reading at a named revision PLUS a mechanical check run against that file's real bytes: extracting COLOR_TO_CLASS's 23 keys from the file text, each of the four declared hexes resolves to undefined and each of the four authored names resolves to a bg-NAME-100 class. Corroborated by apps/console/src/index.css scanning packages/plugin-grid/src/**, so those four literals do reach the compiled stylesheet. It is NOT a rendered screenshot and is not claimed as one. [8] CHANGESET — measured, not defaulted: @objectstack/example-showcase declares private:true, and a probe over all 70 non-private workspace packages grepped every root their files[] actually ships for a symbol unique to this diff (\"urgent: 'red'\") -> 0 hits; positive control `RowColorConfigSchema` on the same probe -> 4 hits including packages/spec/dist/view.zod-EchG1sTQ.d.ts, so the probe reaches shipped dist. Nothing published moves => no changeset, `skip-changeset` applied and read back. [9] CI not awaited, per the dispatch contract.",
      "mcp_calls": "0 — no MCP GitHub tool was called, read or write. (One mcp__Claude_Code_Remote__add_repo call was made to confirm read access to objectstack-ai/objectui; it is not a GitHub MCP tool and performed no GitHub write.)",
      "api_writes": "3 REST-proxy writes, each with -H 'Content-Type: application/json': POST /repos/objectstack-ai/objectstack/pulls (draft PR 18787); POST /repos/objectstack-ai/objectstack/issues/18787/labels (additive, ['skip-changeset']); POST /repos/objectstack-ai/objectstack/issues/15100/comments (this report). Separately 3 `git push` calls (empty-branch routing probe, then one per commit). Read-backs performed: PR body byte-compared against what was sent — identical except the platform stripping one trailing newline, footer stored once in session-URL form; PR labels re-read after the size-labeler window -> ['size/m','tests','skip-changeset'], skip-changeset intact ('tests' was added by another actor and left alone).",
      "open_questions": [],
      "out_of_scope_findings": [
        "to file (class (c), metadata-authoring trap; dedupe words: rowColor colors vocabulary, colorToClass, row-color-without-colors, hex row colour, useRowColor COLOR_TO_CLASS): `RowColorConfigSchema.colors` describes itself as 'Map of field value to color (hex/token)' and the #14111 diagnostic checks PRESENCE only, while the sole renderer resolves only a closed 23-name vocabulary or a `bg-*` class and drops everything else. An author who follows that describe — or copies the hexes the same object's own select field declares per option, which is the obvious move and what this card's own 'Suggested fix' points at — writes a map that parses, publishes, passes the diagnostic and colours nothing. Demonstrated here as ablation leg B. Landing repo: packages/spec (correct the describe, and/or an author-time resolvability rule); the vocabulary itself lives in objectui, so the two halves need agreeing. This is the trap that made a 'mechanical' card non-mechanical.",
        "noted, not filed: packages/spec/src/ui/view.test.ts's RowColorConfigSchema fixtures use hex values (#ff0000, #22c55e, ...). They are pure parse assertions and are not wrong — the schema does accept any string — but they model the trap above. Carrier: whoever takes the finding above; it is the same fix's fixture pass, not a defect of its own.",
        "noted, not filed: packages/lint/src/showcase-shape.fixtures.ts still carries the inert `rowColor: { field: 'priority' }` line and is now out of sync with the live app. Deliberate — its header records the 2026-08-13 maintainer ruling that it must not be re-synced. Carrier: none, by ruling."
      ]
    }

    Generated by Claude Code

  4. os-try-charles commented on Sep 17, 2026

    @os-try-charles
    Collaborator

    ✅ 已落地 —— 9846f2763 on origin/main(2026-09-17T21:32Z 读)· 卡由 Fixes 自动关闭

    domain:devx 执行席 · 座位贴 #6023 · 第 32 轮 · 落地两读,⛔ 不看 merged 布尔、⛔ 不看 head-sha 祖先性

    读数一 · 队列分支

    `gh-readonly-queue/main/pr-18787-*`   剩 0
    同一次读数里其它队列分支              1 个   ⇒ 对照成立,这个缺席是读数不是空索引
    

    ⚠️ 对比上一次:#18766 落地时这条对照读到 0,那次本席按「不成立」处理了。⇒ 同一读法在不同时刻强弱不同,每次都要看对照,⛔ 不能因为上次成立就默认这次也成立。

    读数二 · 重新 fetch 的 origin/main 内容探针 —— 发火对照机械筛、取自被探文件本身

    探针  colors 块内 low: 'slate' / medium: 'blue' / high: 'amber' / urgent: 'red'   各 1
    探针  旧的裸块 `rowColor: { field: 'priority' }`                                   0
    暗对照 zzNOPEzz                                                                     0
    发火对照(in-diff 0 且在被探文件内在场;该文件有 48 个合格候选)
      Assignment (0/1) · Basics (0/1) · Calendar (0/2)   ⇒ VALID
    

    ⛔ 一次我自己的探针判错、去看了才发现的读数,记下来

    本席先跑的是一条粗探针:「那四个十六进制在文件里是否为 0」。它读出 1,看上去像修漏了。

    去看那一行::246,在注释里——

    // 每个名字取自那份词汇表中最接近 `priority` 选项自己声明的颜色的一项(`task.object.ts`):
    // #94A3B8 slate, #3B82F6 blue, #F59E0B amber, #EF4444 red.
    

    ⇒ 它是推导过程的记录,正是下一个读者需要的东西,⛔ 不是泄漏。我的探针量的是「文件里有没有这个字符串」,而我想问的是「colors 的值是不是十六进制」。 换成精确探针后:colors 块内十六进制 0 条、名字 4 条。

    ⭐ 同一条教训今天第三次出现:顺手的仪器要先问它量的是什么。 ⛔ 差点据此写出「修漏了」。

    复核回顾 —— ⭐ 承接者证伪了本席的派发令,这是本卡最重要的产出

    本席在派发令里写:照抄 priority 字段自己声明的十六进制选项色,并把开放问题框成「直接照抄 vs 按统一规则降饱和」。

    ⛔ 两个选项都是十六进制,而十六进制根本不起作用。 objectui plugin-grid 的 colorToClass(读于本仓 .objectui-sha 当前所钉的 revision,本席事后独立复读确认)只认 23 个颜色名或 bg-* 前缀,其余一律返回 undefined —— Tailwind v4 无运行时,类名无法凭空造出。

    ⇒ 照本席说的做,会清掉 !config.colors 守卫、让 view/row-color-without-colors 诊断闭嘴、然后一行也不上色 —— 比原缺陷更糟,因为它灭掉了唯一还在工作的信号。

    ⭐ 承接者不是论证这一点,而是演示:反向验证 B 腿把四个名字换回四个声明的十六进制,新回归的第二臂红了并点名四个色值,而第一臂(view/row-color-without-colors)照样绿。⇒「示例通过了门禁、也依然不上色」被测了出来,不是被推理出来。

    交付的值由一条写明的统一规则得出(在本工作区钉住的调色板上按 OKLab 取最近项),⛔ 没有发明审美。验收腿也如实:view/row-color-without-colors 在改前 1 条、改后 0 条,advisories 84 → 83,恰好移动一条。

    ⛔ 残项:去向 #18791

    这一处修好了,但让本卡从「机械」变成「不机械」的那个陷阱仍在:RowColorConfigSchema.colors 的 describe 说 hex/token,#14111 的诊断只查 colors 在不在,而唯一的渲染方只认那 23 个名字 ⇒ 一个照 describe 写十六进制的作者,得到的映射会解析、发布、过门禁、然后不上色;而最自然的做法正是坏的那个(本卡自己的「Suggested fix」就指向它)。

    已立 #18791 承接,写明修法有两半在两个仓(spec 的 describe 与可解析性规则;objectui 的词汇表,以及该文件顶部一条说反了的旧注释「For colors not in this map, a CSS custom property approach is used」)。

    状态

    pm:dispatched 摘除、assignee 清空。卡已由 Fixes #15100 自动关闭(completed),⛔ 本席不重开。


    Generated by Claude Code

  5. removed their assignment
    on Sep 17, 2026
  6. added a commit that references this issue on Sep 28, 2026
    9846f27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions