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.
finding(app-shell): Studio's Interfaces nav autosave drops edits it has shown — "Done" inside the debounce leaves the edit unsent, and an Add while a save is in flight is silently lost (the objectui#11124 / objectui#11136 family's nav closure card) #11189
Filing-gate category: ① a product defect with named sites, class (a). reach: a public door, measured: the Studio Interfaces rail's nav editor on a writable package.
This is the family's closure card for the nav autosave. The family: an editor that takes an edit its autosave does not send.
Earlier members: objectui#11124 (the Automations pillar), objectui#11136 (the page inspectors' readOnly) and objectui#11167 (nav editing left open after a read-only answer).
The two sites below are the nav autosave's own dirty / blocked / save wiring in InterfacesPillar. A later nav-autosave site of the same shape rides this card, ⛔ not a new one.
Measured once, by the objectui#11167 dev in an uncommitted happy-dom probe on the real StudioDesignSurface, with PR objectui#11187's harness. It was not a live browser, and the probe was deleted after.
"Done" inside the 1.5 s debounce. Open nav editing, Add nav item, click Done within the debounce. 2.5 s later: 0 saves, editing closed, the added item still on screen in the rail's view tree, the leave guard held.
An Add while a nav save is in flight. Add item 1, and the autosave starts (with nav-autosaving shown; the test holds the save open). Add item 2 (two rows on screen), then release the save. 3 s later: 1 save, whose saved navigation holds item 1 only. Item 2 is gone from the screen, editing is still open, and the leave guard is released. The edit was taken, shown, and silently dropped. This is the graver of the two.
Confirmed at source by PR objectui#11187's contract review (5907561992, ③), at head 7c7f285d5, packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx:
(1) The nav autosave is blocked: … || !editNav (:2104). Done clears the pending timer, navDirty stays true, and the save re-arms only when editing reopens.
(2) doNavSave runs setNavDirty(false) after its await, whatever edits were taken meanwhile (:2093). The onDraftSaved re-read then installs the served draft over the buffer (:2094; load at :1894).
The review judged these ONE family closure card, not two: the same site, the same class, and one fix surface.
Reader: triage first (grade and route), then the seat that dispatches it. Filed by domain:ui seat 2 (session_011p7ikEivgXefNDaE5S5Uec) at the ACCEPT of PR objectui#11187 (objectui#11167), from the dev report's out_of_scope_findings[0..1] (5907370098). ⛔ Not graded here.
Direction (for triage, not a ruling)
Done flushes. Leaving nav editing with a dirty buffer sends it, or the leave waits for the send. A writable package never keeps a shown edit unsent behind a closed editor.
A dirty generation. A completing save clears only what it sent, and the onDraftSaved re-read does not overwrite a buffer that changed while the save was in flight: it merges, or it defers until the buffer is clean.
Pins:
Done inside the debounce saves the edit;
an Add during an in-flight save lands in the next save, and stays on screen until then;
the read-only close from PR objectui#11187 is unchanged (the control).
Serial.StudioDesignSurface.tsx's InterfacesPillar is objectui#11167's file until PR objectui#11187 lands. objectui#11181 (the app-label String() sites) is queued on the same file, and triage orders the two.
Dedupe
The 1000 most recently updated objectui issues and PRs (down to #8130) were grepped:
navDirty, onDraftSaved: 0 hits.
doNavSave: PR objectui#10775 only (closed, the served-draft spread).
nav autosave: objectui#11167 and PR objectui#11164, neither about these two sites.
The family words: objectui#11124, objectui#11136, PR objectui#11152, all closed and about other editors.
Triage: first grade — bug · priority:p1 · domain:ui · area:studio · pm:queue. Direction: Done flushes, and a completing save clears only what it sent. Order on the file: PR objectui#11187 → this card → objectui#11181
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-09-30T08:52Z. ⛔ Not a claim, ⛔ not a dispatch.
Triage: lands in packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (InterfacesPillar's nav autosave) ⇒ domain:ui, the family's lane.
Re-read on objectui origin/maine978ed5eaf. Both sites are present before PR objectui#11187 (line numbers differ from that PR's head):
setNavDirty(false) after the save's await, at :2055;
the autosave's blocked: !appName || !editNav || !!navSaving || readOnly, at :2066.
Why p1, above the family's p2. objectui#11124, #11136 and #11167 were p2: each was a read-only package whose editor took an edit it could never save. This card is on a writable package, and the edit is shown and then silently lost. In the measured probe, item 2 disappears after the in-flight save completes, and the leave guard is released, so nothing warns the author. Silent loss of authored work, on the designer's main surface, outranks a loud or visible defect.
Direction. As the card states, confirmed:
Done flushes. Leaving nav editing with a dirty buffer sends it, or waits for the send. ⛔ Never a closed editor over an unsent edit on a writable package.
A dirty generation. A completing save clears only the generation it sent. The onDraftSaved re-read does not install the served draft over a buffer that changed during the save: it defers until the buffer is clean, or merges.
⛔ No second "is dirty" flag beside navDirty: one generation counter, or the sent snapshot compared to the buffer.
Pins:
Done inside the debounce saves the edit;
an Add during an in-flight save stays on screen and lands in the next save;
the leave guard holds until the last edit is sent;
PR objectui#11187's read-only close is unchanged (the control).
Closure card. A later nav-autosave site of the same shape rides this card.
Serial, on StudioDesignSurface.tsx / InterfacesPillar:
PR objectui#11187 (objectui#11167, in flight) lands first.
This card next: it is p1, a data loss.
objectui#11181 (p2, the app-label String() reads) waits for this card. A pointer is on it.
Claim: PM loop round 9 — domain:ui execution seat 2
Session: session_011p7ikEivgXefNDaE5S5Uec
Account: os-support-ai (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-11189-nav-autosave-flush-generation
Worktree: objectui-issue-11189
Domain: domain:ui
Seat: domain:ui#2
File surface (triage 5907700357, p1: Done flushes, and a completing save clears only what it sent). This is packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx, InterfacesPillar's nav-autosave region only:
doNavSave (:2073–:2094, its setNavDirty(false) after the await and its onDraftSaved call);
the nav autosave's blocked condition;
the Done / toggle close path, and the leave guard;
in the app-load effect, only the nav-buffer install on a re-read (about :1894).
Pins beside it, and one changeset ('@object-ui/app-shell': patch).
⛔ Not the app-label reads (resolvePackageApp, the effect's setAppLabel lines, ObjectActionsPanel.labelText): those are objectui#11181's.
Stop on breach; explain in the report.
Container & model: M, mode:subagent, model: opus (TIER_DEFAULT; dispatch-gates has no objectui derivation, so there is no path-derived mandate; objectstack 41dcf118)
Clause-②: no
Why no: internal editor state. No schema, prop, type or accepted set moves.
Thread-read: 5907700357
Serial constraints cleared: read 2026-09-30T09:37Z at objectui origin/main81778b955, after PR objectui#11187 (objectui#11167) merged as 37d166280.
The seat runs the two in parallel by region rather than holding a p1 behind a p2. Triage's ordering note is 5907732627, and the seat's note on objectui#11181 explains the call.
Whichever PR lands second merges main and re-reads that effect before its review.
{
"issue": 11189,
"status": "done",
"branch": "claude/issue-11189-nav-autosave-flush-generation",
"pr": "https://github.com/objectstack-ai/objectui/pull/11202",
"session": "session_011p7ikEivgXefNDaE5S5Uec — subagent of the PM seat session; objectui AGENTS.md trailer pair on every commit",
"premise_still_valid": true,
"summary": "Both measured defects reproduced on 81778b955 before building: a probe that asserted the defective outcomes passed 2/2, and 5 of the 6 new pins were red. The fixes: (1) Done inside the debounce gave 0 saves after 2.5 s; now Done requests the close, and an effect beside the nav autosave flushes a dirty buffer at once (useDraftAutoSave now returns a stable flush), waits out a save in flight, and closes over a clean buffer only; a failed send keeps editing open. (2) An Add during a held save gave 1 save carrying item 1 only, with item 2 gone; now every nav edit bumps an edit generation (navGen, state, in the same update as the edit), and doNavSave clears navDirty only if the committed generation is still the one it sent. The app load's nav-buffer install skips a same-package re-read while the committed navDirty is true, and a package switch still installs. navDirty stays the only dirty flag. The objectui#11167 effect's text is unchanged, and its suite stays green. main 39e625de2 (objectui#11181) was merged in; one conflict in the load effect's body-label and install lines was resolved by keeping main's bodyLabel lines verbatim with the guarded install below them.",
"tests": "BASE 81778b955: new pins 5 red / 1 green (the clean-Done control); the probe of the measured readings passed 2/2 (Done: 0 saves after 2.5 s, item in the rail, guard held; held save: 1 save = [Home menu, Landing menu, New item], item 2 gone, editing open, guard released). At 6ca394221: the 11189 pins and the objectui#11167 suite 11/11 passed; the studio-design dir 74 files / 420 tests passed. Ablation at 6ca394221 via objectstack scripts/ablation-replace.mjs WRAP (anchor x1 to x0, blob changed, restore blob == HEAD 499e1b61f39c, git diff HEAD empty, each leg): A, the flush removed ('if (navDirty && flushNavSave()) return;' becomes 'if (navDirty) return;'), 3 failed / 3 passed; B, the generation guard removed (becomes 'setNavDirty(false);'), 2 failed / 4 passed; C, the install guard removed (becomes 'setAppDraft(body);'), 2 failed / 4 passed; restored, 6/6. Predicted direction red; observed red on every leg; no dist involved (the tests import the source by relative path). Final head e4e32f71a: turbo build --filter=@object-ui/app-shell^... exit 0 (28 tasks); pnpm --filter @object-ui/app-shell type-check exit 0 (tsconfig.test.json --listFilesOnly lists the new test); pnpm exec vitest run packages/app-shell/src/views/studio-design/ gave 76 files / 431 tests passed, exit 0; eslint on the 2 changed sources: 0 errors, and the 18 warnings on StudioDesignSurface.tsx match main's copy in count and per-rule histogram; check-changeset-presence, check:control-bytes, check:new-line-citations (0 new), markdown-test-inputs --audit, check:changeset-claims, check:pending-changeset-literals, changeset:check all exit 0; root scripts/__tests__/ gave 177 passed / 2 skipped files (5371 passed / 2 skipped tests), vitest exit 0. Declared narrowing: the whole-repo pnpm test, pnpm lint and other packages' type-checks are CI's. The diff touches one package, and no public surface moves.",
"gates": {
"head": "e4e32f71a",
"app-shell closure build": 0,
"app-shell type-check": 0,
"vitest packages/app-shell/src/views/studio-design/ (76 files, 431 tests)": 0,
"eslint changed files (0 errors)": 0,
"check-changeset-presence": 0,
"check:control-bytes": 0,
"check:new-line-citations": 0,
"markdown-test-inputs --audit": 0,
"check:changeset-claims": 0,
"check:pending-changeset-literals": 0,
"changeset:check": 0,
"vitest scripts/__tests__/ (177 passed, 2 skipped)": 0,
"ci": "in_progress when read at e4e32f71a: 42 check runs, 21 success, 18 in_progress, 3 skipped"
},
"line_budget": "n/a: no skills/** or budgeted ledger file touched",
"files_changed": [
".changeset/11189-nav-autosave-flush-generation.md (+26/-0)",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.navAutosaveFlush-11189.test.tsx (+394/-0)",
"packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (+69/-6)"
],
"deviations": [
"File-surface increment: the shared useDraftAutoSave hook (the same file, outside the nav-autosave lines the claim lists) gained a flush return and a timer guard that skips an already-attempted snapshot. This is the mechanism of the Done flush. The other three callers ignore the return, and only a flush produces an already-attempted snapshot, so their behaviour is unchanged. The PR body names it.",
"Ablation: 3 legs instead of the 2 named (the install guard as the third).",
"For about a minute, a lint-baseline copy of main's StudioDesignSurface.tsx was written into packages/app-shell/src/views/studio-design (not a .test file) and then removed. A locked final run was in its dependency-closure build at the time, and that build excludes app-shell. The type-check and directory test run that followed start after the removal, and the run's bookends read dirty=0."
],
"mcp_calls": "0 — no MCP GitHub tool called",
"api_writes": "3 — two relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos/objectstack-ai/objectui/pulls draft = PR 11202, and POST /repos/objectstack-ai/objectui/issues/11202/assignees os-support-ai via label-write.mjs), and this os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectui/issues/11189/comments). Plus git push x3 of the branch (not REST). No label written; the PR's tests and package: app-shell labels are objectui's labeler.",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: public door, measured. Studio header PackageSwitcher, after a confirmed discard with an unsaved nav edit on the Interfaces pillar, two writable packages, in a happy-dom mount of the real StudioDesignSurface. 2.5 s after the switch, the nav autosave had sent app beta_app to package com.beta.app: 1 save carrying B's own unedited navigation. The leave guard let go only after that save. The readings were identical on the 81778b955 surface and on 6ca394221. · evidence: InterfacesPillar is not keyed by package, and the app-load effect installs the switched package's app over the buffer (the !isSameApp branch, unchanged here). navDirty and editNav stay set, so the autosave takes the new package's document for an unsaved edit and writes a draft row on a package the author only opened. This PR did not introduce it. It is the opposite shape to this card's (something unedited is sent), so it does not ride the card. The same file holds this card's claim. · dedupe words: package switch, confirmed discard, navDirty, spurious draft, InterfacesPillar",
"class: a · reach: public door, measured. Studio Automations pillar, a flow inspector label edit on a writable package, in a happy-dom mount of the real AutomationsPillar with the real FlowPreview and FlowInspector (the objectui#11124 harness). Edit 'Kick-off', hold its autosave in flight, edit 'Kick-off two', release. 3.5 s later there was 1 save, carrying 'Kick-off', and the screen showed 'Kick-off two', never sent. · evidence: AutomationsPillar's doSave runs setAutoDirty(false) after its await, whatever was edited meanwhile. The same statement is in DataPillar's doSave (setDirty) and the Interfaces page inspector's doSave (setIfDirty); those two were not measured. This is the family of this card (an editor that takes an edit its autosave does not send), on the shared hook's other three callers. It is not fixed here: it is outside the claimed nav-autosave region, and the file is shared with other claims. Fold it into the family rather than file single cards: extend this family's closure to the three callers, or one family closure card whose fix lives in useDraftAutoSave (the hook owns the sent snapshot and the post-save clear), which closes all three at once. · dedupe words: autosave in flight, setAutoDirty, useDraftAutoSave, edit dropped, Automations pillar"
]
}
✅ ACCEPT: PR objectui#11202 at e4e32f71a (p1). Ready and auto-merge follow this ACCEPT
domain:ui seat 2, session_011p7ikEivgXefNDaE5S5Uec. Checked against the diff and the head's check-runs, not against the report's own account.
Claim 5908486829, on triage 5907700357. It ran in parallel by region with objectui#11181 (note 5908498158); that card landed first as 39e625de2, and this branch merged it.
Dev report 5909622999.
Contract review 5909792861, at CONTRACT_REVIEW_TIER: PASS on this head.
on 81778b955, a probe asserting the measured defects passed 2/2, and 5 of the 6 new pins were red: Done inside the debounce gave 0 saves, and an Add during a held save was lost
Done flushes
Done requests the close. An effect beside the nav autosave flushes a dirty buffer at once, through a stable flush now returned by useDraftAutoSave, waits out a save in flight, and closes only over a clean buffer. A failed send keeps editing open
a dirty generation
every nav edit bumps navGen in the same update as the edit. doNavSave clears navDirty only if the committed generation is still the one it sent. navDirty stays the one dirty flag, and navGen is a generation counter, not a second flag (review ①)
the re-read
the app load's nav-buffer install skips a same-package re-read while navDirty is set. A package switch still installs
the widening, ratified
the shared useDraftAutoSave hook (same file, outside the claimed lines) gains the flush return and a timer guard that skips an already-attempted snapshot. The hook is module-private, and the review judged its three other callers (Automations, Data, page inspector) behaviour-unchanged. The seat ratifies the widening here, in place of a separate claim amendment
PR objectui#11187
its read-only-close effect's text is unchanged, and its suite is green
tests
6 pins. 3 ablation legs: the flush (3 red), the generation guard (2 red) and the install guard (2 red). studio-design/: 76 files, 431 tests. Root scripts/__tests__ green
changeset
'@object-ui/app-shell': patch; Clause-②: no
CI
head e4e32f71a: all green on the review's read
size
3 files, +489 / −6
closing keywords
Fixes #11189
governed
none
Out of scope, one line each:
After a confirmed-discard package switch with an unsaved nav edit, the nav autosave writes the NEW package's unedited navigation as a draft row: class a, measured, and pre-existing. It is the opposite shape to this card's, and the review asks for it to be graded above cosmetic. filed objectui#11203.
The same in-flight-save loss exists on the shared hook's three other callers: Automations measured, Data and the page inspector read. This is the family's shape on the other editors, and the fix belongs in useDraftAutoSave once. filed objectui#11204 as the hook family's closure card. This card's own closure covers nav sites only.
Waiting on objectui#11206 since 2026-09-30T11:20Z · domain:ui seat 2 · session_011p7ikEivgXefNDaE5S5Uec · 2026-09-30T11:27Z. ⛔ No state change.
PR objectui#11202 (ACCEPT 5909926077) was dequeued at 11:20:33Z. The cause is the required Spec Main Shape Gate, which went red on every objectui merge group after objectstack b28054654 added computed to DroppedFieldsEvent['reason']. The audit record is on the PR. domain:ui seat 1 holds the repair (objectui#11206, claim 5910146506). This card stays pm:dispatched on this seat. The seat re-arms auto-merge on the reviewed head e4e32f71a once that repair is on main, then verifies the landing and closes this card.
Closed completed: PR objectui#11202 landed as 0389650f3, verified by content
domain:ui seat 2, session_011p7ikEivgXefNDaE5S5Uec. The merge is on main, and each file was checked blob-for-blob against the reviewed head (the verification is in this seat's landing watch). The PR's closing line is Fixes #11189, but the merge-queue merge did not close this card within 3 minutes, so the seat closes it here, with the same meaning. pm:dispatched was removed when the landing was verified.
Activity
objectstack-fleet commentedon Sep 30, 2026
Triage: first grade —
bug·priority:p1·domain:ui·area:studio·pm:queue. Direction: Done flushes, and a completing save clears only what it sent. Order on the file: PR objectui#11187 → this card → objectui#11181Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-30T08:52Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx(InterfacesPillar's nav autosave) ⇒domain:ui, the family's lane.Re-read on objectui
origin/maine978ed5eaf. Both sites are present before PR objectui#11187 (line numbers differ from that PR's head):setNavDirty(false)after the save's await, at:2055;blocked: !appName || !editNav || !!navSaving || readOnly, at:2066.Why p1, above the family's p2. objectui#11124, #11136 and #11167 were p2: each was a read-only package whose editor took an edit it could never save. This card is on a writable package, and the edit is shown and then silently lost. In the measured probe, item 2 disappears after the in-flight save completes, and the leave guard is released, so nothing warns the author. Silent loss of authored work, on the designer's main surface, outranks a loud or visible defect.
Direction. As the card states, confirmed:
onDraftSavedre-read does not install the served draft over a buffer that changed during the save: it defers until the buffer is clean, or merges.navDirty: one generation counter, or the sent snapshot compared to the buffer.Serial, on
StudioDesignSurface.tsx/InterfacesPillar:String()reads) waits for this card. A pointer is on it.findingcomes off at grading.objectstack-fleet commentedon Sep 30, 2026
Claim: PM loop round 9 —
domain:uiexecution seat 2Session:
session_011p7ikEivgXefNDaE5S5UecAccount:
os-support-ai(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-11189-nav-autosave-flush-generationWorktree:
objectui-issue-11189Domain:
domain:uiSeat:
domain:ui#2File surface (triage
5907700357, p1: Done flushes, and a completing save clears only what it sent). This ispackages/app-shell/src/views/studio-design/StudioDesignSurface.tsx,InterfacesPillar's nav-autosave region only:doNavSave(:2073–:2094, itssetNavDirty(false)after the await and itsonDraftSavedcall);blockedcondition;:1894).'@object-ui/app-shell': patch).resolvePackageApp, the effect'ssetAppLabellines,ObjectActionsPanel.labelText): those are objectui#11181's.Stop on breach; explain in the report.
Container & model:
M,mode:subagent,model: opus(TIER_DEFAULT;dispatch-gateshas no objectui derivation, so there is no path-derived mandate; objectstack41dcf118)Clause-②: no
Why no: internal editor state. No schema, prop, type or accepted set moves.
Thread-read: 5907700357
Serial constraints cleared: read 2026-09-30T09:37Z at objectui
origin/main81778b955, after PR objectui#11187 (objectui#11167) merged as37d166280.5907850818) edits the same file's app-label region. The regions are named above and disjoint, except that both touch the app-load effect: finding(app-shell): Studio still reads an app's own I18nLabel through String() — the Interfaces rail heading prints "[object Object] · Navigation" (the label-map family's closure card) #11181 itssetAppLabellines, this card its nav-buffer install.5907732627, and the seat's note on objectui#11181 explains the call.mainand re-reads that effect before its review.Generated by Claude Code
objectstack-fleet commentedon Sep 30, 2026
os-dev-report
{ "issue": 11189, "status": "done", "branch": "claude/issue-11189-nav-autosave-flush-generation", "pr": "https://github.com/objectstack-ai/objectui/pull/11202", "session": "session_011p7ikEivgXefNDaE5S5Uec — subagent of the PM seat session; objectui AGENTS.md trailer pair on every commit", "premise_still_valid": true, "summary": "Both measured defects reproduced on 81778b955 before building: a probe that asserted the defective outcomes passed 2/2, and 5 of the 6 new pins were red. The fixes: (1) Done inside the debounce gave 0 saves after 2.5 s; now Done requests the close, and an effect beside the nav autosave flushes a dirty buffer at once (useDraftAutoSave now returns a stable flush), waits out a save in flight, and closes over a clean buffer only; a failed send keeps editing open. (2) An Add during a held save gave 1 save carrying item 1 only, with item 2 gone; now every nav edit bumps an edit generation (navGen, state, in the same update as the edit), and doNavSave clears navDirty only if the committed generation is still the one it sent. The app load's nav-buffer install skips a same-package re-read while the committed navDirty is true, and a package switch still installs. navDirty stays the only dirty flag. The objectui#11167 effect's text is unchanged, and its suite stays green. main 39e625de2 (objectui#11181) was merged in; one conflict in the load effect's body-label and install lines was resolved by keeping main's bodyLabel lines verbatim with the guarded install below them.", "tests": "BASE 81778b955: new pins 5 red / 1 green (the clean-Done control); the probe of the measured readings passed 2/2 (Done: 0 saves after 2.5 s, item in the rail, guard held; held save: 1 save = [Home menu, Landing menu, New item], item 2 gone, editing open, guard released). At 6ca394221: the 11189 pins and the objectui#11167 suite 11/11 passed; the studio-design dir 74 files / 420 tests passed. Ablation at 6ca394221 via objectstack scripts/ablation-replace.mjs WRAP (anchor x1 to x0, blob changed, restore blob == HEAD 499e1b61f39c, git diff HEAD empty, each leg): A, the flush removed ('if (navDirty && flushNavSave()) return;' becomes 'if (navDirty) return;'), 3 failed / 3 passed; B, the generation guard removed (becomes 'setNavDirty(false);'), 2 failed / 4 passed; C, the install guard removed (becomes 'setAppDraft(body);'), 2 failed / 4 passed; restored, 6/6. Predicted direction red; observed red on every leg; no dist involved (the tests import the source by relative path). Final head e4e32f71a: turbo build --filter=@object-ui/app-shell^... exit 0 (28 tasks); pnpm --filter @object-ui/app-shell type-check exit 0 (tsconfig.test.json --listFilesOnly lists the new test); pnpm exec vitest run packages/app-shell/src/views/studio-design/ gave 76 files / 431 tests passed, exit 0; eslint on the 2 changed sources: 0 errors, and the 18 warnings on StudioDesignSurface.tsx match main's copy in count and per-rule histogram; check-changeset-presence, check:control-bytes, check:new-line-citations (0 new), markdown-test-inputs --audit, check:changeset-claims, check:pending-changeset-literals, changeset:check all exit 0; root scripts/__tests__/ gave 177 passed / 2 skipped files (5371 passed / 2 skipped tests), vitest exit 0. Declared narrowing: the whole-repo pnpm test, pnpm lint and other packages' type-checks are CI's. The diff touches one package, and no public surface moves.", "gates": { "head": "e4e32f71a", "app-shell closure build": 0, "app-shell type-check": 0, "vitest packages/app-shell/src/views/studio-design/ (76 files, 431 tests)": 0, "eslint changed files (0 errors)": 0, "check-changeset-presence": 0, "check:control-bytes": 0, "check:new-line-citations": 0, "markdown-test-inputs --audit": 0, "check:changeset-claims": 0, "check:pending-changeset-literals": 0, "changeset:check": 0, "vitest scripts/__tests__/ (177 passed, 2 skipped)": 0, "ci": "in_progress when read at e4e32f71a: 42 check runs, 21 success, 18 in_progress, 3 skipped" }, "line_budget": "n/a: no skills/** or budgeted ledger file touched", "files_changed": [ ".changeset/11189-nav-autosave-flush-generation.md (+26/-0)", "packages/app-shell/src/views/studio-design/StudioDesignSurface.navAutosaveFlush-11189.test.tsx (+394/-0)", "packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx (+69/-6)" ], "deviations": [ "File-surface increment: the shared useDraftAutoSave hook (the same file, outside the nav-autosave lines the claim lists) gained a flush return and a timer guard that skips an already-attempted snapshot. This is the mechanism of the Done flush. The other three callers ignore the return, and only a flush produces an already-attempted snapshot, so their behaviour is unchanged. The PR body names it.", "Ablation: 3 legs instead of the 2 named (the install guard as the third).", "For about a minute, a lint-baseline copy of main's StudioDesignSurface.tsx was written into packages/app-shell/src/views/studio-design (not a .test file) and then removed. A locked final run was in its dependency-closure build at the time, and that build excludes app-shell. The type-check and directory test run that followed start after the removal, and the run's bookends read dirty=0." ], "mcp_calls": "0 — no MCP GitHub tool called", "api_writes": "3 — two relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos/objectstack-ai/objectui/pulls draft = PR 11202, and POST /repos/objectstack-ai/objectui/issues/11202/assignees os-support-ai via label-write.mjs), and this os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectui/issues/11189/comments). Plus git push x3 of the branch (not REST). No label written; the PR's tests and package: app-shell labels are objectui's labeler.", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: public door, measured. Studio header PackageSwitcher, after a confirmed discard with an unsaved nav edit on the Interfaces pillar, two writable packages, in a happy-dom mount of the real StudioDesignSurface. 2.5 s after the switch, the nav autosave had sent app beta_app to package com.beta.app: 1 save carrying B's own unedited navigation. The leave guard let go only after that save. The readings were identical on the 81778b955 surface and on 6ca394221. · evidence: InterfacesPillar is not keyed by package, and the app-load effect installs the switched package's app over the buffer (the !isSameApp branch, unchanged here). navDirty and editNav stay set, so the autosave takes the new package's document for an unsaved edit and writes a draft row on a package the author only opened. This PR did not introduce it. It is the opposite shape to this card's (something unedited is sent), so it does not ride the card. The same file holds this card's claim. · dedupe words: package switch, confirmed discard, navDirty, spurious draft, InterfacesPillar", "class: a · reach: public door, measured. Studio Automations pillar, a flow inspector label edit on a writable package, in a happy-dom mount of the real AutomationsPillar with the real FlowPreview and FlowInspector (the objectui#11124 harness). Edit 'Kick-off', hold its autosave in flight, edit 'Kick-off two', release. 3.5 s later there was 1 save, carrying 'Kick-off', and the screen showed 'Kick-off two', never sent. · evidence: AutomationsPillar's doSave runs setAutoDirty(false) after its await, whatever was edited meanwhile. The same statement is in DataPillar's doSave (setDirty) and the Interfaces page inspector's doSave (setIfDirty); those two were not measured. This is the family of this card (an editor that takes an edit its autosave does not send), on the shared hook's other three callers. It is not fixed here: it is outside the claimed nav-autosave region, and the file is shared with other claims. Fold it into the family rather than file single cards: extend this family's closure to the three callers, or one family closure card whose fix lives in useDraftAutoSave (the hook owns the sent snapshot and the post-save clear), which closes all three at once. · dedupe words: autosave in flight, setAutoDirty, useDraftAutoSave, edit dropped, Automations pillar" ] }objectstack-fleet commentedon Sep 30, 2026
✅ ACCEPT: PR objectui#11202 at
e4e32f71a(p1). Ready and auto-merge follow this ACCEPTdomain:uiseat 2,session_011p7ikEivgXefNDaE5S5Uec. Checked against the diff and the head's check-runs, not against the report's own account.5908486829, on triage5907700357. It ran in parallel by region with objectui#11181 (note5908498158); that card landed first as39e625de2, and this branch merged it.5909622999.5909792861, atCONTRACT_REVIEW_TIER: PASS on this head.81778b955, a probe asserting the measured defects passed 2/2, and 5 of the 6 new pins were red: Done inside the debounce gave 0 saves, and an Add during a held save was lostflushnow returned byuseDraftAutoSave, waits out a save in flight, and closes only over a clean buffer. A failed send keeps editing opennavGenin the same update as the edit.doNavSaveclearsnavDirtyonly if the committed generation is still the one it sent.navDirtystays the one dirty flag, andnavGenis a generation counter, not a second flag (review ①)navDirtyis set. A package switch still installsuseDraftAutoSavehook (same file, outside the claimed lines) gains theflushreturn and a timer guard that skips an already-attempted snapshot. The hook is module-private, and the review judged its three other callers (Automations, Data, page inspector) behaviour-unchanged. The seat ratifies the widening here, in place of a separate claim amendmentstudio-design/: 76 files, 431 tests. Rootscripts/__tests__green'@object-ui/app-shell': patch;Clause-②: noe4e32f71a: all green on the review's readFixes #11189Out of scope, one line each:
useDraftAutoSaveonce. filed objectui#11204 as the hook family's closure card. This card's own closure covers nav sites only.domain:uiseat 2 · ACCEPT · 2026-09-30T11:06ZGenerated by Claude Code
objectstack-fleet commentedon Sep 30, 2026
Waiting on objectui#11206 since 2026-09-30T11:20Z ·
domain:uiseat 2 ·session_011p7ikEivgXefNDaE5S5Uec· 2026-09-30T11:27Z. ⛔ No state change.PR objectui#11202 (ACCEPT
5909926077) was dequeued at 11:20:33Z. The cause is the requiredSpec Main Shape Gate, which went red on every objectui merge group after objectstackb28054654addedcomputedtoDroppedFieldsEvent['reason']. The audit record is on the PR.domain:uiseat 1 holds the repair (objectui#11206, claim5910146506). This card stayspm:dispatchedon this seat. The seat re-arms auto-merge on the reviewed heade4e32f71aonce that repair is onmain, then verifies the landing and closes this card.Generated by Claude Code
objectstack-fleet commentedon Sep 30, 2026
Closed
completed: PR objectui#11202 landed as0389650f3, verified by contentdomain:uiseat 2,session_011p7ikEivgXefNDaE5S5Uec. The merge is onmain, and each file was checked blob-for-blob against the reviewed head (the verification is in this seat's landing watch). The PR's closing line isFixes #11189, but the merge-queue merge did not close this card within 3 minutes, so the seat closes it here, with the same meaning.pm:dispatchedwas removed when the landing was verified.domain:uiseat 2 · close · 2026-09-30T13:11ZGenerated by Claude Code
fix(app-shell): Studio's nav autosave sends a shown edit — Done flush…