Skip to content

Console: a save that passes a warning-severity rule shows one toast, the record-named save toast carrying the warning #27999

Closed

Description

@objectstack-fleet

domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

Filing gate: ③ triage-directed. The order on #27380 said: take what is ui-only, card the rest. The card thread measured each row on origin/main 5f6dc96c (report 6517004938, out_of_scope_findings). Row 1 is taken in PR #27996.
Reach: any record form save (overlay or page) whose answer carries advisory warnings from a severity: 'warning' validation rule.
Reader who acts: domain:ui. Blocked-by: #27907 (domain:ui seat 4's open PR holds console/AppContent.tsx).
Duplicate search: search_issues "save with warnings two toasts warning severity validation rule record saved toast" → #26172 and #22726, both closed (record naming and the answer's warnings). Not this.

Observed

A save whose answer carries warnings shows two toasts:

  1. The adapter's onWriteWarning channel (app-shell providers/writeWarningToast.ts, emitAnswerWarnings) toasts "Saved — with warnings" plus the rule messages when the write answers.
  2. The form overlay's crud_success handler in console/AppContent.tsx then toasts recordSaveMessage (OBJECT "TITLE" updated, the record naming of Record create/update success toasts name the record by its title, not only the object (ruling C on #25849) #26172).

Wanted

One toast. The save message keeps its record naming and carries the warning lines. The write-warning channel stops toasting answer warnings for a write that a record save surface reports itself; stripped-field notices keep their own toast. Landing: AppContent.tsx crud_success + recordSaveMessage, writeWarningToast.ts emitAnswerWarnings, and the same for RecordFormPage.tsx's page-mode save.

Dedupe words: warning save two toasts, Saved with warnings, crud_success toast, write warning toast, recordSaveMessage.

Related: #27380 (row 2), #26172, #22726.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

    Claim: PM loop round 1
    Session: session_01Utp6CbDAucNyQ4UtzCJKyh
    Account: os-bill
    Branch: claude/project-thread-j9w213 (this seat thread's designated push branch for its in-seat subagent dev, the recorded platform exception to claude/issue-<n>-<slug>)
    Worktree: objectstack-issue-27999
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: ui/packages/app-shell/src/console/AppContent.tsx (the crud_success handler and recordSaveMessage use), ui/packages/app-shell/src/providers/writeWarningToast.ts, ui/packages/app-shell/src/views/RecordFormPage.tsx (page-mode save toast), the module defining recordSaveMessage if it must change, their tests, .changeset/*.md (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: TIER_DEFAULT (dispatch-gates --tier on fec60e00: no path-derived mandate), effort: TIER_DEFAULT
    Clause-②: no
    Metadata-protocol: none
    Responsibility: a record save whose answer carries warning-severity rule messages shows one toast: the save message keeps its record naming and carries the warning lines; the write-warning channel stops toasting answer warnings for a write a record save surface reports itself; stripped-field notices keep their own toast
    Thread-read: none
    Premise: holds
    Serial constraints cleared: #27907 (Blocked-by) merged 11:04Z; no open PR touches the file surface

    Dispatched 2026-10-30T11:09Z to this seat's in-seat subagent; the order lives in the project. ⛔ The subagent posts no claim and writes no assignee.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
    os-dev-report

    Report of 2026-10-30T13:11Z.

    {
      "issue": 27999,
      "status": "done",
      "branch": "claude/project-thread-j9w213",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28114",
      "head": "2fcbdbcfc8531d4cc6806ef2bb2516ab8f0c3e0e",
      "session": "session_01Utp6CbDAucNyQ4UtzCJKyh",
      "premise_still_valid": true,
      "summary": "A record save whose answer carries warning-severity rule messages now shows one toast: the record-named save message (warning variant) with each distinct rule message on its own line, on the overlay (crud_success and child-form task) and on the page-mode form. Route: a claim in providers/writeWarningToast.ts (claimAnswerWarnings) that a record save surface holds while its form is open; emitWriteWarning matches the event against open claims on the adapter it is handed BEFORE its first await and parks the answer warnings there instead of toasting; the surface takes its write's warnings in its success handler. Not a race: the adapter emits the event inside create/update before the write's promise settles, and the form calls onSuccess only after it settles. Stripped-field notices keep their own toast; unclaimed or non-own parked events are shown on the channel toast at take or release, so no warning is dropped. Chosen over a per-write request flag or returning warnings to onSuccess, which would move the published data-objectstack write API and every plugin-form variant (Clause-2 yes); the claim stays in private app-shell with no new i18n key.",
      "files_changed": [
        ".changeset/27999-save-with-warnings-one-toast.md",
        "ui/packages/app-shell/src/console/AppContent.tsx",
        "ui/packages/app-shell/src/console/__tests__/AppContent.recordSaveOneToast-27999.test.tsx",
        "ui/packages/app-shell/src/providers/writeWarningToast.test.ts",
        "ui/packages/app-shell/src/providers/writeWarningToast.ts",
        "ui/packages/app-shell/src/views/RecordFormPage.saveToastCarriesWarnings-27999.test.tsx",
        "ui/packages/app-shell/src/views/RecordFormPage.tsx"
      ],
      "line_budget": "817 changed lines (+800 / -17), 7 files, under the 3000 human-merge threshold (dispatch-gates --ran reading); no skills/** touched",
      "tests": "head 2fcbdbcfc8: narrowed pin set of 61 files (every RecordFormPage* and AppContent* test in app-shell and apps/console, AdapterProvider*, ConsoleToaster*, writeWarningToast.test.ts) via os-verify-lock: VERDICT command-exit 0, Test Files 61 passed (61), Tests 433 passed (433). pnpm --filter @object-ui/app-shell run type-check: VERDICT command-exit 0 (its tsconfig.test.json compiles the new tests: it went red with TS7031 on the new overlay test on an earlier head, which was then fixed). Ablation via scripts/ablation-replace.mjs on writeWarningToast.ts (anchor: the matchingClaim lookup in emitWriteWarning, replaced so no claim is ever consulted; anchor x1->x0, replacement x0->x1, blob af23c268->95733a37); predicted 11 RED / every CONTROL GREEN; observed Tests 11 failed | 24 passed (35), exactly the predicted cells; restored blob af23c268 = HEAD blob, git diff HEAD empty. No dist build/preflight: app-shell tests import the module from source by relative path.",
      "gates": "local subset at head 2fcbdbcfc8, each 'command :: exit code' captured before any pipe: node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0 | node scripts/check-adr-0087-registration.mjs --self-test :: exit 0 | node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0 | node scripts/check-closing-keyword-parity.mjs :: exit 0 | node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0 | node scripts/check-comment-mask-corpus.mjs :: exit 0 | node scripts/check-empty-changeset.mjs --base origin/main :: exit 0 | node scripts/check-empty-changeset.mjs --self-test :: exit 0 | node scripts/check-sdui-manifest.mjs :: exit 0 | node scripts/check-sdui-manifest.mjs --self-test :: exit 0 | node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0 | node scripts/release-pending-publish.mjs --self-test :: exit 0 | pnpm --dir ui exec vitest run scripts/ :: exit 0 | pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0 | pnpm check:changeset-gate-self-tests :: exit 0 | pnpm check:closed-ceremony-text :: exit 0 | pnpm check:cross-package-test-inputs :: exit 0 | pnpm check:dispatcher-error-vocabulary :: exit 0 | pnpm check:driver-memory-census :: exit 0 | pnpm check:engine-double-contract :: exit 0 | pnpm check:gitlink-declared :: exit 0 | pnpm check:nul-bytes :: exit 0 | pnpm check:pm-changeset-deadline-census :: exit 0 | pnpm check:published-files :: exit 0 | pnpm check:query-options-erasure :: exit 0 | pnpm check:refd-timer-probe :: exit 0 | pnpm check:skill-identifier-liveness :: exit 0 | pnpm check:test-source-alias :: exit 0 | pnpm check:tier-file-adoption :: exit 0 | pnpm check:type-check-coverage :: exit 0 | pnpm check:type-check-debt :: exit 0 | pnpm check:undeclared-dep-imports :: exit 0 | pnpm check:watch-hint-literal :: exit 0 | pnpm check:where-matcher :: exit 0 | pnpm --dir ui run check:new-line-citations :: exit 0 | node scripts/check-platform-checklist.mjs --changed-from origin/main :: exit 0. dispatch-gates --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. CI check-runs at report time (head 2fcbdbcfc8): Check Changeset, Check PR Size, Governed Surface Queue Guard, Lint (ESLint, PM dispatch-gates, docs & code guards, repo & tooling gates, CI release & engine gates, scoped x3), PR-body guards, Type Check (consumer gates, debt ledger, source gates, workspace), filter: in_progress; 18.x upgrade harness, Packed-tarball smoke, Schedule gate: skipped. Test UI / Type Check UI / Build & E2E UI / Live E2E UI not yet listed.",
      "dogfood_battery": "n/a — no ! in the PR title and Clause-2 no without a (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write relay, op pr_create -> #28114, read-back identical 11274 bytes, assignees none); POST /repos/objectstack-ai/objectstack/issues/27999/comments (this report, via post-stamped). git push is not a REST write.",
      "deviations": [
        "Narrowed local test run, declared: the whole packages/app-shell suite (1963 files) was started under the lock and stopped after about 30 minutes at --maxWorkers=2 (it would have held the shared lock for over an hour); only my own recorded process group (pgid 5950) was terminated. Replaced by the 61-file pin set above; Test UI in CI runs the full sharded set.",
        "test:repo (vitest repo project) not run locally: the diff does not touch that project and the derived list does not name it; it is CI's (Test Core).",
        "Conflict, dispatch vs os-dev: os-dev bans dev-written HTML comments in GitHub text except a harness-written attribution comment; the dispatch orders the claude-projects-attribution comment on PR body line 2. Followed the dispatch, since that block is the platform's attribution, sent verbatim; it survived the read-back byte-identical.",
        "Conflict, dispatch vs os-dev: os-dev puts os-dev-report on the comment's first line; the dispatch puts the seat signature first. This comment has the signature on line 1 and os-dev-report alone on line 2, as the seat's earlier report comments do.",
        "Commit trailers use the model-free pair from AGENTS.md (Claude-Session + Co-authored-by: Claude) rather than the session's model-named Co-Authored-By line, which AGENTS.md and the dispatch both forbid.",
        "Changeset lists @object-ui/app-shell (private) and @object-ui/console as patch, which is the root .changeset convention for Console fixes; the dispatch asked for a patch changeset.",
        "One merge of origin/main (2fcbdbcfc8) had a conflict in RecordFormPage.tsx imports against #28066 (useLocation dropped there, useRef added here); resolved keeping both sides, then rebuilt the closure and re-ran type-check, the pin set, the ablation and every gate on the merged head."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: the batch path (batchTransaction, used by master-detail record forms) carries no answer warnings into the write-warning event, so a master-detail save has no warnings for either toast. This is a read-only inference, not reproduced, and is in the PR's Acceptance notes."
      ]
    }
  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh

    ACCEPT → PR #28114 comment 6523952409 · 2026-10-30T13:27Z


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions