Repository navigation
Commit 63dc4f7
refactor(data-objectstack): rename the spec-named filter-operator fold (objectui#7265 data-objectstack slice) (#9527)
Part of objectui#7265 — the `@object-ui/data-objectstack` slice of the
`check:spec-symbols` DEBT burn-down. One group remains
(`@object-ui/plugin-detail`), so this carries no closing keyword by
design.
## What moved
`packages/data-objectstack/src/index.ts` declared a module-local
`normalizeFilterOperator` — the exact name `@objectstack/spec/ui`
exports, and which this monorepo's view layer imports from there
(`viewFilterFold`, `filter-converter`, `ListView`, `UserFilters`, the
FilterBuilder). It is now `toAstFilterOperator`; rule 1's `DEBT` block
is regenerated mechanically with `--ledger`.
## Route: RENAME — and the measurement that refused BIND
Re-measured against the **RESOLVED pin, `@objectstack/spec@17.4.0`**
(declared range `^17.2.0`; "same behaviour" is a statement about a
version exactly as "byte-identical" is).
The two functions take the same input and land in different
vocabularies:
| input | spec's `normalizeFilterOperator` | this package's fold |
| --- | --- | --- |
| `eq` | `equals` | the equals symbol |
| `equals` | `equals` | the equals symbol |
| `greater_than` | `greater_than` | the greater-than symbol |
| `before` | `before` | the less-than symbol |
The spec's folds an authored spelling to the canonical VIEW vocabulary
so `ViewFilterRuleSchema`'s enum can judge it (it is the `z.preprocess`
step on `ViewFilterRuleSchema.operator`). This package's translates the
same input into the server's filter-AST SYMBOLS. Same input, different
codomain — so binding would have changed what goes on the wire for most
of the operators a stored view can carry. A function also has no
derive-in-place form: rule 1 records every function declaration with
`derived: false`, which leaves exactly three exits (delete and import,
rename, waive). RENAME removes the collision instead of excusing it, and
the declaration was never exported, so renaming costs nothing outside
the file.
### What the measurement overturned — the `?? op` tail
The dispatch's hypothesis was that the spec's version REFUSES where this
one is lenient. Measured, it is the other way round, in both halves:
- **The lenient tail is COMMON ground, not the divergence.** Both hand
an unrecognised STRING back unchanged:
`normalizeFilterOperator('totally_unknown')` returns
`'totally_unknown'`, and so does this package's table lookup. "The spec
refuses instead" is not a difference that exists.
- **The tail DOES diverge — on the non-string arm, and the spec is the
lenient one.** The spec's body ends `return op as string`, so a
non-string comes straight back (`42` returns `42`, `null` returns
`null`). This package returns `null` there, and `objectFilterEntryToAST`
reads that `null` one line later into a `MalformedFilterError`.
**Binding the spec would therefore have WIDENED what this adapter
accepts onto the wire** — a number in the operator slot of a tuple it is
about to send, instead of a 400-shaped refusal.
That refusal is already pinned end-to-end, through the real adapter and
both `find()` routes, by the `operator: 42` case in
`packages/data-objectstack/src/filter-entry-translation.test.ts`.
**Clause-② stays `no`:** nothing this PR does changes what the package
sends or what it accepts as an operator — the `?? op` tail, the `null`
arm and every row of `FILTER_OPERATOR_ALIASES` are byte-for-byte
unchanged. The trip-wire was checked, not assumed.
## The INTERMEDIATE reading (site edit, not a ledger edit)
The gate was run after the site edit and **before** regenerating the
block. Real output:
```
❌ a spec-named symbol is hand-written, not derived:
• @object-ui/data-objectstack lists 1 symbol in DEBT that no longer collide — `normalizeFilterOperator`.
Delete them from scripts/check-spec-symbol-derivation.mjs (`--ledger` regenerates the
block) so the names cannot be re-forked silently […]
```
The gate's trailing clause is elided on purpose: it spells a closing
keyword immediately before this card's number, and GitHub's linked-issue
parser does not read sentences or spare fenced blocks — quoting it
verbatim here risks closing a card that still has a group left. Read the
full wording in the gate's source (its stale-entry message). Seat
attribution for this run, as prose so it survives an edit:
`session_011QreXiyMEqKLN4U5daMPVa`.
`exit 1`. That message names the entry as **stale** — which is only
reachable if the declaration left the tree first.
## Ledger, before and after
Banner before (at `bbc9dc3`): `18 declared dialects, 2 untriaged
collisions in 2 packages.` — `exit 0`
Banner after: `18 declared dialects, 1 untriaged collision in 1
packages.` — `exit 0`
`--ledger` re-run after the splice is byte-identical to what was spliced
in (idempotent). `--claim-ledger` regenerates `CLAIM_DEBT`
byte-identically across this change — the declaration that moved carried
no spec-alignment claim, so rule 2's block is untouched.
## The stale figure, deleted rather than re-derived
The `DEBT_ISSUE` note carried a figure written by an earlier slice and
overtaken by every slice since: it said how many entries objectui#7265
had burned out of each block. Per AGENTS.md #9 it is **deleted, not
re-derived to a new number**. The sentence now names the routes (BIND /
RENAME / ALLOW) and the instruments (`--ledger`, `--claim-ledger`, and
the run banner) and carries no count at all.
One extra deletion, declared: the same note's preceding clause read `its
18-entry block is live`, and the sentence I was asked to rewrite ended
`only the COUNT above moved` — pointing straight at it. Leaving the
adjective while writing "no count is written here" would have made the
replacement contradict the line above it, so `18-entry` went too. It is
`its block is still live` now; the argument (the anchor is closed while
the block is not empty) is intact.
## Pins that FAIL before and pass after
Both legs were run **from the committed state**, mutation proved on disk
by marker counts and blob hashes, restored with `git checkout HEAD --
PATH` and confirmed by an empty `git diff HEAD`. Neither leaves a file
behind.
**Leg 1 — the site.** Restored `packages/data-objectstack/src/index.ts`
from the pinned base commit (marker counts moved `toAstFilterOperator` 2
to 0, `function normalizeFilterOperator` 0 to 1; on-disk hash changed):
```
GATE EXIT=1
• @object-ui/data-objectstack declares 1 spec-named symbol the spec already owns:
function `normalizeFilterOperator` (exported by `@objectstack/spec/ui`)
PIN EXIT=1
Tests 1 failed | 14 passed (15)
× rule 1 no longer sees `normalizeFilterOperator` — the declaration is `toAstFilterOperator` now
```
Exactly one assertion fails, and it is the site assertion. Green on the
branch: `15 passed (15)`.
**Leg 2 — the figure.** Put the deleted figure back:
```
PIN EXIT=1
× carries no entry count at all
AssertionError: the `DEBT_ISSUE` note has a ledger size written into it again. …
expected [ '18-entr', 'two entr' ] to deeply equal []
```
It catches BOTH re-introduced counts, which is what makes it a ratchet
against a helpful re-derivation rather than a spelling pin.
## Ratchets left behind
- **The name**, in this package's own spec-symbol file
`packages/data-objectstack/src/spec-symbol-batch6.test.ts` — appended to
its existing `RENAMES` table rather than duplicated into a new file.
Both directions: the spec must not come to own `toAstFilterOperator`,
and it must still own `normalizeFilterOperator` (if it stops, the
rename's reason is spent and the plain name can be taken back).
- **The site, the block and the figure**, in
`scripts/__tests__/spec-symbol-ledger-data-objectstack-7265.test.ts` —
the sibling shape of the core / app-shell / types / components pins. Its
controls include one this slice had to add: a fixture that imports the
spec's function and re-declares a wrapper under the same name is STILL
flagged, which is the assertion that records why a function's route set
is smaller than a type's.
- **The behaviour**, in
`packages/data-objectstack/src/filter-operator-ast-parity.test.ts`,
beside the table it is about. The divergence set is DERIVED from the
spec's own vocabularies and enumerated, never counted, with a lit
control (`contains` agrees on both sides) so "they differ" cannot be
vacuous.
## Verification
- `pnpm exec vitest run packages/data-objectstack/ packages/plugin-view/
scripts/__tests__/` — `Test Files 265 passed | 2 skipped (267)`, `Tests
5910 passed | 2 skipped (5912)`.
- `pnpm --filter @object-ui/data-objectstack --filter
@object-ui/plugin-view run type-check` — exit 0, both scripts echoed.
This package's `tsconfig.json` compiles its test tree (confirmed with
`--listFiles`: both edited test files are in the program), so the pins
are checked by `tsc --noEmit` too.
- `pnpm run type-check:scripts` — exit 0 (covers the new
`scripts/__tests__` pin).
- Gates: `check:spec-symbols` exit 0, `check:changeset-presence` exit 0,
`changeset:check` exit 0, `check:new-line-citations` `0 new
citation(s)`, `check:control-bytes` OK, `check:test-path-roots` OK.
- `check-governed-queue-guard --test` over every changed path: `NOT
GOVERNED — none matched`. Ordinary review route.
- **Lint, narrowed and measured.** `eslint --no-inline-config --format
json` over the six changed files reports `6` files linted, `4 errors /
130 warnings`, all in `packages/data-objectstack/src/index.ts`. The same
command over that file at the base commit reports the **same** `4 errors
/ 130 warnings`, same four `no-console` rules, shifted by exactly the 30
lines this PR adds: zero new findings. Type-aware linting is not
configured in `eslint.config.js` (no `parserOptions.project` /
`projectService`), so this diff cannot move the verdict of any file it
does not contain. The repo-wide `pnpm lint` is CI's run, not this one.
## Acceptance notes
`check:changeset-claims` (report-only) flagged four pending changesets
whose bodies name `scripts/check-spec-symbol-derivation.mjs`. Read, as
the gate asks. **This PR falsifies none of them** — three describe
derivation forms and rule 2's comment attachment, all still accurate.
The fourth, `.changeset/6286-explain-batch-cap-from-spec.md`, says "both
of its scanners skip non-exported declarations"; that sentence is
already false, and was made so by objectui#6291 widening rule 1, not by
this branch. It is another card's pending body and it publishes verbatim
into the CHANGELOG — reported rather than edited here.
Noted, not filed:
- `scripts/__tests__/check-spec-symbol-derivation.test.ts` carries a
comment saying `isContextToken` and `normalizeFilterOperator` "are the
live instances … both DEBT entries today". The first half went false
with the `@object-ui/core` slice; this PR takes the second. Not repaired
here on the same reasoning the components slice declined the figure —
another slice's paragraph, not this slice's file moment. Taker: the
`@object-ui/plugin-detail` slice, which empties the block and inherits
the whole sentence.
## Departure from the dispatch, declared
The dispatch's file surface named the site, the gate script and the
parity ratchet. One file outside it is in this diff:
`packages/plugin-view/src/config/__tests__/view-operator-builder-parity.test.ts`,
whose header cited `data-objectstack`'s `normalizeFilterOperator` by
symbol name. A rename that leaves dangling citations is an incomplete
rename, and AGENTS.md #11's whole thesis is that the person who moves
the thing never sees the citation — this seat did see it. One comment,
no behaviour, and `plugin-view` is in the verification set above because
of it.
Do not enqueue; draft by instruction, and auto-merge is deliberately not
enabled.
---
_Generated by [Claude
Code](https://claude.ai/code/session_011QreXiyMEqKLN4U5daMPVa)_
---
_Generated by [Claude Code](https://claude.ai/code)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent bbc9dc3 commit 63dc4f7
7 files changed
Lines changed: 514 additions & 15 deletions
File tree
- .changeset
- packages
- data-objectstack/src
- plugin-view/src/config/__tests__
- scripts
- __tests__
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
18 | 24 | | |
19 | 25 | | |
20 | 26 | | |
| |||
48 | 54 | | |
49 | 55 | | |
50 | 56 | | |
51 | | - | |
| 57 | + | |
52 | 58 | | |
53 | 59 | | |
54 | 60 | | |
| |||
106 | 112 | | |
107 | 113 | | |
108 | 114 | | |
109 | | - | |
| 115 | + | |
110 | 116 | | |
111 | 117 | | |
112 | 118 | | |
| |||
133 | 139 | | |
134 | 140 | | |
135 | 141 | | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
149 | | - | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
150 | 180 | | |
151 | 181 | | |
152 | 182 | | |
| |||
487 | 517 | | |
488 | 518 | | |
489 | 519 | | |
490 | | - | |
| 520 | + | |
491 | 521 | | |
492 | 522 | | |
493 | 523 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
22 | 29 | | |
23 | 30 | | |
24 | 31 | | |
| |||
143 | 150 | | |
144 | 151 | | |
145 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
146 | 167 | | |
147 | 168 | | |
148 | 169 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
14 | | - | |
15 | | - | |
16 | | - | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
17 | 19 | | |
18 | 20 | | |
19 | 21 | | |
| |||
0 commit comments