Skip to content

fix(spec,objectql): correct six false edit distance cannot reach citations - #19126

Merged
os-bill merged 2 commits into
mainfrom
claude/issue-17664-edit-distance-citations
Sep 18, 2026
Merged

os-bill merged 2 commits into
mainfrom
claude/issue-17664-edit-distance-citations

Conversation

@os-bill

@os-bill os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #17664

Clause-②: no

aliases has two jobs, not one: filling a gap the distance fallback leaves empty, and overruling a hit the fallback reaches and gets wrong. The lookup is aliases[aliasProbe(key)] ?? findClosestMatches(key, knownKeys, budget, 1)[0] — the table is consulted first and wins outright — and the budget is Math.max(2, Math.floor(key.length / 3)). A sentence saying distance "cannot reach" the cited case denies the second job. In three of the six places corrected here, the cited case is itself an example of it.

The three sites the card names — three separate verdicts

Measured against the real findClosestMatches and each shape's own key list (read off .shape, never transcribed), at origin/main 1124c4564.

1. packages/objectql/src/validation/record-validator.ts — FALSE, high confidence

Cited: "The rename IS the prescription, and edit distance cannot reach it (latitude -> lat)".

latitude is 8 characters, so the budget is 2. lat is 5 edits away and out of reach — but the fallback is not silent: the declared altitude is exactly 2 edits away, inside the budget. The refusal an author would see without the alias, printed by the ablation below:

Unrecognized key(s) on this location value: `latitude`. Did you mean `latitude` -> `altitude`?

So the entry is overruling a confident wrong answer, and the sentence cites it as proof that no such category exists. Confidence: high — the ablation reproduces the wrong answer verbatim from the running schema.

2. packages/spec/src/data/default-value-shape.ts — FALSE, high confidence, plus a second error

Same sentence, same measurement, so the same verdict. This site carries an additional error the card does not name: the docblock's own worked example is postal_code -> postalCode on AddressValueSchema, and it attributes that output to the curated aliases map. postal_code is not an alias key on that shape at all — scoring folds case and separators on both sides, so it is 1 edit against a budget of 3 and the example is the plain fallback's own answer. The corrected text names both channels and says which produced which. Confidence: high (both halves re-measured).

3. packages/spec/src/data/driver/turso.zod.ts — FALSE, high confidence, and in a different position from the other two

Two things set this one apart, and they are the same distinction read twice.

Position. Sites 1 and 2 cite a single example inline, as proof of a rule. This one is a blanket header standing above a table: "Semantic near-misses only — the spellings edit distance cannot reach." The word doing the damage is only, and it is quantified over six rows.

Bucket. Sites 1 and 2 are in the overrule bucket (reachable, fallback answers a different key). uri is in the agrees bucket: 3 characters, budget 2, and uri/url differ by 1, so the bare fallback already answers url — identically. Five of the six rows (connectionstring, dsn, database, databaseurl, syncinterval) are genuine gaps; uri is not, and the row's real value is that it keeps answering url if this shape ever gains a key within 2 of uri. Confidence: high for the uri row; the other five rows are re-measured and the header's claim holds for them.

Three more carriers of the same claim, fixed in place

The latitude -> lat sentence has five carriers, not two. Three more were corrected here under the bounded in-place-fix exemption, and all four of its conditions are named and shown:

  1. Same defect class as the card — literally the same false sentence about the same alias entry on the same shape, falsified by the same measurement. packages/spec/src/data/field-value.zod.ts (the table's own comment), packages/spec/src/data/field-value.test.ts, packages/spec/src/data/default-value-shape.test.ts.
  2. Mechanical, with the form already pinned — the correction form is the one PR docs(spec): state both roles of aliases, not only the gap it fills #17662 landed in packages/spec/src/kernel/manifest.zod.ts: name the budget formula and where it lives, give the exact distances, say which of the two roles the entry plays, and name the pin test. Prose only.
  3. No other claim holds the file — the open-PR holder map was rebuilt from scratch over all 33 open PRs (281 file rows). Lit control: it names fix(cloud-connection,spec): cite the cloud control-plane decisions as cloud ADR-NNNN, not bare numbers that resolve to this repo's own records #19119 holding 10 files, matching the dispatch's own reading. Dark control: a fabricated path matches 0 rows. All five carrier paths read FREE.
  4. Same gate family, no new verification surface — every one is under packages/spec/src/data/**, already inside this card's declared file surface, and adds no gate. The two new describe blocks live in test files the card's own sites already depend on.

Leaving them would have made the repository contradict itself inside one alias table's documentation. The boundary held elsewhere: the same claim shape about a different table is reported below, not fixed.

Pins

aliases entries are now asserted by role, because the two roles fail differently:

  • packages/spec/src/data/field-value.test.ts — longitude (GAP: nothing within budget), latitude (OVERRULE, with the negative half asserted: the reachable wrong answer must not appear), and altitud as the control that a plain typo still rides the fallback.
  • packages/spec/src/data/driver/turso.test.ts — dsn (GAP) beside uri (reachable, agreeing).

Population re-derivation, its radius, and one target outside it

The card reports the phrase pattern occurring 19 times across 17 tracked files and roughly a dozen unclassified. Re-derived at origin/main 1124c4564, printing every hit, never a count:

instrument flatten result
the card's own pattern leading JSDoc star stripped per line 20 hits / 17 files
this PR's pattern leading JSDoc star and leading // stripped per line 24 hits / 20 files

The card's instrument has a demonstrable blind spot, and it hides carriers of this very defect. The card's prescription names the JSDoc-star wrap and stops there. A line-comment wrap is invisible to it: when // falls between "edit" and "distance", or between "distance" and "cannot", the flattened text reads edit // distance cannot reach and no pattern anchored on the adjacent phrase can see it. Three hits in two files surface only under the comment-aware flatten, and two of them are further carriers of the false latitude -> lat claim — including field-value.zod.ts, the file that owns the alias.

Radius. This instrument sees: tracked files at one commit of objectstack-ai/objectstack, matching the literal words "edit distance" plus a negated modal plus "reach". It does not see: other repositories, untracked files, published npm tarballs, GitHub issue and PR bodies, or any paraphrase that does not spell "edit distance".

One named target outside it: packages/spec/src/automation/builtin-node-config.zod.ts says "object -> objectName is four edits against a threshold of two, so the suggester would say nothing at all for the single most common wrong spelling on this surface". That is exactly the same claim about exactly the same mechanism, and both patterns score that file 0. Lit control on the same file: the paraphrase itself matches twice. (Re-measured: object -> objectName really is a GAP on every CRUD node config, so it is true — but the radius, not the truth, is the point.) The sibling repo objectui was also swept and carries no member of this pattern.

Acceptance notes — noted, not filed

Four members of the population are FALSE and left alone, with the reason each is out of scope:

  • packages/spec/src/ui/action.zod.ts — "Edit distance cannot reach these (visibleWhen -> visible is 4 apart)" heads a ~50-row table containing 6 overruling rows (path -> target with the fallback reaching patch at 1; also args, success, style, op, acl) and 5 agreeing ones. The cited example is itself a genuine GAP, so this is a false blanket, not a false example. Different table, different lane (packages/spec/src/ui/**, outside this card's file surface).
  • packages/spec/src/data/object-strictness-batch20.test.ts — the describe title "aliases — semantic near-misses edit distance cannot reach" blankets three cases, and export -> exportCsv is an overrule (the fallback reaches import at 2). Inside the file surface, but a different alias table: fixing it would widen the diff past the coherence boundary above.
  • packages/spec/CHANGELOG.md — "Three spelled-out near-misses that edit distance cannot reach are curated as aliases: filesystem and paths point at fs, and hosts points at network". hosts is an overrule (the fallback reaches hooks at 2) — the very row PR docs(spec): state both roles of aliases, not only the gap it fills #17662 corrected in the source. RELEASE-OWNED: AGENTS.md prescribes amending a released entry in a dedicated docs-only PR, never as a rider on code changes.
  • packages/objectql/CHANGELOG.md — carries the latitude -> lat claim. RELEASE-OWNED, same remedy.

One more, true but worth knowing: packages/spec/src/data/field-value.zod.ts's second citation (zipCode -> postalCode, a genuine GAP) sits above a table whose postcode -> postalCode row is in the agrees bucket. The sentence is scoped to zipCode and is therefore true; it is noted because it is one edit away from being the same blanket error as the turso header.

Also noted: the whole class would be closed by a guard rather than by sweeps — an assertion that no comment attached to a strictObject options literal claims unreachability for a row that measures reachable. shared/alias-integrity.test.ts already forces every table and already computes what is needed. That is a new gate and a decision, not a rider on this PR.

Evidence

  • Ablation (one-off; the tree was restored and the restore proved): removing latitude: 'lat' from LocationValueSchema's table through scripts/ablation-replace.mjs — anchor hit 1 -> 0, blob ac90b42d814a -> 2610f8d9477b — turns the new pin red and prints the runtime refusal quoted in site 1 above. Restored: blob back to ac90b42d814a, equal to HEAD, git diff HEAD empty.
  • Tests: packages/spec 494 files / 14526 tests pass; packages/objectql 299 files / 5003 tests pass. All five new pins confirmed to have run by name.
  • Typecheck: pnpm --filter @objectstack/spec --filter @objectstack/objectql typecheck exit 0.
  • Gates: all 85 families derived by scripts/pm/dispatch-gates.mjs for this change set are accounted for — 83 exit 0, 2 NOT MEASURED (check:dual-build-cjs-loads, check:type-check-debt), both of which printed PREREQUISITE NOT MET — nothing was measured because they need a full-repo build. Those are CI's run; neither can be moved by a comment-and-test diff.
  • Lint: the repo-wide run, not a narrowing — pnpm lint exit 0 at f61417bb2d, 6878 files linted, 0 errors, 0 warnings, and all 7 edited source files verified present in the linted population.

What on the card turned out otherwise

  • Still present, not already fixed: all three cited sites were re-derived against origin/main before anything was written.
  • The card's census is an undercount for a named mechanical reason (the // wrap), and two of the hits it misses are carriers of the defect it is about.
  • The card's "roughly a dozen unclassified" re-derives to 17 hits, of which 7 are false — 3 the card names, 3 fixed here as the same claim, 4 reported above.
  • The card's own numbers have moved with the tree: its census read 384 surfaces / 1910 alias entries / 1658 gap / 211 agreeing / 41 overruling; the same sweep today reads 419 / 2139 / 1862 / 228 / 49. Lit control visibleWhen still classifies GAP in 4 tables; a fabricated alias token matches 0 rows.

Generated by Claude Code

…tations

`aliases` has two jobs, not one: filling a gap the distance fallback leaves
empty, and overruling a hit the fallback reaches and gets wrong. The lookup is
`aliases[aliasProbe(key)] ?? findClosestMatches(key, knownKeys, budget, 1)[0]`,
with the budget `Math.max(2, Math.floor(key.length / 3))`. Six citations denied
the second job, and three of them cited an example OF it as proof.

Measured against the real `findClosestMatches` and the shapes' own key lists:

  latitude  budget 2  lat 5 edits (out of reach)  altitude 2 edits -> OVERRULE
  longitude budget 3  lng 6 edits, nothing closer                  -> GAP
  postal_code budget 3  postalCode 1 edit                -> pure fallback hit
  uri       budget 2  url 1 edit                        -> reachable, agrees

Prose plus new pins; no alias, schema, key list, strictness, suggestion or
error message moves.

Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation protocol:data tests tooling labels Sep 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/objectql, @objectstack/spec, touching 2 documentable anchor(s). ⚠️ 2 changed file(s) yielded no anchor (packages/objectql/src/validation/record-validator.ts, packages/spec/src/data/default-value-shape.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/data-modeling/field-types.mdx (via LocationValueSchema (symbol, a top-level const))
  • content/docs/data-modeling/validation-rules.mdx (via LocationValueSchema (symbol, a top-level const))
  • content/docs/protocol/objectql/types.mdx (via LocationValueSchema (symbol, a top-level const))
What this run could not see
  • 2 changed file(s) yielded no anchor (packages/objectql/src/validation/record-validator.ts, packages/spec/src/data/default-value-shape.ts) — pages documenting those are invisible to this run
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 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.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 137 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 b7eaf6a617b7353825935631f73b5bdcf7b78f90 → packageMentionDocs.

Which tree this was computed on

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

node scripts/docs-audit/affected-docs.mjs --json b7eaf6a617b7353825935631f73b5bdcf7b78f90

⚠️ 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 b7eaf6a617b7353825935631f73b5bdcf7b78f90 → 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/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

finding: three edit distance cannot reach citations are measurably false — and ~12 more of the 19 occurrences are unclassified

2 participants