Skip to content

docs(fields): location.mdx teaches the deprecated { latitude, longitude } spelling as canonical — the spec's LocationValue is { lat, lng } (docs half of the #6272 A1 ruling) #6660

Description

@os-sales

Filed by the domain:ui execution seat (PM session session_01CRJge11jso9TpXRWFt1Z49) at the moment of dispatching #6272, because the 2026-08-28 A1 ruling explicitly split this half out and assigned the filing to this seat. Filed unlabelled beyond routing — domain:*, type and grading are triage's to produce. Suggested routing at the bottom.

⚠️ Dedup run before filing: #6127 is a different, closed defect on this same file (a fence welding a JSX element and a bare object literal so it parsed as neither ts nor tsx). No card covers the spelling.

What

content/docs/fields/location.mdx teaches the deprecated value spelling as though it were canonical, at :53, :101, :116 and :134-140 — including a tsx snippet whose useState is typed as { latitude, longitude }.

The contract says otherwise, measured against the pinned @objectstack/spec@17.2.0:

LocationValue = { lat: number; lng: number; altitude?: number; accuracy?: number }   // canonical
LocationCoordinates = { latitude, longitude, … }                                     // @deprecated

valueSchemaFor({ type: 'location' }) REJECTS { latitude, longitude } (invalid_type at [lat], [lng]) and ACCEPTS { lat, lng }.

⇒ Every author — human or AI — who follows this page writes a value the platform's own contract refuses. And because location is in STRUCTURED_JSON_TYPES, which is warn-first by default, that value is persisted with a one-time warning rather than rejected. So the page is not merely wrong; it is a live source of records in a spelling the platform has stated it will never convert (os migrate value-shapes: "This one converts nothing").

Why this is its own card

The A1 ruling made #6272's fix an atomic change — LocationField plus the three plugin-detail assertions that pin the old produce shape plus the two example schemas, all in one commit or CI is red. This page is not load-bearing for that flip and does not need to land atomically with it, so the ruling split it rather than widening a fence that was already one file too small.

Scope

  • content/docs/fields/location.mdx — stop teaching { latitude, longitude }; teach the spec's { lat, lng }.
  • ⚠️ The tsx snippet on that page is compiled by check:doc-snippets, so the change has to keep it compiling — this is a real deliverable with a gate behind it, not a prose edit.

⛔ Out of scope

Sequencing

Independent of #6272's PR, but it should not land before it: until the widget flips, the page would be describing a shape the shipped widget does not produce. Landing after is correct; landing alongside is fine.

Suggested routing (triage's call)

domain:ui (the page documents a published widget's authoring surface), documentation, type Task. The direction is already ruled — 2026-08-28, verbatim 「6272 A1 其他同意」 — so this needs no decision, only grading into the queue.

Refs: #6272 (the atomic half, dispatched) · #6154 (closed premise-void; carries the full spec measurement) · #6127 (the earlier, closed fence defect on this file).

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Aug 28, 2026
  2. os-sales commented on Aug 28, 2026

    @os-sales
    CollaboratorAuthor

    ⚠️ Scope correction — line 101 is ALREADY DONE by PR #6667, and this card's stated premise was measured false

    Filed by me (domain:ui @ objectui execution seat, PM session 8ca04858-ea8e-5b85-9182-de59aa49e00c) at #6272's dispatch. Correcting it before a dev reads it and walks into a trap I planted.

    What I got wrong

    I split this card off #6272 on the stated ground that the page "is not load-bearing for the flip and does not need to land atomically with it." That is false, and it was measured false rather than argued:

    content/docs/fields/location.mdx's tsx snippet is compiled by check:doc-snippets. Once LocationField's props carry the spec value type, the snippet's useState type parameter stops being assignable — TS2322 at location.mdx:102, quoted in PR #6667. The page is load-bearing in exactly the way the packages/plugin-detail assertions are, and for exactly the same reason.

    So one line of this card's surface has already moved, inside PR #6667:

    -  const [value, setValue] = useState<{ latitude: number; longitude: number } | null>(null);
    +  const [value, setValue] = useState<{ lat: number; lng: number } | null>(null);
    

    The dev took only what the gate forces, declared the increment rather than absorbing it silently, and left the rest of this card alone. That was the right call in both directions.

    What is still this card's work

    Untouched by #6667 and still owed here — all of it uncompiled prose, plaintext and jsonc, none of it load-bearing for any gate:

    • :53, :116, :134-140 and the surrounding prose, which still teach { latitude, longitude } as the canonical stored shape

    That teaching is the actual defect this card exists for: a published page instructing the next author — human or AI — to write the exact spelling valueSchemaFor({ type: 'location' }) rejects. It is the most plausible source of any deprecated-spelling data in the wild, which is what makes it worth its own card rather than a footnote.

    The trap this comment removes

    This card's own body says the tsx snippet "is compiled by check:doc-snippets, so the change has to keep it compiling." A dev reading that will go looking for a broken snippet, find one already fixed, and then either re-verify a premise that has moved under them or land a hunk that conflicts with #6667. Both cost a cycle for nothing.

    ⛔ Do not re-verify the compile-forced site. Re-verify the four prose sites on the merged ref — #6667 is in flight, so this card should not be dispatched until it lands (same file, serial constraint).

    The correction is recorded rather than edited into the body: the body's sentence was true when written about the page as a whole, and the record of which half moved and why is more useful to the next reader than a silently tidied premise.


    Generated by Claude Code

  3. self-assigned this
    on Aug 28, 2026
  4. os-sales commented on Aug 28, 2026

    @os-sales
    CollaboratorAuthor

    os-dev-report

    {
      "issue": 6660,
      "status": "done",
      "branch": "claude/issue-6660-location-docs-spec-spelling",
      "pr": "https://github.com/objectstack-ai/objectui/pull/6671",
      "premise_still_valid": true,
      "summary": "The scope-correction comment was read first and held: I did not go looking for a broken tsx snippet. content/docs/fields/location.mdx:101 already reads `{ lat: number; lng: number }` on my base (8631c32a = PR #6667's merge commit) and does not appear in my diff. The remaining defect was real and untouched: the page taught `{ latitude, longitude }` as the canonical stored shape in one plaintext data-format block, one jsonc comment, one plaintext validation block, and the surrounding prose — all uncompiled. I corrected those, replaced the now-false prose claim that 'no exported type declares that value shape' (it is `LocationValue` from `@objectstack/spec/data`) and dropped its link to the closed #6154, added a short note naming the deprecated spelling as rejected, and tied the geographic range names to the stored keys. Docs-only, one file, +20/-12; no packages/** and no content/docs/releases/**.",
      "tests": "All gates run on the final commit e7cf3680 (worktree clean), each exit code captured before any pipe, each verdict quoted from the gate's own output. check:doc-snippets EXIT=0 'Semantic phase: 267 of 267 block(s) judged, 0 failed.' / 'Every covered documentation snippet compiles against the built types.' — NOTE its first invocation 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 red measurement, so I ran the build it prescribes (turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2 → 32/32 successful) and re-ran it. check:doc-fences EXIT=0 'every TypeScript block in 223 document(s) is fenced ts/tsx/typescript … No unknown fence spelling hides one.' check:doc-types EXIT=0 'Every documented component type is registered.' check:control-bytes EXIT=0 'OK (scanned 5511 tracked text file(s); skipped 85 binary).' check:docs-route-closure EXIT=0 'gauge: 1349 modules crawled from 148 route roots (144 MDX), every specifier resolved'. scripts/check-doc-links.mjs EXIT=0 'Links are valid across 17 scan roots.' scripts/check-changeset-presence.mjs EXIT=0 'No source of a released package changed in this range, so no changeset is owed.' — the changeset question was ruled by the gate, not guessed; none is owed, and per this repo's rules I did NOT apply a skip-changeset label (it is a phantom here). doc-fences and doc-snippets are the ratchet family, so both were re-run on the final commit rather than only pre-commit. No ablation was performed: nothing in this change is a guard whose failure needed proving, so that field would be padding. The contract itself WAS measured directly rather than taken from the card — a probe run inside the package graph against the pinned @objectstack/spec: `{lat,lng}` ACCEPT; `{latitude,longitude}` REJECT invalid_type@[lat] invalid_type@[lng]; `{lat,lng,altitude,accuracy}` ACCEPT; `{lat:95,...}` REJECT too_big@[lat]; `{...,lng:200}` REJECT too_big@[lng]; `{lat}` alone REJECT invalid_type@[lng]. The last three also re-confirm the page's Validation range claims are true. An earlier run of that probe from the scratchpad returned MODULE_NOT_FOUND — a mis-aimed path, not a measurement — and was re-run from inside the worktree.",
      "mcp_calls": "5 — issue_read(get), issue_read(get_comments), create_pull_request, pull_request_read(get), add_issue_comment",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Census note for the seat

    Per-site, not as a total (a total is satisfied by one block hitting many times). grep -n "latitude:" on the page went 4 → 0. Sites changed: :53-54 plaintext, :116 jsonc comment, :134/:137/:140 plaintext, :40 prose, :41-42 prose, :63-64 prose. Sites deliberately kept: :101 tsx (already correct, gate-compiled, untouched), :3/:6 frontmatter and intro prose, :33 placeholder, :58 input format, :119 center tuple.

    The kept ones are the fence working. LocationField.tsx states it outright — "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." Rewriting the placeholder or the typed input format to lat, lng would have made the page wrong in the other direction. :119's center is a positional [lat, lng] tuple, not an object-key spelling. :116 did change because it describes what the map reads out of this field, and ObjectMap.tsx:437-438 reads location.lat / location.lng first.

    One deliberate survivor is new: the note I added names { latitude, longitude } in order to forbid it. Flagging it so a future spelling census does not count a prohibition as an instance of the thing prohibited.

    Other pages: a measured zero, not an unchecked one

    grep -rn "latitude:" content/docs/ with grep -rn "lat:" content/docs/ as the positive control in the same query shape (control returns location.mdx:101 plus nine plugin-map.mdx hits, so the shape finds what it looks 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 showing a record with separate latitude / longitude columns, the map plugin's latitudeField / longitudeField mode, whose defaults are literally 'latitude' / 'longitude' (ObjectMap.tsx:403-404). That page's ### Object Format section already teaches location: { lat, lng }. So: nothing to fold in, nothing owed to a new card — no findings filed, because none were found.

    GeolocationField was never in reach: the page does not document it.

    For your review queue

    Gate status at report time is in_progress — CI convergence is yours, not mine. The PR is draft and the card asks it not land before #6272's flip; #6667 is already merged and this branch is cut from it, so that constraint is satisfied.

    Generated by Claude Code


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions