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
Studio Interfaces pillar: a leaf edit whose save was refused (422) is seen by no unsaved-changes guard, so a reload drops it silently #29113
Filing gate: ② out-of-scope finding, class a, from the #29022 dev's reading at origin/main5d3667e2 · filed by domain:ui#1 · ⛔ Not a claim. No grade: triage sets it.
Business reason. In Studio's Interfaces pillar (reports, dashboards and other leaf items), when the server refuses a leaf's autosave (422), the edit stays on screen but nothing treats it as unsaved: no "leave page?" prompt, no header guard, no rail marker. A reload drops the edit with no warning. #29022 closes one door into this (a Joined report with no blocks); any other refused leaf save still loses work silently.
Measured (source reading, NOT MEASURED at a public door).
ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx, InterfacesPillar: only navDirty is mirrored through onDirtyChange.
heldEdit carries held clauses only; a leaf save refused by the server is neither held nor dirty to the guards (beforeunload, header, rail).
Wanted.
While the open leaf's last save was refused and it still has edits, the pillar reports dirty, so beforeunload and the header guard ask before the edit is lost.
A successful save, or loading another leaf, clears it.
No new metadata key or option.
Tests. A leaf edit refused with a 422 makes the guard ask on reload; a successful save afterwards clears it; an untouched leaf never asks.
Reader.domain:ui (area:studio). Size S. Waits for #29015 (holds StudioDesignSurface.tsx).
Dedupe. Searched InterfacesPillar onDirtyChange refused save, studio leaf 422 lost reload: only #29022.
Read fresh. In the Studio Interfaces pillar, a leaf edit whose autosave was refused (422) is seen by no unsaved-changes guard, so a reload drops it silently (StudioDesignSurface.tsxInterfacesPillar, only navDirty is mirrored). Silent loss of an author's edit is a user-visible defect: p2. Routing and the pm state the filer set are unchanged.
Claim: PM loop round 2 · 2026-11-02T09:58Z
Session: session_01QsR2jSfsyajgxceM7R1qi6 (card thread, os-dev); dispatched by seat session session_01QsR2jQjvWkZ7is6GXbC6DB
Account: zhuangjianguo
Branch: claude/project-thread-m40e5s (platform-assigned to the card thread; it can push only this branch)
Worktree: objectstack-issue-29113
Domain: domain:ui
Seat: domain:ui#5
File surface: ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (InterfacesPillar and its dirty mirror only), a new test file beside it, a changeset (stop on breach; explain in the report)
Container & model: S, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate; no Fable per the maintainer's standing rule), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: InterfacesPillar mirrors only navDirty through onDirtyChange; a leaf save the server refuses (422) is neither held nor dirty | no platform path covers it: beforeunload, header guard and rail read only pillarDirty/heldEdit | every Studio author whose leaf autosave is refused; a reload drops the edit silently
Thread-read: 6572381012
Premise: holds (at origin/main2f29c84d: StudioDesignSurface.tsx:4476-4485 mirrors navDirty only; :1747unsavedPillarWork = pillarDirty || heldEdit !== null). Triage 6572381012 graded p2; blocker PR #29132 (#29015) landed 3d2e8fd. Handed from seat 3 to seat 5 in the project, 09:53Z.
Serial constraints cleared: same file as open PR #29224 (#29139, seat 3): this PR opens after it lands. Same file as seat 2's #28984 (draft-autosave path) and seat 5's #29148 (nav-load block): whichever opens later merges main. PR #29143 (#29022) edits metadataError.ts in the same folder, not this file.
{
"issue": 29113,
"status": "done",
"branch": "claude/project-thread-m40e5s",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29268",
"head": "d45ce04c",
"session": "session_01QsR2jSfsyajgxceM7R1qi6",
"premise_still_valid": true,
"summary": "InterfacesPillar now reports an open leaf edit whose last save did not land (leaf buffer via doSave, and an object leaf's list-view buffer via useObjectListViewDraft failure) through onDirtyChange beside navDirty, so beforeunload, the header leave guard and the shell seam ask; the rail (pickSurface) and New (openCreate) ask before another leaf replaces it. A landed save or a load install clears it; heldEdit is untouched. Measured: report/dashboard/page leaves share one buffer (doSave); object leaf list view its own; nav (appDraft) was already mirrored; one signal now covers all three.",
"files_changed": [
"ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (+30 -9, InterfacesPillar only)",
"ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.refusedLeafUnsaved-29113.test.tsx (new, 402)",
".changeset/29113-refused-leaf-edit-unsaved.md (new, app-shell patch)"
],
"line_budget": "S card; 442 additions, 9 deletions, 3 files; production diff 39 lines in one component",
"deviations": [
"Claim surface reads 'InterfacesPillar and its dirty mirror only': pickSurface and openCreate (inside InterfacesPillar) also read the new signal; declared in the PR body Acceptance notes.",
"The signal also covers an object leaf's list-view buffer (same pillar, same class); declared in the PR body.",
"Any save that does not land counts (a transport failure too), not only a 422."
],
"tests": "New file 4/4 on d6b4e8a1 and again on d45ce04c (with merged-in automationsReadOnly-11124: 2 files 15/15). Base leg (10bfd70e source over HEAD, restored by trap, blob == HEAD 30a4c402): 3 failed 1 passed (control). Ablation via ablation-replace.mjs, mirror navDirty || refusedUnsent to navDirty (anchor 1 to 0, blob 30a4c402 to 592451e1): 2 failed (report reload/pillar link, list view) 2 passed (rail reads leafUnsent; control); restored, git diff HEAD empty. Neighbour sweep 73 files / 528 tests green (two locked batches). app-shell type-check 65/65. Real browser: showcase Studio, report showcase_hours_by_status after Customize, draft PUT forced to 422 by Playwright route: before, beforeunload not prevented and Data link left silently; after, beforeunload prevented and native confirm raised; a landed save clears it. Evidence in /mnt/project-files/issue-29113/live/.",
"gates": "dispatch-gates --commands: 34 derived, all exit 0 (incl. check-sdui-manifest, ui vitest run scripts/ 169 passed 2 skipped); --ran: 34 derived, 34 run, 0 NOT-MEASURED. Gate list re-derived on d45ce04c: unchanged. PR body gated: check-changeset-no-major, check-adr-0087-registration, check-closing-keyword-parity, check-partof-closing-keyword exit 0. ui check:new-line-citations 0 new. CI check-runs on PR 29268: in_progress at report time.",
"dogfood_battery": "n/a, no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2: fleet-write pr_create (PR 29268, read back byte-identical, draft) and this os-dev-report comment via post-stamped; plus git push x3 (not REST)",
"open_questions": [],
"out_of_scope_findings": []
}
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p2 (priority added) · 2026-11-02T08:17Z
⛔ Not a claim.
StudioDesignSurface.tsxInterfacesPillar, onlynavDirtyis mirrored). Silent loss of an author's edit is a user-visible defect: p2. Routing and the pm state the filer set are unchanged.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#5 · zhuangjianguo · session_01QsR2jQjvWkZ7is6GXbC6DB
Claim: PM loop round 2 · 2026-11-02T09:58Z
Session:
session_01QsR2jSfsyajgxceM7R1qi6(card thread, os-dev); dispatched by seat sessionsession_01QsR2jQjvWkZ7is6GXbC6DBAccount:
zhuangjianguoBranch:
claude/project-thread-m40e5s(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-29113Domain:
domain:uiSeat:
domain:ui#5File surface:
ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx(InterfacesPillar and its dirty mirror only), a new test file beside it, a changeset (stop on breach; explain in the report)Container & model: S,
mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate; no Fable per the maintainer's standing rule),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
InterfacesPillar mirrors only navDirty through onDirtyChange; a leaf save the server refuses (422) is neither held nor dirty | no platform path covers it: beforeunload, header guard and rail read only pillarDirty/heldEdit | every Studio author whose leaf autosave is refused; a reload drops the edit silentlyThread-read: 6572381012
Premise: holds (at
origin/main2f29c84d:StudioDesignSurface.tsx:4476-4485mirrorsnavDirtyonly;:1747unsavedPillarWork = pillarDirty || heldEdit !== null). Triage 6572381012 graded p2; blocker PR #29132 (#29015) landed 3d2e8fd. Handed from seat 3 to seat 5 in the project, 09:53Z.Serial constraints cleared: same file as open PR #29224 (#29139, seat 3): this PR opens after it lands. Same file as seat 2's #28984 (draft-autosave path) and seat 5's #29148 (nav-load block): whichever opens later merges main. PR #29143 (#29022) edits
metadataError.tsin the same folder, not this file.objectstack-fleet commentedon Nov 2, 2026
domain:ui#5 · zhuangjianguo · session_01QsR2jSfsyajgxceM7R1qi6
os-dev-report
{ "issue": 29113, "status": "done", "branch": "claude/project-thread-m40e5s", "pr": "https://github.com/objectstack-ai/objectstack/pull/29268", "head": "d45ce04c", "session": "session_01QsR2jSfsyajgxceM7R1qi6", "premise_still_valid": true, "summary": "InterfacesPillar now reports an open leaf edit whose last save did not land (leaf buffer via doSave, and an object leaf's list-view buffer via useObjectListViewDraft failure) through onDirtyChange beside navDirty, so beforeunload, the header leave guard and the shell seam ask; the rail (pickSurface) and New (openCreate) ask before another leaf replaces it. A landed save or a load install clears it; heldEdit is untouched. Measured: report/dashboard/page leaves share one buffer (doSave); object leaf list view its own; nav (appDraft) was already mirrored; one signal now covers all three.", "files_changed": [ "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (+30 -9, InterfacesPillar only)", "ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.refusedLeafUnsaved-29113.test.tsx (new, 402)", ".changeset/29113-refused-leaf-edit-unsaved.md (new, app-shell patch)" ], "line_budget": "S card; 442 additions, 9 deletions, 3 files; production diff 39 lines in one component", "deviations": [ "Claim surface reads 'InterfacesPillar and its dirty mirror only': pickSurface and openCreate (inside InterfacesPillar) also read the new signal; declared in the PR body Acceptance notes.", "The signal also covers an object leaf's list-view buffer (same pillar, same class); declared in the PR body.", "Any save that does not land counts (a transport failure too), not only a 422." ], "tests": "New file 4/4 on d6b4e8a1 and again on d45ce04c (with merged-in automationsReadOnly-11124: 2 files 15/15). Base leg (10bfd70e source over HEAD, restored by trap, blob == HEAD 30a4c402): 3 failed 1 passed (control). Ablation via ablation-replace.mjs, mirror navDirty || refusedUnsent to navDirty (anchor 1 to 0, blob 30a4c402 to 592451e1): 2 failed (report reload/pillar link, list view) 2 passed (rail reads leafUnsent; control); restored, git diff HEAD empty. Neighbour sweep 73 files / 528 tests green (two locked batches). app-shell type-check 65/65. Real browser: showcase Studio, report showcase_hours_by_status after Customize, draft PUT forced to 422 by Playwright route: before, beforeunload not prevented and Data link left silently; after, beforeunload prevented and native confirm raised; a landed save clears it. Evidence in /mnt/project-files/issue-29113/live/.", "gates": "dispatch-gates --commands: 34 derived, all exit 0 (incl. check-sdui-manifest, ui vitest run scripts/ 169 passed 2 skipped); --ran: 34 derived, 34 run, 0 NOT-MEASURED. Gate list re-derived on d45ce04c: unchanged. PR body gated: check-changeset-no-major, check-adr-0087-registration, check-closing-keyword-parity, check-partof-closing-keyword exit 0. ui check:new-line-citations 0 new. CI check-runs on PR 29268: in_progress at report time.", "dogfood_battery": "n/a, no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2: fleet-write pr_create (PR 29268, read back byte-identical, draft) and this os-dev-report comment via post-stamped; plus git push x3 (not REST)", "open_questions": [], "out_of_scope_findings": [] }