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
app-shell: the full-page record form (/new, /edit route) still toasts "Task updated successfully" — #26172's fix covered AppContent's dialog paths only; RecordFormPage passes the object label alone #26461
Filing gate: ① a product defect, measured live and confirmed in source. It is the incomplete half of closed #26172 (PR #26202), found beside the clauses of a QA run.
Business reason: ruling C on #25849 (comment 6417978207) says a record create or update toast names the record by its title. #26172's acceptance reads "Creating and editing a record that has a title shows a toast naming that title". The dialog paths now do this ('Task "WF Create E3" created'), but a user who edits on the full-page form route still sees "Task updated successfully".
Reader: the domain:ui owner of ui/packages/app-shell/src/views/RecordFormPage.tsx.
Dedupe (open AND closed): #26172 (closed, completed). Its premises P2 and P3 name only AppContent.tsx:816–817 / 842–843, and RecordFormPage.tsx is not mentioned there. No open card covers the page route.
reach: console page route /_console/apps/APP/OBJECT/record/ID/edit (and /new). Measured on a fresh stock showcase boot at 756220c4 as admin; the console was built in-repo from ui/ at that commit.
Checklist item priority: P1
type: Bug
QA-source: #26456 · ux-conventions.write-feedback · observed beside the clauses
Reproduction
Boot the stock showcase and sign in as admin.
Open a task on its full-page edit route, reached by in-app navigation (a cold page load of /edit makes save's navigate(-1) leave the document and drops the toast).
Change the title and Save. A PATCH answers 200.
The toast reads "Task updated successfully".
For contrast, the dialog create on the list reads Task "WF Create E3" created.
Expected:Task "NEW TITLE" updated (or the object-label fallback only when no display name resolves).
Mechanism
ui/packages/app-shell/src/views/RecordFormPage.tsx:162–163 calls t('form.createSuccess', { object: label }) / t('form.updateSuccess', { object: label }) with no record title. AppContent.tsx:846/850 were changed by #26202; this call site was not. The page has the saved record in hand at that point, so it can pass the display name the same way.
Claim: PM loop round 13 · 2026-10-27T05:26Z
Session: session_01SMps7wq7rBTk53e8KTSEup
Account: os-steve
Branch: claude/issue-26461-record-form-page-toast
Worktree: objectstack-issue-26461
Domain: domain:ui
Seat: domain:ui#2
File surface: ui/packages/app-shell/src/views/RecordFormPage.tsx (the save toasts, ~:160), tests beside it, root .changeset/. ⛔ locale packs under ui/packages/i18n unless the card needs a new key (then en + zh only, and say so), ui/.github/**, root ci.yml.
Container & model: M, mode:subagent, model: default tier, effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: a user saving a record on the full-page /new or /edit route | ruling C on #25849 (6417978207): a record write names the record by its title | every object's full-page form route
Thread-read: none
Premise: holds 2026-10-27T05:26Z at origin/main00a4593ad7: RecordFormPage.tsx:160 toasts a fixed success line that does not name the record, while the dialog paths fixed by #26172 (PR #26202) do.
Serial constraints cleared: no open PR touches RecordFormPage.tsx.
Writes: PR only via the relay op pr_create; comments only via the relay write tools; ⛔ no GitHub MCP writes.
Seat's route: reuse exactly the title-naming helper and keys fix(app-shell): record create/update toasts name the saved record #26202 used for the dialog paths (no new wording); a record without a title falls back as the dialog path does. Pin red-first for create and update. Fixes #26461.
{
"issue": 26461,
"status": "done",
"branch": "claude/issue-26461-record-form-page-toast",
"pr": "https://github.com/objectstack-ai/objectstack/pull/26528",
"head": "4a0094b9",
"session": "session_01SMps7wq7rBTk53e8KTSEup",
"premise_still_valid": true,
"summary": "RecordFormPage (/new and /record/ID/edit) handleSuccess now reads the saved record ObjectForm hands to onSuccess and toasts form.createdNamed / form.updatedNamed with its ADR-0079 display name, using getRecordDisplayName from @object-ui/core, the same Record #ID floor and the same keys as recordSaveMessage in ui/packages/app-shell/src/console/AppContent.tsx (PR #26202). A record with nothing nameable, or no record handed back, keeps form.createSuccess / form.updateSuccess. No wording or locale file changed; the keys pass bare like every other t() in the file. Card assignee is empty, so the PR carries no assignee.",
"files_changed": [
"ui/packages/app-shell/src/views/RecordFormPage.tsx",
"ui/packages/app-shell/src/views/RecordFormPage.saveToastNamesRecord-26461.test.tsx (new)",
"ui/packages/app-shell/src/views/RecordFormPage.i18n.test.tsx",
".changeset/26461-record-form-page-toast.md"
],
"line_budget": "+198 / -7 = 205 changed lines over 4 files (dispatch-gates count) vs the 3000 human-merge threshold: under",
"tests": "All at 4a0094b9 under os-verify-lock. Closure: pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build then VERDICT command-exit 0 (first attempt VERDICT queue-timeout exit 99, rejoined with slot). RED-FIRST (RecordFormPage.tsx restored tree-only to base 00a4593a, getRecordDisplayName count 0): new file 3 failed / 3 passed; failed = create named (expected 'Task created successfully' to be 'Task \"Quarterly review\" created'), update named (same, updated), zh named (expected 'Task更新成功'); passed = the three no-name cells, the direction written in the test header. Restore: git checkout HEAD -- path; blob 4442d066 == HEAD blob, git status clean. GREEN: the 10 app-shell test files importing RecordFormPage (9 existing + new): Test Files 10 passed (10), Tests 62 passed (62), VITEST_EXIT=0. pnpm --filter @object-ui/app-shell type-check: TYPECHECK_EXIT=0 (tsconfig.test.json includes src/**/*.test.tsx, so the new file is compiled). Full app-shell suite left to CI.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 4a0094b9: 34 derived, 34 run, --ran reconciliation 34/34 accounted (RAN_EXIT=0). 33 :: exit 0, including node scripts/check-sdui-manifest.mjs :: exit 0 (present and intact, sha256 1f6e1ccb925a, 106 components) and --self-test :: exit 0, and pnpm --dir ui exec vitest run scripts/ :: exit 0 (178 files passed / 2 skipped, 5097 tests passed). pnpm check:type-check-debt :: exit 3 PREREQUISITE NOT MET, twice: its --re-measure closure build never got a turn on the shared lock (VERDICT queue-timeout exit 99); NOT MEASURED, CI Type Check · debt ledger is the reading of record. No registry component contract changed, so sdui.manifest.json was not regenerated. PR check-runs at report time: in_progress (not awaited, per contract).",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches then fleet-write run 40462089677 then POST /repos/objectstack-ai/objectstack/pulls, draft #26528, body read back byte-identical, 5120 bytes); this os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/26461/comments). Plus git push (not a REST write).",
"deviations": [
"The dispatch named the dialog paths in 'apps/console AppContent.tsx'; the helper PR #26202 added lives in ui/packages/app-shell/src/console/AppContent.tsx (ui/apps/console/src/AppContent.tsx is a thin wrapper over DefaultAppContent). Reused that one.",
"The helper there is a component-local useCallback, not an export, so 'reuse exactly' was done as the same resolver call, same floor and same keys inside RecordFormPage (about six repeated lines). AppContent.tsx is outside the claim's file surface, so no shared builder was extracted (see open_questions).",
"check:type-check-debt NOT MEASURED (exit 3, lock queue-timeout). A background re-run of it was left to end on its own after a kill of its recorded waiter pid was refused by the permission classifier; it ended at exit 3 before the worktree was removed.",
"Commit trailers use the model-free pair AGENTS.md requires (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By line."
],
"open_questions": [
{
"question": "Extract recordSaveMessage into one shared builder used by both AppContent and RecordFormPage?",
"options": [
"A: follow-up card for a pure helper in app-shell utils, called from both surfaces, so the two cannot drift",
"B: leave the two six-line copies as they are"
],
"recommendation": "A, because the page and the dialog already share helpers this way (isObjectFieldVisible, selectRecordFormView), and one builder stops the two surfaces from drifting; it needs AppContent.tsx on a claim."
}
],
"out_of_scope_findings": []
}
Status: the full-page record form's save toast names the saved record (Task "Quarterly review" updated), the same as the dialog paths. pm:dispatched removed.
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: first grade —
bug·priority:p2·domain:ui·area:records·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T04:55Z⛔ Not a claim, ⛔ not a dispatch.
RecordFormPage(/newand/edit) still toasts the object label alone. Ruling C on qa(checklist): ux-conventions — 5 ledger edits from the 18.2.0 release sweep (#25807) #25849 says the toast names the record by its title. Reuse Record create/update success toasts name the record by its title, not only the object (ruling C on #25849) #26172's helper, ⛔ no second wording. Found by the 18.2.0 wave-2 sweep ([sweep] v18.2.0 release test sweep #25807).Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 13 · 2026-10-27T05:26Z
Session:
session_01SMps7wq7rBTk53e8KTSEupAccount:
os-steveBranch:
claude/issue-26461-record-form-page-toastWorktree:
objectstack-issue-26461Domain:
domain:uiSeat:
domain:ui#2File surface:
ui/packages/app-shell/src/views/RecordFormPage.tsx(the save toasts, ~:160), tests beside it, root.changeset/. ⛔ locale packs underui/packages/i18nunless the card needs a new key (then en + zh only, and say so),ui/.github/**, rootci.yml.Container & model:
M,mode:subagent,model: default tier,effort: mediumClause-②: no
Metadata-protocol: none
Responsibility:
a user saving a record on the full-page /new or /edit route|ruling C on #25849 (6417978207): a record write names the record by its title|every object's full-page form routeThread-read: none
Premise: holds 2026-10-27T05:26Z at
origin/main00a4593ad7:RecordFormPage.tsx:160toasts a fixed success line that does not name the record, while the dialog paths fixed by #26172 (PR #26202) do.Serial constraints cleared: no open PR touches
RecordFormPage.tsx.Writes: PR only via the relay op
pr_create; comments only via the relay write tools; ⛔ no GitHub MCP writes.Fixes #26461.objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 26461, "status": "done", "branch": "claude/issue-26461-record-form-page-toast", "pr": "https://github.com/objectstack-ai/objectstack/pull/26528", "head": "4a0094b9", "session": "session_01SMps7wq7rBTk53e8KTSEup", "premise_still_valid": true, "summary": "RecordFormPage (/new and /record/ID/edit) handleSuccess now reads the saved record ObjectForm hands to onSuccess and toasts form.createdNamed / form.updatedNamed with its ADR-0079 display name, using getRecordDisplayName from @object-ui/core, the same Record #ID floor and the same keys as recordSaveMessage in ui/packages/app-shell/src/console/AppContent.tsx (PR #26202). A record with nothing nameable, or no record handed back, keeps form.createSuccess / form.updateSuccess. No wording or locale file changed; the keys pass bare like every other t() in the file. Card assignee is empty, so the PR carries no assignee.", "files_changed": [ "ui/packages/app-shell/src/views/RecordFormPage.tsx", "ui/packages/app-shell/src/views/RecordFormPage.saveToastNamesRecord-26461.test.tsx (new)", "ui/packages/app-shell/src/views/RecordFormPage.i18n.test.tsx", ".changeset/26461-record-form-page-toast.md" ], "line_budget": "+198 / -7 = 205 changed lines over 4 files (dispatch-gates count) vs the 3000 human-merge threshold: under", "tests": "All at 4a0094b9 under os-verify-lock. Closure: pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build then VERDICT command-exit 0 (first attempt VERDICT queue-timeout exit 99, rejoined with slot). RED-FIRST (RecordFormPage.tsx restored tree-only to base 00a4593a, getRecordDisplayName count 0): new file 3 failed / 3 passed; failed = create named (expected 'Task created successfully' to be 'Task \"Quarterly review\" created'), update named (same, updated), zh named (expected 'Task更新成功'); passed = the three no-name cells, the direction written in the test header. Restore: git checkout HEAD -- path; blob 4442d066 == HEAD blob, git status clean. GREEN: the 10 app-shell test files importing RecordFormPage (9 existing + new): Test Files 10 passed (10), Tests 62 passed (62), VITEST_EXIT=0. pnpm --filter @object-ui/app-shell type-check: TYPECHECK_EXIT=0 (tsconfig.test.json includes src/**/*.test.tsx, so the new file is compiled). Full app-shell suite left to CI.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 4a0094b9: 34 derived, 34 run, --ran reconciliation 34/34 accounted (RAN_EXIT=0). 33 :: exit 0, including node scripts/check-sdui-manifest.mjs :: exit 0 (present and intact, sha256 1f6e1ccb925a, 106 components) and --self-test :: exit 0, and pnpm --dir ui exec vitest run scripts/ :: exit 0 (178 files passed / 2 skipped, 5097 tests passed). pnpm check:type-check-debt :: exit 3 PREREQUISITE NOT MET, twice: its --re-measure closure build never got a turn on the shared lock (VERDICT queue-timeout exit 99); NOT MEASURED, CI Type Check · debt ledger is the reading of record. No registry component contract changed, so sdui.manifest.json was not regenerated. PR check-runs at report time: in_progress (not awaited, per contract).", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches then fleet-write run 40462089677 then POST /repos/objectstack-ai/objectstack/pulls, draft #26528, body read back byte-identical, 5120 bytes); this os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/26461/comments). Plus git push (not a REST write).", "deviations": [ "The dispatch named the dialog paths in 'apps/console AppContent.tsx'; the helper PR #26202 added lives in ui/packages/app-shell/src/console/AppContent.tsx (ui/apps/console/src/AppContent.tsx is a thin wrapper over DefaultAppContent). Reused that one.", "The helper there is a component-local useCallback, not an export, so 'reuse exactly' was done as the same resolver call, same floor and same keys inside RecordFormPage (about six repeated lines). AppContent.tsx is outside the claim's file surface, so no shared builder was extracted (see open_questions).", "check:type-check-debt NOT MEASURED (exit 3, lock queue-timeout). A background re-run of it was left to end on its own after a kill of its recorded waiter pid was refused by the permission classifier; it ended at exit 3 before the worktree was removed.", "Commit trailers use the model-free pair AGENTS.md requires (Claude-Session + Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By line." ], "open_questions": [ { "question": "Extract recordSaveMessage into one shared builder used by both AppContent and RecordFormPage?", "options": [ "A: follow-up card for a pure helper in app-shell utils, called from both surfaces, so the two cannot drift", "B: leave the two six-line copies as they are" ], "recommendation": "A, because the page and the dialog already share helpers this way (isObjectFieldVisible, selectRecordFormView), and one builder stops the two surfaces from drifting; it needs AppContent.tsx on a claim." } ], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Landed · seat 2 · 2026-10-27T07:24Z
185512cc, head4a0094b9(+198/−7, seat record on #26528)origin/maingit merge-base --is-ancestorexit 0)gh-readonly-queue/main/pr-26528-*: none left (consumed)Fixes #26461on #26528Status: the full-page record form's save toast names the saved record (
Task "Quarterly review" updated), the same as the dialog paths.pm:dispatchedremoved.