Skip to content

docs(fields): teach the spec's { lat, lng } as the stored location value - #6671

Merged
os-sales merged 1 commit into
mainfrom
claude/issue-6660-location-docs-spec-spelling
Aug 28, 2026
Merged

docs(fields): teach the spec's { lat, lng } as the stored location value#6671
os-sales merged 1 commit into
mainfrom
claude/issue-6660-location-docs-spec-spelling

Conversation

@os-sales

Copy link
Copy Markdown
Collaborator

Fixes #6660

content/docs/fields/location.mdx taught the deprecated { latitude, longitude }
spelling as the canonical stored shape of a type: 'location' value. The contract,
measured on this branch against the pinned @objectstack/spec:

{ lat: 37.7749, lng: -122.4194 }             ACCEPT
{ latitude: 37.7749, longitude: -122.4194 }  REJECT  invalid_type@[lat] invalid_type@[lng]
{ lat: 1, lng: 2, altitude: 10, accuracy: 5 } ACCEPT
{ lat: 95, lng: -122.4194 }                  REJECT  too_big@[lat]
{ lat: 37.7749, lng: 200 }                   REJECT  too_big@[lng]
{ lat: 37.7749 }                             REJECT  invalid_type@[lng]

A published page instructing the next author — human or AI — to write the exact
spelling the platform's own contract refuses is the most plausible source of
deprecated-spelling data in the wild. That is what this PR closes.

The last two probe rows also re-confirm the page's ## Validation section is
telling the truth: the range claims are really enforced (too_big), so only the
key spelling in that block needed to move.

Per-site census

Every occurrence on the page, with the block it sits in and whether a gate reads
that block. Line numbers are on this PR's base (8631c32a), re-located on that ref
rather than taken from the card, whose numbers predate PR #6667.

Site Block Gate reads it? Before After
:53-54 plaintext no latitude: / longitude: changed to lat: / lng:
:116 jsonc comment no read as { latitude, longitude } changed to read as { lat, lng }
:134, :137, :140 plaintext no { latitude: …, longitude: … } x3 changed to { lat: …, lng: … } x3
:40 prose no "an object carrying a latitude and a longitude" changed to lat / lng
:41-42 prose no "No exported type declares that value shape today" + link to #6154 changed — the claim is now false; names LocationValue from @objectstack/spec/data
:63-64 prose no "Latitude: -90 to 90" changed to "Latitude (lat)" — ties the geographic name to the stored key
:101 tsx yescheck:doc-snippets already { lat: number; lng: number } untouched by me
:3, :6 frontmatter / prose no "latitude and longitude" kept — the geographic quantities, not key names
:33 ts yes placeholder: 'latitude, longitude' kept — see fence below
:58 prose no "Input format: latitude, longitude" kept, clarified
:119 jsonc comment no center as [latitude, longitude] kept — a positional tuple, not an object-key spelling

After the change, grep -n "latitude:" content/docs/fields/location.mdx returns
0 hits (before: 4). The surviving latitude/longitude words are the six
deliberate ones above, plus one new mention inside the note that forbids the
spelling — named in order to be ruled out, not taught.

:101 was already correct — and I did not touch it

PR #6667 moved that one line because it is the only site on the page any gate
compiles: check:doc-snippets collects ts/tsx/typescript fences
(TS_FENCE_LANGUAGES, scripts/check-doc-snippet-types.mjs:317) and the widget's
new prop type made the old useState type argument stop being assignable. It reads
{ lat: number; lng: number } on this PR's base and it does not appear in this
PR's diff.

That gate boundary is also the whole explanation for why this card exists: the
compiled block was forced correct by CI, and the plaintext, jsonc and prose
around it — which no gate compiles — kept teaching the opposite.

Fence: geolocation and the geographic wording are deliberately untouched

GeolocationField / type: 'geolocation' is out of scope: geolocation is not a
member of the spec's closed FieldType union and its value schema accepts both
spellings, so it legitimately keeps { latitude, longitude }. This page does not
document it, so nothing was changed on that account.

Separately, the page keeps saying "latitude, longitude" wherever it means the
geographic quantities rather than the stored keys — the placeholder, the input
format, and the center tuple. That is not an oversight; it is what the merged
implementation says, in packages/fields/src/widgets/LocationField.tsx:

The coordinates are still called latitude and longitude to a human — only the
STORED key names are the spec's, which is why the placeholder is unchanged.

The widget parses a comma-separated latitude-then-longitude string and stores
onChange({ lat, lng }). Rewriting the placeholder or the input format to
lat, lng would make the page wrong in the other direction, so the note at :58
now states that split explicitly instead.

:119's center is likewise a positional [lat, lng] tuple, not an object —
ObjectMap.listViewMapConfigReach.test.tsx:170 pins it as "center is [lat, lng]
(ObjectMapConfigSchema's own description)", i.e. latitude first. The doc comment
already describes that ordering correctly.

:116 did change, because it describes what the map reads out of this page's
field
: ObjectMap.tsx:437-438 reads location.lat / location.lng first
(const lat = location.lat || location.latitude;), so { lat, lng } is the
canonical answer there.

Other pages teaching the same spelling: none found

Checked content/docs/** for the deprecated spelling as an object key
(grep -rn "latitude:" content/docs/), with grep -rn "lat:" content/docs/ as the
positive control in the same query shape — the control returns hits on
location.mdx:101 and nine plugin-map.mdx sites, so the query shape does find
what it is looking for.

The only hit outside this card's file is content/docs/plugins/plugin-map.mdx:414,
and it is correct as written: it sits under ### Separate Fields and shows a
record with separate latitude / longitude columns, which is the map plugin's
latitudeField / longitudeField mode — those are real config keys whose defaults
are literally 'latitude' / 'longitude' (ObjectMap.tsx:403-404). That same page's
### Object Format section already teaches location: { lat, lng }.

content/docs/plugins/index.md:200 is the prose bullet "Latitude/longitude support".

So: nothing folded in, and nothing owed to another card on this repo's docs.
(The framework-side docs defect is recorded separately as objectstack#12935 — other
repo, other seat.)

Gates

Run on the final commit e7cf3680; exit codes captured before any pipe, verdict
lines quoted from each gate's own output.

Gate Exit Verdict line
check:doc-snippets 0 Semantic phase: 267 of 267 block(s) judged, 0 failed. / Every covered documentation snippet compiles against the built types.
check:doc-fences 0 ✅ check:doc-fences — every TypeScript block in 223 document(s) is fenced ts/tsx/typescript … No unknown fence spelling hides one.
check:doc-types 0 ✅ Every documented component type is registered.
check:control-bytes 0 ✅ check-control-bytes: OK (scanned 5511 tracked text file(s); skipped 85 binary).
check:docs-route-closure 0 ✅ gauge: 1349 modules crawled from 148 route roots (144 MDX), every specifier resolved …
scripts/check-doc-links.mjs 0 Links are valid across 17 scan roots.
scripts/check-changeset-presence.mjs 0 ✅ No source of a released package changed in this range, so no changeset is owed.

check:doc-snippets first returned exit 2, PRECONDITION NOT MET (exit 2) — The snippet program was NOT run. That is the gate's own "I could not run", not a
finding, so it is not reported as a red measurement: the packages it resolves
against were unbuilt in a fresh worktree. I ran the build the gate itself prescribes
(turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2, 32/32 successful) and re-ran it for the exit 0 above.

check:doc-fences and check:doc-snippets are the ratchet-family gates here, so
both were re-run on the final commit rather than only pre-commit; the working tree
was clean at that point.

Changeset

None owed — ruled by the gate, not guessed:

Compared the working tree with 8631c32ad (merge-base with origin/main): 1 file(s)
changed, 0 of them published source of a package the release covers, 0 under a
package changesets ignores, 0 changeset(s) added.
✅  No source of a released package changed in this range, so no changeset is owed.

Sequencing

The card asks that this not land before #6272's widget flip. PR #6667 is already
merged (this branch is cut from it, 8631c32a), so the page now describes the
shape the shipped widget actually produces.

Docs-only: no packages/** source, no content/docs/releases/**.

Generated by Claude Code


Generated by Claude Code

…value

`content/docs/fields/location.mdx` taught the deprecated `{ latitude,
longitude }` spelling as the canonical stored shape in its prose, `plaintext`
and `jsonc` blocks -- none of which any gate compiles, which is why the
spelling survived there after the compiled `tsx` snippet was corrected.

`valueSchemaFor({ type: 'location' })` REJECTS that spelling (`invalid_type`
at `[lat]` and `[lng]`) and accepts `{ lat, lng, altitude?, accuracy? }`, so
the page was instructing the next author -- human or AI -- to write a value
the platform's own contract refuses.

Geographic wording is deliberately kept: the input format, the placeholder and
the `center` tuple all still read "latitude, longitude" because only the
STORED key names are the spec's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
@os-sales
os-sales marked this pull request as ready for review August 28, 2026 12:15
@os-sales
os-sales added this pull request to the merge queue Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

✅ ACCEPT — flipped ready, auto-merge on

Reviewer: domain:ui @ objectui execution seat, PM session 8ca04858-ea8e-5b85-9182-de59aa49e00c.

Gate reading, stated precisely — this PR's check population is 25, not the usual 29

All 25 check runs read and the returned count compared against total_count: 25, so nothing is truncated out of view: 22 success, 3 skipped, 0 failing, 0 still running.

⚠️ Four checks that ran on this round's sibling PRs are absent here: Bundle Analysis, Changeset Bump Policy, Changeset Overwrite Report, Live E2E (informational). Absent is not green and it is not red — it means those workflows did not trigger.

The coherent explanation is that this is a docs-only diff (one file, +20/-12, no packages/**) and the changeset gate ruled that no changeset is owed — so the two changeset-conditional jobs have nothing to inspect and the two build-dependent jobs have no package source to weigh. ⚠️ That is an inference, not a measurement, and it is recorded as one. The mechanical check on it is the merge queue itself: a genuinely missing required check makes the queue refuse the PR, which is a stronger guarantee than my reasoning about workflow triggers.

What the dev did that this seat asked for, and did not do what it warned against

The scope-correction comment on #6660 existed to remove a trap this seat planted: the card's body still described a broken tsx snippet at :101 that PR #6667 had already fixed. The dev read the comment first and did not go looking for it. location.mdx:101 already reads { lat: number; lng: number } on the base (8631c32a, #6667's merge commit) and does not appear in this diff. That is the trap not being paid for.

The remaining defect was real and is what got fixed: the page taught { latitude, longitude } as the canonical stored shape in a plaintext data-format block, a jsonc comment, a plaintext validation block and the surrounding prose — none of it compiled by any gate, all of it instructing the next author, human or AI, to write the spelling valueSchemaFor({ type: 'location' }) rejects.

⭐ A second defect found and fixed that the card did not name

The page claimed "no exported type declares that value shape." That claim is now false — it is LocationValue, exported from @objectstack/spec/data — and its link pointed at #6154, which is closed. Correcting a page about a stale spelling while leaving a stale claim beside it would have been a half-fix. It was found by reading rather than by following the card.

The contract was measured, not quoted

Rather than taking the shape from the card, a probe ran inside the package graph against the pinned @objectstack/spec:

value verdict
{lat,lng} ACCEPT
{latitude,longitude} REJECT — invalid_type at [lat], [lng]
{lat,lng,altitude,accuracy} ACCEPT
{lat:95,…} REJECT — too_big at [lat]
{…,lng:200} REJECT — too_big at [lng]
{lat} alone REJECT — invalid_type at [lng]

The last three do double duty: they re-confirm the page's own Validation range claims are true, which a docs fix could easily have left unchecked.

Two process readings I am ratifying

  • check:doc-snippets first returned EXIT=2 PRECONDITION NOT MET — The snippet program was NOT run. That was handled as the gate's own "I could not run", not as a red: the prescribed build was run (32/32 successful) and the gate re-run to EXIT=0, 267 of 267 block(s) judged, 0 failed. That is the NOT-MEASURED discipline applied correctly rather than recited.
  • No ablation, with a stated reason: nothing in this change is a guard whose failure needed proving, so the field would have been padding. Declining ceremony that would prove nothing is the right call — an ablation on a prose edit measures the ablation, not the edit.
  • An earlier probe returned MODULE_NOT_FOUND and was reported as "a mis-aimed path, not a measurement", then re-run from inside the worktree. Fourth instance of that class this rotation, and the first one caught before it reached a conclusion.

The changeset question was ruled by the gate (No source of a released package changed in this range, so no changeset is owed) rather than guessed, and no phantom skip-changeset label was applied.


Generated by Claude Code

Merged via the queue into main with commit ece6888 Aug 28, 2026
26 checks passed
@os-sales
os-sales deleted the claude/issue-6660-location-docs-spec-spelling branch August 28, 2026 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant