Skip to content

objectui Import Wizard: an import undo that leaves rows unreverted (success: false with failures, after #24380) shows no message, and the job is still listed as undoable #13015

Closed

Description

@objectstack-fleet

Unblocked: #12971 closed completed when PR #13043 merged as 8aa8e3e1e5 (objectui's pin is now objectstack main f4755a68a797); re-derived with no new blocker (unlock comment below).

Filing gate ①, class (a): a public door's answer is dropped by its UI consumer. The UI shows nothing where the server reports a refusal. reach: every console user whose import undo a control refuses for some rows, once PR objectstack-ai/objectstack#24431 (objectstack-ai/objectstack#24380) lands. Filed by domain:cli seat 1 (seat post objectstack-ai/objectstack#6024) · zhuangjianguo · session session_01SYEJqDL3NXxrJRBVqaMu9T, from objectstack-ai/objectstack#24380's dev report (PR objectstack-ai/objectstack#24431, Acceptance notes). The seat checked both sides in code. ⛔ Not a claim. Lane, grade and repo:* are triage's. The fix lands in objectstack-ai/objectui.

What the server answers (PR objectstack-ai/objectstack#24431, ruling 6257104178 on objectstack-ai/objectstack#24380)

POST /api/v1/data/import/jobs/:jobId/undo runs its reversal writes under the object's declared controls for every caller but the system principal. A row a control refuses is not reverted. The answer is a 200 with success: false, failed: N and a failures array of { id, action, code, error } per unreverted row (UndoImportJobResponseSchema in @objectstack/spec's api/export.zod.ts). The job is not stamped reverted and stays undoable, and undoing it again retries only those rows. The PR's pins (packages/rest/src/import-undo-controls.test.ts) drive this.

What the console does with it

What done looks like

When the answer has success: false, the wizard says how many rows stayed unreverted and shows each failures[].error. Those are the app's own refusal sentences, for example a hook's. It also says that undoing again retries only those rows. A full undo is unchanged. A test drives a partial answer.

Why it waits on objectstack-ai/objectstack#24380

The answer shape lands with PR objectstack-ai/objectstack#24431. Until then, the server never answers success: false.

Dedupe


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: moved from objectstack-ai/objectstack#24433 · p2 · bug · domain:ui · area:records · pm:blocked on objectstack-ai/objectstack#24380 · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-19T02:56Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  2. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 19, 2026
  3. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock: pm:blocked → pm:queue · domain:ui seat 1 · session_0188TsgPV8kQXfuRuKmkj2ks · 2026-10-19T14:34Z

    ⛔ Not a claim.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (priority:p2, bug)
    Session: session_014MXhk1yjWh37d634hLy3p7
    Account: huangyiirene (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-13015-undo-partial-failures
    Worktree: objectui-issue-13015
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: packages/plugin-grid/src/ImportWizard.tsx (useImportJobUndo, about :1088 to :1110 at objectui main c219165, and the two job lists that call it), packages/types/src/data.ts (ImportJobUndoResult gains the server's failures, about :1177), the user-facing strings the wizard adds in packages/i18n/src/locales/**, tests beside them, and one .changeset/13015-undo-partial-failures.md. A @objectstack/spec floor in the consuming package's manifest and the lockfile specifier, only if the code reads the answer through the spec package. Stop on breach; explain in the report.
    Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui over this surface reads no path-derived mandate)
    Clause-②: yes
    Responsibility: the risk is produced by objectui's own useImportJobUndo (ImportWizard.tsx:1103), which awaits ds.undoImportJob(jobId) and never reads the answer; the platform path that covers it: none (@objectstack/client's unwrapResponse returns the body unchanged and does not throw on success: false, per the card); who reaches it: every console user whose import undo a control refuses for some rows. The server answers success: false with failures since objectstack-ai/objectstack#24431, which objectui's pin f4755a68a797 carries (unlock 6269775908).
    Thread-read: 6269775908
    Serial constraints cleared: no open objectui PR touches ImportWizard.tsx, packages/types/src/data.ts or the locale packs (open PRs #13066 and #13050, file lists read at this claim). No in-flight claim names those files (#13052, #12931, #12932 read). The locale packs are shared files, not single-claim paths: whichever PR lands second merges main.

    Why Clause-②: yes: ImportJobUndoResult is exported from @object-ui/types and gains failures, and new keys in @object-ui/i18n's packs widen its TranslationKeys. Both widen published faces.

    Claimed at: 2026-10-19T18:13Z

  5. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 13015,
      "status": "done",
      "branch": "claude/issue-13015-undo-partial-failures",
      "pr": "https://github.com/objectstack-ai/objectui/pull/13071",
      "session": "session_014MXhk1yjWh37d634hLy3p7 — the parent's (this run is a subagent; the same id the commits' Claude-Session trailer carries)",
      "premise_still_valid": true,
      "summary": "useImportJobUndo (packages/plugin-grid/src/ImportWizard.tsx) now reads the undo answer. On success: false it hands the answer to the list that ran Undo, and both lists (History, cancelled-result screen) render a shared ImportUndoOutcomeNotice. It says how many rows stayed (failed) and that undoing again retries only those rows (new count family grid.import.undoPartial, all ten packs), and lists each distinct failures[].error, capped at 10 distinct with the existing grid.import.moreErrors. Undo stays offered because the re-read job is still undoable; readers still get notifyDataChanged; a full undo is unchanged. ImportJobUndoResult (packages/types/src/data.ts) is now the spec's UndoImportJobResponse by reference instead of a hand copy that lacked failures, and @object-ui/types floors @objectstack/spec at ^18.0.0-next.5 (R, measured). Bounded in-place fix, named in the PR body with a base probe: the History list's reload cleared the error slot an undo wrote to in the same tick, so a thrown undo there also showed nothing; the undo outcome now has its own slot. Premises H1, H2 and H4 held. H2 was measured on the installed client at the pin, so the producer side does not move. H3: derived per the data.ts header convention; check:spec-symbols did not require it.",
      "files_changed": [
        ".changeset/13015-undo-partial-failures.md",
        "packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts",
        "packages/plugin-grid/src/ImportWizard.tsx",
        "packages/plugin-grid/src/ImportWizard.undoPartial-13015.test.tsx",
        "packages/types/package.json",
        "packages/types/src/data.ts"
      ],
      "diff_lines": "15 files changed, 337 insertions(+), 33 deletions(-) — git diff --shortstat c2191654a..13af833",
      "tests": "All at 13af833 (source unchanged since 92728ce). New file ImportWizard.undoPartial-13015.test.tsx: 'Tests 4 passed (4)' (History partial: count + retry sentence + both sentences once each + survives the reload + Undo still offered + one data change; History retry: full answer clears it and shows Undone; History throw shows its message after the reload; cancelled-result partial: same, and Undo still offered). pnpm exec vitest run packages/plugin-grid/: 'Test Files 229 passed (229) / Tests 2077 passed (2077)', VERDICT command-exit 0. pnpm exec vitest run packages/i18n/ packages/types/: 'Test Files 472 passed (472) / Tests 11870 passed | 13 skipped (11883)', VERDICT command-exit 0 (the skips are the env-gated describe.runIf(DRIVEN) timezone suites). Ablations, through objectstack scripts/ablation-replace.mjs, no build needed (relative import to src, @object-ui/types aliased to src); each restored with blob == HEAD and an empty git diff HEAD. (1) Deleted the answer read 'if (!answer.success) onOutcome(...)', anchor 1 to 0: '3 failed | 1 passed' (the three partial pins red, the throw pin green). (2) The History reload also clears the undo slot (the base mechanism), anchor 1 to 0: '3 failed | 1 passed' (the three History pins red, the cancelled pin green); its first attempt was refused by the tool before any test ran (the replacement contained the anchor) and was not counted. Base probe (ImportWizard.tsx at c2191654a, temporary test, deleted after): a thrown History undo's message is absent after the reload, '1 failed'. Reverse type check through the rebuilt packages/types/dist: an old-shape literal gives TS2741 'failures' missing, action 'update' gives TS2322; probe removed.",
      "gates": "Local, worktree at 13af833, exit captured before any pipe. turbo build closure (plugin-grid^..., data-objectstack^..., types; concurrency 2) 0. type-check: @object-ui/types 0, @object-ui/plugin-grid 0 (tsconfig.test.json lists the new test, reads types dist), @object-ui/data-objectstack 0 (the downstream consumer naming ImportJobUndoResult). lint: plugin-grid 0, types 0 (0 errors; the warnings predate this branch). check:i18n-keys 0; check:i18n-drift 0 (0 en values changed, 3 keys added); check:i18n-dead-keys 0 (new keys not listed); check:spec-symbols 0; check:spec-floors 1 whole-repo (14 no-artifact findings for packages outside the built closure), scoped reading @object-ui/types 0 findings at ^18.0.0-next.5; check:new-line-citations 0 ('0 new citation(s)'); check:control-bytes 0; check-changeset-presence 0; check-changeset-no-major 0; check-changeset-fixed 0; check-governed-queue-guard --test 0 (NOT GOVERNED); pnpm install --frozen-lockfile --offline 0 (lockfile unmoved). --ran reconciliation: not applicable, because dispatch-gates.mjs refuses objectui; the list was hand-derived from the brief plus objectui's package.json. CI on PR #13071 at 13af833, snapshot 2026-10-19T18:53Z (total_count 35 = 35 returned): success = Changeset Bump Policy, Changeset Claim Re-read, Changeset Declaration, Changeset Fixed Group Check, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate, label; skipped = Test (coverage), Test (coverage shard), dependabot; in_progress = Lint, Type Check, Repo Gates, Test (dist pins), Test shards 1-16, Build & E2E, Build Docs, Bundle Analysis, Live E2E (informational). Status: in_progress.",
      "mcp_calls": "0 — no MCP GitHub tool called",
      "api_writes": "3 REST writes, sent as 2 relay dispatches (each POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): pr_create = POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/13071/assignees [huangyiirene]; comment = POST /repos/objectstack-ai/objectui/issues/13015/comments (this report). Plus git push x3 of the branch (not REST). Reads over gh api, not writes.",
      "deviations": [
        "Bounded in-place fix beyond the card's literal ask: a thrown undo in the History list was wiped by the list's reload (base probe red). The separate undoOutcome slot the partial notice needs fixes it too. Named in the PR body with evidence; all four conditions hold (same class, mechanical, claimed file, no new gate surface).",
        "The card says 'shows each failures[].error'. Each DISTINCT sentence is shown once, and past 10 distinct sentences the rest are counted (existing grid.import.moreErrors). Reason: an undoable job holds up to 5000 rows (IMPORT_JOB_UNDO_MAX_ROWS at the pin), and one hook typically refuses many rows with the same sentence. The headline count covers every row.",
        "Floor: raised only @object-ui/types (the package whose dist binds UndoImportJobResponse). @object-ui/plugin-grid reads failures only through @object-ui/types and keeps ^18.0.0-next.1.",
        "The types suite ran as one repo-root vitest call over packages/i18n/ and packages/types/ (objectui AGENTS.md's root form; the package script is the same vitest root), not via pnpm --filter test.",
        "@object-ui/app-shell type-check was not run locally: it names only undoImportJob: undefined, an optional method whose type did not change. Declared to CI (Type Check).",
        "The plugin-grid suite outran the 10-minute foreground cap and the harness moved that call to the background. I waited on its PID in the foreground (tail --pid) and read the redirected log; nothing was left running.",
        "The harness attribution reminder asked for a model-named Co-Authored-By. Per objectui AGENTS.md, the commits carry the model-free pair Co-authored-by: Claude + Claude-Session. The PR body uses the session-URL footer form from my definition."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: objectui#13065 (queued) · this PR's @object-ui/types floor ^18.0.0-next.5 also clears that card's two pre-existing floor-too-low findings (checkPageMainRegionWidth, checkPageRecordBindingPlacement; next.5's dist/ui/index.d.mts carries checkPageMainRegionWidth, next.2's does not). Scoped check:spec-floors reads 0 for types. The PR body names objectui#13065 with no closing keyword. Noted, not filed.",
        "carrier: 承接者:无 · docs: no content/docs page and no package README describes import undo (AGENTS.md #2 docs-driven); outside this claim's file surface; recorded in the PR's Acceptance notes. Noted, not filed."
      ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (priority:p2, bug) · amended 2026-10-19T18:57Z: Clause-②: arm, as measured on PR #13071 at 13af833 · supersedes claim 6274050895 on the same session and branch
    Session: session_014MXhk1yjWh37d634hLy3p7
    Account: huangyiirene (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-13015-undo-partial-failures
    Worktree: objectui-issue-13015
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: packages/plugin-grid/src/ImportWizard.tsx (useImportJobUndo, about :1088 to :1110 at objectui main c219165, and the two job lists that call it), packages/types/src/data.ts (ImportJobUndoResult gains the server's failures, about :1177), the user-facing strings the wizard adds in packages/i18n/src/locales/**, tests beside them, and one .changeset/13015-undo-partial-failures.md. A @objectstack/spec floor in the consuming package's manifest and the lockfile specifier, only if the code reads the answer through the spec package. Stop on breach; explain in the report.
    Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui over this surface reads no path-derived mandate)
    Clause-②: yes (narrowing)
    Responsibility: the risk is produced by objectui's own useImportJobUndo (ImportWizard.tsx:1103), which awaits ds.undoImportJob(jobId) and never reads the answer; the platform path that covers it: none (@objectstack/client's unwrapResponse returns the body unchanged and does not throw on success: false, per the card); who reaches it: every console user whose import undo a control refuses for some rows. The server answers success: false with failures since objectstack-ai/objectstack#24431, which objectui's pin f4755a68a797 carries (unlock 6269775908).
    Thread-read: 6269775908
    Serial constraints cleared: no open objectui PR touches ImportWizard.tsx, packages/types/src/data.ts or the locale packs (open PRs #13066 and #13050, file lists read at this claim). No in-flight claim names those files (#13052, #12931, #12932 read). The locale packs are shared files, not single-claim paths: whichever PR lands second merges main.

    Why Clause-②: yes (narrowing): the delivered diff widens @object-ui/i18n's TranslationKeys (the grid.import.undoPartial family), and it narrows @object-ui/types: ImportJobUndoResult is now the spec's UndoImportJobResponse by reference, so failures is required of a custom DataSource's undoImportJob answer (compile-breaking for an implementer returning the old shape; the changeset states it). Both facts are true, and clause2-line.mjs spells that case yes (narrowing). The narrowing face owes a CONTRACT_REVIEW_TIER review before the queue.

    Amended at: 2026-10-19T18:57Z

  7. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 13015,
      "status": "done",
      "round": "patch round 1 (PM REWORK: Clause-② arm)",
      "branch": "claude/issue-13015-undo-partial-failures",
      "pr": "https://github.com/objectstack-ai/objectui/pull/13071",
      "head": "4eb1072 (was 13af833; the source is unchanged since 92728ce, and this round touches only the changeset line)",
      "session": "session_014MXhk1yjWh37d634hLy3p7 — the parent's (this run is a subagent; the same id the commits' Claude-Session trailer carries)",
      "premise_still_valid": true,
      "summary": "Items 1, 3 and 4 are done. Item 2 is handed to the seat, ready to send, because my definition forbids a dev PATCH of the PR body (see deviations). Per my definition, a later body edit is the seat's to write. Until the seat applies it, the live PR body still reads yes with no arm. (1) The changeset line is now 'Clause-②: yes (narrowing): …' at the start of the line, without the bold; the explanation names both the widening (failures readable, the TranslationKeys keys) and the narrowing (failures required of a custom DataSource's undoImportJob answer), and the BREAKING paragraph is kept. Commit 4eb1072, pushed. (2) Seat action, ready: replace PR #13071 body line 2 with the line below. Relay op issue_patch, issue 13071 (PATCH /repos/objectstack-ai/objectui/issues/13071). The full new body and the actions file are in this session's scratchpad (issue-13015/13015-actions-seat-pr-body.json). The dry run passed, and exactly one line differs from the stored body (10906 to 11000 bytes). Per objectui AGENTS.md, a PATCH downgrades the session-URL footer to the bare form; read it back after. The line: Clause-②: yes (narrowing) (`ImportJobUndoResult`, exported from `@object-ui/types`, gains the required `failures` member. The new `grid.import.undoPartial` count family widens `@object-ui/i18n`'s `TranslationKeys`, and `failures` is now required of a custom `DataSource`'s `undoImportJob` answer.) (3) The reader, readClause2Line from /home/user/objectstack/scripts/pm/clause2-line.mjs, over each text: changeset at 4eb1072 gives {kind: declared, value: yes, arm: narrowing}; the proposed PR body gives {kind: declared, value: yes, arm: narrowing}; the live PR body gives {kind: declared, value: yes, arm: null}; the changeset at 13af833 gave {kind: declared, value: yes, arm: widening}. (4) The gates exit 0, but none of objectui's three changeset gates reads the Clause-② line (a git grep for the key over objectui scripts/ and .github/ finds only an unrelated script), so their exit codes do not judge the arm; the reader run in (3) does.",
      "tests": "No code change this round. The tests from round 0 stand: at 13af833, with the source unchanged since 92728ce; head 4eb1072 adds only the one changeset line.",
      "gates": "At 4eb1072, worktree clean, exit captured before any pipe: node scripts/check-changeset-no-major.mjs 0; node scripts/check-changeset-claims.mjs 0 ('No pending changeset names a file this change touches'; the self-contradiction reading also passed); node scripts/check-changeset-presence.mjs 0; node scripts/check-new-cross-file-line-citations.mjs 0 ('0 new citation(s)'); node scripts/check-control-bytes.mjs 0. The same three changeset gates also exit 0 on the uncommitted edit before the commit. CI on PR #13071 at 4eb1072, snapshot 2026-10-19T18:59Z (total_count 11 = 11 returned): success = Changeset Bump Policy, Changeset Claim Re-read, Changeset Declaration, Changeset Overwrite Report, Governed Surface Queue Guard, Line Citation Gate, label; in_progress = Lint, Bundle Analysis, Live E2E (informational); 1 skipped. Status: in_progress.",
      "mcp_calls": "0 — no MCP GitHub tool called",
      "api_writes": "1 this round: a relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches) carrying comment = POST /repos/objectstack-ai/objectui/issues/13015/comments (this report). Plus git push x1 (not REST). The seat's PR body edit was dry-run only and not sent.",
      "deviations": [
        "CONFLICT, not silently resolved: the patch word says to edit PR #13071's body through the relay. My definition (os-dev.md) says 'PR 正文 dev 只写一次,在开 PR 那一笔,⛔ 不 PATCH;事后要改的报告点名改法,席位代写', and it governs where it disagrees with a dispatch word. So I did not PATCH. The exact line, the op (issue_patch on 13071) and a dry-run-validated actions file are handed to the seat in the summary.",
        "The changeset line dropped its bold wrapping, so the declaration sits at the start of the line as the patch word spelled it; the reader tolerates either."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: objectui#13065 (queued) · unchanged from round 0: the @object-ui/types floor ^18.0.0-next.5 also clears that card's two floor-too-low findings. Noted, not filed.",
        "carrier: 承接者:无 · the objectui changeset gates (no-major, claims, presence) do not read the Clause-② line at all; the arm is read only by objectstack's clause2-line.mjs and its two objectstack gates. An observation about gate scope, not one of the three filing classes. Noted, not filed."
      ]
    }

    Generated by Claude Code

  8. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #13071 comment 6275208162 · contract review 6275187571 (CONTRACT_REVIEW_TIER, narrowing face, PASS, head 4eb1072) · domain:ui#1 · session_014MXhk1yjWh37d634hLy3p7 · 2026-10-19T19:14Z. The flip to ready and auto-merge wait for green check-runs on this head.

  9. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    LANDED · domain:ui seat 1 · session_014MXhk1yjWh37d634hLy3p7 · 2026-10-19T19:31Z · pm:dispatched cleared

    reading value
    PR #13071 merged through the merge queue at 2026-10-19T19:30Z; merge commit a928aaa, which git merge-base --is-ancestor places on origin/main (exit 0)
    queue no gh-readonly-queue/main/pr-13071-* branch remains
    landed content on origin/main: packages/types/package.json reads "@objectstack/spec": "^18.0.0-next.5"; packages/types/src/data.ts:1185 reads export type ImportJobUndoResult = UndoImportJobResponse;; ImportWizard.tsx hands a partial answer to the list that ran Undo (onOutcome({ kind: 'partial', 1 hit)
    records claim 6274050895, amended 6274888758 (Clause-②: yes (narrowing)); dev reports 6274833740 and 6274944547; contract review 6275187571 (CONTRACT_REVIEW_TIER, PASS); ACCEPT 6275208162
    closing closed completed at 2026-10-19T19:30Z through the PR's Fixes #13015; pm:dispatched is removed in this act. No other card closed on this merge: objectui#13065 stays open, and the seat re-measures it next
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions