Skip to content

fix(spec): drop four dead ghost members from SEARCH_AUTO_EXCLUDED_TYPES and extend the [#13695] pin to every search type vocabulary - #13869

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-13716-search-excluded-ghosts
Aug 31, 2026
Merged

fix(spec): drop four dead ghost members from SEARCH_AUTO_EXCLUDED_TYPES and extend the [#13695] pin to every search type vocabulary#13869
os-warren merged 1 commit into
mainfrom
claude/issue-13716-search-excluded-ghosts

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes #13716

What

SEARCH_AUTO_EXCLUDED_TYPES (packages/spec/src/data/search-fields.ts) declared four members — 'object', 'grid', 'geometry', 'encrypted' — that are not members of the 49-value FieldType enum, so none could ever match a real field's type. Per the card's premise-first mandate, each member was judged dead vocabulary vs stale spelling from git history before anything was touched. Verdict: all four are dead vocabulary — deleted; no member is a stale spelling of a real type, so the exclusion set's live behaviour is unchanged. The [#13695] pin is extended to hold every search type vocabulary in the file to FieldType membership.

Per-member history verdicts (measured, not read)

The set was born as EXCLUDED_TYPES in objectql commit aaa859b40 (2026-06-21, ADR-0061 P1+P2, $search end-to-end) and moved verbatim to spec in af2a0958c (2026-07-31, #4254). All four ghosts are present in the birth commit; the repository history is complete for this question (the clone was unshallowed before measuring; --all sweeps every branch).

member ever a FieldType member? rename candidate? verdict
'geometry' Never — zero commits touch the string in either historical enum file (packages/spec/src/zod/meta/field.zod.ts, packages/spec/src/data/field.zod.ts) across all branches 'location' entered the enum 2026-01-20 (686442183) — five months before the list existed — and the birth commit already excludes 'location' alongside 'geometry'. Nothing was renamed; both names co-existed in the list from day one dead
'encrypted' Never — zero commits, same sweep 'secret' entered the enum 2026-05-31 (6514f8df1), before the list; the birth commit already excludes 'secret' (and 'password') alongside 'encrypted' dead
'object' Never — the only historical hit in the enum file (07a4e26e6) is a summary-config key-alias map value (child: 'object'), not an enum member the real embedded-object type 'composite' entered the enum 2026-05-27 (482eb67cc), before the list; no rename event exists dead
'grid' Never — the only historical hit (a2496a62c) is the inlineEdit form-factor union (boolean | 'grid' | 'form'), not an enum member no sibling rename; 'json' (the storage shape a grid/subtable would take) was already in both enum and list at birth dead

The decisive shape, common to all four: at the moment the list was created, the canonical modern types ('location', 'secret', 'json') were already both in the enum and in this exclusion list, sitting next to the ghosts. A rename that left a stale spelling behind would show the old name being replaced in the enum and the new name arriving later in the list — neither ever happened. The four names read as imported vocabulary from outside this repo's type system, and no commit ever made them types here.

Because the members never matched anything, deleting them moves no resolution: autoDefaultFields uses the set membership-only (.has(t)), and the sole external consumer (packages/objectql/src/search-filter.ts) is a pass-through re-export.

Comment repair (in-scope per the card)

The fail-closed tiebreak comment in autoDefaultFields named 'encrypted' as one of the semantically heavy members ("secret, password, encrypted and vector") — asserting a safety property for a name that cannot occur, which is the card's own point. It now names secret, password and vector. The "56-type domain" measurement note is annotated: the union of FieldType and the three vocabularies is FieldType since this cleanup (the extended pin makes that a checked fact).

Pin extension ([#13695] → all four vocabularies)

search-fields.test.ts's [#13695] block now asserts SEARCHABLE_TEXTUAL_TYPES, SEARCHABLE_ENUM_TYPES, SEARCH_AUTO_EXCLUDED_TYPES and SEARCH_VIRTUAL_TYPES are each subsets of FieldType.options (collecting all ghosts per set, not first-fail), plus a vacuity control (non-empty enum, non-empty vocabularies, one known-real member per set). SEARCH_AUTO_EXCLUDED_FIELDS is deliberately absent — its members are field names, not types.

Ablation (reverse verification), from the committed fix: re-introducing the four ghost members into the set literal (mutation proven on disk by anchored literal-line grep counts 0→1/1 and a non-empty git diff --stat; no build leg exists on either side — the test imports ./search-fields by relative source path, so vitest reads the mutation directly) turned exactly the extended SEARCH_AUTO_EXCLUDED_TYPES pin red — AssertionError: SEARCH_AUTO_EXCLUDED_TYPES names types that are not FieldType members: expected [ 'encrypted', 'geometry', 'grid', 'object' ] to deeply equal [] — with the other 28 tests green (the ghosts are still rejected by the auto-default, so the #6934 direction pins rightly stay green). Restoration proven by git checkout HEAD -- PATH (the mutated file's absolute path) + empty git diff HEAD + git hash-object equal to the HEAD blob (5616ff7… both sides).

Clause-② declaration

No — all four members judged dead and deleted; the exclusion set's observable behaviour is unchanged (no member could match any field), no spelling was corrected, no accept/reject behaviour moves. Per the claim comment's split, this is the plain draft-PR path, no needs:contract-review.

Verification

Run at commit 08062e6ce (the PR head):

  • pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/data/search-fields.test.tsTest Files 1 passed (1), Tests 29 passed (29); all five new [#13695] tests listed by the verbose reporter.
  • Ablation as above (red exactly where predicted, restore proven).
  • pnpm --filter @objectstack/spec testTest Files 445 passed (445), Tests 11934 passed (11934); verify-lock line: VERDICT command-exit 0.
  • pnpm --filter @objectstack/spec typecheck — clean; includes check:test-typecheck: OK — @objectstack/spec's test layer compiles under packages/spec/tsconfig.test.json (the program that actually contains the edited test file — the build tsconfig excludes **/*.test.ts by design).
  • pnpm --filter @objectstack/spec check:generatedAll 14 generated artifacts are up to date. (api-surface included; no export was added or removed — only members of an exported set value changed).
  • node scripts/pm/dispatch-gates.mjs (no paths passed; derivation stderr pinned to this tree at 08062e6ce) — 42 derived families + the 6 convention-triggered test-file families all run locally, exit codes captured redirect-first (never through a pipe): all green, with two exceptions that are the gates' own NOT MEASURED shapes, not reds — scripts/check-test-completeness.mjs (exit 3: "pass a saved turbo run test log — or, running the family locally, record this gate as NOT MEASURED"; CI owns it) and the live scripts/pm/check-half-states.mjs census (exit 3: GitHub-route refusal from this container, per its own text; the pnpm check:pm-half-states self-test spelling passes its 1826 cases). The workspace closure was built first (turbo run build --filter='./packages/*' --filter='./packages/*/*' — 70/70 successful) exactly as lint.yml does, which un-gated check:type-check-debt --re-measure, check:type-check-coverage, check:dual-build-cjs-loads, check-dev-prereqs and check:doc-formula-expressions — all green.
  • pnpm lint (eslint . --no-inline-config, the full CI sweep, not a narrowed run) — exit 0.
  • node scripts/check-nul-bytes.mjs — OK (7602 text files, no raw control bytes).

Out-of-scope finding (reported to the PM, not filed from this seat, per dispatch): packages/cli/src/commands/generate.ts's migration-codegen switch (fType) carries its own ghost field-type vocabulary — 'slug', 'ip_address', 'encrypted', 'integer' are cases, none a FieldType member — the same defect class as this card, one package over.

Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2

Generated by Claude Code


Generated by Claude Code

… extend the [#13695] pin to every search type vocabulary

'object', 'grid', 'geometry' and 'encrypted' were never FieldType members
at any commit, so none could match a real field's type. The [#13695] pin
now holds all four search type vocabularies to FieldType membership.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 3 documentable anchor(s).

21 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 9b21037d4198cd14105abd354b019e9323b4fe57.

4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 9b21037d4198cd14105abd354b019e9323b4fe57packageMentionDocs.

Which tree this was computed on

This run read content/docs from d16ff3fb38e4fe1e2ac1041c83249881d0c2f552 — the merge of head 08062e6cee54889c523e820b3d285ccb34eff0a1 into base 9b21037d4198cd14105abd354b019e9323b4fe57, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin d16ff3fb38e4fe1e2ac1041c83249881d0c2f552 && git checkout d16ff3fb38e4fe1e2ac1041c83249881d0c2f552
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 9b21037d4198cd14105abd354b019e9323b4fe57 08062e6cee54889c523e820b3d285ccb34eff0a1 && git checkout -B drift-repro 9b21037d4198cd14105abd354b019e9323b4fe57 && git merge --no-ff 08062e6cee54889c523e820b3d285ccb34eff0a1

node scripts/docs-audit/affected-docs.mjs --json 9b21037d4198cd14105abd354b019e9323b4fe57

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 9b21037d4198cd14105abd354b019e9323b4fe57 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:data size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SEARCH_AUTO_EXCLUDED_TYPES contains 4 members not in the FieldType enum — more dead vocabulary in search-fields.ts

2 participants