Repository navigation
Commit 4634544
docs(error-catalog): INVALID_FIELD names the refusal of a search over an empty resolved search set (#24353)
Fixes #24331
Clause-②: no
## What
One sentence is added to the **Cause** text of `### INVALID_FIELD` in
`content/docs/api/error-catalog.mdx`, right after the `internal: true`
sentence. It names the refusal that PR #24320 (`ec749fbb44`) added. When
an object's resolved search set is empty, a non-blank `search` gets `400
INVALID_FIELD` with `param: 'search'`. It no longer gets every row back.
The sentence also gives the two remedies the refusal message itself
prescribes. No other entry changes and no section is added. The diff is
+4 / -0 lines, all inside that entry.
## Read from the code, not from the card
The wording comes from the producer as it stands on the base
`33f700b87b`. No commit between `ec749fbb44` and the base touches
`packages/objectql/src/engine.ts` or
`packages/objectql/src/search-filter.ts`: the `git log` over that range
and those paths is empty. `git merge-base --is-ancestor ec749fb
33f700b` exits 0.
- **Where.** `ObjectQL.expandSearchOnAst` in
`packages/objectql/src/engine.ts`. When `expandSearchToFilter` returns
`null` and the normalized term is non-blank, it throws
`emptySearchSetError(...)`. `find`, `findOne`, `count` and `aggregate`
all reach this call.
- **Envelope.** `status: 400`, `code: 'INVALID_FIELD'`, `object`,
`param: 'search'`. This matches the card.
- **When the set is empty.** `resolveSearchFieldResolution` in
`packages/spec/src/data/search-fields.ts` runs over the object's fields
after the `internal: true` ones are removed. A `searchableFields` entry
counts only when it names an existing field that is not a `formula`. If
no entry does, the auto-default is used, and the refusal fires only when
the auto-default is empty too. The auto-default skips hidden fields, the
system names in `SEARCH_AUTO_EXCLUDED_FIELDS` (`id`, `created_at`,
`owner_id`, and others), and every type outside the textual set plus
`select`.
- **Where the code differs from the card.** The card says the set is
empty when "the object has no textual or enum stored field and no
`searchableFields` entry naming one". The code differs in two ways. Some
textual fields do not count: a hidden one, a system-named one, or one
marked `internal: true`. And a declared entry may name any stored field,
such as a `lookup` or `json` column, not only a textual one. So the
sentence says "the default search scans none" and "`internal: true`
fields never count", not "no textual or enum stored field".
- **Remedy.** The message ends with the two remedies: declare
`searchableFields` on the object naming a stored field, or mirror the
composed title onto a stored text field and search that. The card's
remedies match the message. The sentence keeps both. It says "a composed
title" because the catalog sets up no junction object for "the" to refer
to.
## Verification
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived the commands from the tree at
`d87f5a77f`, the head of this PR. The change set is 1 path and the list
has 41 commands, the same list as the dispatch-time reading.
- All 41 were run. Each exit code was captured before any pipe, and
every final exit is 0.
- Six commands first refused with exit 3 (`PREREQUISITE NOT MET`)
because packages were not built. Five needed the `@objectstack/lint`
closure: `check:doc-formula-expressions`, `check:doc-security-posture`,
spec `check:docs`, `check:docs-transcript-drift` and spec
`check:skill-examples`. The client SDK case of `check:skill-examples`
also needed the client packages built.
- The closures were built through `scripts/pm/os-verify-lock.sh`. The
`@objectstack/lint...` build was 4/4 tasks, all cache hits. The
`@objectstack/client-react...` plus `@objectstack/client...` build was
35/35 tasks, 34 of them cache hits. The six commands were then re-run,
and all six exited 0.
- The `--ran` reconciliation printed: `41 derived, 41 run, 0
NOT-MEASURED, 0 UNRUN`.
- Sanity check (not a gate): the edited page compiles with `@mdx-js/mdx`
3.1.1 (exit 0), and the new sentence appears once in the output.
- Left to CI: `Build Docs`, `Test Core` and the type-check lanes. The
derivation lists these as CI-only.
- No package is touched, so no package test or typecheck is owed. There
is no changeset because the change is docs only (`skip-changeset`).
- `origin/main` has moved to `dd72a047f`, which touches only
`.claude/skills/pm-dispatch/**`. That is disjoint from this diff, so
main was not merged in.
## Acceptance notes
These other hand-written pages describe how `search` behaves on the data
read route, and none of them mentions this refusal. They are left
unchanged here because they are outside this card's file surface:
- `content/docs/protocol/kernel/error-handling.mdx:626`: says the
catalog's `INVALID_FIELD` entry "enumerates every read axis this one
code answers on". Its list in parentheses names `select`, `expand`,
`searchFields`, `groupBy` and `aggregations[].field`, but not `search`.
- `content/docs/api/data-api.mdx:26`: the `search` parameter row. Also
`content/docs/api/data-api.mdx:153-158`: a table of `search` /
`searchFields` requests and their results, with no row for a bare
`?search=` on an object that has no searchable field.
- `content/docs/data-modeling/queries.mdx:476` (the Full-Text Search
section) and `content/docs/protocol/objectql/query-syntax.mdx:1120`:
both describe how search fields are resolved and how `searchFields` is
refused, but not this refusal.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 69147ab commit 4634544
1 file changed
Lines changed: 4 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
159 | 159 | | |
160 | 160 | | |
161 | 161 | | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
162 | 166 | | |
163 | 167 | | |
164 | 168 | | |
| |||
0 commit comments