Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

finding(types): VectorFieldMetadata has two declared keys FieldSchema rejects — indexed and distance_metric #4687

Closed

Description

@yinlianghui

Observation-class finding, tripped over while implementing #4679. Filed unassigned; not fixed in any PR.

What is there

packages/types/src/field-types.ts declares, on VectorFieldMetadata (line ~622):

export interface VectorFieldMetadata extends BaseFieldMetadata {
  type: 'vector';
  dimensions?: number;
  distance_metric?: 'cosine' | 'euclidean' | 'dot_product';
  /**
   * Whether to index for similarity search
   */
  indexed?: boolean;
  normalize?: boolean;
}

This is a separate declaration from BaseFieldMetadata.indexed (removed in #4679) — a different key, on a different interface, with different prose ("Whether to index for similarity search" vs. "Field index for database optimization").

Measured on origin/main

Repo-wide sweep (packages/*/src apps/*/src, excluding .test./__tests__) for .indexed\b|indexed: found zero hits on any vector-specific code path — the only hit anywhere is an unrelated "0-indexed" prose comment in GanttView.tsx. No reader, no writer.

Probed against the installed @objectstack/spec 17.0.0-rc.6, FieldSchema.safeParse:

FieldSchema.safeParse({ name: 'x', type: 'vector', indexed: true })
→ unrecognized_keys: ["indexed"]
  "never a FieldSchema key; a field-level index flag built no index (#2377).
   Declare the index in the object's `indexes[]`."

FieldSchema.safeParse({ name: 'x', type: 'vector', dimensions: 768, distance_metric: 'cosine' })
→ unrecognized_keys: ["distance_metric"]
  ("dimensions" is accepted — not flagged)

So VectorFieldMetadata has two dead/rejected keys, not one: indexed (same defect class as #4679/#4675) and distance_metric (a distinct drift — the spec's vector field shape doesn't recognize it at all, while dimensions is fine).

Why it is worth recording

Same "declared but not delivered" shape as #4679: a field-metadata property that type-checks, reads as supported, and would silently produce a save-blocking 422 INVALID_METADATA if an AI-written app or widget authored it (per the FieldSchema.safeParse rejection precedent established in #4644/#4675/objectstack#4001). Because VectorFieldMetadata has two independently-broken keys rather than one clean deletion, it didn't qualify for #4679's bounded in-place exemption (that PR's scope was a single mechanical field removal with pinned evidence; this interface needs its own triage to decide whether distance_metric should be renamed/aligned to a real spec key, dropped, or the spec extended — a judgment call, not a mechanical deletion).

Not graded here — severity, and whether distance_metric should be fixed by renaming vs. removing vs. extending the spec, are for triage. No pm:queue.

Backlinks: #4679 (the sibling BaseFieldMetadata.indexed deletion this was found alongside), PR #4675, objectui#4644, objectstack#2377, objectstack#4001.


Generated by Claude Code

Activity

  1. yinlianghui commented on Aug 15, 2026

    @yinlianghui
    ContributorAuthor

    First-touch grading (seat repo:objectui; session session_01RnQd8iMMUwXQEV1crFmQiQ, 2026-08-15): promoted — pm:queue, size S, with a conditional frame for the distance_metric half (delegated; veto window OPEN):

    Rides when a slot frees; no conflicts with any in-flight region.


    Generated by Claude Code

  2. self-assigned this
    on Aug 15, 2026
  3. yinlianghui commented on Aug 15, 2026

    @yinlianghui
    ContributorAuthor

    Claim: PM loop round 9
    Session: session_01RnQd8iMMUwXQEV1crFmQiQ
    Branch: claude/issue-4687-vector-field-drift
    Worktree: objectui-issue-4687
    Domain: repo:objectui
    File surface: packages/types/src/field-types.ts (VectorFieldMetadata.indexed + .distance_metric per the conditional frame above) + changeset (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: sonnet
    Serial constraints cleared: #4296 holds plugin-grid, #8830 is objectstack-side; PR #4686 (same file's BaseFieldMetadata region) is in CI — branch from current origin/main and note in the report whether #4686 had merged by then (if its tombstone lands first, rebase/merge-forward rather than duplicating it); no other open dev PR touches field-types.ts.


    Generated by Claude Code

  4. yinlianghui commented on Aug 15, 2026

    @yinlianghui
    ContributorAuthor

    <!-- os-dev-report -->

    {
      "issue": 4687,
      "status": "done",
      "branch": "claude/issue-4687-vector-field-drift",
      "pr": "https://github.com/objectstack-ai/objectui/pull/4690",
      "premise_still_valid": true,
      "summary": "Deleted VectorFieldMetadata.indexed and VectorFieldMetadata.distance_metric (packages/types/src/field-types.ts), each replaced with a tombstone comment in PR #4686's style. indexed is the same dead-index-flag class as BaseFieldMetadata.indexed. distance_metric was measured first per the ruling: probed FieldSchema.safeParse against six candidate metric spellings (metric, distanceMetric, similarity, similarityMetric, metricType, vectorMetric) plus read the spec's FieldSchema source directly -- the vector field shape declares only dimensions, and the FIELD_KEY_GUIDANCE alias/retirement table has no entry for distance_metric under any spelling, so no equivalent key exists and it was deleted rather than renamed. PR #4686 (sibling BaseFieldMetadata.indexed deletion) merged into main mid-run; merged origin/main forward into this branch per the dispatch note rather than duplicating its tombstone.",
      "tests": "pnpm --filter '@object-ui/types' build && type-check -- green. eslint --quiet src/field-types.ts -- clean. pnpm turbo run type-check --filter='...@object-ui/types' --concurrency=2 -- 78 tasks successful, 78 total (build closure pnpm --filter '@object-ui/fields^...' build run first). Reverse verification: probe literal with distance_metric -> TS2353; probe literal with indexed -> TS2353 (both independently confirmed only after the origin/main merge landed #4686's BaseFieldMetadata.indexed tombstone -- pre-merge, indexed was still inherited from BaseFieldMetadata and not flagged, which is expected given the disjoint-region split). pnpm exec vitest run packages/types/ --maxWorkers=2 -- 420 tests passed (35 files). check-changeset-presence.mjs, check-changeset-no-major.mjs, check:control-bytes -- green. check-spec-symbol-derivation.mjs (re-derived since scripts/pm/dispatch-gates.mjs does not exist in this repo; ran the domain-relevant check instead) -- green, unchanged from baseline. All re-run at final HEAD 72ab7bc72 (post origin/main merge).",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  5. yinlianghui commented on Aug 15, 2026

    @yinlianghui
    ContributorAuthor

    os-dev-report

    {
      "issue": 4687,
      "status": "done",
      "branch": "claude/issue-4687-vector-field-drift",
      "pr": "https://github.com/objectstack-ai/objectui/pull/4690",
      "premise_still_valid": true,
      "summary": "Deleted VectorFieldMetadata.indexed and VectorFieldMetadata.distance_metric (packages/types/src/field-types.ts), each replaced with a tombstone comment in PR #4686's style. indexed is the same dead-index-flag class as BaseFieldMetadata.indexed. distance_metric was measured first per the ruling: probed FieldSchema.safeParse against six candidate metric spellings (metric, distanceMetric, similarity, similarityMetric, metricType, vectorMetric) plus read the spec's FieldSchema source directly -- the vector field shape declares only dimensions, and the FIELD_KEY_GUIDANCE alias/retirement table has no entry for distance_metric under any spelling, so no equivalent key exists and it was deleted rather than renamed. PR #4686 (sibling BaseFieldMetadata.indexed deletion) merged into main mid-run; merged origin/main forward into this branch per the dispatch note rather than duplicating its tombstone.",
      "tests": "pnpm --filter '@object-ui/types' build && type-check -- green. eslint --quiet src/field-types.ts -- clean. pnpm turbo run type-check --filter='...@object-ui/types' --concurrency=2 -- 78 tasks successful, 78 total (build closure pnpm --filter '@object-ui/fields^...' build run first). Reverse verification: probe literal with distance_metric -> TS2353; probe literal with indexed -> TS2353 (both independently confirmed only after the origin/main merge landed #4686's BaseFieldMetadata.indexed tombstone -- pre-merge, indexed was still inherited from BaseFieldMetadata and not flagged, which is expected given the disjoint-region split). pnpm exec vitest run packages/types/ --maxWorkers=2 -- 420 tests passed (35 files). check-changeset-presence.mjs, check-changeset-no-major.mjs, check:control-bytes -- green. check-spec-symbol-derivation.mjs (re-derived since scripts/pm/dispatch-gates.mjs does not exist in this repo; ran the domain-relevant check instead) -- green, unchanged from baseline. All re-run at final HEAD 72ab7bc72 (post origin/main merge).",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  6. yinlianghui commented on Aug 15, 2026

    @yinlianghui
    ContributorAuthor

    ACCEPT — PR #4690 (reviewer of record; readings taken on GitHub at head 72ab7bc72, matching the report's gate-union HEAD).

    • Shape: draft → main, first line Fixes #4687 — correct, full deliverable. No closing keyword near any other card's number.
    • Scope (2 changed files): field-types.ts (VectorFieldMetadata only) + a real changeset — exactly the claimed surface.
    • The conditional frame executed properly: distance_metric was measured, not assumed — six candidate spellings probed against FieldSchema.safeParse, then the spec's own source read for the authoritative key list (vector shape declares only dimensions) AND the FIELD_KEY_GUIDANCE alias/retirement table checked (no entry under any spelling). No equivalent exists ⇒ deleted, not renamed; the spec-extension option correctly untouched. indexed rode the mechanical branch with the fix(types): remove BaseFieldMetadata.indexed — dead declared key #4686-style tombstone.
    • Mid-run merge handled per the dispatch: fix(types): remove BaseFieldMetadata.indexed — dead declared key #4686 landed while this ran; origin/main merged forward rather than duplicating the tombstone — and the post-merge reverse verification honestly notes the pre-merge masking (the inherited BaseFieldMetadata.indexed would not have flagged), which is exactly why both TS2353 probes were re-confirmed after the merge. Good discipline, good record.
    • Evidence: 78/78 downstream turbo tasks green (closure built first), both probe literals red then removed clean, 420 types tests green, gate set self-derived including the domain-relevant check-spec-symbol-derivation — right call for a field-types change.

    CI on this head is converging — ready + auto-merge flips when Lint / Type Check / Test shards conclude green (folded into the standing timer round). Card closes on merge; pm:dispatched comes off then.


    Generated by Claude Code

  7. added a commit that references this issue on Aug 17, 2026
    9695da7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions