Repository navigation
Commit a43b9d0
fix(lint): walk the four list-view field-naming keys that had no position row (#18860)
Fixes #18835
Clause-②: no (narrowing)
`POSITIONS` in `packages/lint/src/validate-list-view-field-refs.ts`
declares, per view face, which field-reference keys are walked and at
what level. Four declared, authorable field-naming keys had no row at
all — `calendar.allDayField` (`view.zod.ts:1552`) and the three
objectui-lifted `gantt` bindings `borderColorField` (`:1660`),
`lockField` (`:1661`) and `objectField` (`:1662`), every one of them
`z.string().optional()`. A misspelt field name at any of them cleared
the schema door, was walked by nothing, and was dropped by the renderer
in silence. Each now has a row.
## The tier is per key, and deliberately not per schema shape
All four are `.optional()`. That is the one thing they share, and it is
not what tiers them: each is tiered by what its own renderer does with a
name no record carries, read off the key's own `.describe()` and
measured in objectui `dda8f3815` (the pin this repo builds against is
`53ded82b`; the two gantt readings below are unchanged between them —
the code is `plugin-gantt/src/ObjectGantt.tsx` in both).
| key | tier | what a misspelt name does |
|:--|:--|:--|
| `calendar.allDayField` | `warning` | `ObjectCalendar` maps every event
with `allDay: allDayField ? Boolean(record[allDayField]) : !endDate`. A
name no record carries reads `undefined` on every row, so nothing is
banded — and the renderer's own no-end-date inference is switched off
too, because a DECLARED key is absolute (the spec's own "⛔ No default
field name" note). Every event still renders, at its start time: the
all-day band is the one decoration dropped. |
| `gantt.borderColorField` | `warning` | `borderColorRaw =
borderColorField ? record[borderColorField] : undefined` leaves
`borderColor` undefined for every task. Every bar keeps its fill and
renders without its alert outline — `colorField`'s case, eight rows up.
|
| `gantt.lockField` | **`error`** | A declared WRITE GUARD that fails
OPEN. `locked: lockField ? !!record[lockField] : undefined` reads
`undefined` on every row, and the drawer's `recLocked` falls the same
way, so every row the author froze becomes draggable, resizable,
progress-draggable, link-able, inline-editable and deletable — and the
drag persists. |
| `gantt.objectField` | **`error`** | `isSyntheticRow` is `!!objectField
&& !String(rec[objectField] ?? '').trim()`, so a name no record carries
answers TRUE for every row. `onTaskClick` then never calls
`navigation.handleClick` and `renderRecordOverlay` returns null: no bar
in the chart opens a drawer or a detail page. |
## The two `error` rows are a consequence the rule's severity note did
not name
Its two tiers read "the miss changes what data the view returns, or
collapses the layout it configures" against "the renderer drops one
decoration and renders the rest". `lockField` and `objectField` are
neither: nothing is missing from the picture, which is exactly why they
gate. The note now names the third consequence — a binding whose job is
to RESTRICT or to ROUTE, where the miss is read as "no restriction" /
"no route" on every row. Both are the shape Prime Directive #10 names, a
capability advertised in the metadata and not delivered by the runtime,
and both are worse DECLARED than omitted, because each renderer guards
its behaviour on the key's mere presence.
`allDayField` is deliberately NOT put in that third class: no
restriction and no route rides on it, and a wrongly-banded event is
still an event the user can click.
## Controls — both arms, all four keys separately
One instrument, run against the rule before the edit and after it, over
one list view carrying every walked position, one mutation at a time.
The diff of the two runs is four lines long.
### LIT — each key pointed at a field that does not exist
| probe | before | after |
|:--|:--|:--|
| `calendar.allDayField` | SILENT | `warning` `list-view-field-unknown`
at `views[0].list.calendar.allDayField` |
| `gantt.borderColorField` | SILENT | `warning`
`list-view-field-unknown` at `views[0].list.gantt.borderColorField` |
| `gantt.lockField` | SILENT | `error` `list-view-field-unknown` at
`views[0].list.gantt.lockField` |
| `gantt.objectField` | SILENT | `error` `list-view-field-unknown` at
`views[0].list.gantt.objectField` |
Four lit for four. No key was proven by a neighbour: each is its own
mutation, its own path assertion and its own tier assertion, and the
suite-level pin puts all four misses on one stack and asserts four
findings rather than one.
### DARK — must read zero, and does
| probe | before | after |
|:--|:--|:--|
| the 53 already-walked position probes | 53 reported, each at its
severity | the same 53, each at its same severity — byte-identical lines
|
| each of the four keys pointed at a REAL field, one at a time | SILENT
| SILENT |
| the clean fixture, all four bound to real fields | 0 findings | 0
findings |
| the four keys carrying a dotted path whose head resolves | no finding
| no finding (they join `POSITIONS` and deliberately not `DOTTED_AXIS`;
pinned) |
## Does anything in this repository redden? No, and it is a proof rather
than a sample
The four rows read exactly four keys. `git grep` over every tracked file
finds those key names only in the spec declaration, its own schema
tests, the generated reference docs, the changesets that landed them,
and unrelated identifiers (`objectFieldLabelKey`,
`objectFieldTypeRefusal`). `git grep` over `examples/` matches nothing
at all. No example app, fixture or seed in this tree authors any of the
four, so no existing declaration can start reporting — 0 findings
before, 0 after, with no declaration data touched.
## Completeness, since this was a hole in a table
After these four rows, every `*Field` / `*Fields` key declared on
`ListViewShapeSchema` and on each of the seven view-face config schemas
(`Kanban`, `Calendar`, `Gantt`, `Timeline`, `Gallery`, `ListMap`,
`Tree`) has either a `POSITIONS` row or a named owner elsewhere
(`searchableFields`, `sort`). Enumerated from `view.zod.ts` key by key,
not recalled.
## Verification
Measured on `496b71de99`, this branch merged with `origin/main`:
- `pnpm --filter @objectstack/lint exec vitest run
src/validate-list-view-field-refs.test.ts` — 130 passed.
- `pnpm --filter @objectstack/lint test` — 104 files, 3902 tests, all
passed.
- `pnpm --filter @objectstack/lint typecheck` — green (`tsc --noEmit`
plus `check:test-typecheck`).
- `pnpm --filter '@objectstack/lint^...' build` and `pnpm --filter
'@objectstack/lint...' build` — green.
- `pnpm exec eslint . --no-inline-config` over the WHOLE repository —
exit 0, 6846 files linted, 0 errors, 0 warnings. Not a narrowing: the
repo-wide run is the reading.
- The gate families derived from this diff by
`scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` on the merged tree — 58 commands, **54
green**.
- ⊘ NOT MEASURED, 4 of the 58, every one of them `PREREQUISITE NOT MET`
(exit 3, which is neither a pass nor a finding) for want of a
whole-workspace build this worktree does not carry:
`check:dual-build-cjs-loads`, `check:lean-entry-closure`,
`check:type-check-debt`, and `check:docs-transcript-drift` — the last
was re-run after building `@objectstack/lint` and is **green**, so three
remain. CI builds before it runs them.
## Acceptance notes
- **`gantt.objectField`'s own headline use case is out of this rule's
reach, by construction.** Its `.describe()` frames it for "an api
provider composing parent-object rows with child-object rows", and this
rule's fourth skip drops any list view whose `data.provider` is not
`object` — such a view binds to no object graph, so no field name on it
is resolvable here. The row still earns its place: `isSyntheticRow` runs
whatever the provider is, so an object-provider list view that declares
a misspelt `objectField` loses every drawer in the chart, and that is
the case the row reports. Noted, not filed — nothing here is a defect,
it is the skip doing what it says.
- **The floor assertion's remaining slack is untouched.** It moved 47 →
51, by exactly the four cases added; the table now holds 52. Whether the
floor should be tight against the table is the separate card's question
and its semantics were not altered here.
- **`calendar-view-renderer.tsx` in objectui defaults `allDayField` to
the literal `allDay`**, where `ObjectCalendar` has no default and the
spec forbids one. Checked and it is not a contradiction: that renderer
serves the `calendar-view` node with inline `schema.data`, a different
surface from a list view's `calendar` block, and it defaults every one
of its five field names the same way. Noted, not filed.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent e8ba892 commit a43b9d0
3 files changed
Lines changed: 233 additions & 2 deletions
File tree
- .changeset
- packages/lint/src
| 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 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
49 | 57 | | |
50 | 58 | | |
51 | 59 | | |
| |||
81 | 89 | | |
82 | 90 | | |
83 | 91 | | |
| 92 | + | |
84 | 93 | | |
85 | 94 | | |
86 | 95 | | |
| |||
98 | 107 | | |
99 | 108 | | |
100 | 109 | | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
101 | 113 | | |
102 | 114 | | |
103 | 115 | | |
| |||
235 | 247 | | |
236 | 248 | | |
237 | 249 | | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
238 | 254 | | |
239 | 255 | | |
240 | 256 | | |
| |||
247 | 263 | | |
248 | 264 | | |
249 | 265 | | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
250 | 273 | | |
251 | 274 | | |
252 | 275 | | |
| |||
284 | 307 | | |
285 | 308 | | |
286 | 309 | | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
287 | 314 | | |
288 | | - | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
289 | 408 | | |
290 | 409 | | |
291 | 410 | | |
| |||
535 | 654 | | |
536 | 655 | | |
537 | 656 | | |
538 | | - | |
| 657 | + | |
539 | 658 | | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
540 | 669 | | |
541 | 670 | | |
542 | 671 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
57 | 68 | | |
58 | 69 | | |
59 | 70 | | |
| |||
345 | 356 | | |
346 | 357 | | |
347 | 358 | | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
348 | 372 | | |
349 | 373 | | |
350 | 374 | | |
| |||
362 | 386 | | |
363 | 387 | | |
364 | 388 | | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
365 | 417 | | |
366 | 418 | | |
367 | 419 | | |
| |||
0 commit comments