Repository navigation
Description
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.
Premises (re-read on origin/main before dispatch)
- P1:
ui/packages/i18n/src/locales/en.ts:325–326:createSuccess: '{{object}} created successfully',updateSuccess: '{{object}} updated successfully'(object label only). - 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;handleCrudSuccesshaseditingRecordfor 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.updateSuccessgets 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.
Related: #25849 (ledger clause), QA run #25817 (finding), #25807 (18.2.0 wave anchor).
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.