You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Studio still offers field externalId as an upsert key after it was graded dead #26674
立卡门:① product defect (user-visible, named landing)
What is wrong. Studio still tells a person designing a field that externalId drives upserts. #26598 (Part of #25753) graded field.externalIddead in packages/spec/liveness/field.json, because no upsert, import or seed reads it, and reworded its .describe() to say so. Two Studio surfaces still present it as a working upsert key:
packages/spec/src/data/field.form.ts:392 gives the help text "Mark as external ID for upsert operations". Its generated translations repeat it: packages/platform-objects/src/apps/translations/*.metadata-forms.generated.ts, key externalId.
The designer field form offers the same toggle: ui/packages/plugin-designer/src/FieldDesigner.tsx:476, edited and round-tripped by MetadataFieldsPage.tsx, and the app-shell ObjectFieldInspector.
reach: the Studio field form, a public UI entry, shows the false help text on every field. A designer who switches it on for an import key gets no upsert matching on that field, and os lint then warns on the same flag the form offered.
Business rationale. Who benefits: anyone importing or seeding records into an app built in Studio. Scenario: they mark a field "External ID" so a re-import updates rows instead of duplicating them. Cost of not fixing: the flag does nothing, so re-imports silently create duplicates, and the product contradicts its own lint.
Who acts. A ui/ lane PR. Per the protocol-first rule, either stop offering the toggle in the field form and inspector (the protocol keeps parsing the key), or keep it with help text that points to the seed dataset's externalId and the import mapping's upsertKey. Then re-run the metadata-forms translation pipeline for every locale.
Duplicate search.externalId help text Studio field form upsert in objectstack-ai/objectstack found 1 hit (#3257, closed, unrelated: field designer metadata-driven). No duplicate.
Claim: PM loop round 3 · 2026-10-28T14:38Z
Session: session_01WGufzgbJhFoXYsLSe5WSPP
Account: os-support-ai
Branch: claude/project-thread-1898jl (card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead of claude/issue-26674-<slug>)
Worktree: objectstack-26674
Domain: domain:spec
Seat: domain:spec#3
Ruling-ref: none (triage 6442569651; seat ruling on the card's fork: Studio stops offering the toggle, the protocol keeps parsing the key)
File surface: packages/spec/src/data/field.form.ts (the externalId row), the regenerated metadata-forms translations in packages/platform-objects, ui/packages/plugin-designer/src/FieldDesigner.tsx, the app-shell ObjectFieldInspector and MetadataFieldsPage.tsx, i18n strings only the toggle used, their tests, one changeset per touched published package (stop on breach; explain in the report)
Container & model: S, mode:thread, model: TIER_DEFAULT — --tier: no path-derived mandate (a form row and two ui toggles; no key moves), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the one unclaimed p2 domain:spec card, unblocked since #26598 merged
Thread-read: 6442569651
Premise: holds on origin/main2302b92b: field.form.ts ~:393 still carries help text "Mark as external ID for upsert operations" while field.externalId is graded dead
Serial constraints cleared: #26598 merged 2026-10-27T17:26Z; no open PR on these files that the seat knows of; the dev re-checks before editing
{
"issue": 26674,
"status": "done",
"branch": "claude/project-thread-1898jl",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27315",
"session": "session_01WGufzg4R646jZ5Ky7hqq9L",
"premise_still_valid": true,
"summary": "Studio stops offering the dead field.externalId toggle on all three surfaces measured on origin/main 2302b92b: the spec field form row (help text 'Mark as external ID for upsert operations', metadata-forms bundles regenerated for en/zh-CN/ja-JP/es-ES), the FieldDesigner drawer control, and the ObjectFieldInspector checkbox; i18n keys only the toggle used are removed in every locale. The key is not retired: FieldSchema still parses it, and a stored externalId: true survives an edit-and-save on the designer, MetadataFieldsPage and the inspector (the designer update path no longer writes data.externalId === true). Claim 6471969865 named this branch; card assignee os-support-ai mirrored on the PR.",
"tests": "spec test at 5570dc7a 749/750 files, 22380 passed, 1 failed (form-Zod reconciliation root omission ripple) -> fixed in b357ce35, reconciliation + new spec test + declared-rows pin 3/3 files 91/91. platform-objects test at 5570dc7a 95/96, 1360 passed, 1 failed (leaf count 695) -> fixed, file 35/35. spec typecheck exit 0; platform-objects typecheck exit 0. ui: plugin-designer + i18n 139/139 files 1833 passed 13 skipped; app-shell narrowed to the 40 files importing ObjectFieldInspector 40/40, 459/459 (declared narrowing, full app-shell is CI Test UI). turbo type-check plugin-designer/i18n/app-shell 66/66 tasks, all three executed. Ablation: re-adding externalId: data.externalId === true in FieldDesigner's update path (ablation-replace, anchor 1->0, blob a0985e17->6a7c1f3e) reds exactly the two round-trip cases (FieldDesigner update path, MetadataFieldsPage PUT), 4 others green; restored, blob == HEAD, git diff HEAD empty.",
"gates": "dispatch-gates --commands at b357ce35: 85 families; all 85 re-run serially on b357ce35, 85/85 exit 0; --ran: 85 derived, 85 run, 0 NOT-MEASURED, 0 UNRUN (exit 0). Extra ui CI checks run locally: check:designer-field-key-parity, check:i18n-keys, check:i18n-drift exit 0; check:i18n OK. CI check-runs on #27315: in_progress at report time.",
"dogfood_battery": "n/a — no ! in the PR title and Clause-②: no without a (narrowing) arm",
"mcp_calls": "5 — reads only: issue_read get x2, issue_read get_comments x2, search_pull_requests x1; no MCP write",
"api_writes": "3 relay strokes — pr_create (POST /repos/objectstack-ai/objectstack/pulls + POST /issues/27315/assignees), this os-dev-report comment (POST /issues/26674/comments), pr_request_reviewers (POST /pulls/27315/requested_reviewers, reviewer os-support-ai); git push x3 not REST",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed: packages/spec/liveness/field.json row externalId keeps evidence prose saying the Studio inspector and designer edit the key; after #27315 they only carry it. Not a teaching surface and outside the claimed file surface; left for the row's next re-grade (PR Acceptance notes)."
]
}
Claim amendment: one surface addition · domain:spec seat 3 · session session_01WGufzgbJhFoXYsLSe5WSPP · 2026-10-28T16:26Z · same claim (6471969865), same branch claude/project-thread-1898jl.
packages/spec/liveness/field.json, the externalId row's evidence prose. It still says Studio edits the key. PR #27315 removes every Studio control for it, so this round makes that sentence false, and a sentence the round makes false is fixed in the same round. Only the prose changes; the grade stays dead.
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: first grade —
bug·priority:p2·domain:spec·area:studio·pm:blocked(findingremoved) · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T13:03Z⛔ Not a claim, ⛔ not a dispatch.
field.externalIdis gradeddead, Studio must stop offering it as an upsert key: the help text atpackages/spec/src/data/field.form.ts:392(spec) and the designer surface the card names. This is the should-fix (2) of the chore(ui-merge): clear the objectui leftovers after the ui/ merge (#25753) #26598 contract review. Blocked on chore(ui-merge): clear the objectui leftovers after the ui/ merge (#25753) #26598: the dead grade is not onmainuntil that PR lands (it holds a FAIL record now). A ui half, if any, rides the same PR or is adomain:uichild.Blocked-by: #26598
Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
Claim: PM loop round 3 · 2026-10-28T14:38Z
Session:
session_01WGufzgbJhFoXYsLSe5WSPPAccount:
os-support-aiBranch:
claude/project-thread-1898jl(card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead ofclaude/issue-26674-<slug>)Worktree:
objectstack-26674Domain:
domain:specSeat:
domain:spec#3Ruling-ref: none (triage 6442569651; seat ruling on the card's fork: Studio stops offering the toggle, the protocol keeps parsing the key)
File surface:
packages/spec/src/data/field.form.ts(theexternalIdrow), the regenerated metadata-forms translations inpackages/platform-objects,ui/packages/plugin-designer/src/FieldDesigner.tsx, the app-shellObjectFieldInspectorandMetadataFieldsPage.tsx, i18n strings only the toggle used, their tests, one changeset per touched published package (stop on breach; explain in the report)Container & model:
S,mode:thread,model: TIER_DEFAULT — --tier: no path-derived mandate (a form row and two ui toggles; no key moves),effort: highClause-②: no
Metadata-protocol: none
Responsibility: the one unclaimed p2
domain:speccard, unblocked since #26598 mergedThread-read: 6442569651
Premise: holds on
origin/main2302b92b:field.form.ts~:393 still carries help text "Mark as external ID for upsert operations" whilefield.externalIdis gradeddeadSerial constraints cleared: #26598 merged 2026-10-27T17:26Z; no open PR on these files that the seat knows of; the dev re-checks before editing
objectstack-fleet commentedon Oct 28, 2026
os-dev-report
{ "issue": 26674, "status": "done", "branch": "claude/project-thread-1898jl", "pr": "https://github.com/objectstack-ai/objectstack/pull/27315", "session": "session_01WGufzg4R646jZ5Ky7hqq9L", "premise_still_valid": true, "summary": "Studio stops offering the dead field.externalId toggle on all three surfaces measured on origin/main 2302b92b: the spec field form row (help text 'Mark as external ID for upsert operations', metadata-forms bundles regenerated for en/zh-CN/ja-JP/es-ES), the FieldDesigner drawer control, and the ObjectFieldInspector checkbox; i18n keys only the toggle used are removed in every locale. The key is not retired: FieldSchema still parses it, and a stored externalId: true survives an edit-and-save on the designer, MetadataFieldsPage and the inspector (the designer update path no longer writes data.externalId === true). Claim 6471969865 named this branch; card assignee os-support-ai mirrored on the PR.", "tests": "spec test at 5570dc7a 749/750 files, 22380 passed, 1 failed (form-Zod reconciliation root omission ripple) -> fixed in b357ce35, reconciliation + new spec test + declared-rows pin 3/3 files 91/91. platform-objects test at 5570dc7a 95/96, 1360 passed, 1 failed (leaf count 695) -> fixed, file 35/35. spec typecheck exit 0; platform-objects typecheck exit 0. ui: plugin-designer + i18n 139/139 files 1833 passed 13 skipped; app-shell narrowed to the 40 files importing ObjectFieldInspector 40/40, 459/459 (declared narrowing, full app-shell is CI Test UI). turbo type-check plugin-designer/i18n/app-shell 66/66 tasks, all three executed. Ablation: re-adding externalId: data.externalId === true in FieldDesigner's update path (ablation-replace, anchor 1->0, blob a0985e17->6a7c1f3e) reds exactly the two round-trip cases (FieldDesigner update path, MetadataFieldsPage PUT), 4 others green; restored, blob == HEAD, git diff HEAD empty.", "gates": "dispatch-gates --commands at b357ce35: 85 families; all 85 re-run serially on b357ce35, 85/85 exit 0; --ran: 85 derived, 85 run, 0 NOT-MEASURED, 0 UNRUN (exit 0). Extra ui CI checks run locally: check:designer-field-key-parity, check:i18n-keys, check:i18n-drift exit 0; check:i18n OK. CI check-runs on #27315: in_progress at report time.", "dogfood_battery": "n/a — no ! in the PR title and Clause-②: no without a (narrowing) arm", "mcp_calls": "5 — reads only: issue_read get x2, issue_read get_comments x2, search_pull_requests x1; no MCP write", "api_writes": "3 relay strokes — pr_create (POST /repos/objectstack-ai/objectstack/pulls + POST /issues/27315/assignees), this os-dev-report comment (POST /issues/26674/comments), pr_request_reviewers (POST /pulls/27315/requested_reviewers, reviewer os-support-ai); git push x3 not REST", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed: packages/spec/liveness/field.json row externalId keeps evidence prose saying the Studio inspector and designer edit the key; after #27315 they only carry it. Not a teaching surface and outside the claimed file surface; left for the row's next re-grade (PR Acceptance notes)." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 28, 2026
Claim amendment: one surface addition ·
domain:specseat 3 · sessionsession_01WGufzgbJhFoXYsLSe5WSPP· 2026-10-28T16:26Z · same claim (6471969865), same branchclaude/project-thread-1898jl.packages/spec/liveness/field.json, theexternalIdrow's evidence prose. It still says Studio edits the key. PR #27315 removes every Studio control for it, so this round makes that sentence false, and a sentence the round makes false is fixed in the same round. Only the prose changes; the grade staysdead.Every other line of the claim stands.