Skip to content

docs(ui): the searchableFields boundary is allowed-set membership, not field type (#6897) - #6922

Merged
os-project-manager merged 1 commit into
mainfrom
claude/issue-6897-views-searchable-set-membership
Aug 9, 2026
Merged

docs(ui): the searchableFields boundary is allowed-set membership, not field type (#6897)#6922
os-project-manager merged 1 commit into
mainfrom
claude/issue-6897-views-searchable-set-membership

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#6897

Premise: valid, and re-measured rather than trusted

The card was filed ~1h before dispatch, so I re-measured both directions from scratch at
both layers before touching prose — the dispatch order and the card body were treated
as leads, not as the record.

content/docs/ui/views.mdx:106 (landed by PR #6670) said:

Entries must be the object's own columns: a lookup (project_id) or a dotted path
(project_id.name) is refused, and every toolbar search on the list then returns
400 INVALID_FIELD (#4254)

The dotted-path half is correct. The lookup half is false, and it is false in a way that
is self-contradictory in its own terms: a lookup is one of the object's own columns.
The real boundary is membership in the object's server-resolved allowed set
(resolveSearchFieldResolution, packages/spec/src/data/search-fields.ts:119), whose
declared branch is searchableFields?.filter((f) => all[f]) — filtered by existence,
never by type
. The type lists (SEARCHABLE_TEXTUAL_TYPES / SEARCHABLE_ENUM_TYPES) are
reached only from autoDefaultFields, i.e. the no-declaration branch.

Why it matters, concretely: an author following the old row would delete a narrowing
that works, and an AI author would refuse to emit one.

Measured — the REAL ingress gate, four directions

Object support_case declaring searchableFields: ['subject', 'account_id'] where
account_id is { type: 'lookup', reference: 'crm_account' }, plus a twin open_case
with the identical field map and no declaration. Driven through a real ObjectQL
engine and ObjectStackProtocolImplementation.findData (so
assertSearchFieldsAreSearchable really runs), with two rows planted so the term lives in
exactly one column each — c1 carries it only in the lookup, c2 only in the text column
the object left out. That planting is what makes "accepted" mean scanned rather than
merely not thrown.

directionrequestresult
A declared LOOKUPsearchFields: ['account_id'] on support_caseACCEPTED, and really scanned — returned exactly ['c1']
B TEXT outside the setsearchFields: ['account_name'] on support_caseREFUSEDstatus: 400, code: 'INVALID_FIELD', field: 'account_name'
C mirror image, no declarationsame two names on open_casetext accepted (returned ['c2']), lookup refused by TYPE
D dotted pathsearchFields: ['account_id.name']REFUSED on both branches — the old row's correct half

A and B are the pair the card names: a text column refused and a lookup accepted on
the same object
, which no type-based reading can produce. C is what makes A and B mean
something rather than read as a coincidence — it shows the type list is real, just
reachable only from the other branch.

The two verbatim runtime messages, which are themselves the boundary stated twice:

Field 'account_name' on object 'support_case' is not searchable. The object declares
'searchableFields' (subject, account_id), which is the set 'search' scans — a field
outside it cannot be a search target until it is added there.
Field 'account_id' on object 'open_case' is not searchable. With no 'searchableFields'
declared, 'search' scans the text-like columns (text / email / phone / url / autonumber /
textarea / markdown / select / status), and 'account_id' is type 'lookup'. Declare
'searchableFields' on the object to choose the searchable set explicitly.

Lint layer, re-run rather than trusted — the "SKILL.md parity (#6675)" block landed by the
merged PR #6898, including the two directions above:

✓ objectstack-ui SKILL.md parity (#6675) > a lookup INSIDE the object's declared set is
accepted; a text column OUTSIDE it is not
✓ objectstack-ui SKILL.md parity (#6675) > with no object declaration, the auto-default
type list decides
✓ objectstack-ui SKILL.md parity (#6675) > `searchableFields: []` is ABSENT, not
"search off" — it resolves to the FULL allowed set
Test Files 1 passed (1) Tests 33 passed (33)

The measurement harness was a scratch file, run in the foreground and deleted before the
commit; git status is clean apart from the one edited page.

What changed — one file, content/docs/ui/views.mdx

  1. The searchableFields row now states the rule as set membership and stops
    prescribing against a supported configuration. It also gets shorter: the cell was
    already the longest in the table, and the correct rule needs a two-row table to state
    honestly, so the cell links down instead of trying to carry it.
  2. A new ### Toolbar search (searchableFields) section, immediately after the
    properties table. The dispatch asked whether the surrounding prose repeats the same
    type-first error — on this page it does not; line 106 was the only occurrence. But a
    corrected one-line cell would still have left the page teaching nothing about which
    set is meant, which is the mental model the card says is the real damage. The section
    carries: the allowed-set table (declared vs auto-default), the both-directions sentence
    (declared lookup accepted / outside-text refused), the dotted-path clause with the
    stored-mirror link preserved, a warn callout for the one-bad-entry blast radius, and
    the os validate / runtime verdict table.

Terminology deliberately mirrorsskills/objectstack-ui/SKILL.md → "Toolbar Search
(searchableFields, ADR-0061)" (merged PR #6898, #6675) so the docs corpus and the skills
corpus say the same thing in the same words. Both intra-repo anchors were computed with
the repo's own github-slugger@2.0.0 rather than guessed
(#toolbar-search-searchablefields, #global-search--searchable--searchablefields), with
the two already-linked headings on the page used as controls.

On "reverse verification" — reported straight, not template-shaped

There is no direction in which restoring the old prose turns a test red: documentation
sentences are not asserted by anything in this repo
, so manufacturing a before-red /
after-green artifact here would be a fabrication that reads as verification.

The evidence that carries this change is the opposite move and it is real: the old row's
claim, executed against the harness above, is falsified by direction A — the request
the row says returns 400 INVALID_FIELD returns rows instead, and returns exactly the row
whose term lives only in the lookup column.

Sibling pages: checked, all already correct

The card asked to check the pages landed by the same PR before editing. Each states the
set-membership rule already, so none needed a change and none is touched:

  • content/docs/data-modeling/schema-design.mdx:134,143 — "If the object declares no
    searchableFields at all…"; "searchableFields admits any field the object declares".
  • content/docs/api/data-api.mdx:27,144 — "its declared searchableFields, or a
    text-like auto-default when none are declared"; the three-causes split.
  • content/docs/protocol/objectql/query-syntax.mdx:862 and
    content/docs/data-modeling/queries.mdx:508 — same phrasing.

The type-first error was unique to views.mdx:106.

Gates (foreground, inside the shared verification lock)

pnpm lint exit 0, no output
check:doc-authoring ✓ self-test + 374 files clean — no bare metadata literals
check:docs-audit-scope ✓ 32 + 22 self-test cases; 179 hand-written doc(s) in sync
check:nul-bytes ✓ self-test 56 assertions; OK (6420 tracked text files)
check:adr-links ✓ 531 relative link destination(s) resolve
check:role-word OK (44 baselined file(s), no new occurrences)
check:quick-reference-counts ✓ 13 section(s) match their tables
check:skill-examples ✅ 208 prose examples type-check against @objectstack/spec

check:skill-examples covers this page's four os:check blocks
(content/docs/ui/views.mdx:16 / 172 / 404 / 438 — the last three shifted by the
insertion); all four still type-check. fumadocs-mdx regenerates the page cleanly, so the
new callout and tables parse. Control-byte self-scan beyond the gate:
grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' content/docs/ui/views.mdx — no hits.

Docs Drift Check does not fire here: it triggers on packages/**, and this PR touches
none.

Scope — deliberately not done


Generated by Claude Code

…t field type (#6897)
views.mdx:106 said a lookup in a view's `searchableFields` is always refused.
Measured at both layers, that is false: the boundary is membership in the
object's server-resolved allowed set, and field TYPE is consulted only on the
auto-default branch (the object declares nothing). On an object declaring
`searchableFields: ['subject', 'account_id']`, a view narrowing to the lookup
`account_id` is ACCEPTED and scanned, while a `text` column the object left out
is REFUSED — the exact inverse of a type-based reading. An author following the
old row would delete a narrowing that works.
The row now states the set-membership rule and links to a new
`### Toolbar search (searchableFields)` section that mirrors the terminology
landed in skills/objectstack-ui/SKILL.md by PR #6898, so the two corpora agree.
The dotted-path half of the old row was correct and is kept.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F8q5J1MQyocgtNspb15fSn
@vercel

vercelBot commented Aug 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 9, 2026 4:22am

Request Review

@os-project-manageros-project-manager added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 9, 2026 — with Claude
@github-actionsgithub-actionsBot added size/s documentation Improvements or additions to documentation labels Aug 9, 2026
@os-project-manager
os-project-manager marked this pull request as ready for review August 9, 2026 04:36
@os-project-manager
os-project-manager added this pull request to the merge queueAug 9, 2026
Merged via the queue into main with commit 255588bAug 9, 2026
25 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-6897-views-searchable-set-membership branch August 9, 2026 04:52
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

content/docs/ui/views.mdx states a lookup in a view's searchableFields is always refused — measured, it is accepted whenever the object declares it

2 participants

@os-project-manager@claude