Skip to content

fix(lint): consolidate did-you-mean suggestion helpers into object-graph's shared nearestName - #14575

Merged
baozhoutao merged 4 commits into
mainfrom
claude/issue-14268-lint-suggest-consolidation
Sep 2, 2026
Merged

fix(lint): consolidate did-you-mean suggestion helpers into object-graph's shared nearestName#14575
baozhoutao merged 4 commits into
mainfrom
claude/issue-14268-lint-suggest-consolidation

Conversation

@claude

@claude claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes #14268

What changed

Four hand-copied "Did you mean?" helpers in packages/lint/src are now one shared helper. object-graph.ts's already-exported nearestName/suggestName gained the containment pre-pass that validate-widget-bindings.ts's private didYouMean carried, and the three private copies were deleted:

  • validate-object-references.ts — deleted its private suggest/distance, imports suggestName from ./object-graph.
  • validate-sortable-fields.ts — same.
  • validate-widget-bindings.ts — deleted its private didYouMean/levenshtein/suggest, imports suggestName from ./object-graph.
  • object-graph.tsnearestName now checks containment first (matching c.length/target.length when one contains the other, scored by length delta) before falling back to Levenshtein distance within the existing max(2, floor(len/3)) budget; suggestName and the private distance (the one surviving edit-distance body) are unchanged. Docblock rewritten to describe the now-shared behaviour instead of pointing at the "consolidating the three copies is recorded as a follow-up" note this card resolves.

This is the ruling's decision (comment 5502887598 on #14268): the containment pre-pass becomes nearestName's behaviour for every caller, including object-graph.ts's own two describeFieldPathVerdict call sites (:325/:342, both already routed through suggestName).

Hints newly supplied

None. A/B comparison on the same base tree (commit fed4fa409, no test file touched): the full @objectstack/lint suite run with the four files at their origin/main state (93 files / 2812 tests passed, 5 skipped) and again with the port applied — byte-identical pass/fail results. No existing suggestion assertion needed a hint text change; the containment pre-pass is additive but none of the three rules' current test fixtures happen to exercise a containment-eligible typo the edit-distance budget didn't already catch. Re-run on the final merged tree (after picking up unrelated upstream commits) also passes clean: 93 files / 2817 tests passed, 0 skipped (the skip-count change is from unrelated upstream work, not this PR).

Verification

$ git grep -n "function suggest\|function distance\|function levenshtein\|function didYouMean" \
    packages/lint/src/validate-object-references.ts \
    packages/lint/src/validate-sortable-fields.ts \
    packages/lint/src/validate-widget-bindings.ts
# zero hits
  • pnpm --filter @objectstack/lint build — clean (dist emitted, no dangling references to the deleted functions).
  • pnpm --filter @objectstack/lint typecheck — clean (tsc --noEmit + check:test-typecheck).
  • pnpm --filter @objectstack/lint test — 93 files / 2817 tests passed on the final merged tree (commit referenced below).
  • pnpm lint narrowed to the 5 touched files (--format json): 0 errors, 1 informational warning (.changeset/*.md has no ESLint config — expected, not a finding). The repo's eslint.config.mjs enables no type-aware linting (no parserOptions.project anywhere), so this diff cannot move any untouched file's verdict — the narrowed run is a complete reading of this diff's lint surface, not a partial one.
  • Dispatch-gates union (28 commands derived from the touched-file surface) — all green except two expected NOT MEASURED (both require artifacts this local run cannot produce, not repo-scoped to this PR): check-test-completeness.mjs (needs a saved turbo run test log CI produces) and check:dual-build-cjs-loads (needs a full monorepo pnpm build, ~78 packages).

Changeset

.changeset/lint-suggest-name-consolidation.md@objectstack/lint: patch.

Out of scope

Per the ruling and the claim comment, the following private "did you mean?" copies in packages/lint/src are not touched by this PR — filed as follow-ups, listed in the report below with file:line for the PM to route:

  • validate-action-name-refs.ts:84 (distance) / :101 (suggest)
  • validate-ai-tool-references.ts:70 (distance) / :87 (suggest)
  • validate-chart-bindings.ts:83 (distance) / :100 (suggest)
  • validate-searchable-fields.ts:275 (suggest) / :289 (distance)
  • validate-translation-references.ts:159 (distance) / :186 (suggest)
  • validate-react-page-props.ts:167 (nearestKnown)
  • validate-rule-schema-formats.ts:266 (nearestRegisteredFormat)

Generated by Claude Code

@github-actions github-actions Bot added the size/m label Sep 2, 2026
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

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

2 release-owned page(s) name something this change touched. These are read-only:

  • content/docs/releases/v16.mdx (via validateWidgetBindings (symbol, a top-level function))
  • content/docs/releases/v17.mdx (via validateWidgetBindings (symbol, a top-level function))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 3 name(s) were too generic to anchor anything (single lowercase words)
  • 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 — 5 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 7286dd58e806ed321cbdfc23a1c455db8f80b1adpackageMentionDocs.

Which tree this was computed on

This run read content/docs from 9facf49a1b39d1800a237487f10ab7b34c4780de — the merge of head 17d9e56a01ced2fc12b588399641aebe3c34aafa into base 7286dd58e806ed321cbdfc23a1c455db8f80b1ad, 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 9facf49a1b39d1800a237487f10ab7b34c4780de && git checkout 9facf49a1b39d1800a237487f10ab7b34c4780de
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7286dd58e806ed321cbdfc23a1c455db8f80b1ad 17d9e56a01ced2fc12b588399641aebe3c34aafa && git checkout -B drift-repro 7286dd58e806ed321cbdfc23a1c455db8f80b1ad && git merge --no-ff 17d9e56a01ced2fc12b588399641aebe3c34aafa

node scripts/docs-audit/affected-docs.mjs --json 7286dd58e806ed321cbdfc23a1c455db8f80b1ad

⚠️ 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 7286dd58e806ed321cbdfc23a1c455db8f80b1ad → 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 size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] suggest / distance ("did you mean?") is hand-copied four times across packages/lint — the same shape #4330 already fixed for SYSTEM_FIELDS

2 participants