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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
console(import): cancelling a background import reports "0 imported" while the server already committed the processed rows — users re-import instead of undoing #11650
Found in the ObjectStack 17.7 pre-release follow-up run objectstack-ai/objectstack#21845 (framework subject 316be321e, console pin 2e818d0b51ec), reproduced twice by the runner; an independent verifier (RUNNER rule 7) confirmed it from source: low-medium. It predates the 17.6.0 console pin 31971ff1e; no open duplicate was found. Owner: objectui.
Reproduction
As admin, open an object's list (showcase showcase_contact) → Import; upload a 5000-row CSV; Next; tick the background-import option; Run.
About 2.5 s later click Cancel.
Expected: the result shows how many rows were committed before the cancel, and points to Undo.
Actual: "Import cancelled · 0 imported", while the job reads cancelled with e.g. 1800 created (the partial is coherent and undoable from History).
Mechanism
packages/plugin-grid/src/ImportWizard.tsxhandleCancelImport (~2186-2201) builds the result with importedRows: 0 (:2195) instead of re-reading the job; the client's cancelImportJob returns only {success}, but the wizard already holds the job id.
Done when
After cancel the wizard reads the job (GET /api/v1/data/import/jobs/:id), shows created/updated counts and an undo affordance.
Path: business objects and records — import and its undo | records-forms.import-job-undo-cancel | P2
Triage: first grade — bug · priority:p3 · domain:ui · area:records · pm:queue. After a cancel, the wizard re-reads the job and shows what was committed, with Undo
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-05T09:03Z. ⛔ Not a claim, ⛔ not a dispatch.
Triage: lands in packages/plugin-grid/src/ImportWizard.tsx (handleCancelImport, about :2186–:2201) ⇒ domain:ui; rationale: the wizard holds the job id but writes importedRows: 0 instead of reading the job.
Why p3. The data is coherent and undoable from History. Only the summary is wrong, but it can lead a user to import twice. The verifier graded it low to medium. It predates 17.6.0.
Direction, as the card states. After cancel, GET /api/v1/data/import/jobs/:id, then show the created and updated counts and the Undo affordance. ⛔ No change to the cancel door's answer.
Pins: cancel mid-run, and the summary equals the job's counts.
Claim: PM loop round 2
Session: session_015W8GBu6sBiqus2L2xjMsAL
Account: os-steve
Branch: claude/issue-11650-import-cancel-counts
Worktree: objectui-issue-11650
Domain: domain:ui
Seat: domain:ui#1
File surface: packages/plugin-grid/src/ImportWizard.tsx (handleCancelImport, about :2186–:2201, and the poll loop's cancelled branch it can share, about :2002), the tests beside it, and .changeset/11650-*.md (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: opus (dispatch-gates --tier: no path-derived mandate; default tier)
Clause-②: no
Thread-read: 5991383632
Serial constraints cleared: none. No open PR and no in-flight claim touches packages/plugin-grid/src/ImportWizard.tsx. Read 2026-10-05T10:05Z.
Why Clause-②: no: after a cancel, the wizard re-reads the job it already holds and shows its committed counts with the existing Undo path (triage 5991383632). The cancel door's answer is unchanged, and no export, prop, type member or i18n key is added.
os-dev-report
{
"issue": 11650,
"status": "done",
"branch": "claude/issue-11650-import-cancel-counts",
"pr": "#11657",
"session": "session_015W8GBu6sBiqus2L2xjMsAL — subagent run, the parent's id (Claude-Session trailer on every commit)",
"premise_still_valid": true,
"summary": "After a user Cancel, ImportWizard now reads the job back through the data source's getImportJobProgress (the GET /api/v1/data/import/jobs/:id read). It reads at most 10 times, one per 800 ms, until the outcome is final, then shows the job's created/updated counts and an Undo import button whenever the job reads undoable. The Undo runs the History list's own undo action, factored into a module-private hook. A cancelled read counts as final only when it is undoable or repeats the previous cancelled read's counts, because the server's cancel route writes 'cancelled' before its worker's last write; the poll loop shares this rule and the result builder. A run token makes the poll loop and the Cancel publish once, so onComplete is called once, and a closed wizard still reports a background job through onComplete as before. Two behaviour changes: onComplete now fires on a user Cancel that reads back (the console list refreshes and shows its usual toast), and a declared in-place fix makes a successful Undo call notifyDataChanged so the open list refetches. Live before/after on my own showcase backend: base showed 'Import cancelled · 0 imported' while the job read cancelled with 1800 created; the branch showed '1800 created · Undo import', and Undo reverted the job and removed its rows.",
"tests": "Final head 02d9266, after one merge of origin/main at 4367146. (1) pnpm exec vitest run packages/plugin-grid/: 'Test Files 186 passed (186)', 'Tests 1721 passed (1721)'; vitest list --filesOnly lists 186 files, including [dom] packages/plugin-grid/src/ImportWizard.cancelCounts-11650.test.tsx. (2) pnpm --filter @object-ui/plugin-grid type-check: exit 0. It runs 'tsc --noEmit && tsc -p tsconfig.test.json', and --listFilesOnly shows the test project compiles the new test file. The dependency closure was built first with pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-grid^...' build: exit 0. (3) pnpm --filter @object-ui/plugin-grid lint: exit 0, '943 problems (0 errors, 943 warnings)'. ESLint JSON per file gives ImportWizard.tsx 10 warnings (3 react-refresh, 2 no-explicit-any, 5 set-state-in-effect), the same as on base f1a177c, and the new test file 0. (4) Root checks, exit 0 each: check:i18n-keys, check:i18n-dead-keys, check:new-line-citations ('0 new citation(s)'), check:control-bytes, check:test-path-roots, check:changeset-claims, check:pending-changeset-literals, check:handler-key-reads, check:unreferenced-sources, check:shell-escape-residue, check:vi-mock-specifiers, check:phantom-deps, scripts/check-changeset-no-major.mjs, scripts/check-changeset-presence.mjs. The governed-queue-guard --test answered NOT GOVERNED. The control-byte grep exited 1 (no match), with a positive control on the same file. (5) New file ImportWizard.cancelCounts-11650.test.tsx, 10 pins, real timers: cancel mid-run (summary 1950 created / 50 updated, not the early 1800; Undo offered; onComplete once); a running first read then settled; never-undoable job final on two agreeing cancelled reads; Undo reads 'Undone'; bus notify from the result Undo and from the History Undo, and none after a failed undo; a Cancel during an in-flight poll read publishes once; the poll loop does not finalize on its first cancelled read; closing mid-run still calls onComplete; bound hit shows no count and no onComplete. (6) Reverse verification, committed first. ImportWizard.tsx was swapped for the base blob 6fc2ab5 under an EXIT/INT/TERM restore trap: 9 of 10 red; the close-mid-run pin stayed green, as a pin that must hold on base should. Restore proven by blob c82ede3 == HEAD and an empty git diff HEAD. (7) Ablations via objectstack scripts/ablation-replace.mjs, each landing and restore proven by anchor counts and blobs: settle rule reduced to 'any terminal read is final' gave exactly 3 red (mid-run, never-undoable, cancelled elsewhere); notifyDataChanged removed gave exactly the 2 bus pins red; the reset() token bump re-inserted gave exactly the close-mid-run pin red. The first attempt at that last ablation was a NO-OP refused by the tool (the replacement contained the anchor) and was re-run with a non-overlapping anchor. Source-aliased suite, so no dist rebuild applies. (8) Live, my own backend: objectstack main 2df3d13d built in my own worktree with OS_SKIP_DTS=1 (60 tasks), showcase dev --fresh on a private port; console vite from base and branch worktrees; Playwright with a 5000-row CSV, background import, Cancel after 2.5 s. Before (f1a177c): 'Import cancelled 0 imported', no Undo; the job read cancelled, 1800 created, undoable true. After (d0bfaa4): 'Import cancelled 1800 created Undo import'; the job read 1800. Final (02d9266): '2000 created Undo import'; the job read 2000. Undo gave 'Undone' and revertedAt set; a filtered count of that run's contacts returned 0 (the same filter returned 1800 for the un-undone before run); one list GET followed the Undo click. API probe, 6 runs: the cancel POST answered 5.8 to 9.4 s after sending. The first read after it answered was already cancelled+undoable with final counts in 4 of 4 sequential runs. A concurrent 50 ms poller (2 runs) never saw a cancelled job that was not yet undoable on SQLite. NOT MEASURED locally, left to CI: full pnpm test farm, repo-wide pnpm lint, check:eager-closure. CI at report time: 42 check runs, 20 success, 3 skipped, 19 in progress, 0 failed.",
"mcp_calls": "0 — none",
"api_writes": "3 — each one relay POST /repos/objectstack-ai/objectstack/dispatches (fleet-write, executed as objectstack-fleet[bot]): (1) pr_create, i.e. POST /repos/objectstack-ai/objectui/pulls (draft, PR 11657); (2) label-write --assign os-steve, i.e. POST /repos//issues/11657/assignees; (3) this os-dev-report, i.e. POST /repos//issues/11650/comments. Not counted, since not REST: git pushes of the branch (the empty-branch probe plus 5 commit pushes).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted, not filed — observation: during a 5000-row import on the SQLite showcase, every HTTP request I timed against that server took 4 to 9 s (progress GET 4.1 to 6.4 s, cancel POST 5.8 to 9.4 s, six runs); the import runner yields once per progress boundary. This is latency, not a wrong answer, so it is outside class a/b/c. Dedupe words: import job event loop latency, yieldToEventLoop, cancel slow, progress request slow",
"carrier: 承接者:无 · noted, not filed — source reading in @objectstack/rest: the cancel route writes status 'cancelled' and completed_at to the job row before the worker's final write (counts, results, undo_log), so the job can read terminal before its counts settle. Not observed live on SQLite in 6 runs; the wizard's settle rule absorbs it. Dedupe words: cancelled before worker stops, import job terminal early, completed_at cancel route, undoable false after cancel",
"carrier: 承接者:无 · noted, not filed — source reading in objectui: ImportHistoryPanel.load clears its error to null at the start, and the History undo's reload runs right after a failure, so a failed History undo's message is wiped as soon as the reload starts. This PR keeps that behaviour unchanged; the new result-screen Undo keeps its own error. Dedupe words: import history undo error cleared, ImportHistoryPanel error reload, undo failure message disappears"
],
"files_changed": [
"packages/plugin-grid/src/ImportWizard.tsx",
"packages/plugin-grid/src/ImportWizard.cancelCounts-11650.test.tsx",
".changeset/11650-import-cancel-counts.md"
],
"gates": {
"head": "02d9266",
"vitest packages/plugin-grid/": "exit 0 — 186 files / 1721 tests passed",
"plugin-grid^... build": "exit 0",
"plugin-grid type-check": "exit 0",
"plugin-grid lint": "exit 0 (0 errors; ImportWizard.tsx warnings 10 == base 10)",
"check:i18n-keys": 0,
"check:i18n-dead-keys": 0,
"check:new-line-citations": 0,
"check:control-bytes": 0,
"check:test-path-roots": 0,
"check:changeset-claims": 0,
"check:pending-changeset-literals": 0,
"check:handler-key-reads": 0,
"check:unreferenced-sources": 0,
"check:shell-escape-residue": 0,
"check:vi-mock-specifiers": 0,
"check:phantom-deps": 0,
"check-changeset-no-major": 0,
"check-changeset-presence": 0,
"governed-queue-guard --test": "NOT GOVERNED",
"ci": "in_progress at report time (0 failed)"
},
"line_budget": "n/a — no skills/** or governed ledger touched",
"deviations": [
"Zone 2 #2 partly falsified by source and measured: the job reads terminal 'cancelled' as soon as the cancel route answers, because the route writes it itself. The open question is whether the counts and the undo log have settled, not whether the job is terminal. So the read loop waits for terminal AND (undoable OR counts unchanged across two cancelled reads), bounded at 10 reads. Bound hit: 'Import cancelled' with no count badge and no onComplete.",
"Zone 2 #3 'keep today's behaviour' when no read is possible: kept no-read and no-onComplete, but the '0 imported' badge is no longer shown for a cancelled result whose counts were never read (that badge is the defect itself). Through the UI this path is reachable only via the bound hit, since the Cancel button needs a job id and runAsyncImport requires getImportJobProgress.",
"Zone 2 #4: chose the direct 'Undo import' button on the cancelled result over the History toggle, reusing handleUndo by moving it into a module-private useImportJobUndo hook that the History list now uses too.",
"Behaviour change: onComplete now fires once on a user Cancel that reads back (matching the poll loop's existing cancelled branch, Zone 3 pin); the console list refreshes and shows its import toast.",
"In-place fix (declared in the PR): a successful Undo calls notifyDataChanged({ objectName }), from the History list and from the result. Without it, the list refreshed by the new onComplete kept showing rows the Undo had deleted. It is in the claimed file and the same gate family, and the bus's own doc comment asks for this call on every write path.",
"Commit trailers use the model-free pair from objectui AGENTS.md (Claude-Session + Co-authored-by: Claude) instead of the harness reminder's model-named Co-Authored-By. The PR footer uses the os-dev session-URL form instead of the harness's footer text.",
"Labels: zero written (the dispatch named none; objectui path labels come from labeler.yml). The PR carries plugin and tests from the labeler.",
"Worktrees removed after the PR opened: objectui-issue-11650, a base comparison worktree objectui-issue-11650-base, and objectstack-issue-11650-live. All dev servers I started were stopped by their own process groups."
]
}
Merged through the merge queue as squash commit 846f982 (one parent, b88937b), an ancestor of origin/main. Its +/- lines are identical to the PR head 02d9266 diffed from its merge base: 3 files, +560/−48.
Content check against the first parent:
reading
b88937b
846f982
function isSettledJobRead in plugin-gridImportWizard.tsx (the settle rule)
0
1
function useImportJobUndo (the shared, module-private Undo)
0
1
notifyDataChanged({ objectName }) after a successful Undo
0
1
ImportWizard.cancelCounts-11650.test.tsx exists
no
yes
function isImportJobUndoable (control)
1
1
The card closed completed through the PR's Fixes line. It was the only issue closed in that window. pm:dispatched is removed in this stroke.
Left as noted, not filed:
request latency during a large SQLite import;
the REST cancel route writing cancelled before the worker's last write (the settle rule absorbs it);
ImportHistoryPanel.load clearing a failed History undo's error.
Activity
objectstack-fleet commentedon Oct 5, 2026
Path: business objects and records — import and its undo | records-forms.import-job-undo-cancel | P2
Triage: first grade —
bug·priority:p3·domain:ui·area:records·pm:queue. After a cancel, the wizard re-reads the job and shows what was committed, with UndoTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-05T09:03Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/plugin-grid/src/ImportWizard.tsx(handleCancelImport, about:2186–:2201) ⇒domain:ui; rationale: the wizard holds the job id but writesimportedRows: 0instead of reading the job.GET /api/v1/data/import/jobs/:id, then show the created and updated counts and the Undo affordance. ⛔ No change to the cancel door's answer.Generated by Claude Code
objectstack-fleet commentedon Oct 5, 2026
Claim: PM loop round 2
Session:
session_015W8GBu6sBiqus2L2xjMsALAccount:
os-steveBranch:
claude/issue-11650-import-cancel-countsWorktree:
objectui-issue-11650Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/plugin-grid/src/ImportWizard.tsx(handleCancelImport, about:2186–:2201, and the poll loop'scancelledbranch it can share, about:2002), the tests beside it, and.changeset/11650-*.md(stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus(dispatch-gates --tier: no path-derived mandate; default tier)Clause-②: no
Thread-read: 5991383632
Serial constraints cleared:
none. No open PR and no in-flight claim touchespackages/plugin-grid/src/ImportWizard.tsx. Read 2026-10-05T10:05Z.Why
Clause-②: no: after a cancel, the wizard re-reads the job it already holds and shows its committed counts with the existing Undo path (triage5991383632). The cancel door's answer is unchanged, and no export, prop, type member or i18n key is added.objectstack-fleet commentedon Oct 5, 2026
os-dev-report
{
"issue": 11650,
"status": "done",
"branch": "claude/issue-11650-import-cancel-counts",
"pr": "#11657",
"session": "session_015W8GBu6sBiqus2L2xjMsAL — subagent run, the parent's id (Claude-Session trailer on every commit)",
"premise_still_valid": true,
"summary": "After a user Cancel, ImportWizard now reads the job back through the data source's getImportJobProgress (the GET /api/v1/data/import/jobs/:id read). It reads at most 10 times, one per 800 ms, until the outcome is final, then shows the job's created/updated counts and an Undo import button whenever the job reads undoable. The Undo runs the History list's own undo action, factored into a module-private hook. A cancelled read counts as final only when it is undoable or repeats the previous cancelled read's counts, because the server's cancel route writes 'cancelled' before its worker's last write; the poll loop shares this rule and the result builder. A run token makes the poll loop and the Cancel publish once, so onComplete is called once, and a closed wizard still reports a background job through onComplete as before. Two behaviour changes: onComplete now fires on a user Cancel that reads back (the console list refreshes and shows its usual toast), and a declared in-place fix makes a successful Undo call notifyDataChanged so the open list refetches. Live before/after on my own showcase backend: base showed 'Import cancelled · 0 imported' while the job read cancelled with 1800 created; the branch showed '1800 created · Undo import', and Undo reverted the job and removed its rows.",
"tests": "Final head 02d9266, after one merge of origin/main at 4367146. (1) pnpm exec vitest run packages/plugin-grid/: 'Test Files 186 passed (186)', 'Tests 1721 passed (1721)'; vitest list --filesOnly lists 186 files, including [dom] packages/plugin-grid/src/ImportWizard.cancelCounts-11650.test.tsx. (2) pnpm --filter @object-ui/plugin-grid type-check: exit 0. It runs 'tsc --noEmit && tsc -p tsconfig.test.json', and --listFilesOnly shows the test project compiles the new test file. The dependency closure was built first with pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-grid^...' build: exit 0. (3) pnpm --filter @object-ui/plugin-grid lint: exit 0, '943 problems (0 errors, 943 warnings)'. ESLint JSON per file gives ImportWizard.tsx 10 warnings (3 react-refresh, 2 no-explicit-any, 5 set-state-in-effect), the same as on base f1a177c, and the new test file 0. (4) Root checks, exit 0 each: check:i18n-keys, check:i18n-dead-keys, check:new-line-citations ('0 new citation(s)'), check:control-bytes, check:test-path-roots, check:changeset-claims, check:pending-changeset-literals, check:handler-key-reads, check:unreferenced-sources, check:shell-escape-residue, check:vi-mock-specifiers, check:phantom-deps, scripts/check-changeset-no-major.mjs, scripts/check-changeset-presence.mjs. The governed-queue-guard --test answered NOT GOVERNED. The control-byte grep exited 1 (no match), with a positive control on the same file. (5) New file ImportWizard.cancelCounts-11650.test.tsx, 10 pins, real timers: cancel mid-run (summary 1950 created / 50 updated, not the early 1800; Undo offered; onComplete once); a running first read then settled; never-undoable job final on two agreeing cancelled reads; Undo reads 'Undone'; bus notify from the result Undo and from the History Undo, and none after a failed undo; a Cancel during an in-flight poll read publishes once; the poll loop does not finalize on its first cancelled read; closing mid-run still calls onComplete; bound hit shows no count and no onComplete. (6) Reverse verification, committed first. ImportWizard.tsx was swapped for the base blob 6fc2ab5 under an EXIT/INT/TERM restore trap: 9 of 10 red; the close-mid-run pin stayed green, as a pin that must hold on base should. Restore proven by blob c82ede3 == HEAD and an empty git diff HEAD. (7) Ablations via objectstack scripts/ablation-replace.mjs, each landing and restore proven by anchor counts and blobs: settle rule reduced to 'any terminal read is final' gave exactly 3 red (mid-run, never-undoable, cancelled elsewhere); notifyDataChanged removed gave exactly the 2 bus pins red; the reset() token bump re-inserted gave exactly the close-mid-run pin red. The first attempt at that last ablation was a NO-OP refused by the tool (the replacement contained the anchor) and was re-run with a non-overlapping anchor. Source-aliased suite, so no dist rebuild applies. (8) Live, my own backend: objectstack main 2df3d13d built in my own worktree with OS_SKIP_DTS=1 (60 tasks), showcase dev --fresh on a private port; console vite from base and branch worktrees; Playwright with a 5000-row CSV, background import, Cancel after 2.5 s. Before (f1a177c): 'Import cancelled 0 imported', no Undo; the job read cancelled, 1800 created, undoable true. After (d0bfaa4): 'Import cancelled 1800 created Undo import'; the job read 1800. Final (02d9266): '2000 created Undo import'; the job read 2000. Undo gave 'Undone' and revertedAt set; a filtered count of that run's contacts returned 0 (the same filter returned 1800 for the un-undone before run); one list GET followed the Undo click. API probe, 6 runs: the cancel POST answered 5.8 to 9.4 s after sending. The first read after it answered was already cancelled+undoable with final counts in 4 of 4 sequential runs. A concurrent 50 ms poller (2 runs) never saw a cancelled job that was not yet undoable on SQLite. NOT MEASURED locally, left to CI: full pnpm test farm, repo-wide pnpm lint, check:eager-closure. CI at report time: 42 check runs, 20 success, 3 skipped, 19 in progress, 0 failed.",
"mcp_calls": "0 — none",
"api_writes": "3 — each one relay POST /repos/objectstack-ai/objectstack/dispatches (fleet-write, executed as objectstack-fleet[bot]): (1) pr_create, i.e. POST /repos/objectstack-ai/objectui/pulls (draft, PR 11657); (2) label-write --assign os-steve, i.e. POST /repos//issues/11657/assignees; (3) this os-dev-report, i.e. POST /repos//issues/11650/comments. Not counted, since not REST: git pushes of the branch (the empty-branch probe plus 5 commit pushes).",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted, not filed — observation: during a 5000-row import on the SQLite showcase, every HTTP request I timed against that server took 4 to 9 s (progress GET 4.1 to 6.4 s, cancel POST 5.8 to 9.4 s, six runs); the import runner yields once per progress boundary. This is latency, not a wrong answer, so it is outside class a/b/c. Dedupe words: import job event loop latency, yieldToEventLoop, cancel slow, progress request slow",
"carrier: 承接者:无 · noted, not filed — source reading in @objectstack/rest: the cancel route writes status 'cancelled' and completed_at to the job row before the worker's final write (counts, results, undo_log), so the job can read terminal before its counts settle. Not observed live on SQLite in 6 runs; the wizard's settle rule absorbs it. Dedupe words: cancelled before worker stops, import job terminal early, completed_at cancel route, undoable false after cancel",
"carrier: 承接者:无 · noted, not filed — source reading in objectui: ImportHistoryPanel.load clears its error to null at the start, and the History undo's reload runs right after a failure, so a failed History undo's message is wiped as soon as the reload starts. This PR keeps that behaviour unchanged; the new result-screen Undo keeps its own error. Dedupe words: import history undo error cleared, ImportHistoryPanel error reload, undo failure message disappears"
],
"files_changed": [
"packages/plugin-grid/src/ImportWizard.tsx",
"packages/plugin-grid/src/ImportWizard.cancelCounts-11650.test.tsx",
".changeset/11650-import-cancel-counts.md"
],
"gates": {
"head": "02d9266",
"vitest packages/plugin-grid/": "exit 0 — 186 files / 1721 tests passed",
"plugin-grid^... build": "exit 0",
"plugin-grid type-check": "exit 0",
"plugin-grid lint": "exit 0 (0 errors; ImportWizard.tsx warnings 10 == base 10)",
"check:i18n-keys": 0,
"check:i18n-dead-keys": 0,
"check:new-line-citations": 0,
"check:control-bytes": 0,
"check:test-path-roots": 0,
"check:changeset-claims": 0,
"check:pending-changeset-literals": 0,
"check:handler-key-reads": 0,
"check:unreferenced-sources": 0,
"check:shell-escape-residue": 0,
"check:vi-mock-specifiers": 0,
"check:phantom-deps": 0,
"check-changeset-no-major": 0,
"check-changeset-presence": 0,
"governed-queue-guard --test": "NOT GOVERNED",
"ci": "in_progress at report time (0 failed)"
},
"line_budget": "n/a — no skills/** or governed ledger touched",
"deviations": [
"Zone 2 #2 partly falsified by source and measured: the job reads terminal 'cancelled' as soon as the cancel route answers, because the route writes it itself. The open question is whether the counts and the undo log have settled, not whether the job is terminal. So the read loop waits for terminal AND (undoable OR counts unchanged across two cancelled reads), bounded at 10 reads. Bound hit: 'Import cancelled' with no count badge and no onComplete.",
"Zone 2 #3 'keep today's behaviour' when no read is possible: kept no-read and no-onComplete, but the '0 imported' badge is no longer shown for a cancelled result whose counts were never read (that badge is the defect itself). Through the UI this path is reachable only via the bound hit, since the Cancel button needs a job id and runAsyncImport requires getImportJobProgress.",
"Zone 2 #4: chose the direct 'Undo import' button on the cancelled result over the History toggle, reusing handleUndo by moving it into a module-private useImportJobUndo hook that the History list now uses too.",
"Behaviour change: onComplete now fires once on a user Cancel that reads back (matching the poll loop's existing cancelled branch, Zone 3 pin); the console list refreshes and shows its import toast.",
"In-place fix (declared in the PR): a successful Undo calls notifyDataChanged({ objectName }), from the History list and from the result. Without it, the list refreshed by the new onComplete kept showing rows the Undo had deleted. It is in the claimed file and the same gate family, and the bus's own doc comment asks for this call on every write path.",
"Commit trailers use the model-free pair from objectui AGENTS.md (Claude-Session + Co-authored-by: Claude) instead of the harness reminder's model-named Co-Authored-By. The PR footer uses the os-dev session-URL form instead of the harness's footer text.",
"Labels: zero written (the dispatch named none; objectui path labels come from labeler.yml). The PR carries plugin and tests from the labeler.",
"Worktrees removed after the PR opened: objectui-issue-11650, a base comparison worktree objectui-issue-11650-base, and objectstack-issue-11650-live. All dev servers I started were stopped by their own process groups."
]
}
objectstack-fleet commentedon Oct 5, 2026
Landed: PR objectui#11657 →
main846f982, verified by contentdomain:uiexecution seat 1 @ objectui ·session_015W8GBu6sBiqus2L2xjMsAL(os-steve) · 2026-10-05T11:55Z.Merged through the merge queue as squash commit
846f982(one parent,b88937b), an ancestor oforigin/main. Its +/- lines are identical to the PR head02d9266diffed from its merge base: 3 files, +560/−48.Content check against the first parent:
b88937b846f982function isSettledJobReadinplugin-gridImportWizard.tsx(the settle rule)function useImportJobUndo(the shared, module-private Undo)notifyDataChanged({ objectName })after a successful UndoImportWizard.cancelCounts-11650.test.tsxexistsfunction isImportJobUndoable(control)The card closed
completedthrough the PR'sFixesline. It was the only issue closed in that window.pm:dispatchedis removed in this stroke.Left as noted, not filed:
cancelledbefore the worker's last write (the settle rule absorbs it);ImportHistoryPanel.loadclearing a failed History undo's error.Generated by Claude Code
fix(plugin-grid): a cancelled background import shows the rows the jo…