Repository navigation
Commit ced3e1a
Part of #21464
Clause-②: yes (narrowing)
## What this does
The S-kanban-cf stage of the `ComponentPropsMap` `z.unknown()`
close-out: the exit of the `object-kanban` `conditionalFormatting` hold,
per the claim `5977940136`, the landing note `5977935364`, triage's
direction `5961300594` and the seat answer `5963787404` (item 2). The
census ran first. It found no working writer that the list view's member
refuses, and the reader's declared dialect is exactly the list view's
rule. So the member is typed by reference (def identity) to
`ListViewSchema.shape.conditionalFormatting`, as `object-grid`'s is. The
enumeration pin's `held-for-decision` line leaves the ledger, and so
does the emptied `held-for-decision` stage.
| member | was | now | read point at the `.objectui-sha` pin
`ab1879721595` |
|:--|:--|:--|:--|
| `object-kanban` `conditionalFormatting` | `z.unknown()` |
`ListViewSchema.shape.conditionalFormatting`, by reference: `[{
condition, style }]`, a non-blank CEL `condition` (string or `{ dialect,
source }` envelope) and a `style` map of strings |
`KanbanBoardCore.tsx:114` hands `schema.conditionalFormatting` to the
board; `getCardStyles` (`KanbanImpl.tsx:182`) evaluates it through
`resolveConditionalFormatting`
(`core/src/evaluator/listConditional.ts:532`), the evaluator the grid's
rows use (`ObjectGrid.tsx:2970`) |
No new export and no new schema: the row reads the list view's member,
so one rule is judged the same way on the list view, `object-grid` and
`object-kanban`.
## The hold's exit
- **Why it was held** (`5963787404` item 2): objectui's kanban authored
a second rule dialect, the native `{ field, operator, value,
backgroundColor }` rule and the flat colour rule, which the list view's
member refuses.
- **What changed in objectui**: objectui#11522's state is `completed`,
landed by objectui#11532 (`c73cdb5695`). `object-kanban`'s
`conditionalFormatting` takes the spec list view's `{ condition, style
}` rule only, and the native and flat-colour dialects are refused by
name. `git merge-base --is-ancestor c73cdb5695 ab1879721595` exits 0,
and so does the pin against objectui `main` `2e818d0b51`. Exit 0 proves
itself in any checkout, so no control leg is owed.
- **The reader's declaration at the pin**:
`KanbanConditionalFormattingRuleSchema` extends the spec list view's
rule element, read by reference (`types/src/zod/objectql.zod.ts:337`,
`:3074`), with tombstones for `field`, `operator`, `value`,
`backgroundColor`, `borderColor` and `textColor`. Its TS twin
`KanbanConditionalFormattingRule` extends
`SpecConditionalFormattingRule` (`types/src/objectql.ts:5166`). The
registration's description reads the same
(`plugin-kanban/src/index.tsx:676`, recorded in this repo's
`sdui.manifest.json`).
- **Two differences remain. Neither is a working rule:**
1. The shared evaluator still reads the native, `expression` and
top-level colour arms, for a rule a relay hands the board in a stored
dialect (`KanbanImpl.tsx:160-166`, `listConditional.ts:495-499`). It is
the grid's evaluator, unchanged. No authored `object-kanban` writer uses
those arms (census below), and objectui's own faces refuse them.
2. objectui's `condition` takes a string first, so its mirror still
admits a blank `condition` (`objectql.zod.ts:363-366`, pinned by
objectui's `spec-expression-wire-slots-10946.test.ts:151-155`). The
evaluator answers a blank predicate with the caller's fallback
(`listConditional.ts:252-260`, single-eval route `:339-340`), and the
board passes `fallback: false` (`:546`), so such a rule paints no card.
It is refused here, as on the list view and on `object-grid`. This was
read, not run.
- **Pin to objectui `main` `2e818d0b51`**: `KanbanBoardCore.tsx`,
`KanbanImpl.tsx`, `ObjectKanban.tsx`, `plugin-kanban/src/index.tsx`,
`listConditional.ts` and `ObjectGrid.tsx` are byte-identical (`git diff
--quiet`, exit 0 each). The two `@object-ui/types` files changed only
around `grouping`: zero changed lines mention `conditional`, and the
rule schema's line `3074` did not move.
## The census
A writer is a value written on the block: a page-component node (an
object literal naming `object-kanban`, flat or in its `properties` bag,
or a literal asserted as one), a direct parse through the row, the
block's React component inside its `schema` prop, or the argument of a
same-file helper that mounts one. Values resolve through same-file
constants and spreads, and parameters resolve at every same-file call
site and `it.each` table. Instrument 1 is a TypeScript-AST walk over
every tracked file naming `conditionalFormatting` (code, `.json`, and
fenced code in `.md` / `.mdx`). It records each `conditionalFormatting`
member with its static value and block context, and parses the value
through the list view's member. Instrument 2 parses every rule-shaped
object within 400 characters after a `conditionalFormatting` token, in
any syntax (tuples, `key:` / `value:` rows), as a one-rule list. Each
hit outside a block context was read by hand. Controls: instrument 1
finds the showcase's list-view writer and the `object-grid` pin's
writers in this repo.
| corpus | `object-kanban` writers | parse | refused |
|:--|:--|:--|:--|
| objectstack `16d241a6af` (every tracked file; 33 name
`conditionalFormatting`) | 1 | 0 | 1 ·
`packages/spec/src/ui/component.test.ts:3947` |
| objectui pin `ab1879721595` (94 files name the member, 61 of them also
`kanban`) | 9 working, 10 probe | 9 | 10 · all probes |
| objectui `main` `2e818d0b51` | the same 19 | 9 | 10 |
| hotcrm `4054ec2680` | 0 | | |
| cloud `2205b53010` | 0 | | |
- **objectstack's one writer** is this package's own test that the key
survived the `quickAdd` retirement: `[{ field: 'priority', value: 'high'
}]`. It has no `operator`, so the evaluator built no predicate from it
(`listConditional.ts:474`) and painted nothing, and objectui's own faces
refuse it. Its assertion is about the key, not the value, so it is
respelled to `{ condition: "record.priority == 'high'", style: {
backgroundColor: '#fee2e2' } }` and still asserts `success: true`.
- **objectui's nine working writers**, every one a test fixture, all `{
condition, style }`: the board test's three rules through its mount
helper
(`ObjectKanban.structuredMembersReachTheirSinks-8313.test.tsx:472`,
`:492`, `:509`), the asserted node in
`objectFieldsIsAPropNotASchemaKey-7742.test.tsx:97`, the declared-keys
row in `structuredKeysAreDeclaredAndHonoured-8313.test.ts:109` (which
parses through this very row on the installed spec), the live-member row
in `object-kanban-allow-collapse-retired-8801.test.ts:198`, the dialect
test's control (`kanban-conditional-formatting.test.ts:48`), and the
wire-slot test's string and envelope conditions
(`spec-expression-wire-slots-10946.test.ts:123`).
- **objectui's ten refused values are refusal probes.** Nine are refused
by objectui's own faces too: the native rule
(`kanban-conditional-formatting.test.ts:88`), the flat colour rule
(`:103`), a colour beside `style` (`:118`, three keys), an undeclared
`label` (`:139`), and three malformed conditions
(`spec-expression-wire-slots-10946.test.ts:158`). The tenth is that
file's probe that its mirror still admits a blank `condition` (`:152`),
which the board answers with no paint (above).
- **Not writers, and all of them parse:** eight rules mount the runtime
`KanbanBoard` directly (`cardPredicateScope.test.tsx`). Nine are
view-face relays of a list view's rules
(`ObjectView.kanbanConditionalFormatting.test.tsx`,
`objectViewHostSurface.test.tsx`). The other members in those 61 files
are `object-grid` or list-view writers, which the list view's member
already judges. The non-test hits are run-time hand-offs and the schema
declarations. objectui `main` adds one non-writer
(`InterfaceListPage.relayCensus-11572.test.ts`, a relay census record).
- **hotcrm and cloud** have no `conditionalFormatting` at all,
case-insensitive and snake case included. Controls: `kanban` in 48 and
35 files, and `objectName` in 115 and 145.
## Changes
- `packages/spec/src/ui/component.zod.ts`: the `object-kanban` row's
`conditionalFormatting` is `ListViewSchema.shape.conditionalFormatting`
with a card-level `.describe()`, and its docblock records the read
points, objectui's declaration, the two differences and the census. The
import comment names the kanban member beside the grid's.
- `packages/spec/src/ui/component-props-unknown-members.pin.test.ts`:
the `held-for-decision` line and stage leave, along with the now-unused
`staged()` helper. The kanban rule's
`conditionalFormatting[].condition.ast` joins the expression-AST lines,
exactly as the grid's does. The new §5 pins the def identity, three
accepted values parsing to what the list view's member answers, eight
refusals by `code` and path, the absent case, and the D3 id. The header
records the exit.
- `packages/spec/src/ui/component.test.ts`: the one census writer,
respelled (above). This file is outside the claim's file list. It is the
member's own fixture, and the change reddens it otherwise.
-
`packages/spec/src/migrations/entries/semantic/18.ui-object-kanban-conditional-formatting-typed.ts`
(new) and `packages/spec/src/migrations/registry.ts`: one step-18 D3
entry (the semantic region regenerated by `gen:migration-registry`), and
one rationale fragment at **order 77**, the next free order on `main` at
the base (73 to 76 are taken, 74 twice), inserted where its id sorts.
#21702 also adds a fragment, so whichever lands later re-reads the order
and merges `origin/main` through `scripts/pm/os-regen-merge.sh`. No D2
conversion and no `RETIRED_KEYS_BY_MAJOR` row: a page component's
`properties` is not parsed on the save or load path, and the refused
values are nested member values.
- `content/docs/references/ui/component.mdx`: regenerated by
`check:generated --fix`, which proved only `check:docs` stale.
-
`.changeset/21464-component-props-kanban-conditional-formatting-typed.md`:
`@objectstack/spec` `minor`, BREAKING banner, the `Clause-②` line, FROM
→ TO, the census, and the ADR-0087 marker registering
`ui-object-kanban-conditional-formatting-typed`.
## Measurements
Head `011e53fa2a` (this branch merged with `main` `7e0066af7a`, a
comment-only re-anchor of spec test citations that touches none of these
files). Base `16d241a6af`. Heavy runs went through
`scripts/pm/os-verify-lock.sh`, and every exit code was captured before
any pipe.
- **Red first, on the published `@objectstack/spec@17.6.0`** (the npm
tarball, `ComponentPropsMap['object-kanban'].safeParse`) and on `main`
`16d241a6af` (built): each of these is ACCEPTED on both:
`conditionalFormatting: 42`, `'red'`, the native rule, the flat colour
rule, an `expression` rule, a rule with no `style`, a blank `condition`,
and a `style` value of `5`. Control: `navigation: 42` is REFUSED there
(`invalid_type` at `navigation`). Each junk value is refused on this
branch, pinned in §5 by `code` and path.
- **`pnpm --filter @objectstack/spec test`** at `011e53fa2a`: exit 0,
Test Files 612 passed (612), Tests 18199 passed, 1 todo, nothing
skipped. The same at `27a0e12a09`, before the merge.
- **`pnpm --filter @objectstack/spec typecheck`** at `011e53fa2a`: exit
0, `check:test-typecheck: OK` (52 files / 246 errors / 135 signatures
held). `tsc -p tsconfig.test.json --listFilesOnly` names both touched
tests and the new D3 entry.
- **Build and generated artifacts**: the spec build is green.
`check:generated` proved only `check:docs` stale, `--fix` regenerated
that one, and the re-check at `011e53fa2a` reads "All 15 generated
artifacts are up to date". `check:api-surface` reads "public API surface
+ factory signatures unchanged". `turbo run build
--filter=!@objectstack/docs --concurrency=2` built 72 of 72 tasks.
- **Consumers**: `pnpm --filter @objectstack/lint test` (after building
lint's dependency closure, `--filter '@objectstack/lint^...'`): 119
files passed, 5622 tests passed, 5 skipped. The 5 read lint's own
`dist`; after `pnpm --filter @objectstack/lint build`,
`validate-component-props`, `lazy-deps` and `runtime-lazy-deps` passed
61 of 61, nothing skipped. The first lint run before that closure build
failed 56 files on `Failed to resolve entry for package
"@objectstack/formula"` / `"@objectstack/sdui-parser"`: unbuilt
dependencies, not a measurement.
- **The public door, both ways** (`validateComponentProps` from lint
`src` over the built spec, one `object-kanban` node per page). These
report nothing: a `{ condition, style }` rule, and an envelope
condition. These are reported: `42` as `component-props-invalid` at
`properties.conditionalFormatting`; a rule with no `style` as
`component-props-invalid` at `…conditionalFormatting.0.style`; the
native rule as `component-props-invalid` at `.0.condition` and
`.0.style` plus `component-props-unknown-key` at `.0.field`,
`.0.operator`, `.0.value` and `.0.backgroundColor`; an `expression` rule
at `.0.condition` plus `component-props-unknown-key` at `.0.expression`;
and a blank condition as `component-props-invalid` at `.0.condition`.
- **Ablation**, one leg, on the committed tree (`27a0e12a09`; the merge
did not touch these files). The driver used `node
scripts/ablation-replace.mjs` in wrap mode, inside its own `EXIT INT
TERM` restore trap on the absolute path, with an empty hash read as
failure, against HEAD blob `830a02f619`. The kanban member went back to
`z.unknown().optional()`: anchor x1 → x0, replacement x0 → x1, blob →
`4b67209318`, re-counted in the leg
(`ListViewSchema.shape.conditionalFormatting` 2 → 1). **Red: 12 failed,
421 passed.** §1 received exactly `[ "object-kanban
conditionalFormatting" ]` as unlisted, and `[ "object-kanban
conditionalFormatting[].condition.ast" ]` as an outliving line. §5
failed its identity, the string-condition parse and all eight refusals.
Still green, as expected under `z.unknown()`: the envelope and
empty-list parses, the absent case, the D3 id, and §1's size control
(one member in, one out). Restore: blob equals HEAD (`830a02f619`), `git
diff HEAD` is empty, and `git status` is clean. The pins import
`./component.zod` from source, so no build or `dist` preflight sits
between mutation and run.
- **Derived gates** at `011e53fa2a`: `node scripts/pm/dispatch-gates.mjs
--repo objectstack-ai/objectstack --commands` (no paths; merge base
`7e0066af7`, 7 paths, 276 changed lines) derived 114 commands, all exit
0. `--ran` printed "114 derived, 114 run, 0 NOT-MEASURED, 0 UNRUN". At
`27a0e12a09` the first pass recorded six exit-3 `PREREQUISITE NOT MET`
refusals for unbuilt packages. After the builds above they re-ran exit
0, and the pass at `011e53fa2a` ran all 114 clean.
- **`check-widening-tells`** over the branch diff: `--declaration no`
exits 0. That is no tell: the row takes an existing member by reference
and adds no key, arm or export. `--declaration yes` exits 0.
- **Narrowed lint**: `eslint --no-inline-config --format json` over the
5 changed TypeScript files reports 5 files, 0 errors and 0 warnings. The
population comes from eslint's own `--print-config`: those 5 resolve a
config, and the changeset and `component.mdx` resolve none. Invariance:
`eslint.config.mjs` never enables type-aware linting (its own text,
about line 327), so this diff cannot move a verdict on an untouched
file. The full `pnpm lint` is CI's.
- **NOT MEASURED**: the Console Pin Gate, the Dogfood Regression Gate
and the full `pnpm lint` are CI-owned. objectui was read at the pin and
at `main`, not built against this spec. The board's paint for a blank
`condition` was read, not run. The showcase `validate` was not run: no
example in this repository authors an `object-kanban` node. CI on this
PR was not waited on.
- **Rationale order**: #21702's branch (`c4e3ab9631`) also takes order
77 for `ui-report-joined-block-dataset-required`. That is not refused,
because `joinRationale` breaks a tie by id. Whichever lands later
re-reads the next free order and merges `origin/main` through
`scripts/pm/os-regen-merge.sh`.
## Acceptance notes
- **objectui's next `@objectstack/spec` bump** reads this row in one
place only, `structuredKeysAreDeclaredAndHonoured-8313.test.ts`, whose
value parses. objectui's `object-kanban` node is its own flat
`ObjectKanbanSchema` and takes no `propsBag` over this row. The
console's member-pin prose for `object-kanban.conditionalFormatting`
(`apps/console/src/__tests__/registry-inputs-spec-parity.test.ts:3003`)
says "The spec row is `z.unknown()`", which goes stale with that bump.
Carrier: objectui's next spec bump. Noted, not filed.
- **The blank condition** is the one value objectui's mirror admits and
this row refuses. The same split already exists on the list view and on
`object-grid`, and the board paints nothing for it. Noted, not filed.
- **The lint door's nested unknown-key message** reads "`field` is not a
prop `object-kanban` declares" for a key inside a rule. The path
(`properties.conditionalFormatting.0.field`) and the zod text ("on this
conditional formatting rule") are right. The wording predates this
change and reads the same on `object-grid`. Noted, not filed.
---
_Generated by [Claude
Code](https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 100f68b commit ced3e1a
7 files changed
Lines changed: 259 additions & 17 deletions
File tree
- .changeset
- content/docs/references/ui
- packages/spec/src
- migrations
- entries/semantic
- ui
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
944 | 944 | | |
945 | 945 | | |
946 | 946 | | |
947 | | - | |
| 947 | + | |
948 | 948 | | |
949 | 949 | | |
950 | 950 | | |
| |||
974 | 974 | | |
975 | 975 | | |
976 | 976 | | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
977 | 984 | | |
978 | 985 | | |
979 | 986 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6318 | 6318 | | |
6319 | 6319 | | |
6320 | 6320 | | |
| 6321 | + | |
| 6322 | + | |
| 6323 | + | |
| 6324 | + | |
| 6325 | + | |
| 6326 | + | |
| 6327 | + | |
| 6328 | + | |
| 6329 | + | |
| 6330 | + | |
| 6331 | + | |
| 6332 | + | |
| 6333 | + | |
6321 | 6334 | | |
6322 | 6335 | | |
6323 | 6336 | | |
| |||
20195 | 20208 | | |
20196 | 20209 | | |
20197 | 20210 | | |
| 20211 | + | |
| 20212 | + | |
| 20213 | + | |
| 20214 | + | |
| 20215 | + | |
| 20216 | + | |
| 20217 | + | |
| 20218 | + | |
| 20219 | + | |
| 20220 | + | |
| 20221 | + | |
| 20222 | + | |
| 20223 | + | |
| 20224 | + | |
| 20225 | + | |
| 20226 | + | |
| 20227 | + | |
| 20228 | + | |
| 20229 | + | |
| 20230 | + | |
| 20231 | + | |
| 20232 | + | |
| 20233 | + | |
| 20234 | + | |
| 20235 | + | |
| 20236 | + | |
| 20237 | + | |
| 20238 | + | |
| 20239 | + | |
| 20240 | + | |
| 20241 | + | |
| 20242 | + | |
| 20243 | + | |
| 20244 | + | |
20198 | 20245 | | |
20199 | 20246 | | |
20200 | 20247 | | |
| |||
0 commit comments