fix(app-shell): the drill URL spells $empty as filter[F][empty], so a composed 「is empty」 drill no longer opens on a superset on spec 17.6.0 (objectui#11547) - #11548
Conversation
…i#11438) Regenerated with pnpm 10.31.0 only, by the raise-and-restore route the 17.5.0 bump used: every @objectstack/* specifier raised to ^17.6.0 for one `pnpm install`, every manifest restored byte-for-byte to HEAD, then a second `pnpm install` reconciles the importers to their declared ranges. Resolution census against the base lock: the seven @objectstack/* packages (spec, types, core, client, formula, lint, sdui-parser) move 17.5.0 -> 17.6.0 and nothing else moves. No importer specifier changes. The registry's new `deprecated` field on twelve @yuku-analyzer/binding-* 0.8.7 entries is written into the lock by the same tooling. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…, a component under a name @objectstack/spec 17.6.0 now exports (objectui#11438) @objectstack/spec 17.6.0 exports `EmptyState` from `@objectstack/spec/ui`: the authoring type of a list view's empty-state config (title, message, icon). @object-ui/components publishes `EmptyState` as an alias of the `DataEmptyState` React component. A component is not a config shape, so neither import nor derivation fits; the alias is a published name, so its retirement or rename belongs to its own card. Same disposition objectui#11073 gave the four `Object*Props` collisions 17.5.0 surfaced. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…ing now that @objectstack/spec 17.6.0 carries the arm (objectui#11438) objectui#11206 widened `STRIPPED_LINE`'s key type by `| 'computed'` so it compiled against both a three-arm pin and objectstack `main`, and left a tripwire in `writeWarningToast.test.ts` for the bump that carries the arm. 17.6.0's `DroppedFieldsEventSchema.reason` lists `computed`, so this does what the tripwire says: the key type is the spec union again, the `computed` case is spelled as the literal, the spent tripwire is deleted, and spec-symbol-batch6's `_ReasonIsTheEnum` pins the exact four-member union. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…spec/migrations, where 17.6.0 moved it (objectui#11438) 17.6.0 carries the spec's migrations-entry-split: `MIGRATIONS_BY_MAJOR` is exported from `@objectstack/spec/migrations` and no longer from the root. The test read the root dynamically so it compiled against both the old pin and objectstack `main`, with no fallback, and its docblock asked the bump that moves the pin past the split to replace that with a static import from the subpath. This does that. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…jectstack/spec 17.6.0 refuses by name (objectui#11438) 17.6.0 carries objectstack#20758: `PageHeaderProps.breadcrumb` is a tombstone refused by name. objectui's renderer has not read it since objectui#11166, and its `inputs` entry said it stayed only while the spec accepted the key and would leave with the retirement. It leaves now, so the registry no longer publishes an input the contract refuses (`registry-inputs-spec-parity.test.ts`, "page:header declares no top-level input the spec does not accept"). The slotted-pages guide example drops `breadcrumb: true`, which the contract now refuses (its pin parses the example against the spec row), and the page-header doc and the renderer comment say the key is refused rather than "accepted until retired". Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…7.6.0 made stale (objectui#11438) objectui#11111 decision 3 = B booked `action:button.endpoint` and `action:icon.endpoint` as spec keys held unpublished, owed to objectui#11168. 17.6.0 refuses `endpoint` on both blocks (objectstack b3917d90, the rename to `target`), so neither entry names a key the spec declares, and the dangling-exemption check reds on them. Both are struck and the ledger cap falls from 3 to 1 (`undoable` stays, still owed to objectui#11168). Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
… group, which @objectstack/spec 17.6.0 adds (objectui#11438) 17.6.0's `GetTranslationsResponseSchema.translations` carries a `picklists` group (objectstack addbbf02, the `picklist` metadata kind). The recogniser's group list is written out, and the console's `loadLanguage.test.tsx` walks the spec's list so a group the spec adds turns it red instead of a bundle carrying only that group being returned untransformed and read by nothing. Added; the transform already copies an unlisted group through onto `app`. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…t its key, as @objectstack/spec 17.6.0 raises it (objectui#11438) Through 17.5.0 the spec raised the reserved-name refusal on the `fields` map (`custom @ fields`). objectstack#20997 names the key, and 17.6.0 carries it (`custom @ fields.constructor`). The pin said only this reading moves when that lands; it moves, in the instrument row and in the banner row, which now names `fields.constructor`. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…@objectstack/spec 17.6.0 leaves true, and ledger the four that name a past release (objectui#11438) `check:installed-pin-claims` reads every present-tense claim about the installed `@objectstack/*` version against the resolved artifact. 38 sites named 17.5.0. Each was decided, never find-and-replaced: - RESTAMPED after re-measuring the fact the sentence states against the installed 17.6.0 (each probe was also run against a 17.5.0 tarball as the control, and answered the same on both): `FieldSchema`'s `dependsOn`, `rows` and option `description` readings; `object-calendar.data` and `.calendar`; `record:details.columns`; `record:highlights` `fields[]` and `layout`; `SelectOptionSchema` labels; the `@objectstack/lint` field-rule verdict text; `referenceTo` and its four alias spellings; `CalendarConfigSchema`'s required key, options and refusal hints; `record:alert.visible`; `object-kanban`'s fifteen keys; the screen node's `waitForInput`; `object-calendar`'s ten flat members; `ObjectListViewSchema`'s members; the `view.list.navigation.view` tombstone in the gantt README pin; and the sites whose own tests measure the fact and pass on 17.6.0. - REWORDED where the fact moved: the retired-key type is the branded `[REMOVED]` mark at the pinned 17.6.0 (bare `undefined` through 17.5.0), on `retired-key-type.ts` and the five pins that cite its spellings. - LEDGERED as `historical` (four files, seven sites): lines whose version says WHEN something changed or names a release's record set, where `pinned` is an unrelated verb or the sentence sits under a dated update heading. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…438) Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…ack/spec 17.6.0 moves, and pair the live-e2e backend with it (objectui#11438) Each pin names what moved, measured against a 17.5.0 control: - `ObjectSchema`'s accepted keys are 44, not 43: 17.6.0 adopts `imageField` (gained set exactly that one, lost set empty). Both corpus-guard counts are re-pointed as the 17.3.0 adoption was. - The spec's exports map has 21 entries, not 20: `./migrations` is added (no `browser` arm), nothing removed. Every count and its prose follow. - `check-lockfile-integrity`'s two lockfile samples are rebuilt on the 17.6.0 snapshot keys their own tripwire named. - The objectui#11111 owner total for objectui#11168 follows the cap to 1 (the two `endpoint` entries struck earlier on this branch). - `e2e/live/ci/backend.env` pins `OBJECTSTACK_VERSION=17.6.0`, the version the lockfile resolves, as the pin requires (`@objectstack/cli@17.6.0` resolves to the 17.6.0 tag commit). - The page-header doc drops the version literal it gained on this branch; `doc-version-claims` holds docs to pointers, not version numbers. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…k/spec 17.6.0, so it joins the covered arms (objectui#11438) 17.6.0 types `ComponentPropsMap['object-grid'].grouping` as the grouping config instead of `z.unknown()`. The authored arm's `properties` is that row by reference, so a padded grouping field name is now refused at its entry on all four faces. The census's recorded reason for leaving the bag member uncovered stopped holding; it moves to the declaring table and is pinned like every other arm. The node-level `grouping` stays uncovered: it is the flat spelling's by-name refusal. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…stack/spec 17.6.0's walk descends it (objectui#11438) objectui#11223's block (e) held `page:card`'s `properties.footer` as the one slot the spec's exported walk did not descend, and said to retire itself when that changed. 17.6.0's walk descends `properties.footer[]`, objectui's faces now judge a footer child, and block (d) asked for the position to be added to (a). It is: the footer is a row of (a) on both faces, (e) is deleted, and the CLI doc no longer names the footer as an unjudged slot. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
… @objectstack/spec 17.6.0's root entry shed (objectui#11438) The second payback of objectui#11073's ruled raise, objectstack#20646, reaches objectui with the 17.6.0 bump: the spec root no longer exports its migration chain. Measured with two console builds in one lock hold (`CI=true pnpm exec vite build` after the packages build): `main` at `2d576e46` (17.5.0) weighs 3,636,289 gzipped eager bytes, this branch at `2ba091c` weighs 3,386,193; `vendor-objectstack` alone is -250,108, the other 329 chunks +12. Left alone, the ceiling would sit 3.01x the regression above the payload and the gate's own sensitivity check exits 2 (a blind gauge). So, as objectui#11101 did for the first payback: `MAX_EAGER_CLOSURE_GZIP_BYTES` 3,660,380 -> 3,410,284 and `vendor-objectstack` 1,689,265 -> 1,439,157, each lowered by exactly what it recovered; BASELINE and PER_CHUNK_BASELINE move to the `2ba091c` reading; headroom 0.26x and 0.20x, the bands `main` already had. The test's rendered literal is re-taken (3306.8). The changeset says what the console gains. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
…#11536 under objectui#11438 ruling A′ (objectui#11438) @objectstack/spec 17.6.0 gives `record:line_items` a ComponentPropsMap row (objectstack 24c554da, #21142 / #21244), so registry-inputs-spec-parity judges it from that pin on. objectui#11438 ruling A′ (record 5965062249) applies objectui#11111 decision 3 = B to the bump: the population is re-pinned and every difference is booked to the owner card filed for the group, objectui#11536, with an expiry. Nothing is declared or pinned here. - EXPECTED_COVERED gains `MINOR_17_6_BLOCKS` (`record:line_items`), armed when the installed spec carries it; the census goes 55 -> 56 carried and 39 -> 40 judged. - UNPUBLISHED_EXEMPTIONS books the ten keys `inputs` omit; MEMBER_PIN_EXEMPTIONS books `columns` and `dataSource`, and MEMBER_PIN_EXEMPTION_CEILING goes 0 -> 2 with the booking. - The objectui#11111 ledger gains objectui#11536 as a fourth owner, routed by block. Its entries cite ruling A′ and decision 3 = B and expire 2026-11-02 (thirty days after the ruling, as the 17.5.0 entries' 2026-10-30 is after theirs). Caps: unpublishedKeys 1 -> 11, memberPins 0 -> 2, owner total 12. Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w Co-authored-by: Claude <noreply@anthropic.com>
… beside a pin marker (objectui#11438)
`check:installed-pin-claims` read two of the lines the booking added as
present-tense claims about the installed spec: the `MINOR_17_6_BLOCKS`
guard's docblock ("Does the installed ... carry the 17.6.0 set?") and the
`memberPins` cap comment, where the version sat beside the objectui#11168
slice's "pinned". Both were true at 17.6.0 and would go stale at the next
bump. The guard's docblock now asks about the spec this tree resolves, and
the two cap comments name the ruling that booked the entries instead of the
version. No assertion moves.
Claude-Session: https://claude.ai/code/session_01HRYqpqGcWpJuJkDmbRF75w
Co-authored-by: Claude <noreply@anthropic.com>
…y on @objectstack/spec 17.6.0 (objectui#11094) 17.6.0 stops folding the empty pair onto is_null / is_not_null and lowers it to $empty, which joins FILTER_OPERATORS (objectstack#20570, objectstack#20446). The matcher had arms only for the null pair, so a stored is_empty rule on a provider: 'value' source reached the refusal arm and selected no row. The AST arm gains is_empty / is_not_empty and the object arm gains $empty, both through the spec's isEmptyFilterValue with no declared row: this adapter holds no field declarations, so it judges by value (null, absent, '' and [] are empty). A non-boolean $empty flag is refused. ValueDataSource.astFilterVocabulary is rewritten to the new fold, the dollar-vocabulary parity table gains $empty, and the conformance file's staged-$empty partition moves into the executed table as its expiry row instructed. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…it refused (objectui#11094) $empty is a member of FILTER_OPERATORS since @objectstack/spec 17.6.0, and ValueDataSource now executes it, but the $-dialect lowering had no arm and threw "Unknown filter operator". The objectui#8976 shape, one operator over: the README pin's FILTER_OPERATORS completeness check reddened on it. $empty: true lowers to [f, 'is_empty', true] and false to [f, 'is_not_empty', true], the inverse of the spec's parseFilterAST, written the way $null is. A non-boolean flag throws the INVALID_FILTER / 400 envelope, matching ValueDataSource's refusal. The unknown-operator message lists $empty, and the data-objectstack README gains its row. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
… and declare the slice's changeset (objectui#11094) filter-source-merge: the server now reads the valueless is_empty 2-tuple as $empty: true, not $null: true; the assertion's point (no invented value slot) is unchanged. FilterConditionField.operators: the expiry row flips to "FILTER_OPERATORS admits $empty". The entry stays in KNOWN_UNREACHABLE with its reason restated: which builder row authors $empty is objectui#10813's decision, and a new expiry row reddens the day a builder operator emits it. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…ription / emptyState rows — publish both, type emptyState text as I18nLabel, resolve maps at both renderers (objectui#11227) @objectstack/spec 17.6.0 declares description, emptyState and keyboardNavigation on its object-grid row (objectstack#20694). This slice follows the first two: - GRID_QUERY_INPUTS publishes description (string and object arms, an I18nLabel the grid already resolves) and emptyState. - ObjectGridSchema.emptyState is the spec's EmptyState; the zod twin takes EmptyStateSchema by reference, not a second shape. NamedListView.emptyState indexes ListViewSchema's own member. title and message are I18nLabel. - ObjectGrid and ListView resolve emptyState.title / .message with the spec's resolveI18nLabel against the display locale. ObjectGrid handed a map to DataEmptyState as an object child, which React refuses; ListView's typeof guard drew the default copy for every map. - The objectui#11276 bag pins flip to the 17.6.0 readings (not deleted), the objectui#11068 twin pin reads invalid_union, member pins are registered for object-grid.description and .emptyState, and the docs move description into the bag (written flat it is now refused toward properties.description). keyboardNavigation is not published: nothing reads it yet. The parity gate stays red on that one key, reported for a decision. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…e pending changesets its slice falsified .changeset/11227-object-grid-17-6-keys.md declares plugin-grid and types minor and plugin-list patch. Three pending changesets of the same release said emptyState was three optional strings or not authorable in a document; each gets a dated correction paragraph instead of a rewrite. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…ng to any (objectui#11094) The new $empty pin's row helper casts to QueryParams['$filter'], and the FilterConditionField expiry row needs no cast at all (BuilderCondition's value is already loose). Runtime-identical; eslint's no-explicit-any count on the touched files returns to its base reading. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
… and the READMEs drop the version literal (objectui#11094) The full suite caught two things the targeted run could not: - filter-refusal-subject-9050 enumerates every FilterOperatorError throw site in filter-converter.ts and reddened on the new $empty one (13 sites, 12 rows). Its row names $empty as the subject. - doc-version-claims refuses an unledgered version literal on a scanned doc surface; the data-objectstack README now cites objectstack#20446 instead of the release number, and the core adapters README cites objectstack#20570 the same way. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…e-read the NamedListView loose census, cite objectstack#20694 instead of a version literal (objectui#11227) - imported-defaults-8317: the flat mirror now imports the spec's EmptyStateSchema, so it joins IMPORTED and the differential measures it. - object-view-unmirrored-keys-7779: NamedListView.emptyState no longer restates a nested object literal, so the loose regex reads 73 (gap 9), not 76 (gap 12). The member census is unchanged at 64. - The plugin-grid README, plugin-grid.mdx and schema-reference.md cite the upstream card instead of a spec version literal, which doc-version-claims refuses unless ledgered. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
One conflict, resolved mechanically: packages/plugin-grid/src/index.tsx, GRID_QUERY_INPUTS. main's rewritten `conditionalFormatting` input (objectui#11533) is kept exactly as main has it, and objectui#11227's `emptyState` comment and entry follow it. No other edit. Claude-Session: https://claude.ai/code/session_01YLg8XqWGJ785fwQ5v4pH37 Co-authored-by: Claude <noreply@anthropic.com>
…ctui#11094's slice
…ensus to objectui#11334 under objectui#11438 ruling A″ The spec that objectui#11531 resolves adds `checkDashboardWidgetDimensionlessMeasureArity` to `DashboardWidgetSchema` (objectstack `11d28c17`, #21053). objectui's mirror cannot re-attach it by static import: objectstack `main` renamed the export (`32d57690`), and the Spec Main Shape Gate refuses the 17.6 name. objectui#11438 ruling A″ (record 5968177777) books row 3 to objectui#11334 with an expiry, in objectui#11111 decision 3 = B's shape. - The `DashboardWidgetSchema (complex.zod.ts)` row's `notAttachable` list books the check, written OWED TO objectui#11334. Expires when objectui resolves an `@objectstack/spec` carrying `32d57690`, or 2026-11-02, whichever is first. - The census bounds the booking: the row's count equality and the exact export-name match admit nothing beyond the listed entry, and the expiry condition turns the name census red by name. - An empty-frontmatter changeset declares no release; the test is excluded from `dist`. Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn Co-authored-by: Claude <noreply@anthropic.com>
…ws of both 8894 measure-door tests to objectui#11334 under objectui#11438 ruling A″ Both files derive FAMILY by effect, so the spec's dimensionless measure-arity check (objectstack `11d28c17`, #21053) put pie, donut, funnel, scatter, treemap, sankey and radar into it, and objectui's door does not refuse them: the mirror waits for objectui#11334, because objectstack `main` renamed the export (`32d57690`). The seat ruled Q1 = A on objectui#11334 (record 5968413148): a bounded in-file ledger with inverted pins, under ruling A″ (record 5968177777) and objectui#11111 decision 3 = B (record 5902351047). - `OWED_TO_OBJECTUI_11334` names exactly the seven types in each file, with the owner, the rulings and the expiry: objectui resolves an `@objectstack/spec` carrying `32d57690`, or 2026-11-02, whichever is first. - The listed types' rows assert today's difference: the spec refuses, and objectui's door accepts (types); the add control is offered and no stored refusal is shown (panel). - Cap rows require the FAMILY types objectui fails to refuse to equal the ledger exactly, so a new difference is red, and so is a listed type objectui starts refusing once the mirror attaches. - The metric family's rows keep their assertions byte for byte; they iterate FAMILY minus the ledger, and a row keeps that set non-empty. Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn Co-authored-by: Claude <noreply@anthropic.com>
…igation, to objectui#11068 under objectui#11438 ruling A″ @objectstack/spec 17.6.0's object-grid row declares `keyboardNavigation`, and the grid's `inputs` do not publish it: objectui#11068 is building the key's reader and publishes the key with it. objectui#11438 ruling A″ (record 5968177777) books a row whose slice is not accepted when the row-3 booking is pushed "the same way, to their own cards", in objectui#11111 decision 3 = B's shape (record 5902351047). On the trunk tip c4775ed the parity file had exactly two red rows, both reading ['keyboardNavigation']; with this booking it reads 255 / 255. - UNPUBLISHED_EXEMPTIONS books `object-grid.keyboardNavigation` OWED TO objectui#11068, with an expiry: 2026-11-02 (ruling A″ is of the same day as ruling A′), or when objectui#11068 lands, whichever is first. - objectui#11068 joins the ledger's owners as the fifth, routed by exact id; the `unpublishedKeys` cap goes 11 -> 12 and the per-owner totals gain objectui#11068: 1. No other cap moves (the key is boolean-armed, so no member pin is owed). - `the four GA blocks resolve their ruled split` refused any exemption on the four GA blocks except the ruled carve-out, so the ledger entry alone left it red. It now admits this one OWED id BY NAME: the OWED entries on the four blocks must equal ['object-grid.keyboardNavigation'] exactly, the undeclared set must equal the booked set (so the build's landing turns it red until the booking is struck), and every other exemption on the four blocks is still refused. objectui#4648's docblock states the exception. - Changeset: empty frontmatter; the file is unreachable from the console bundle and `plugin.*`. Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn Co-authored-by: Claude <noreply@anthropic.com>
…, in English (objectui#11068) The owner paragraph quoted the maintainer's order in Chinese; this repo's codebase rule keeps code comments English, so it now cites record 5968177777 and says what the order was. No assertion moves. Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn Co-authored-by: Claude <noreply@anthropic.com>
…es, to objectui#11344 under objectui#11438 ruling A″ @objectstack/spec 17.6.0's ActionSchema declares `outcomeMessages`, and objectui does not read it yet: objectui#11344 is building the reader and lists the key with it. objectui#11438 ruling A″ (record 5968177777) books a row whose slice is not accepted when the row-3 booking is pushed "the same way, to their own cards", in objectui#11111 decision 3 = B's shape (record 5902351047). On the trunk tip bebd7ec the pin file had exactly one red row, "lists every key the spec ActionSchema declares", reading missing ['outcomeMessages'] and stale []; with this booking it reads 20 / 20. - `OWED_TO_OBJECTUI_11344` books `outcomeMessages`, with the owner, the rulings and the expiry: 2026-11-02, or when objectui#11344's slice lands, whichever is first. - "lists every key the spec ActionSchema declares" now requires `missing` to EQUAL the ledger exactly, and `stale` stays []. A new spec key is red, and so is the booked key once objectui lists it, so the booking cannot outlive the reader. - A new OWED row asserts today's difference: the spec declares the key, and neither `SPEC_ACTION_KEYS` nor `KNOWN_ACTION_KEYS` knows it. - Changeset: empty frontmatter; the file is under `src/**/__tests__/**`, which the package's build program excludes. Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn Co-authored-by: Claude <noreply@anthropic.com>
…jectui#11227) `@object-ui/types` publishes types that read `EmptyState` and a zod mirror that reads `EmptyStateSchema`, both from `@objectstack/spec/ui`. Neither export exists in `@objectstack/spec` 17.5.0, which the old `^17.5.0` range admitted; both ship from 17.6.0. `pnpm check:spec-floors`, over a full workspace build of the trunk tip, named exactly this floor (two floor-too-low findings, this package only). The lockfile moves only this importer's `specifier:` line; the resolved `@objectstack/spec` stays 17.6.0. Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn Co-authored-by: Claude <noreply@anthropic.com>
…de/issue-11227-types-spec-floor-17-6 The trunk moved by the row-5 booking only, which is disjoint from this slice's three files. Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn Co-authored-by: Claude <noreply@anthropic.com>
… that moves (objectui#11227) The objectui#11438 changeset said no declared range moves and that check:spec-floors finds no floor that has to rise. That was true when it was written and went false once @object-ui/types began reading EmptyState / EmptyStateSchema, which @objectstack/spec 17.5.0 does not export. The sentence now names that floor and where it is declared; front matter untouched, prose only. Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn Co-authored-by: Claude <noreply@anthropic.com>
…d 17.6.0 drill keeps the condition (objectui#11547)
From @objectstack/spec 17.6.0, parseFilterAST lowers is_empty / is_not_empty
to { $empty: true | false } instead of $null. composeDrillFilter goes through
that lowering, so a widget filter saying "is empty" reached
serializeDrillFilterParams as $empty, hit no arm, and wrote no param: the
/data list opened on a superset of what the widget counted.
Following the objectui#9159 precedent, drillUrlFilters gains EMPTY_FILTER:
- write: { $empty: bool } -> filter[F][empty]=true|false, beside any [null]
param and range bound; a non-boolean writes nothing;
- read: parseUrlFilterTriples reads [empty]=true|false back as is_empty /
is_not_empty (comparand true), kept out of URL_FILTER_OPS so "Save as
view" keeps the canonical rule; any other value is dropped;
- chips: the filter builder's existing is_empty / is_not_empty keys.
$empty and $null on one field are two params, so both are written and read
back, matching convertFiltersToAST. The NULL_FILTER docblock's "a COMPOSED
drill filter only ever arrives spelled $null" is corrected for 17.6.0.
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
… operator, not the operator object (objectui#11547) Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
…ctui#11547's slice Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
… (objectui#11547) Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
…slice The trunk claude/issue-11438-objectstack-17-6-0 landed on main as 6158e4c and its branch is gone; main's tree is byte-identical to the trunk tip 0507d67 this slice already carries, so this merge moves no file and only re-anchors the slice on main. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewServed-tier: Read: card objectui#11547 (body, claim Check-runs on the head (gate verdicts): 26 success, 3 skipped (the coverage jobs and dependabot), 0 failure. Build & E2E, Test (dist pins), Bundle Analysis, Live E2E, README Export Check, Changeset Declaration / Bump Policy / Fixed Group, Line Citation Gate, Control Byte Scan, Governed Surface Queue Guard and Inert vi.mock Specifier Check are all green. ① Derived judgmentsThe spec lowering, at 17.6.0. All four empty spellings now lower to
At 17.5.0 the same four lowered to The serializer's
The
Chips: correct. They reuse Docblocks, judged at 17.6.0: true.
Accepted set of the ADR-0055
Pins: red first, ablations, nothing weakened or skipped.
② Semver level
The ③ Boundary flags
Implemented-by: VERDICT: PASS |
objectui#11547 (PR #11548) landed the drill URL's [empty] arm. The merge is clean; drillUrlFilters.ts auto-merged, and the merged tree equals git merge-tree of the slice head and 7121221. The slice's two drill sentences are reconciled with the new arm in the next commit, prose only. Claude-Session: https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn Co-authored-by: Claude <noreply@anthropic.com>
Fixes #11547
Clause-②: yes (widening)
What this PR is
On
@objectstack/spec17.6.0, a composed drill whose widget filter says 「is empty」 dropped that condition from the drill URL. The spec now lowersis_empty/is_not_emptyto$empty, and thefilter[…]dialect spelled emptiness only from$null/$exists. So the/datalist opened on a superset. This is a regression the 17.6.0 bump (objectui#11531) introduced, against 17.5.0'sfilter[F][null]=true.The fix follows objectui#9159's precedent for
[null]:{ F: { $empty: true | false } }→filter[F][empty]=true|false, beside any[null]param and range bound. A non-boolean$emptywrites nothing.parseUrlFilterTriples, the ADR-0055/datasurface):[empty]=true|false→[F, 'is_empty' | 'is_not_empty', true], the triplesconvertFiltersToASTemits. Any other value is dropped. The pair stays out ofURL_FILTER_OPS, for the reason theNULL_FILTERdocblock gives ("Save as view" correctness).filterBuilder.operators.is_empty/is_not_emptykeys. No new string.$emptyand$nullon one field are two params, both written and both read back. That matchesconvertFiltersToAST's['and', …]for the same object, so nothing degrades.NULL_FILTERdocblock's "a COMPOSED drill filter only ever arrives spelled$null" is corrected for 17.6.0.⛔ The equality route's operator arm (
parseUrlEqualityFilterTriples, objectui#9196) is untouched, as arecomposeDrillFilter, the dataset inspector and the i18n packs.Tests
13f07dd0f: 10 of 12 new cases failed (for example'?filter[stage]=won'with no emptiness param). The 2[null]controls passed.ObjectView.*importers, 394 tests; app-shell type-check exit 0.check:i18n-keys, the vi-mock family,check:spec-symbols. Governed-queue guard: NOT GOVERNED.Changeset
.changeset/11547-drill-url-is-empty-operator.md:@object-ui/app-shellminor. That is the level objectui#9159 and objectui#9508 used for a URL-dialect widening.Measured reach: 0 authored dashboard or chart widget filters with an empty operator across objectstack examples, hotcrm, cloud and objectui. Stored customer dashboards are not measured. This lands before the next objectui release, which is held on #5400 until it does.
Claim
5969214761· dev report5969555930· the at-tier contract review follows on this PR.🤖 Generated with Claude Code
https://claude.ai/code/session_016tKoy8NJa35Yih1FdzrVmn