fix(objectql,runtime): stop platform stamps failing spec validation — /meta/diagnostics reads clean again (#7561) - #7591
Conversation
…7561) `GET /api/v1/meta/diagnostics` reported 94 of 94 registry entries INVALID. Both error shapes were self-inflicted — the platform reporting defects about columns it wrote itself, on documents no author wrote or could fix — so the endpoint carried no signal at all. - `provisionSearchCompanion` stamped `index: true` on `__search`. Field-level `index` was removed from `FieldSchema` in the 16.x line (#2377, ADR-0049) and `FieldSchema` is a `strictObject`, so the key was rejected by name. Same mechanism as #6810 (`applySystemFields`/`indexed` on `organization_id`), same retired key, one field over. Stamp and the false "It IS `index`ed" docblock claim both removed. Unlike #6810 no `indexes[]` entry replaces it: the column's only reader is `{ __search: { $contains: term } }`, a leading-wildcard LIKE no B-tree can serve, and `IndexSchema` cannot express a trigram/GIN index. Behaviour-neutral either way — nothing read the flag. - `DefaultDatasourcePlugin.registerVisibility` published the `default` row without `config`, which `DatasourceSchema` requires. Now stamped `{}` — deliberately empty rather than the host's real config, which carries connection credentials that would otherwise reach every metadata reader. Fixed at the producer, not by widening the spec. Two pins land with the fix, since patching one key at a time is what turned #6810 into this card: a class pin walking every platform-stamped field through `FieldSchema` across all stamper branches, and a baseline pin asserting a realistically-built registry sweeps clean, naming both error shapes. Both reverse-verified red against the unfixed producers. `search-companion.test.ts` asserted `col.index === true` — it pinned the defect rather than the contract; it now pins the key's absence. Fixes #7561 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019MfMR4enbnPgoH6efeKmDJ
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 2 package(s): 29 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also reference the affected code. These are read-only:
|
Fixes #7561
Premise verification (against
origin/main@97b6658, not a working tree)The card was filed against framework
a86db175; every quoted fact was re-measured on currentorigin/main. Premise holds, both halves, reproduced from live code:index: truestamp — confirmed atpackages/objectql/src/search-companion.ts:155, and it is the only field-levelindex/indexedwriter left inpackages/. The docblock at:132claimed "It ISindexed — every search touches it".indexwas removed fromFieldSchemain the 16.x line ([11.0][A2] Remove dead author-facing metadata properties (ADR-0049 enforce-or-remove) #2377, ADR-0049) — the comment atpackages/spec/src/data/field.zod.ts:~921states the driver builds indexes fromindexes[]and a field-levelindex: truecreated no index. No driver reads a field-levelindextoday. Dropping the key is behaviour-neutral for indexing.confighalf is now located (it was not in the card):DefaultDatasourcePlugin.registerVisibility(packages/runtime/src/default-datasource-plugin.ts:250) publishes thedefaultdatasource row as{ name, label, driver, origin }, whileDatasourceSchema.config(packages/spec/src/data/datasource.zod.ts:406) is a requiredz.record(...).originis declared (:522), soconfigis the only missing key.What changed
1.
provisionSearchCompanionno longer stampsindex: true(+ the false docblock claim replaced with the measured account). Producer-side fix, exactly #6810's shape.2. No
indexes[]entry replaces it — a measured divergence from #6810, not an omission. #6810's predicate isorganization_id = ?, equality, which a B-tree serves. This column's only reader isbuildSearchFilter(search-filter.ts:122), which emits{ __search: { $contains: term } }— a leading-wildcardLIKE '%term%'no B-tree can answer.IndexSchema(object.zod.ts:372) spells onlyname/fields/unique— no trigram/GIN method — so the sanctioned spelling cannot express an index this column could use. Declaring one would buy write amplification on every row for a read path that cannot use it. Recorded in the docblock; a real substring index needs anIndexSchemathat can express one, which is a separate change.3.
DefaultDatasourcePluginstampsconfig: {}— deliberately empty, notthis.def.config. That registration is a deliberately non-secret projection: the host's real config carries connection credentials (user/password), andDatasourceSchemaitself refuses an inlinedpassword, so publishing it would put credentials onGET /api/v1/meta/datasourcesfor every metadata reader.{}carries exactly what the row always carried; only the spelling changes.⛔ No
packages/spectouch. Neither half is fixed by wideningFieldSchema(that would re-open a key ADR-0049 retired) or by relaxingDatasourceSchema.config(a real datasource genuinely needs its config; relaxing trades one honest verdict for a permanently weaker one). The #6017 declare-and-proceed convention was therefore not triggered.The durable ask
diagnostics-clean-baseline.test.ts— builds a registry the way the platform builds one (every stamper live, both tenancy modes), asserts the sweep finds nothing, and names both of the card's error shapes explicitly so a reintroduction fails on the reported shape, not a generic countFieldSchemastamped-system-fields-spec-conformance.test.ts— walks every fieldapplySystemFields+provisionSearchCompanionstamp, across every ownership /managedBy/systemFields/ tenancy branch, throughFieldSchema; plus an explicit "noindex/indexedon any stamped field" assertionBoth pins guard the guard (they fail if the matrix stamps nothing, or if
__searchstops being provisioned) so neither can pass vacuously.Reverse-verified
Both pins were re-run against the unfixed producers and confirmed red with the card's exact shapes — a pin that cannot fail is worth nothing:
__search: Unrecognized key(s) on this field: \index``object/showcase_{account,contact,order,note} + sys_thing → fields.__search: unrecognized_keysacross both tenancy modes, andconfig: invalid_typesearch-companion.test.tsassertedexpect(col.index).toBe(true)— it pinned the defect, not the contract. It now pins the key's absence, with a comment saying why.Gates
pnpm check:durability-log-levelpnpm check:engine-double-contractpnpm check:error-code-casingnode scripts/check-engine-split-ratio.mjspnpm check:nul-bytespnpm --filter @objectstack/spec check:generated@objectstack/objectqltypecheck@objectstack/runtimetypecheckobjectql,runtime,metadata-protocol+ deps)Suites: full
@objectstack/objectql— 180 files / 3183 tests pass;@objectstack/runtime(default-datasource-plugin,standalone-stack,app-plugin) — 57 pass;plugin-pinyin-search— 14 pass.Changeset included (
patch×2) — user-visible: diagnostics endpoint verdicts.Generated by Claude Code