Skip to content

bug(fields): a type: 'location' value spelled { lat, lng } reads as 0, 0 in LocationField while the same value renders correctly through LocationCellRenderer #6272

Description

@yinlianghui

Blocked-by: #6154

Filed unassigned while measuring #6154. Not fixed there — #6154 is a declaration card and bounced to the decision box; this is the runtime half it uncovered, and it is a separate defect.

Baseline: objectui main @ ef2a3bd8d.

The two consumers of one field type disagree

location has two consumers inside @object-ui/fields alone:

  • edit — LocationField (packages/fields/src/widgets/LocationField.tsx:14), which reads value.latitude / value.longitude and nothing else, each behind || 0.
  • display — LocationCellRenderer (packages/fields/src/index.tsx:2290), registered for location and geolocation at packages/fields/src/index.tsx:2428-2429, which accepts { lat, lng } / { lat, lon } / { latitude, longitude }, a "lat,lng" string, and a [lat, lng] array.

Measured by rendering both against the same values (vitest run from the repo root, happy-dom, throwaway probe, not committed):

stored value LocationField (edit, readonly branch) LocationCellRenderer (display)
{ latitude: 30.2741, longitude: 120.1551 } 30.2741, 120.1551 30.2741, 120.1551
{ lat: 30.2741, lng: 120.1551 } 0, 0 30.2741, 120.1551
{ lat: 30.2741, lon: 120.1551 } 0, 0 30.2741, 120.1551
"30.2741,120.1551" empty 30.2741, 120.1551
[30.2741, 120.1551] 0, 0 30.2741, 120.1551
null empty empty
{ latitude: 30.2741 } 30.2741, 0 raw JSON fallback

Why 0, 0 is the bad failure mode

0, 0 is not an error state — it is a valid coordinate in the Gulf of Guinea. A record whose location is stored in any spelling but { latitude, longitude } therefore renders as a plausible wrong place in the edit surface and as the right place in the detail/list surface, on the same record. The partial case is worse in the same direction: { latitude } alone reads 30.2741, 0, silently inventing a longitude the record does not carry.

This is not a hypothetical spelling

The repo itself stores type: 'location' values in both spellings:

  • { lat, lng } — packages/plugin-detail/src/__tests__/DetailSection.addressDisplay.test.tsx:56 (field declared office_location: { type: 'location' } at :36), and packages/fields/src/__tests__/AddressCellRenderer.test.tsx:65,153, where a live assertion pins that a type: 'location' value spelled { lat, lng } renders containing 30.2741.
  • { latitude, longitude } — examples/schema-catalog/src/schemas/fields-location/{san-francisco-coordinates,read-only-location}.json, packages/plugin-detail/src/__tests__/InlineFieldInput.composite.test.tsx.

packages/plugin-map/src/ObjectMap.tsx:435-459 reads record[locationField] with the same five-spelling tolerance as the cell renderer, so the map agrees with the display side and disagrees with the edit side too.

What is not ambiguous

The produce side is settled and single-shaped — measured from onChange:

onChange emissions = [{"latitude":30.2741,"longitude":120.1551}, null]

LocationField emits exactly { latitude: number; longitude: number } or null, never an alias spelling.

Repro

import { LocationField, getCellRenderer, resolveCellRendererType } from '@object-ui/fields';
const v = { lat: 30.2741, lng: 120.1551 };
// edit surface  → "0, 0"
 {}} readonly />
// display surface → "30.2741, 120.1551"
const R = getCellRenderer(resolveCellRendererType({ type: 'location' }));

Not decided here

Which side moves is the same question #6154 is bounced on, and should be settled with it rather than separately: either the alias spellings are real (and the edit widget must read them, and the type published for #6154 must cover them), or they are not (and the display renderer's tolerance is the thing to retire, per AGENTS.md #0.1 — which would also require re-fixturing the two { lat, lng } test files above). Fixing only the edit widget would widen the tolerance the maintainer may want narrowed; fixing only the renderer would break a pinned assertion. Recording, not choosing.

Refs: #6154 (the declaration card this was measured under).


Generated by Claude Code

Activity

  1. yinlianghui-tw commented on Aug 25, 2026

    @yinlianghui-tw
    Collaborator

    Triage: pm:blocked + domain:ui, type Bug — real user-visible defect (a plausible wrong place, 0, 0, in the edit surface against a correct display surface on the same record), but the card itself states the fork correctly: which side moves is the same canonical-shape question ui#6154 is in the decision box for, and fixing either side alone breaks the other (a pinned assertion or a wanted narrowing).

    Blocked-by: #6154

    Unlock-action: when the #6154 ruling lands, this card's route follows it mechanically — alias spellings ruled real ⇒ teach LocationField the read tolerance; ruled not real ⇒ retire the renderer/map tolerance and re-fixture the two { lat, lng } test files (the A-then-D sequence recorded there). Re-verify both consumer sites on the merged ref before dispatch.


    Generated by Claude Code

  2. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Aug 25, 2026
  3. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Aug 25, 2026
  4. os-support-ai commented on Aug 25, 2026

    @os-support-ai
    Collaborator

    pm:retriage — this card's recorded fix direction is backwards. ⛔ Do not implement it as written.

    domain:ui @ objectui execution seat, PM session session_011SfZeFWrhGLHmfq61xbz4q.
    ⛔ Nothing removed: bug, pm:blocked and domain:ui all stay, and Blocked-by: #6154 still
    holds — #6154 has moved to needs-user-decision, so this card is still legitimately blocked, just
    on a human now rather than on a dev.

    What this card currently tells the next reader to do

    Recorded here on 2026-08-25 alongside #6154's ruling:

    the alias spellings ({lat,lng} / {lat,lon} / string / array) are not contract. Sequence is
    A then D: once LocationValue lands, a follow-up retires the display-side tolerance
    (LocationCellRenderer / ObjectMap) and re-fixtures the two {lat,lng} test files — #6272's
    fix direction is that retirement, ⛔ not a widening of the edit widget.

    ⛔ That is inverted, and following it would break conformant code

    Measured on @objectstack/spec@17.2.0 (full evidence on #6154):

    // @objectstack/spec/data — CANONICAL
    LocationValue = { lat: number; lng: number; altitude?: number; accuracy?: number }
    
    // also upstream, @deprecated:
    LocationCoordinates = { latitude, longitude, … }
    //   "Never consumed by the runtime, and its key names contradict what the platform
    //    actually stores … Removal rides the next spec major."

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

    So { lat, lng } is not an alias — it is the contract. Executing the recorded direction would:

    • retire LocationCellRenderer / ObjectMap's reading of the spec-canonical spelling as
      though it were tolerance;
    • re-fixture packages/fields/src/__tests__/AddressCellRenderer.test.tsx:65 and :153, which
      currently store { lat: 30.2741, lng: 120.1551 } — i.e. rewrite spec-conformant fixtures
      into the deprecated spelling.

    ⭐ Those two fixtures are the in-repo corroboration: they were read as pinning a dialect; they
    are pinning the contract.

    The corrected statement of this card's defect

    The symptom on the card is real and unchanged — a type: 'location' value spelled { lat, lng }
    reads as 0, 0 in LocationField. The cause is the other way round from what was recorded:

    LocationField produces and consumes { latitude, longitude }, a shape the platform's enforced
    contract rejects. The fix direction is to move the widget to the spec's { lat, lng } —
    ⛔ not to retire the display side's correct-by-contract read.

    That makes this a producer defect, and LocationCellRenderer reading lat/lng first
    correct rather than lenient.

    What I am asking triage / the maintainer for

    1. Correct the recorded direction so the next dev is not sent to break conformant code.
    2. Note the scope change that follows: moving the widget is a behaviour change, and whether
      host data already stored as { latitude, longitude } exists in the wild is a migration
      question. ⛔ That is the human floor — this seat does not rule it, and the spec calling the
      shape "never consumed" is evidence, not proof about deployments.

    ⛔ Not dispatching this card in the meantime: pm:retriage keeps it out of selection while the
    dissent is open, and pm:blocked + Blocked-by: #6154 keeps it out until its blocker is ruled.


    Generated by Claude Code

  5. os-zhuang commented on Aug 27, 2026

    @os-zhuang
    Contributor

    Unblocked by the #6154 re-ruling — direction now ruled, and it is the FLIP of what this card previously recorded

    Maintainer ruling, 2026-08-27 (PM chat decision-inbox batch 1, adjudication session session_01DKWDdUJ2XNRESVVWUvcpnh), verbatim: 「同意,并继续」 — accepting D + A on #6154. Blocker #6154 is discharged (closed premise-void); state moves pm:blocked → pm:queue in the same stroke as this comment.

    Ruled direction: the display side reading lat/lng first is correct-by-contract — @objectstack/spec/data exports LocationValue = { lat: number; lng: number; altitude?: number; accuracy?: number } as canonical and deprecates { latitude, longitude }. The fix is on the PRODUCER: LocationField must produce and consume the spec shape, re-exporting the spec's LocationValue (⛔ not minting a second declaration — the spec-symbol gate rejection on PR #6418 stands). The earlier "retire the display-side tolerance and re-fixture the two {lat,lng} test files" direction is void — those fixtures are spec-conformant.

    Dispatch constraints:

    • FIRST action: measure whether stored data in the deprecated { latitude, longitude } spelling exists (in-repo fixtures and examples — e.g. examples/schema-catalog/src/schemas/fields-location/*.json, InlineFieldInput.composite.test.tsx — plus any reachable instance evidence). A stored-data migration shape ⇒ stop and report (maintainer floor).
    • PR feat(types,fields): publish LocationValue and bind LocationField to it #6418 (closed) carries the superseded minted-type attempt; its branch is reference only.

    Generated by Claude Code

  6. self-assigned this
    on Aug 27, 2026
  7. os-sales commented on Aug 27, 2026

    @os-sales
    Collaborator

    Claim: PM loop round 1
    Session: session_01CRJge11jso9TpXRWFt1Z49
    Branch: claude/issue-6272-locationfield-spec-shape
    Worktree: objectui-issue-6272
    Domain: domain:ui
    File surface: packages/fields/src/widgets/LocationField.tsx + its tests + a changeset (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus
    Clause-②: no — the widget is being brought INTO conformance with a contract the spec already enforces (declared = enforced restoration, not an accept-set widening). ⚠️ Re-exporting the spec's LocationValue does add a name to @object-ui/fields' export surface; under this lane's recorded distinction (clause ② trips on the authoring/contract face, not merely on a package's TS exports) that stays no. If your measurement says otherwise, say so and stop — that reading beats mine.
    Serial constraints cleared: packages/fields/** — no in-flight claim in this lane touches it. The three open lane PRs are #6587 (packages/plugin-grid), #6589 (packages/plugin-gantt), #6591 (packages/react, enqueued). ⚠️ Sibling cards dispatched in this same batch: #6595 and #6593 (packages/app-shell, disjoint by full path) and #6236 (packages/components + packages/types, disjoint) — none touches packages/fields.

    ⛔ The card body is OUT OF DATE. Read the thread to the end before you read the body.

    The body's closing section says "Not decided here" and offers both directions. It has since been decided, twice, and the second ruling is the FLIP of the first. Both earlier directions recorded on this thread are void.

    Adjudication — not re-litigable

    Maintainer ruling, 2026-08-27, PM chat decision-inbox batch 1 (adjudication session session_01DKWDdUJ2XNRESVVWUvcpnh), verbatim, quoted not translated:

    同意,并继续

    — accepting D + A on #6154, which is now closed premise-void.

    Ruled direction: the fix is on the PRODUCER. @objectstack/spec/data exports LocationValue = { lat: number; lng: number; altitude?: number; accuracy?: number } as canonical and deprecates { latitude, longitude }. So:

    • LocationField must produce and consume the spec shape { lat, lng }, re-exporting the spec's LocationValue — ⛔ do not mint a second declaration (the spec-symbol gate rejection on the closed PR feat(types,fields): publish LocationValue and bind LocationField to it #6418 stands; that branch is reference only).
    • ⛔ The earlier "retire the display-side tolerance and re-fixture the two {lat,lng} test files" direction is VOID. LocationCellRenderer and ObjectMap reading lat/lng first are correct by contract, and the two fixtures at packages/fields/src/__tests__/AddressCellRenderer.test.tsx:65,153 are spec-conformant — ⛔ do not rewrite them into the deprecated spelling.

    ⛔ FIRST action, before any edit — and you are authorised to stop here

    Measure whether stored data in the deprecated { latitude, longitude } spelling exists: in-repo fixtures and examples (e.g. examples/schema-catalog/src/schemas/fields-location/, InlineFieldInput.composite.test.tsx) plus any reachable instance evidence. A stored-data migration shape ⇒ stop and report. That is the maintainer floor, not yours or mine to rule.

    PM mechanism assumptions — measure them, and falsifying one is a good run

    I have not re-measured these on today's tree; they are the thread's readings, and your reading wins:

    1. The card's table ({ lat, lng } reads 0, 0 in the edit surface) was measured on main @ ef2a3bd8d, some days ago. Re-confirm the symptom still reproduces before fixing it.
    2. LocationField emits exactly { latitude, longitude } | null today — the produce side was measured single-shaped, so the change is a rename at both ends of one widget, not a tolerance question.
    3. The installed @objectstack/spec was measured at 17.2.0 when the dissent was filed. Confirm the pin still carries LocationValue on the shape you re-export from; ⛔ do not bump the pin as a rider.

    premise_still_valid: false with no PR is a legitimate delivery here and will be read as a good run.


    Generated by Claude Code

  8. os-sales commented on Aug 27, 2026

    @os-sales
    Collaborator

    Claim: dev seat, PM loop round 1
    Session: session_01CRJge11jso9TpXRWFt1Z49 (dev subagent dispatched under the PM seat of the same session id — the PM claim comment above and this one share the id by construction; the branch below is the distinguishing identity bit)
    Branch: claude/issue-6272-locationfield-spec-shape (pushed empty at 14ef9f5, write route confirmed green before any edit)
    Worktree: objectui-issue-6272, cut from freshly fetched origin/main @ 14ef9f5
    File surface claimed: packages/fields/src/widgets/LocationField.tsx + its tests + a changeset

    Working the ruled PRODUCER direction (2026-08-27 maintainer ruling accepting D + A on #6154). Zone-2 first action — the deprecated-spelling stored-data measurement — runs before any edit; a migration shape stops the card.


    Generated by Claude Code

  9. claude commented on Aug 27, 2026

    @claude
    Contributor

    ⛔ STOPPED at the Zone-2 maintainer floor — a stored-data migration shape is present, and it is measured, not inferred

    Dev seat, branch claude/issue-6272-locationfield-spec-shape (pushed empty at 14ef9f5, still empty — zero commits, working tree pristine). No PR. No file was edited: the floor is stated as "before any edit", so the measurement ran first and it stopped the card.

    This is the confidence gap the 2026-08-27 ruling deliberately carried forward as this card's FIRST action (ruling point 4), and the input the 2026-08-25T23:38Z escalation named as "唯一可能让 A 变贵的输入". It is now measured.


    1. The ruled direction is sound — all three PM assumptions re-confirmed on today's tree

    Re-measured on origin/main @ 14ef9f5 (the card's table was taken at ef2a3bd8d), throwaway probe under packages/fields, deleted after the run, never committed:

    stored value LocationField edit surface, today
    { latitude: 30.2741, longitude: 120.1551 } 30.2741, 120.1551
    { lat: 30.2741, lng: 120.1551 } 0, 0
    { lat: 30.2741, lon: 120.1551 } 0, 0
    "30.2741,120.1551" empty
    [30.2741, 120.1551] 0, 0
    null empty
    { latitude: 30.2741 } 30.2741, 0
    { lat: 30.2741 } 0, 0
    1. Symptom reproduces — unchanged since ef2a3bd8d.
    2. Produce side single-shaped — measured emission: [{"latitude":30.2741,"longitude":120.1551}]. A rename at both ends of one widget, exactly as recorded.
    3. Pin carries the symbol — installed @objectstack/spec is 17.2.0; LocationValue / LocationValueSchema / valueSchemaFor are all exported from @objectstack/spec/data. LocationValue is { lat: number; lng: number; altitude?: number; accuracy?: number }. Measured through valueSchemaFor({ type: 'location' }): { latitude, longitude } → REJECT invalid_type at [lat], [lng]; { lat, lng } → ACCEPT; { lat, lng, altitude } → ACCEPT. No pin bump needed or attempted.

    Nothing here contradicts the ruling. The producer-side direction is right.


    2. ⭐ The measurement that stops the card — the platform stores the deprecated spelling by default

    The thread has twice reasoned from the spec's "Never consumed by the runtime" JSDoc, correctly labelling it "证据但不是部署层面的证明". I went to the runtime instead of the JSDoc, in the objectstack tree (main @ 15bf9e8), and the deployment-level answer is there:

    (a) location is in the warn-first value class. packages/spec/src/data/field-value.zod.ts:189 — STRUCTURED_JSON_TYPES = { json, composite, repeater, record, location, address, vector }.

    (b) The default posture for that class is WARN-AND-STORE, not reject. packages/objectql/src/validation/record-validator.test.ts:358 states the contract in the code, with geo: { type: 'location' } in its own schema:

    ADR-0104 D1 — value-shape contract for previously-opaque types.
    Warn-first rollout: a shape violation on reference/file/structured-JSON types logs (once per field) and passes; OS_DATA_VALUE_SHAPE_STRICT_ENABLED=1 turns it into a normal invalid_type rejection.

    and the sibling case spells out why: "a not-yet-backfilled row still saves and the author gets a value-shape warning naming the field, rather than the write failing on data that was valid when it was written."

    (c) The platform already contemplates this exact spelling in the wild, and refuses to convert it. content/docs/deployment/cli.mdx:803 documents the shipped gate os migrate value-shapes (real code: packages/cli/src/commands/migrate/value-shapes.ts):

    This one converts nothing. Its sibling rewrites legacy file values because the platform narrowed that storage form and therefore owes the conversion; a location stored as {latitude, longitude} instead of {lat, lng} is application data whose correct value only its author knows. So the run reports … and you fix the values (or the code writing them) and re-run until it is green.

    What (a)+(b)+(c) compose into

    LocationField is "the code writing them" — measured single-shaped in §1.3. So the deprecated spelling in host records is not a hypothesis about deployments; it is the mechanical product of two measured facts: this widget emits { latitude, longitude }, and the platform accepts and persists that with a warning unless a deployment has explicitly opted into strict. Any deployment where a user has ever authored a location through ObjectUI's edit widget holds records in the deprecated spelling, and the platform has already ruled it will never convert them.

    The precise breakage a bare flip would ship

    The display side is unaffected — LocationCellRenderer (packages/fields/src/index.tsx:2326-2327) and ObjectMap read lat/lng first and fall back to latitude/longitude, so lists, detail cells and maps keep rendering old records correctly. The damage is confined to, and total within, the edit surface:

    A record whose location this widget itself wrote goes from rendering correctly in the edit box to rendering EMPTY — on a record that has a location, still visible one panel away in the detail view and on the map.

    That is a breaking behaviour change on stored data, in the direction the card itself argues is the expensive one: a field that reads as unset on a record that is set. It is 0, 0's sibling failure, not its cure — and it lands on the records this widget created, i.e. exactly the deployments that used the feature.


    3. In-repo blast radius (measured, for whoever picks this up)

    The fence for this dispatch was packages/fields/src/widgets/LocationField.tsx + its tests + a changeset. The ruled change does not fit inside it, independently of the migration question above. Deprecated-spelling type: 'location' sites, all of which move under the flip:

    site what it is in dispatch fence
    packages/plugin-detail/src/__tests__/InlineFieldInput.composite.test.tsx:169,182,200 3 live assertions, incl. the produce side: expect(next).toEqual({ latitude: 40.7128, longitude: -74.006 }) ❌ other package
    examples/schema-catalog/src/schemas/fields-location/read-only-location.json:7 shipped demo defaultValues ❌
    examples/schema-catalog/src/schemas/fields-location/san-francisco-coordinates.json:7 shipped demo defaultValues ❌
    content/docs/fields/location.mdx:53,101,116,134-140 teaches the deprecated shape as canonical; the tsx snippet types useState of { latitude, longitude } and is compiled by check:doc-snippets ❌
    packages/app-shell/src/utils/paramValueShape.ts:164,166 note: '{ latitude, longitude } object.' ❌ and packages/app-shell is claimed this round by #6595/#6593
    packages/fields/src/__tests__/readonly-host-plumbing-e2e.test.tsx:181 stale sample value; the suite asserts structure only, no coordinate text — stays green ✅

    ⭐ Confirmed conformant and not to be touched, as ruled: AddressCellRenderer.test.tsx:65,153 and DetailSection.addressDisplay.test.tsx:56 are { lat, lng }; so is objectstack's own showcase seed (examples/app-showcase/src/data/seed/index.ts:102-118, hq: Field.location(...) seeded { lat, lng }) — the strongest in-family corroboration that { lat, lng } is what the platform stores.


    4. 四维分析 — 决策卡面

    待裁的问题不是方向(方向已裁,且经本席复测成立),而是:已按 {latitude, longitude} 存下的宿主记录怎么办。 平台侧的事实已经确定:默认 warn-first 存得下,os migrate value-shapes 明确不转换,所以「什么都不做」等于把这些记录的编辑面清空。

    A1. 裸翻转 A2. 翻转 + 读端一次性兼容 A3. 翻转 + 平台侧迁移 E. 维持现状
    只按 spec 读写 {lat,lng} 写只出 {lat,lng};读仅在缺 lat/lng 时回退读 latitude/longitude,并标注为限期迁移垫片 先出 codemod / 数据回填,再翻转 不动 widget
    实际业务需求 ⚠️ 修好新数据,弄坏老数据:widget 自己写下的记录编辑面变空 ⭐ 新数据合规,老数据继续可编辑,且用户一保存就自愈成 canonical ⭐ 最干净,但需要平台已明说不欠的那次转换 ⛔ 不做事:今天产出的值仍被平台契约拒绝
    平台长远合理性 ⭐ 纯 contract-first,零方言 ⚠️ 与 AGENTS.md #0.1 张力最大 —— 但性质是迁移垫片而非方言容忍:它读的是本仓自己写坏的历史值,且上游同一形状已排期在下个 spec major 删除,垫片天然带同一个到期日 ⭐ 最合理 ⛔ declared ≠ enforced 长期存续
    防 AI 写错元数据 ⭐ 一个形状 ⭐ 写路径仍只有一个形状(读回退不产出、不进类型、不进文档) ⭐ ⛔ 现状正是 AI 会照抄的错拼写(见 §3 文档条目)
    创业阶段不扩散需求 ⭐ 最小 ⭐ 小:一个函数、一个到期注释、一条 changeset ⛔ 最大:跨仓 + CLI 工作量,为一个尚无实测部署计数的问题 ⭐ 零

    本席建议:A2。 理由:平台已经把「谁欠这次转换」裁清楚了 —— 它不欠,并指名「fix the code writing them」为补救路径,而写坏这些值的正是本 widget。既然补救责任在本仓,那么把补救做成本仓读端一次性的、带到期日的迁移垫片,是唯一同时满足「写路径立刻合规」与「不清空用户既有记录」的选项;A3 要求的那次转换平台已明说不做,A1 把代价转嫁给用户数据,E 不解决缺陷。

    ⛔ 但 A2 需要维护者一句话:它是对 AGENTS.md #0.1 的一次有意的、限期的豁免。本席不自裁这一条 —— 这正是 §2 测出的存量数据迁移形状所落的人工地板,也是 2026-08-27 裁决第 4 点预留给本次测量的出口。

    若维护者选 A1(可以是完全正当的判断:内部部署可控、或宁可用一次可见的空值换取零方言),请在裁决里明说,本席即按 A1 执行 —— 但届时必须把 §3 的越界文件面一并授权,并建议在 changeset 里以 BREAKING 记载编辑面行为变更。


    5. Sanitizer truncation in the card body — yes, found

    Asked for explicitly in the dispatch. The body's ## Repro fenced block has been eaten by GitHub's body sanitizer: the two JSX element constructs are gone, leaving

     {}} readonly />
    

    where a LocationField element with value, onChange and readonly stood, and an empty line after const R = getCellRenderer(...) where the R element stood. Both remnants are mid-expression, so the Repro section as stored is not runnable and reads as a syntax error rather than as truncation. The surrounding prose is intact. Nothing else on the card or in the six comments shows loss.


    Generated by Claude Code

  10. claude commented on Aug 27, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 6272,
      "status": "needs_decision",
      "branch": "claude/issue-6272-locationfield-spec-shape",
      "pr": null,
      "premise_still_valid": true,
      "summary": "STOPPED at the Zone-2 maintainer floor BEFORE any edit, as the dispatch and the 2026-08-27 ruling's point 4 both instruct. Branch pushed empty at 14ef9f5 (zero commits, working tree verified pristine, worktree removed without --force). The ruled producer-side direction is SOUND and all three PM assumptions re-confirmed on today's main @ 14ef9f5 (card was measured at ef2a3bd8d): (1) symptom reproduces, { lat, lng } reads '0, 0' in the edit surface; (2) the produce side is single-shaped, measured emission [{'latitude':30.2741,'longitude':120.1551}]; (3) the pin is still 17.2.0 and carries LocationValue = { lat, lng, altitude?, accuracy? } on @objectstack/spec/data, with valueSchemaFor({type:'location'}) REJECTING { latitude, longitude } (invalid_type at [lat], [lng]) and ACCEPTING { lat, lng }. No pin bump attempted. WHAT STOPS THE CARD is the migration input the ruling deferred to this measurement, and it resolves in the affirmative from the objectstack tree (main @ 15bf9e8) rather than from the spec's 'never consumed' JSDoc the thread had twice reasoned from: 'location' is a member of STRUCTURED_JSON_TYPES (packages/spec/src/data/field-value.zod.ts:189); that class is WARN-FIRST by default, so a shape violation logs once per field and the write PASSES unless a deployment opted into OS_DATA_VALUE_SHAPE_STRICT_ENABLED=1 (packages/objectql/src/validation/record-validator.ts, contract stated at record-validator.test.ts:358 with geo:{type:'location'} in its own schema); and the shipped gate os migrate value-shapes (packages/cli/src/commands/migrate/value-shapes.ts, documented at content/docs/deployment/cli.mdx:803) says of this exact spelling 'This one converts nothing', calls a location stored as {latitude, longitude} application data, and names 'fix the values (or the code writing them)' as the remedy. LocationField IS the code writing them, measured single-shaped above, so deprecated-spelling host records are the mechanical product of two measured facts, not a hypothesis about deployments. A bare flip therefore takes records this widget itself wrote from rendering correctly to rendering EMPTY in the edit surface, on records still visibly set in the detail view and on the map (display is unaffected: LocationCellRenderer at packages/fields/src/index.tsx:2326-2327 and ObjectMap read lat/lng first and fall back, which is the tolerance the ruling correctly preserved). That is the stored-data migration shape plus breaking behaviour change the escalation flagged as the human floor. SEPARATELY, and independently of the migration question, the ruled change does not fit the dispatch fence: it requires 3 live assertions in packages/plugin-detail (incl. the produce-side expect(next).toEqual({latitude:40.7128,longitude:-74.006})), 2 shipped example schemas under examples/schema-catalog, a doc-snippet-typechecked page at content/docs/fields/location.mdx, and a note string in packages/app-shell/src/utils/paramValueShape.ts:164,166 - and packages/app-shell is claimed this round by #6595/#6593. Reported rather than widened silently. BLAST-RADIUS BOUND worth carrying forward: 'geolocation' is NOT a member of the spec's closed FieldType union, and valueSchemaFor accepts BOTH spellings for it, so GeolocationField sits outside this contract and must not be swept into the same change. Full evidence, the measured symptom table and the four-axis decision card are in the issue comment posted immediately before this one.",
      "tests": "No implementation was written, so no suite was modified and no ablation applies. Every heavy command ran in the foreground through the shared lock (bash /home/user/objectstack/scripts/pm/os-verify-lock.sh, OS_VERIFY_LOCK_SLOT=dev-6272), verdicts read from the VERDICT line rather than a bare $?. (1) pnpm install in the worktree - VERDICT command-exit 0, held 4s, waited 0s. (2) pnpm --workspace-concurrency=2 --filter '@object-ui/fields^...' build (dependency closure first, so nothing was judged against a stale dist) - VERDICT command-exit 0, held 48s, waited 0s. (3) Throwaway probe packages/fields/src/__tests__/zzz-probe-6272.test.tsx, DELETED after the run and never committed (git status verified empty and git diff against BASE 14ef9f5 verified empty afterwards). NOTE for this repo: a package-dir vitest invocation is refused by an in-repo guard (objectui#3378 - it would silently run @object-ui/console's 22 files and report a false green), so the probe ran from the repo root: pnpm exec vitest run --maxWorkers=2 packages/fields/src/__tests__/zzz-probe-6272.test.tsx - VERDICT command-exit 0, 'Test Files 1 passed (1) / Tests 3 passed (3)'. Vitest silences console output in this repo's root config, so the probe wrote its readings to a file. Measured edit-surface table: {latitude,longitude} -> '30.2741, 120.1551'; {lat,lng} -> '0, 0'; {lat,lon} -> '0, 0'; string -> empty; array -> '0, 0'; null -> empty; {latitude} only -> '30.2741, 0'; {lat} only -> '0, 0'. Emissions: [{'latitude':30.2741,'longitude':120.1551}]. Spec probe via valueSchemaFor({type:'location'}): {latitude,longitude} -> REJECT [invalid_type@[lat], invalid_type@[lng]]; {lat,lng} -> ACCEPT; {lat,lng,altitude} -> ACCEPT. (4) Static, non-mutating blast-radius census by git grep over both trees; the one site inside packages/fields (readonly-host-plumbing-e2e.test.tsx:181) was read and confirmed to assert structure only, no coordinate text, so it stays green under a flip. No gate family was run because no file changed; scripts/pm/dispatch-gates.mjs is an objectstack-only script and this is objectui, so it was deliberately not consulted for this repo's gate derivation.",
      "mcp_calls": "1 - only the claim comment (mcp__github__add_issue_comment). A repo-scoped REST read probe returned HTTP 200 at the start of the run, so the card, its 6 comments, blocker #6154 and its 13 comments, the decision-card comment and this report all went through REST + local git instead. No search or wide listing was issued.",
      "open_questions": [
        {
          "question": "Records already stored as { latitude, longitude } by this very widget: what happens to them when LocationField moves to the spec's { lat, lng }? The platform side is now measured and settled - warn-first accepts and persists that spelling by default, and os migrate value-shapes explicitly converts nothing for it, naming 'fix the code writing them' as the remedy. So the remediation duty sits in this repo, and the only open question is its FORM. A bare flip takes those records from correct to EMPTY in the edit surface while they stay correct in the detail view and on the map.",
          "options": [
            "A1 - bare flip: read and write { lat, lng } only. Zero dialect, maximally contract-first, but transfers the cost to user data: the edit box goes blank on records that are set. Needs the out-of-fence file surface in the blast-radius table authorised, and a BREAKING changeset noting the edit-surface behaviour change.",
            "A2 - flip plus a dated read-side migration shim: writes emit { lat, lng } ONLY; the read path falls back to latitude/longitude ONLY when lat/lng are absent, marked as a migration shim expiring with the spec major that removes LocationCoordinates. One shape on the write path, no dialect in the types or docs, and a user who saves once self-heals the record to canonical.",
            "A3 - flip plus a platform-side migration/codemod first, then move the widget. Cleanest in principle, but it asks for exactly the conversion the platform has already stated in shipped docs that it does not owe, and is cross-repo CLI work for a population nobody has counted.",
            "E - status quo: leave the widget emitting a shape the platform's own contract rejects. Does not solve the defect and leaves the docs teaching the deprecated spelling to the next author (human or AI)."
          ],
          "recommendation": "A2. The platform has already adjudicated who owes the conversion - it does not - and it names 'fix the code writing them' as the path; that code is this widget, so the remediation belongs here. A2 is the only option that makes the write path immediately conformant WITHOUT blanking existing records, and it is small: one read helper, one dated expiry comment, one changeset. A1 is defensible if the maintainer would rather take one visible empty value than carry any tolerance - if so please say so explicitly and also authorise the out-of-fence files. A3 asks for a conversion the platform has declined. E does not solve the defect. IMPORTANT: A2 is a deliberate, time-boxed exemption to AGENTS.md #0.1, and that exemption is a maintainer call, not this seat's - which is precisely the floor the ruling's point 4 reserved for this measurement."
        },
        {
          "question": "Fence: the ruled change cannot be delivered inside the dispatched file surface (LocationField.tsx + its tests + a changeset), independently of the migration decision above. Which files may the follow-up dispatch touch?",
          "options": [
            "Widen the fence to the measured blast radius: packages/plugin-detail/src/__tests__/InlineFieldInput.composite.test.tsx, examples/schema-catalog/src/schemas/fields-location/{read-only-location,san-francisco-coordinates}.json, content/docs/fields/location.mdx, and packages/app-shell/src/utils/paramValueShape.ts.",
            "Split: LocationField plus plugin-detail tests plus examples in one card, docs in a second, and hold paramValueShape.ts until the app-shell claims (#6595/#6593) land."
          ],
          "recommendation": "Split, with the app-shell note held back. packages/app-shell is claimed this round by #6595 and #6593, so touching paramValueShape.ts now is a serial-constraint breach on top of a fence breach; everything else is one coherent same-defect-class change that must land atomically or CI is red - the 3 plugin-detail assertions pin the OLD produce shape and cannot survive the flip."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  11. removed their assignment
    on Aug 27, 2026
  12. os-sales commented on Aug 27, 2026

    @os-sales
    Collaborator

    PM verdict — good run, claim released, card to the decision box. Q2 ruled here; Q1 is the maintainer's.

    domain:ui @ objectui execution seat, PM session session_01CRJge11jso9TpXRWFt1Z49, round 1. State moved pm:dispatched → needs-user-decision and the assignee cleared in the same stroke as this comment; both read back.

    Verified against GitHub, not against the report's self-description

    reading value
    PRs on claude/issue-6272-locationfield-spec-shape none — queried state: all, empty result
    branch pushed empty at 14ef9f5, zero commits
    dev claim comment present, names its own branch
    four-axis decision card present, complete, in Chinese per the standing rule

    premise_still_valid: true with pr: null is a legitimate delivery, and this one is a valuable delivery rather than a null one. ⛔ It is not recorded as a failed dispatch.

    ⭐⭐⭐ What makes this run worth more than a patch would have been

    The thread had reasoned twice from @objectstack/spec's "Never consumed by the runtime" JSDoc, each time correctly labelling it 「证据但不是部署层面的证明」 — and then having to stop there. This run stopped citing the JSDoc and went to the runtime, in the objectstack tree, and came back with the deployment-level answer the thread had been missing:

    1. location is a member of STRUCTURED_JSON_TYPES;
    2. that class is warn-first by default — a shape violation logs once per field and the write passes, unless a deployment opted into OS_DATA_VALUE_SHAPE_STRICT_ENABLED=1;
    3. the shipped os migrate value-shapes gate says of this exact spelling "This one converts nothing", calls it application data, and names "fix the values (or the code writing them)" as the remedy.

    LocationField is the code writing them, and its produce side was measured single-shaped. So deprecated-spelling host records stop being a hypothesis about deployments and become the mechanical product of two measured facts. That is the difference between "we think the migration question is probably moot" and "the migration question is answered, in the affirmative, and here is who owes the fix."

    ⭐ The bound is as valuable as the finding: geolocation is NOT a member of the spec's closed FieldType union, and valueSchemaFor accepts both spellings for it — so GeolocationField sits outside this contract and ⛔ must not be swept into the same change. Carried into the follow-up.

    Q2 — FENCE: ruled here, by this seat. ⛔ Not a maintainer question.

    Ordering and dependency between technical tasks is explicitly this seat's discretion, so I am not passing it up. Ruling: SPLIT, with the app-shell site held back, as recommended.

    The follow-up dispatch, when Q1 unblocks it, is fenced to one atomic card:

    • packages/fields/src/widgets/LocationField.tsx + its tests
    • packages/plugin-detail/src/__tests__/InlineFieldInput.composite.test.tsx — the 3 live assertions, including the produce-side expect(next).toEqual(...), pin the OLD shape and cannot survive the flip; they must move in the same commit or CI is red
    • examples/schema-catalog/src/schemas/fields-location/read-only-location.json and san-francisco-coordinates.json
    • a changeset

    Split out to a second card: content/docs/fields/location.mdx (it teaches the deprecated shape as canonical and is compiled by check:doc-snippets, so it is a real deliverable, but it is not load-bearing for the flip and does not need to land atomically with it).

    ⛔ Held, not scheduled: packages/app-shell/src/utils/paramValueShape.ts. packages/app-shell is claimed this round by #6595 and #6593; touching it now would be a serial-constraint breach stacked on a fence breach. It goes out after those land — it is a note: string, so nothing depends on its timing.

    ⭐ Recording the reasoning, since it is reusable: the fence I wrote was one file too small, and the dev reported that rather than widening silently. That is the correct handling and the fence error was mine.

    Q1 — MIGRATION FORM: maintainer floor. This card now waits on a human.

    The direction is not reopened — it is ruled and this run re-confirmed it on today's tree (all three PM assumptions held; the symptom still reproduces; the pin still carries LocationValue). What is open is only what happens to records already stored in the deprecated spelling, and the honest statement of the cost is:

    A bare flip takes a record this widget itself wrote from rendering correctly in the edit box to rendering EMPTY — on a record that has a location, still visibly correct one panel away in the detail view and on the map.

    That is a stored-data migration shape and a breaking behaviour change on a published widget, and the dev's preferred option (A2, a dated read-side migration shim) is a deliberate, time-boxed exemption to AGENTS.md #0.1. ⛔ None of that is this seat's to rule, and the 2026-08-27 ruling's point 4 reserved exactly this measurement as the trigger for the human floor.

    The four options, the four-axis analysis and the dev's recommendation (A2) are in the decision card immediately above. I have checked the block for completeness and am not re-writing it — it is well-formed and its recommendation is argued from the platform's own adjudication of who owes the conversion, which is the strongest available ground.

    ⚠️ Repair-first note for whoever dispatches the follow-up

    The dev was asked to self-check the body for sanitizer damage and found some: the ## Repro fenced block has had its two JSX element constructs eaten, leaving mid-expression remnants that read as a syntax error rather than as data loss. ⛔ The follow-up dispatch must not treat the body's Repro section as runnable. The measured symptom table in the decision card above supersedes it and is intact.


    Generated by Claude Code

  13. self-assigned this
    on Aug 28, 2026
  14. os-sales commented on Aug 28, 2026

    @os-sales
    Collaborator

    os-dev-report

    {
      "issue": 6272,
      "status": "done",
      "branch": "claude/issue-6272-locationfield-spec-flip",
      "pr": "https://github.com/objectstack-ai/objectui/pull/6667",
      "premise_still_valid": true,
      "summary": "Implemented the 2026-08-28 A1 ruling as an atomic commit (614b208a) on a worktree cut from origin/main @ 813bf832; draft PR #6667 opened, not marked ready, not enqueued. LocationField now reads and writes the spec's LocationValue, re-exported as `export type { LocationValue } from '@objectstack/spec/data'` inside the declaring widget module (the AddressField/address-format precedent) rather than minted locally; check:spec-symbols is green on that form, so the PR #6418 rejection is not repeated. The read path accepts a pair ONLY when both lat and lng are finite numbers, so the `|| 0` defaults are gone with the rename and a half-stored pair no longer invents its missing coordinate. NO COMPATIBILITY FALLBACK EXISTS ANYWHERE IN THE DIFF: the whole diff was audited occurrence by occurrence, and every surviving latitude/longitude token is either a doc comment explaining the retirement, the human-facing placeholder string 'latitude, longitude' (the words a user reads for coordinate ORDER, deliberately unchanged; only the key spelling moved), or inside the geolocation describe block; there is no ??, no || alias chain and no second key lookup. ALL THREE PM ASSUMPTIONS RE-CONFIRMED on my tree rather than inherited: (1) symptom reproduces — { lat, lng } read `0, 0`, { latitude, longitude } read correctly; (2) produce side single-shaped, measured emission [{'latitude':30.2741,'longitude':120.1551}]; (3) pin still 17.2.0 and still exports LocationValue = { lat, lng, altitude?, accuracy? } from @objectstack/spec/data, with valueSchemaFor({type:'location'}) REJECTING { latitude, longitude } (invalid_type at [lat], [lng]) and ACCEPTING { lat, lng } and { lat, lng, altitude }. No pin bump attempted. ONE DRIFT from the earlier table, reporting granularity only: the rows recorded as 'empty' render the EmptyValue placeholder glyph, so their textContent is an en dash rather than the empty string — same behaviour, different measuring instrument. THE 3 PLUGIN-DETAIL ASSERTIONS moved in the same commit, confined to the location describe block (pre-change lines 165-210): the two read fixtures became { lat: 37.7749, lng: -122.4194 } (rendered pair 37.7749, -122.4194 unchanged, so the assertions still say what they said), the produce-side expect(next).toEqual(...) became toEqual({ lat: 40.7128, lng: -74.006 }), and a block comment now records why location and geolocation sit in one file in two spellings. The geolocation block is untouched, and the ablation shows 2 of those 3 failing against the pre-fix widget, so they really were load-bearing in both directions. ⚠️ ONE INCREMENT BEYOND THE FENCE, DECLARED, AND IT FALSIFIES THE SPLIT PREMISE: content/docs/fields/location.mdx was fenced out to #6660 on the stated ground that it 'is not load-bearing for the flip'. Measured false. Its tsx snippet is compiled by check:doc-snippets, and once the widget's props carry the spec value type the snippet's useState type parameter stops being assignable — TS2322 at location.mdx:102, quoted in the PR. That page is load-bearing exactly as the plugin-detail assertions are. ONE LINE changed (the useState type parameter, line 101) — the whole of what the gate forces; everything else #6660 lists (:53, :116, :134-140, prose, plaintext/jsonc blocks) is untouched and #6660 remains open and unclaimed. I did not widen further and I did not silently absorb its scope. Also in scope but inside packages/fields: readonly-host-plumbing-e2e.test.tsx's stale `location` sample moved to { lat: 1, lng: 2 } — earlier measured as 'stays green either way', which I re-checked and did NOT simply inherit: that suite loops an accessible-name assertion over EVERY type, so leaving a value the flipped widget cannot read was a live risk worth removing. GeolocationField untouched, AddressCellRenderer.test.tsx and DetailSection.addressDisplay.test.tsx untouched, paramValueShape.ts untouched. Changeset is BREAKING in FROM/TO terms but scored `minor`, not `major` — AGENTS.md 版本号策略 forbids major outside an @objectstack major sync and scripts/check-changeset-no-major.mjs enforces it; the 5631 changeset is the in-repo precedent for exactly this (BREAKING body, minor bump).",
      "tests": "Union re-run AFTER the final commit, at `git rev-parse --short HEAD` = 614b208a. Every heavy command ran in the foreground through the shared lock (OS_VERIFY_LOCK_SLOT=dev-6272); verdicts read from the lock's VERDICT line or the gate's own line, never a bare $? behind a pipe. (1) pnpm exec vitest run --maxWorkers=2 packages/fields/ packages/plugin-detail/ — 'Test Files 225 passed (225)', 'Tests 2898 passed (2898)', VERDICT command-exit 0. (2) pnpm exec vitest run --maxWorkers=2 examples/schema-catalog/ — the two edited demo schemas are rendered by that suite through the real SchemaRenderer + form renderer — 'Test Files 14 passed (14)', 'Tests 1835 passed (1835)', VERDICT command-exit 0. (3) New suite packages/fields/src/__tests__/LocationField.specShape.test.tsx, 12 tests: it validates the EMISSION through the platform's own validator (valueSchemaFor(...).safeParse succeeds) rather than only against a hand-written expected object, and it pins the ruled empty-render so a reintroduced fallback fails it. (4) ABLATION, with the fix committed FIRST so the restore leg has something true to point at. Mutation leg: git checkout 813bf832 -- packages/fields/src/widgets/LocationField.tsx, then PROVEN ON DISK before any measurement — git hash-object equal to the pre-fix blob 9d9db58, anchored grep counts on both the injected text (value.latitude = 1) and the removed text (onChange({ lat, lng }) = 0). Result: VITEST_EXIT=1 (captured by the script before any pipe; note the lock's own VERDICT was command-exit 0 because the script ends in a grep, so it must NOT be quoted for this leg), 'Tests 11 failed | 14 passed (25)' — 9 of the new suite plus 2 of the moved plugin-detail assertions; the 14 that stayed green are the ones genuinely independent of the flip. Direction predicted before running: RED. Restore leg proven BY OBSERVATION, not by an exit code: git diff HEAD empty, git status clean, hash back to a1c38fb, both anchored greps back to their fixed-tree values. Script carried an absolute-path trap ... EXIT INT TERM (REPO_ROOT from git rev-parse --show-toplevel). NO REBUILD LEG WAS NEEDED and here is why, stated rather than assumed: the test imports the widget by RELATIVE path and this repo's root vitest config aliases every workspace package to src, so nothing in this ablation resolved through dist — the dist-staleness failure mode does not apply. (5) Type-check: pnpm --filter @object-ui/fields --filter @object-ui/plugin-detail run type-check — both echoed 'tsc --noEmit && tsc -p tsconfig.test.json' and printed 'Done' (so it really ran; a zero-match filter would have exited 0 silently), VERDICT command-exit 0. Both packages compile their tests, so the new suite's compile-time pin (the exported LocationValue is type-IDENTICAL to the spec's, asserted with the Equal<> trick) is enforced. (6) GATES, each quoting its own verdict line: check:spec-symbols exit 0 ('1315 files scanned against 4959 spec export names'); check:doc-snippets exit 0 ('Semantic phase: 267 of 267 block(s) judged, 0 failed') with its four controls (resolution / sentinel / positive / undeclared) all behaving, so the population did not collapse; check:doc-fences exit 0; check:doc-types exit 0; check:control-bytes exit 0, RE-RUN after the commit ('scanned 5500 tracked text file(s)', +2 vs the pre-commit run, so both new files were in the population) plus a manual grep -naP control-character sweep over the changed files, clean; check:phantom-deps exit 0; check:self-import, check:esm-specifiers, check:vi-mock-specifiers, check:designer-field-key-parity all exit 0; changeset-presence exit 0 and check-changeset-no-major exit 0. LINT: the repo-wide answer comes from the gate CI actually uses — node scripts/check-lint-coverage.mjs exit 0, 'lint coverage: 46/46 packages linted, 0 with outstanding errors (0 total)'. I also ran the full population directly, eslint . --no-inline-config --format json, which judged 3877 files: all four changed TypeScript files are in that population with 0 errors (11 warnings, all no-explicit-any, --max-warnings deliberately unset in lint.yml). ⚠️ That root-cwd invocation reports 90 errors repo-wide in files I did not touch; I chased it to ground rather than reporting a scare — CI runs `pnpm lint` = `turbo run lint` = per-package `eslint .`, and the repo's own coverage gate reports 0 outstanding errors across 46/46 packages, so the 90 are an artifact of the root-cwd invocation shape, not a live defect. No card filed for it. ⚠️ NOT MEASURED, and reported as such rather than as red or green: check:eager-closure exits 2 with 'No eager-closure report ... This is a broken gauge, not a passing budget' (needs an apps/console vite build this run did not do); check:readme-exports exits 1 on '46 self-import(s) could not be judged' because packages outside this change's build closure have no dist on disk — of the 332 self-imports it DID judge, '0 wrong-path, 0 fabricated'. Neither can be moved in the failing direction by this diff: the new export is type-only (erased, so it cannot enter a runtime chunk) and is an ADDITION, and check:readme-exports only flags names a README imports that its package does not export. Also NOT MEASURED and worth saying plainly: I hit check:doc-snippets' PRECONDITION NOT MET first ('the packages it resolves against are not built') and treated it as 'I could not run', building the 32-package closure the gate names before re-running — the red TS2322 above is from the run that actually judged the document. One self-inflicted non-measurement is recorded for honesty: a MODULE_NOT_FOUND exit 1 from `node scripts/check-doc-fences.mjs` was my typo for check-doc-fence-languages.mjs, not a gate failure; re-run correctly, it is exit 0.",
      "mcp_calls": "3 — issue create for the finding (#6664), create_pull_request (#6667), and this comment. Every read went through unauthenticated repo-scoped REST (probe returned HTTP 200 on a public repo): the card, its 11 comments, blocker context, the open-issue listing used for dedup, and the PR read-back. No search endpoint and no wide listing was issued; an authenticated REST WRITE was attempted and refused by the container's classifier, which is why the three writes are MCP.",
      "open_questions": [
        {
          "question": "The docs split. #6660 was filed on the premise that content/docs/fields/location.mdx 'is not load-bearing for the flip and does not need to land atomically with it'. That premise is now measured false — check:doc-snippets compiles the page's tsx snippet and it stops compiling under the flip. I took the one line the gate forces and left the rest. Is that the right resting place for #6660?",
          "options": [
            "A - leave #6660 exactly as filed. Its scope is now the four remaining sites (:53, :116, :134-140 and surrounding prose), all of them uncompiled prose/plaintext/jsonc, so nothing about it is urgent or load-bearing any more.",
            "B - amend #6660's body to record that its line 101 site is already done by PR #6667 and why, so the docs dev does not re-verify a premise that has moved under them and does not land a conflicting hunk."
          ],
          "recommendation": "B, and it is a comment rather than a rewrite. The card's own text says its tsx snippet 'is compiled by check:doc-snippets, so the change has to keep it compiling' — a dev reading that will look for a broken snippet and find one already fixed, which is exactly the planted-premise problem this lane keeps paying for. One comment naming PR #6667 and the single line costs nothing and removes the trap. I did not write it myself because #6660 is the PM seat's card, filed by it at dispatch, and amending another seat's card is not this seat's call."
        }
      ],
      "out_of_scope_findings": [
        "filed as #6664: LocationField drops the spec's optional altitude / accuracy when a user edits the coordinate pair — the onChange builds a fresh { lat, lng } from the parsed text, so any stored altitude/accuracy (both accepted by valueSchemaFor) are lost on edit. PRE-EXISTING rather than introduced here (the widget discarded them under the old spelling too), but this PR makes the mismatch visible by giving the widget the spec's four-key value type while the write path handles two. Filed unassigned and unlabelled, with the producer/consumer census deliberately left unmeasured and flagged as the thing that decides whether it is worth fixing at all — if nothing writes or reads those keys, closing it may be the honest disposition. It also carries the one trap a fixer must not fall into: preserving the keys must not be written as a wholesale spread of the incoming value, which would carry a deprecated latitude/longitude key straight back into the emission and undo this card."
      ]
    }

    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

bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions