fix(spec): drop four dead ghost members from SEARCH_AUTO_EXCLUDED_TYPES and extend the [#13695] pin to every search type vocabulary - #13869
Conversation
… 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
📓 Docs Drift CheckThis PR changes 1 package(s): 21 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # 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
|
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-valueFieldTypeenum, so none could ever match a real field'stype. 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 toFieldTypemembership.Per-member history verdicts (measured, not read)
The set was born as
EXCLUDED_TYPESin objectql commitaaa859b40(2026-06-21, ADR-0061 P1+P2,$searchend-to-end) and moved verbatim to spec inaf2a0958c(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;--allsweeps every branch).FieldTypemember?'geometry'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'encrypted''secret'entered the enum 2026-05-31 (6514f8df1), before the list; the birth commit already excludes'secret'(and'password') alongside'encrypted''object'07a4e26e6) is a summary-config key-alias map value (child: 'object'), not an enum member'composite'entered the enum 2026-05-27 (482eb67cc), before the list; no rename event exists'grid'a2496a62c) is theinlineEditform-factor union (boolean | 'grid' | 'form'), not an enum member'json'(the storage shape a grid/subtable would take) was already in both enum and list at birthThe 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:
autoDefaultFieldsuses 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
autoDefaultFieldsnamed'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 namessecret,passwordandvector. The "56-type domain" measurement note is annotated: the union ofFieldTypeand the three vocabularies isFieldTypesince this cleanup (the extended pin makes that a checked fact).Pin extension ([#13695] → all four vocabularies)
search-fields.test.ts's[#13695]block now assertsSEARCHABLE_TEXTUAL_TYPES,SEARCHABLE_ENUM_TYPES,SEARCH_AUTO_EXCLUDED_TYPESandSEARCH_VIRTUAL_TYPESare each subsets ofFieldType.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_FIELDSis 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-fieldsby relative source path, so vitest reads the mutation directly) turned exactly the extendedSEARCH_AUTO_EXCLUDED_TYPESpin 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 bygit checkout HEAD -- PATH(the mutated file's absolute path) + emptygit diff HEAD+git hash-objectequal to theHEADblob (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.ts—Test Files 1 passed (1),Tests 29 passed (29); all five new[#13695]tests listed by the verbose reporter.pnpm --filter @objectstack/spec test—Test Files 445 passed (445),Tests 11934 passed (11934); verify-lock line:VERDICT command-exit 0.pnpm --filter @objectstack/spec typecheck— clean; includescheck: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.tsby design).pnpm --filter @objectstack/spec check:generated—All 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 at08062e6ce) — 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 livescripts/pm/check-half-states.mjscensus (exit 3: GitHub-route refusal from this container, per its own text; thepnpm check:pm-half-statesself-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-gatedcheck:type-check-debt --re-measure,check:type-check-coverage,check:dual-build-cjs-loads,check-dev-prereqsandcheck: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-codegenswitch (fType)carries its own ghost field-type vocabulary —'slug','ip_address','encrypted','integer'are cases, none aFieldTypemember — 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