You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 5d8319f
Browse filesBrowse the repository at this point in the historyBrowse files
fix(spec): the rowColor prescription stops handing authors the one spelling the renderer drops (#18849)
Fixes#18791
Clause-②: yes
`RowColorConfigSchema.colors` advertised `Map of field value to color
(hex/token)`, and
the `view/row-color-without-colors` diagnostic checked PRESENCE only.
The sole renderer —
objectui `plugin-grid`'s `useRowColor` — resolves far less than that. So
the chain ran:
the gate fires, **the gate's own `fix` string hands the author a hex**,
the hex parses,
publishes, clears the `!config.colors` guard, turns the gate GREEN, and
colours nothing.
A control whose own prescription switches it off.
## What the renderer actually does
Read at the pinned `.objectui-sha`
`53ded82bf7a494f54e344e19099dbf00854b8694`, not at
objectui's local HEAD (a different tree this repo does not consume):
- `COLOR_TO_CLASS` has **23** entries, every key a bare lower-case word
(`red`, `slate`,
`grey`, …), each mapping to `bg-NAME-100`.
- `colorToClass` returns a `bg-`-prefixed value untouched; otherwise it
looks up
`color.toLowerCase().trim()` with `hasOwnProperty` and returns
`undefined` for
everything else. Tailwind v4 has no runtime, so no class can be
fabricated from a hex.
## Three landing points
1. **The `describe`** now names the two spellings that reach a class and
names a hex only
as the thing that does not.
2. **The `fix` string** (highest priority — the only half that ACTIVELY
pushed authors
into the trap) now prescribes a resolvable colour name. `token` went
with the hex: it
named nothing an author could look up and stood beside hex as an equal
alternative.
3. **A new author-time warning, `view/row-color-unresolvable-value`** —
the half
presence-only structurally cannot see, because a hex map CLEARS the
guard that
silences the older rule.
The new rule judges the **shape** a value has and deliberately does not
transcribe
objectui's 23-entry map. Two structural facts carry it, and neither
depends on what the
map contains: the `bg-` branch tests the raw value, and every key is a
bare lower-case
word matched after `toLowerCase()` and `trim()`. That makes it **sound**
— it never
accuses a value the renderer would have resolved, including `'RED'` and
`' red '` — and
deliberately **incomplete**: an unknown name such as `chartreuse` is
shaped like a key and
is passed, pinned as a NON-rule. A hand-copy of another repo's
vocabulary is a second
opinion that drifts silently in both directions.
## Item 3 was gated on blast radius — measured, and it clears
The gate: if the rule would refuse anything currently authored, stop and
report.
- **Nothing is refused at all, and nothing fails on a DEFAULT run.** The
finding is
`warning`, and `@objectstack/lint`'s `splitBySeverity` sorts everything
that is not
`error` into advisories, so `os build` / `os validate` / `os lint` still
exit 0 on
their default paths. The registration-time twin in
`@objectstack/objectql` calls
`checkFieldCompleteness` and never the view predicate, and warns without
ever throwing.
⚠️ **Corrected after the at-tier review (record `5723359135`):** under
`os lint --strict` and `os validate --strict` a warning IS a failure —
`lint.ts:922`
computes `failing = errors.length + (strict ? warnings.length : 0)` and
`validate.ts:715` exits 1 on `flags.strict && a non-zero warning count`
— so a stack
carrying an unresolvable `rowColor.colors` value starts failing those
strict runs.
That is what the flag is for (its own docblock: so an app can rely on
the
warning-level rules this registry ships **as its gate**), which is why
the seat ruled
this additive rather than breaking; the changeset now states the
consequence and the
fix. ⛔ `os build` is NOT in that pair: `build.ts` is an alias for
Compile, which
carries `--strict-body` and no `--strict`.
- **This repo and the five example apps:** the only shipped
`rowColor.colors` map is
`examples/app-showcase`'s task grid — `{ low: 'slate', medium: 'blue',
high: 'amber',
urgent: 'red' }` — four colour names, all resolving. Every other
`rowColor` in the tree
is `field`-only and belongs to the older rule. Grep controls run both
ways: a lit
control hitting 11 lines under `examples/`, a fabricated dark control
returning exit 1.
- **objectui at the pinned sha** does hold three hex `colors` literals,
named here so the
zero is checkable rather than asserted: all three are objectui's own
React test
fixtures (`ObjectView.rowColorRelay-7218.test.tsx`, in `app-shell` and
`plugin-view`).
They assert a relay by `toEqual` and never traverse
`checkViewCompleteness`, so this
rule does not judge them and does not change their verdict.
## Verification
Round resumed after a container restart killed the previous session
mid-flight; nothing
it implied was taken on trust, and re-measuring found two real gaps,
both fixed here.
| Run | Verdict |
|:---|:---|
| `pnpm --filter @objectstack/spec build` | exit 0 — `check-dts-emitted:
34/34` |
| `pnpm --filter @objectstack/spec test` (project `local`) | exit 0 —
487 files / 14051 tests |
| `pnpm --filter @objectstack/spec test:repo` (project `repo`) | exit 0
— 31 files / 536 tests |
| `pnpm --filter @objectstack/spec typecheck` | exit 0 |
| `pnpm --filter @objectstack/spec check:generated` | exit 0 — all 15
artifacts current |
| `check-adr-0087-registration` / `check-changeset-no-major` /
`check-empty-changeset` | exit 0 |
| `pnpm check:nul-bytes`, `check-spec-docblock-symbol-anchors` | exit 0
|
Counts read against `c5e927f9506`. Heavy runs went through
`scripts/pm/os-verify-lock.sh`; every exit code was captured after a
redirect, never
through a pipe.
**Gap 1 — the changeset named a symbol that does not exist.** Its "not
breaking"
paragraph rested on `partitionFindings`; `git grep` found exactly one
occurrence in the
repository, the changeset's own sentence. The mechanism was real, the
name was not — the
router is `splitBySeverity` (`packages/lint/src/authoring-rules.ts`).
Corrected, because
this text ships to consumers as `CHANGELOG.md` and an unresolvable
symbol there is a dead
end for the reader who greps it — the same defect class as the card
itself.
**Gap 2 — two generated artifacts were stale.**
`VIEW_ROW_COLOR_UNRESOLVABLE_VALUE` is a
new public const on `./kernel`, so `check:api-surface` and
`check:export-origins` were
both red. The tree carried no `.d.ts` at all (a prior `OS_SKIP_DTS=1`
build), under which
`gen:api-surface` cannot run — so this was rebuilt for real first, then
only the two the
aggregate proved stale were regenerated. The diff is two added lines and
nothing else;
`check:api-surface` reads it as `0 breaking (removed/narrowed), 1
added`, which is the
accept-set reading the `minor` bump and the clause-② widening
declaration already claimed.
Test-fixture triage went by the rule's consumer radius, not by the
edited package: the
`RowColorConfigSchema` fixture that pins "a hex does parse" is
deliberately KEPT (the
assertion is correct — what was wrong is believing a parse means a
colour), while the
corpus fixtures that were merely *demonstrating* a hex were respelled,
because a fixture
is read as an example.
## Acceptance notes
Out of scope for this PR, noted rather than fixed:
- **objectui's three hex `rowColor.colors` test fixtures** at the pinned
sha model the
exact trap this card is about, as an example an AI or a human would
copy. They are
correct *as relay assertions*, so this is a readability trap and not a
broken test, and
objectui is read-only from here. Reported to the seat with dedupe words
rather than
filed by me.
- `content/docs/references/api/protocol.mdx` and
`content/docs/references/data/object.mdx`
render `rowColor` as an inline type and so never expand the `colors`
describe; only
`view.mdx` carries the nested-shape tables that received the new
sentence. Generated
output, correct as generated — noted, not filed.
⛔ Not addressed here and deliberately untouched: the
`view.exportOptions` format enum
region of `view.zod.ts`, which on-hold card #8346 declares as its
trigger region. This
change lives at the `RowColorConfigSchema` describe and does not enter
it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01LvwGppdonww4zGLWZo5rho
---
_Generated by [Claude
Code](https://claude.ai/code/session_01LvwGppdonww4zGLWZo5rho)_
---
_Generated by [Claude Code](https://claude.ai/code)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: content/docs/references/ui/view.mdx
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1051,7 +1051,7 @@ View filter rule
1051
1051
| Property | Type | Required | Description |
1052
1052
| :--- | :--- | :--- | :--- |
1053
1053
|**field**|`string`| ✅ | Field whose value is looked up in the `colors` map below to pick a row colour (typically a select/status field). The map is what does the colouring — with no `colors`, no row is ever coloured, whatever this field holds. Author-time diagnostic `view/row-color-without-colors` reports that combination. |
1054
-
|**colors**|`Record<string, string>`| optional | Map of field value to color (hex/token)|
1054
+
|**colors**|`Record<string, string>`| optional | Map of field value to row colour. The spellings that actually paint a row are not free-form: objectui `plugin-grid`'s `useRowColor` hands a value already written as a complete Tailwind background class (`bg-red-200`) straight through, otherwise lower-cases and trims it and resolves it through its own closed vocabulary of colour NAMES (`red`, `blue`, `slate`, … each mapping to `bg-NAME-100`), and returns undefined for anything else. A hex, an `rgb()` or a CSS variable parses here, publishes, and colours no row — Tailwind v4 has no runtime, so no class can be fabricated from one. Author-time diagnostic `view/row-color-unresolvable-value` reports a value that cannot resolve.|
|**field**|`string`| ✅ | Field whose value is looked up in the `colors` map below to pick a row colour (typically a select/status field). The map is what does the colouring — with no `colors`, no row is ever coloured, whatever this field holds. Author-time diagnostic `view/row-color-without-colors` reports that combination. |
1452
-
|**colors**|`Record<string, string>`| optional | Map of field value to color (hex/token)|
1452
+
|**colors**|`Record<string, string>`| optional | Map of field value to row colour. The spellings that actually paint a row are not free-form: objectui `plugin-grid`'s `useRowColor` hands a value already written as a complete Tailwind background class (`bg-red-200`) straight through, otherwise lower-cases and trims it and resolves it through its own closed vocabulary of colour NAMES (`red`, `blue`, `slate`, … each mapping to `bg-NAME-100`), and returns undefined for anything else. A hex, an `rgb()` or a CSS variable parses here, publishes, and colours no row — Tailwind v4 has no runtime, so no class can be fabricated from one. Author-time diagnostic `view/row-color-unresolvable-value` reports a value that cannot resolve.|
@@ -1607,7 +1607,7 @@ Row color configuration based on field values
1607
1607
| Property | Type | Required | Description |
1608
1608
| :--- | :--- | :--- | :--- |
1609
1609
|**field**|`string`| ✅ | Field whose value is looked up in the `colors` map below to pick a row colour (typically a select/status field). The map is what does the colouring — with no `colors`, no row is ever coloured, whatever this field holds. Author-time diagnostic `view/row-color-without-colors` reports that combination. |
1610
-
|**colors**|`Record<string, string>`| optional | Map of field value to color (hex/token)|
1610
+
|**colors**|`Record<string, string>`| optional | Map of field value to row colour. The spellings that actually paint a row are not free-form: objectui `plugin-grid`'s `useRowColor` hands a value already written as a complete Tailwind background class (`bg-red-200`) straight through, otherwise lower-cases and trims it and resolves it through its own closed vocabulary of colour NAMES (`red`, `blue`, `slate`, … each mapping to `bg-NAME-100`), and returns undefined for anything else. A hex, an `rgb()` or a CSS variable parses here, publishes, and colours no row — Tailwind v4 has no runtime, so no class can be fabricated from one. Author-time diagnostic `view/row-color-unresolvable-value` reports a value that cannot resolve.|
0 commit comments