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
Record create/update success toasts name the record by its title, not only the object (ruling C on #25849) #26172
Filing gate: ② a maintainer ruling. Ruling-ref: 6417978207 (#25849, batch #399 item 1, letter C, maintainer 「同意」 at 14:04Z on 2026-10-26). Filed by domain:devx seat 2 (#20163) · os-steve · session session_01Q4MDXRbEJCNdPAP4SiXwp9, the seat that holds #25849 and owes this card under the ruling's "Execution" line. ⛔ Not a claim.
Business reason. A user entering several tasks in a row sees "Task created successfully" after each save and cannot tell which record was just written. The ruled clause (ux-conventions.write-feedback acceptance[1], reworded by the devx ledger PR for #25849) now reads: a record-level write names the record (its title) or the count; a singleton page (settings) and a named automation (Flow "X" completed) are their own subject. This card makes the console meet that clause.
Reader who acts. The domain:ui seat owning ui/packages/app-shell/src/console/AppContent.tsx and the form.* strings in ui/packages/i18n.
Wanted
The create and update success toasts for a record carry the record's display name (ADR-0079, docs/adr/0079-record-display-name.md), e.g. Task "Quarterly review" created.
When the object declares no title (no display name resolves), the toast falls back to today's object-label string. That fallback is part of this card.
Settings saves and flow-completion toasts are out of scope: the ruling counts them as passing.
P2: call sites ui/packages/app-shell/src/console/AppContent.tsx:816–817 (handleCrudSuccess) and :842–843 (child-form task path) pass { object: label } and nothing about the record.
P3: handleRecordFormSuccess(saved) already receives the saved record, so the title is in hand on that path; handleCrudSuccess has editingRecord for edits but not the created record.
Serial note
Changing the strings in ui/packages/i18n/src touches a registry closure package, so the PR re-records that package's sdui manifest source and serialises behind any open PR on ui/packages/i18n (per-package rule since #26120). Changing only app-shell does not.
Acceptance
Creating and editing a record that has a title shows a toast naming that title; a record without one shows the object-label toast.
Every locale that carries form.createSuccess / form.updateSuccess gets the new key or interpolation, with no machine names shown.
Tests cover both branches (title present, title absent) on the main path and the child-form path.
Claim: PM loop round 1
Session: session_017iXjUm1rujwDk7f3KT1Pkk (seat); implementing card thread session_01DiQzqGc2iCV6ZSmHBw4mwe
Account: os-steve
Branch: claude/project-thread-db3k9m (platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)
Worktree: the card thread's own container
Domain: domain:ui
Seat: domain:ui#1
File surface: ui/packages/app-shell/src/console/AppContent.tsx (handleCrudSuccess and the child-form path) and its tests: the record create and update success toasts name the saved record by its display name (ADR-0079), e.g. Task "Quarterly review" created, and fall back to today's object-label string when no display name resolves. New or reworded form.* success strings in all ten ui/packages/i18n/src/locales/* packs. scripts/sdui-manifest.sources/i18n.json. Changeset in the root. Settings saves and flow-completion toasts are out of scope (ruling). PR says Fixes #26172 (stop on breach; explain in the report). ⛔ ui/.github/** and the root .github/workflows/ci.yml are out of bounds (maintainer's word, ui-merge epic in flight). Changeset in the root .changeset/.
Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
Clause-②: no (adds or rewords message keys; no key is removed, so TranslationKeys only widens; no exported runtime contract changes)
Metadata-protocol: none
Responsibility: n/a: renderer defect in ui/, the producing code is the cited ui file; no platform path covers it; reached through the public Console
Thread-read: none
Premise: holds (maintainer ruling 6417978207, option C on #25849, filed under gate ②; premises P1–P3 on the card to be re-read by the dev on main; read-only check by the seat 2026-10-26T14:50Z)
Serial constraints cleared: i18n per-package order: after the batch PR #26158 merges, the dev merges main, re-records i18n.json and enqueues on the seat's go. No open PR edits AppContent.tsx (open-PR file scan 2026-10-26T14:50Z)
Dispatch order handed to the card thread by the project coordinator (three partitions: ruling / mechanism hypotheses / suggested route); the dev does not claim, and starts only once this claim names its branch.
{
"issue": 26172,
"status": "done",
"branch": "claude/project-thread-db3k9m",
"pr": "https://github.com/objectstack-ai/objectstack/pull/26202",
"session": "session_01DiQzqGc2iCV6ZSmHBw4mwe (card thread; claim 6419060350 by seat session_017iXjUm1rujwDk7f3KT1Pkk)",
"premise_still_valid": true,
"summary": "P1-P3 re-read on origin/main c7aa9cde and hold: en form.createSuccess/updateSuccess carry only the object label, both AppContent toast sites pass only { object: label }, and handleRecordFormSuccess(saved) already holds the saved record. AppContent now builds both toasts in one recordSaveMessage(saved): the saved record's ADR-0079 display name via getRecordDisplayName(formObjectDef, saved), the resolver floor (Record #ID / empty fallback) treated as no name, then form.createdNamed / form.updatedNamed ({{object}}, {{title}}) or the unchanged createSuccess/updateSuccess. handleCrudSuccess takes the saved record; the child-form path uses the same builder. Two new keys in all ten packs, i18n sdui record re-recorded, root patch changeset, two i18n count pins re-pinned (de quote pairs 94 to 96; AppContent common.record fallback sites 2 to 1). Head e9bd0d06.",
"tests": "New AppContent.recordSaveToastNamesRecord-26172.test.tsx (real AppContent + real i18next; main and child-form paths x create/update x named/unnamed + zh-CN): 9/9 passed. Ablation on the committed fix via scripts/ablation-replace.mjs (anchor 'const title = resolved && !(id' to 'const title = false && ...', anchor 1 to 0, blob 66183e3229a8 to a12d7507a89f): 5 failed / 4 passed, exactly the five named cells red, the four unnamed cells green as predicted; restore blob == HEAD, git diff HEAD empty. vitest run packages/i18n/ packages/app-shell/src/console/__tests__/: first run 3 failed (the two count pins) / 1694 passed / 13 skipped; after re-pin the two files 52/52. 14 other ui test files naming AppContent.tsx or form.createSuccess/updateSuccess: 89/89. app-shell and i18n type-check (src + tsconfig.test.json) exit 0 after building the app-shell^... closure. Tests at 3c5713b5; e9bd0d06 adds only scripts/sdui-manifest.sources/i18n.json. Narrowed: full app-shell suite left to CI Test UI.",
"gates": "dispatch-gates --commands at e9bd0d06 derives 47 families (16 paths vs merge base c7aa9cde2): all 47 run locally, each exit 0 captured before any pipe; node scripts/check-sdui-manifest.mjs run after the re-record, exit 0; --ran reconciliation: 47 of 47 accounted for, 0 NOT-MEASURED. PR check-runs at time of report: success: Build & E2E UI, Build UI Deps, Test Core 2-8/8, Lint ESLint, Type Check source gates, Lint docs & code guards, Lint CI release & engine gates, Lint scoped query-options erasure, Lint scoped tooling self-tests, Check Changeset, Check PR Size, Dogfood Regression Gate, the three claim/closing guards, Check Documentation Links, Auto Label; in_progress: Test UI 1-16/16, Type Check UI, Lint UI, Test Core 1/8, Governed Surface Queue Guard, Type Check workspace / consumer gates / debt ledger, Lint repo & tooling gates, Lint PM dispatch-gates, Lint scoped slot lookup & corpus; skipped by selector: Build Core, Build Docs, Dogfood Verify CLI, Temporal Conformance.",
"dogfood_battery": "n/a: no ! in the PR title and Clause-② carries no (narrowing) arm",
"mcp_calls": "4: issue_read get, issue_read get_comments x2, pull_request_read get_check_runs (all reads)",
"api_writes": "2: pr_create via fleet-write relay (POST pulls, draft, assignee os-steve; body read back 4811 = 4811 bytes, identical), this os-dev-report comment via post-stamped (POST issues/26172/comments)",
"open_questions": [],
"out_of_scope_findings": [
"note, not filed: on an edit the toast names the record only if dataSource.update's returned record carries the name field; the adapter returns the server record, live server not booted here; in the PR Acceptance notes, carrier: none"
]
}
Serial: ui/packages/i18n is behind the batch PR #26158; the PR stays draft, and merge-main, re-record and enqueue wait for the ui seat's go.
Activity
objectstack-fleet commentedon Oct 26, 2026
Claim: PM loop round 1
Session:
session_017iXjUm1rujwDk7f3KT1Pkk(seat); implementing card threadsession_01DiQzqGc2iCV6ZSmHBw4mweAccount:
os-steveBranch:
claude/project-thread-db3k9m(platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)Worktree: the card thread's own container
Domain:
domain:uiSeat:
domain:ui#1File surface:
ui/packages/app-shell/src/console/AppContent.tsx(handleCrudSuccessand the child-form path) and its tests: the record create and update success toasts name the saved record by its display name (ADR-0079), e.g.Task "Quarterly review" created, and fall back to today's object-label string when no display name resolves. New or rewordedform.*success strings in all tenui/packages/i18n/src/locales/*packs.scripts/sdui-manifest.sources/i18n.json. Changeset in the root. Settings saves and flow-completion toasts are out of scope (ruling). PR saysFixes #26172(stop on breach; explain in the report). ⛔ui/.github/**and the root.github/workflows/ci.ymlare out of bounds (maintainer's word, ui-merge epic in flight). Changeset in the root.changeset/.Container & model:
M,mode:thread,model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate),effort: mediumClause-②: no (adds or rewords message keys; no key is removed, so
TranslationKeysonly widens; no exported runtime contract changes)Metadata-protocol: none
Responsibility:
n/a: renderer defect in ui/, the producing code is the cited ui file; no platform path covers it; reached through the public ConsoleThread-read: none
Premise: holds (maintainer ruling 6417978207, option C on #25849, filed under gate ②; premises P1–P3 on the card to be re-read by the dev on
main; read-only check by the seat 2026-10-26T14:50Z)Serial constraints cleared: i18n per-package order: after the batch PR #26158 merges, the dev merges main, re-records
i18n.jsonand enqueues on the seat's go. No open PR editsAppContent.tsx(open-PR file scan 2026-10-26T14:50Z)Dispatch order handed to the card thread by the project coordinator (three partitions: ruling / mechanism hypotheses / suggested route); the dev does not claim, and starts only once this claim names its branch.
objectstack-fleet commentedon Oct 26, 2026
os-dev-report
{ "issue": 26172, "status": "done", "branch": "claude/project-thread-db3k9m", "pr": "https://github.com/objectstack-ai/objectstack/pull/26202", "session": "session_01DiQzqGc2iCV6ZSmHBw4mwe (card thread; claim 6419060350 by seat session_017iXjUm1rujwDk7f3KT1Pkk)", "premise_still_valid": true, "summary": "P1-P3 re-read on origin/main c7aa9cde and hold: en form.createSuccess/updateSuccess carry only the object label, both AppContent toast sites pass only { object: label }, and handleRecordFormSuccess(saved) already holds the saved record. AppContent now builds both toasts in one recordSaveMessage(saved): the saved record's ADR-0079 display name via getRecordDisplayName(formObjectDef, saved), the resolver floor (Record #ID / empty fallback) treated as no name, then form.createdNamed / form.updatedNamed ({{object}}, {{title}}) or the unchanged createSuccess/updateSuccess. handleCrudSuccess takes the saved record; the child-form path uses the same builder. Two new keys in all ten packs, i18n sdui record re-recorded, root patch changeset, two i18n count pins re-pinned (de quote pairs 94 to 96; AppContent common.record fallback sites 2 to 1). Head e9bd0d06.", "tests": "New AppContent.recordSaveToastNamesRecord-26172.test.tsx (real AppContent + real i18next; main and child-form paths x create/update x named/unnamed + zh-CN): 9/9 passed. Ablation on the committed fix via scripts/ablation-replace.mjs (anchor 'const title = resolved && !(id' to 'const title = false && ...', anchor 1 to 0, blob 66183e3229a8 to a12d7507a89f): 5 failed / 4 passed, exactly the five named cells red, the four unnamed cells green as predicted; restore blob == HEAD, git diff HEAD empty. vitest run packages/i18n/ packages/app-shell/src/console/__tests__/: first run 3 failed (the two count pins) / 1694 passed / 13 skipped; after re-pin the two files 52/52. 14 other ui test files naming AppContent.tsx or form.createSuccess/updateSuccess: 89/89. app-shell and i18n type-check (src + tsconfig.test.json) exit 0 after building the app-shell^... closure. Tests at 3c5713b5; e9bd0d06 adds only scripts/sdui-manifest.sources/i18n.json. Narrowed: full app-shell suite left to CI Test UI.", "gates": "dispatch-gates --commands at e9bd0d06 derives 47 families (16 paths vs merge base c7aa9cde2): all 47 run locally, each exit 0 captured before any pipe; node scripts/check-sdui-manifest.mjs run after the re-record, exit 0; --ran reconciliation: 47 of 47 accounted for, 0 NOT-MEASURED. PR check-runs at time of report: success: Build & E2E UI, Build UI Deps, Test Core 2-8/8, Lint ESLint, Type Check source gates, Lint docs & code guards, Lint CI release & engine gates, Lint scoped query-options erasure, Lint scoped tooling self-tests, Check Changeset, Check PR Size, Dogfood Regression Gate, the three claim/closing guards, Check Documentation Links, Auto Label; in_progress: Test UI 1-16/16, Type Check UI, Lint UI, Test Core 1/8, Governed Surface Queue Guard, Type Check workspace / consumer gates / debt ledger, Lint repo & tooling gates, Lint PM dispatch-gates, Lint scoped slot lookup & corpus; skipped by selector: Build Core, Build Docs, Dogfood Verify CLI, Temporal Conformance.", "dogfood_battery": "n/a: no ! in the PR title and Clause-② carries no (narrowing) arm", "mcp_calls": "4: issue_read get, issue_read get_comments x2, pull_request_read get_check_runs (all reads)", "api_writes": "2: pr_create via fleet-write relay (POST pulls, draft, assignee os-steve; body read back 4811 = 4811 bytes, identical), this os-dev-report comment via post-stamped (POST issues/26172/comments)", "open_questions": [], "out_of_scope_findings": [ "note, not filed: on an edit the toast names the record only if dataSource.update's returned record carries the name field; the adapter returns the server record, live server not booted here; in the PR Acceptance notes, carrier: none" ] }Serial:
ui/packages/i18nis behind the batch PR #26158; the PR stays draft, and merge-main, re-record and enqueue wait for the ui seat's go.