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
finding(plugin-form): an edit form that stays mounted sends the first-read updated_at as ifMatch on its second save, so the OCC guard would answer 409 against the user's own first save #10565
Filing-gate category: ① a product defect with a named site, read at source. Reader: triage first (route and grade), then the domain:ui execution seat that claims it.
Filed by the domain:ui#4 execution seat (session_01BP8CMtACxTdLjqR6rhd33C) from the dev report and contract review of PR objectui#10546 (objectui#10156). ⛔ Filed bare, not graded here. ⛔ Not measured against a server.
The defect
The OCC-guarded edit save, saveWithOcc in packages/plugin-form/src/occSave.tsx, takes its token as ifMatch = occVersionOf(baseRecord). baseRecord is initialData in SimpleObjectForm and formData in ModalForm and DrawerForm. Neither is refreshed after a successful save. So the second save from a form that stays mounted sends the updated_at it read before the first save. The first save moved the stored updated_at, so a server enforcing the guard should answer 409. The user then sees the conflict dialog for a conflict with their own earlier save.
This is on main too. PR objectui#10546 (objectui#10156) does not change OCC. It narrows what Overwrite resends: the dirty fields rather than the whole record.
Evidence
Read at source by the dev of PR objectui#10546 and confirmed by its contract reviewer at head 13ac7751e: occSave.tsx is not in that diff, and neither initialData nor formData is written after a save, at base or head.
⛔ Not measured. No run against a server enforcing ifMatch confirms the 409.
Grading notes (for triage, not a grade)
Measure first. Save twice from one mounted edit form against a server enforcing ifMatch, and record whether the second save answers 409.
If it does, the likely shape is to take the token from the saved record the write returns, next to where PR objectui#10546 advances the loaded-record baseline.
Pin: the second save's ifMatch equals the first save's returned version.
Dedupe
REST page walk over the 1000 most recently updated objectui items. updated_at or ifMatch near second save, stale, 409 or own save, and ifMatch, occVersionOf or optimistic concurrency on their own ⇒ 0 defect hits (one hit, objectui#1905, a closed matrix-view feature, is unrelated).
Dedupe words: edit form second save stale ifMatch 409 · occVersionOf baseRecord not refreshed after save · mounted form OCC conflict with own save
Triage: lands in packages/plugin-form/src/occSave.tsx (saveWithOcc takes ifMatch from a baseRecord never refreshed after a save) ⇒ domain:ui; rationale: a mounted edit form's second save sends the first-read updated_at as ifMatch, so the OCC guard would answer 409 against the user's own first save. Read at source only ⇒ p2, measure first.
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01CRZSc7dU8oDStbTbSwhuZe · 2026-09-25T11:00Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectui origin/main.
Execution note: measure first — two saves from one mounted edit form against a server enforcing ifMatch; if the second answers 409, take the token from the saved record the write returns, beside PR objectui#10546's baseline advance. If it does not, report here and close.
Claim: PM loop round 1 — domain:ui execution seat (serial dispatch)
Session: session_01BA3nKVUwKQJf8DBxrSVtNC
Branch: claude/issue-10565-occ-token-after-save
Worktree: objectui-issue-10565
Domain: domain:ui
Seat: domain:ui#1
File surface: packages/plugin-form/src/occSave.tsx (useOccSave / saveWithOcc and occVersionOf only), pins beside the existing OCC tests, and one .changeset/10565-…md. The six baseRecord call sites (ObjectForm.tsx, ModalForm.tsx, DrawerForm.tsx, TabbedForm.tsx, SplitForm.tsx, WizardForm.tsx) are touched only if the token cannot be kept inside useOccSave, and ⛔ never inside the hunks of open PR objectui#10620 (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: opus (default judgement tier) — priority:p2: measure first; a mounted edit form's second save may send the first-read updated_at as ifMatch
Clause-②: no
Thread-read: 5831289536
Serial constraints cleared: open-PR file lists read 2026-09-25T13:03Z. Draft PR objectui#10620 (another seat) edits packages/plugin-form/src/ObjectForm.tsx (hunks from about :716, :1175, :1315, :1645, :1800 on main), close to SimpleObjectForm's OCC call (about :1144–:1158). Hence the occSave.tsx-first surface above. Seat 2's PR objectui#10628 (objectui#10564) edits MasterDetailForm.tsx only: file-disjoint. PR objectui#10546 (the baseline advance) and PR objectui#10626 (objectui#10563, this seat) are merged. The seat runs serially by the maintainer's instruction: this is the only dev in flight.
Scope
The triage (5831289536): 「measure first — two saves from one mounted edit form against a server enforcing ifMatch; if the second answers 409, take the token from the saved record the write returns, beside PR objectui#10546's baseline advance. If it does not, report here and close.」
Measure first, against the real enforcement point: find where the ObjectStack data layer or REST adapter enforces ifMatch and drive two saves through it. If no enforcing path can be run here, say so; ⛔ a mock that enforces by assumption does not count as the measurement.
409 reproduced ⇒ the token for the next save comes from the version the last successful write returned, for all six layouts. Keeping it inside useOccSave (one place) is preferred to six call-site edits.
No 409 ⇒ report with the evidence; the seat closes the card.
os-dev-report
{
"issue": 10565,
"status": "done",
"branch": "claude/issue-10565-occ-token-after-save",
"pr": "#10641",
"session": "session_01BA3nKVUwKQJf8DBxrSVtNC — the harness-stamped id of this run (subagent, so the parent's id; the relay read the same id from the container)",
"premise_still_valid": true,
"summary": "Measured first, against the real enforcement: the defect reproduces. On a real ObjectStack stack, the second save from one mounted edit form sent the first read's updated_at, got 409 CONCURRENT_UPDATE and opened the conflict dialog. The first write's response carries the new updated_at. The fix is inside useOccSave only. Per object and record, it remembers the version its last successful write returned (the guarded save and the Overwrite retry alike) and sends it while the form still holds the same read. A newer read's token wins. A read without updated_at stays unguarded. A result without a version falls back to the read. There is no new export and no payload change, and ObjectForm.tsx and the six call sites are untouched, so there is no overlap with PR objectui#10620. Draft PR objectui#10641 opened, zero label writes. File surface beyond the claim: packages/plugin-form/README.md, content/docs/plugins/plugin-form.mdx and the pending .changeset/10156-edit-form-writes-only-changed-fields.md each said an edit save always carries the updated_at the form read. This change made that false, so each got a prose correction (the changeset's front matter is untouched; check-changeset-overwrite reports that edit, as intended). Standard-text conflicts, noted here and not in open_questions: (1) os-dev pushes an empty branch first, while the dispatch budget allowed only a comment if there was no repro; the defect reproduced, so this did not matter. (2) The harness asked for a Co-Authored-By trailer naming a model; the dispatch and os-dev require model-free trailers, so the commits carry only Claude-Session. Assignee untouched (os-bill, the PM's).",
"tests": "MEASUREMENT (the real enforcement code; no mock enforces anything). Rig: objectstack origin/main 949e99bed9 in a scratch detached worktree. Closure built with turbo under the lock: 32 tasks plus verify and client, OS_SKIP_DTS=1. A one-object app booted with @objectstack/verify bootStack (sqlite-wasm driver, ObjectQL, REST, Hono, auth, security), served on a loopback HTTP listener. objectui side: the real ObjectStackAdapter over @objectstack/client 17.4.0. PRE-FIX (objectui e0f8202), raw HTTP: read V0, then PATCH If-Match V0 answered 200 and returned a record with a newer updated_at V1, then PATCH If-Match V0 answered 409 CONCURRENT_UPDATE with currentVersion V1. Control: PATCH If-Match V1 answered 200. Real useOccSave over the real adapter: the 2nd save sent V0, got 409, the conflict dialog opened, and the outcome was cancelled. Mounted ObjectForm in edit mode: the 2nd submit sent the first read's token, got 409, and the dialog opened. POST-FIX, same rig: the 2nd hook save sent V1 and answered 200 with no dialog. The ObjectForm 2nd submit sent the first write's version and answered 200 with no dialog. Another writer between the two saves still earned 409 and the dialog, so the guard is live. PINS: packages/plugin-form/src/occSave.secondSave.test.tsx, 10 rows. The double is shaped from the measured wire: an ISO-Z version stamped per write, the whole record returned, and the 409 body built the way @objectstack/client builds it and passed through the real normaliseClientError. GATES at HEAD 7e1e06d: pnpm exec vitest run packages/plugin-form/ (repo root) gave Test Files 122 passed (122), Tests 1309 passed and 1 skipped (1310). pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-form^...' run build exited 0 (the 12-package closure). pnpm --filter @object-ui/plugin-form run type-check exited 0; it echoed tsc --noEmit && tsc -p tsconfig.test.json, and tsc --listFiles on tsconfig.test.json includes the new test. ABLATION at 7e1e06d via ablation-replace.mjs (versionToSend returns the read's token): the anchor went 1 to 0, the marker 0 to 1, and the blob f0d66a02 to 02c4b75a. Over the 3 OCC suites: 5 failed, 16 passed (21). Red: the 2nd save, 3rd save, other-writer, after-Overwrite and ObjectForm rows. Green: the single-save control, 4 other new rows, and all 11 existing OCC rows. Restore: blob f0d66a02 equals HEAD, git diff HEAD is empty, marker count 0. No dist in the path: vitest aliases @object-ui/* to src, and the pins import ./occSave. Other gates: pnpm check:control-bytes OK. pnpm check:new-line-citations: 0 new. node scripts/check-changeset-presence.mjs: 1 changeset for 1 released package. check-changeset-no-major OK. check-changeset-overwrite reports the one deliberate 10156 prose edit. pnpm check:changeset-claims: the self-contradiction reading is clean, and it asked for a re-read of .changeset/6237-wizard-step-config-split.md (it names plugin-form.mdx); I read it and it is still true. check-vi-mock-override-shape OK. check-test-path-roots OK. check-governed-queue-guard --test: NOT GOVERNED (6 paths). ESLint, narrowed to the 2 touched source files, with all three proofs. (1) Population: eslint --print-config lints occSave.tsx with react-hooks/exhaustive-deps on (warn) and rules-of-hooks on (error). (2) Count: --format json reported 2 files. (3) Invariance: parserOptions has no project or projectService, so the config is not type-aware and this diff cannot move a verdict on an untouched file. Per rule, head against base: occSave.tsx @typescript-eslint/no-explicit-any 3 and 3, exhaustive-deps 0 and 0; the new test 0 findings. NOT MEASURED: the repo-wide pnpm lint and the full pnpm test (CI-owned), and check-doc-links (the docs edits are prose-only and change no link). CI is in progress and was not awaited.",
"mcp_calls": "0",
"api_writes": "2 — (1) pr_create through the fleet relay: POST /repos/objectstack-ai/objectstack/dispatches (204), whose run 36141795003 executed POST /repos/objectstack-ai/objectui/pulls with draft=true as objectstack-fleet[bot], giving PR 10641; (2) this os-dev-report comment through post-stamped.mjs: POST /repos//issues/10565/comments. Separately, 3 git pushes: the empty branch first, then the fix commits.",
"open_questions": [],
"out_of_scope_findings": [
"observation (not a/b/c) · two saves in flight at once (a double submit before the first resolves) read the same token, so the later one can meet a 409. This predates this change and was not measured · carrier: none · noted in PR Acceptance notes, not filed",
"observation (not a/b/c) · booting objectstack's @objectstack/verify bootStack logs 'Port 0 is in use, using port N instead' from the Hono server plugin, which is only a misleading log line · carrier: none · noted in PR Acceptance notes, not filed"
]
}
✅ ACCEPT — PR objectui#10641 at 7e1e06d0f · entering the merge queue once CI is green
domain:ui seat #1, session_01BA3nKVUwKQJf8DBxrSVtNC. The seat read the dev report and the diff against the triage 5831289536 and the claim 5832865538. No review-tier record is owed, because Clause-②: no holds: occSave.tsx is not re-exported from @object-ui/plugin-form's entry (index.tsx names it 0 times), and neither the payload nor any export moves.
draft · base main · Fixes #10565 · Clause-②: no at line start · 6 files (+391 / −8) · merges clean onto main
the measurement, real enforcement
The dev booted a one-object ObjectStack stack from objectstack origin/main949e99bed9 (@objectstack/verifybootStack, with ObjectQL, REST, Hono, auth and security) and drove it with objectui's real ObjectStackAdapter over @objectstack/client 17.4.0. ⛔ No mock enforced anything. Pre-fix: read V0, then PATCH If-Match V0 answered 200 and returned V1, then PATCH If-Match V0 answered 409 CONCURRENT_UPDATE (currentVersion V1). Control: If-Match V1 answered 200. The real useOccSave and a mounted ObjectForm in edit mode both sent V0 on the second save, got 409, and opened the conflict dialog. ⇒ the premise holds, and the first write's response carries the new version
the fix
Inside useOccSave only. Per objectName + recordId, the hook remembers the version its last successful write returned (the guarded save and the Overwrite retry alike), paired with the read that write superseded. It sends that version only while the form still holds the SAME read, so a newer read wins. A read without updated_at stays unguarded, and a result without a version falls back to the read. The seat read every non-comment line: recordKey, versionToSend and remember are module-private, and the six baseRecord call sites and ObjectForm.tsx are untouched, so there is no overlap with open PR objectui#10620
post-fix, same rig
The second hook save sent V1 and answered 200 with no dialog, as did the ObjectForm second submit. Another writer between the two saves still earns 409 and the dialog, so the guard is live
pins + ablation
occSave.secondSave.test.tsx, 10 rows, over a double shaped from the measured wire (per-write ISO-Z version, the whole record returned, and the 409 body passed through the real normaliseClientError). Ablation (versionToSend returns the read's token): 5 red / 16 green across the three OCC suites, red exactly on the second save, third save, other writer, after Overwrite and ObjectForm rows. The single-save control and the 11 existing OCC rows stayed green. Restored by blob
docs made true
packages/plugin-form/README.md, plugin-form.mdx and the pending objectui#10156 changeset each said an edit save always carries the updated_at the form read. Each got a prose correction, with the changeset's frontmatter untouched (check-changeset-overwrite case 2)
tests + gates
packages/plugin-form/ 122 files, 1309 tests pass. The type-check passes after the closure build. eslint per rule matches base (exhaustive-deps 0 → 0). Control bytes, new line citations, changeset presence / no-major / overwrite / claims (the 6237 flag read and still true), vi-mock shape, test-path roots and the governed guard (NOT GOVERNED) exit 0. Changeset: patch on @object-ui/plugin-form
Dev notes — routed
Two saves in flight at once (a double submit before the first resolves) read the same token, so the later one can meet a 409. This predates this change and was not measured ⇒ PR Acceptance notes. 承接者:无.
objectstack's bootStack logs 「Port 0 is in use, using port N instead」 from the Hono server plugin, a misleading log line in the platform repo ⇒ PR Acceptance notes. 承接者:无.
Activity
objectstack-fleet commentedon Sep 25, 2026
Path: business objects, records and views | records-forms.concurrent-edit-conflict | P2
Triage: first grade —
bug·priority:p2·domain:ui·area:records·pm:queue(findingremoved — graded)Triage: lands in
packages/plugin-form/src/occSave.tsx(saveWithOcctakesifMatchfrom abaseRecordnever refreshed after a save) ⇒domain:ui; rationale: a mounted edit form's second save sends the first-readupdated_atasifMatch, so the OCC guard would answer 409 against the user's own first save. Read at source only ⇒ p2, measure first.Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T11:00Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, and objectuiorigin/main.Execution note: measure first — two saves from one mounted edit form against a server enforcing
ifMatch; if the second answers 409, take the token from the saved record the write returns, beside PR objectui#10546's baseline advance. If it does not, report here and close.objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 1 —
domain:uiexecution seat (serial dispatch)Session:
session_01BA3nKVUwKQJf8DBxrSVtNCBranch:
claude/issue-10565-occ-token-after-saveWorktree:
objectui-issue-10565Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/plugin-form/src/occSave.tsx(useOccSave/saveWithOccandoccVersionOfonly), pins beside the existing OCC tests, and one.changeset/10565-…md. The sixbaseRecordcall sites (ObjectForm.tsx,ModalForm.tsx,DrawerForm.tsx,TabbedForm.tsx,SplitForm.tsx,WizardForm.tsx) are touched only if the token cannot be kept insideuseOccSave, and ⛔ never inside the hunks of open PR objectui#10620 (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus(default judgement tier) —priority:p2: measure first; a mounted edit form's second save may send the first-readupdated_atasifMatchClause-②: no
Thread-read: 5831289536
Serial constraints cleared: open-PR file lists read 2026-09-25T13:03Z. Draft PR objectui#10620 (another seat) edits
packages/plugin-form/src/ObjectForm.tsx(hunks from about:716,:1175,:1315,:1645,:1800onmain), close toSimpleObjectForm's OCC call (about:1144–:1158). Hence theoccSave.tsx-first surface above. Seat 2's PR objectui#10628 (objectui#10564) editsMasterDetailForm.tsxonly: file-disjoint. PR objectui#10546 (the baseline advance) and PR objectui#10626 (objectui#10563, this seat) are merged. The seat runs serially by the maintainer's instruction: this is the only dev in flight.Scope
The triage (
5831289536): 「measure first — two saves from one mounted edit form against a server enforcingifMatch; if the second answers 409, take the token from the saved record the write returns, beside PR objectui#10546's baseline advance. If it does not, report here and close.」ifMatchand drive two saves through it. If no enforcing path can be run here, say so; ⛔ a mock that enforces by assumption does not count as the measurement.useOccSave(one place) is preferred to six call-site edits.⇒
Fixes #10565(only if the defect reproduces).domain:uiseat #1 ·session_01BA3nKVUwKQJf8DBxrSVtNC· claim · 2026-09-25T13:04Zobjectstack-fleet commentedon Sep 25, 2026
os-dev-report
{
"issue": 10565,
"status": "done",
"branch": "claude/issue-10565-occ-token-after-save",
"pr": "#10641",
"session": "session_01BA3nKVUwKQJf8DBxrSVtNC — the harness-stamped id of this run (subagent, so the parent's id; the relay read the same id from the container)",
"premise_still_valid": true,
"summary": "Measured first, against the real enforcement: the defect reproduces. On a real ObjectStack stack, the second save from one mounted edit form sent the first read's updated_at, got 409 CONCURRENT_UPDATE and opened the conflict dialog. The first write's response carries the new updated_at. The fix is inside useOccSave only. Per object and record, it remembers the version its last successful write returned (the guarded save and the Overwrite retry alike) and sends it while the form still holds the same read. A newer read's token wins. A read without updated_at stays unguarded. A result without a version falls back to the read. There is no new export and no payload change, and ObjectForm.tsx and the six call sites are untouched, so there is no overlap with PR objectui#10620. Draft PR objectui#10641 opened, zero label writes. File surface beyond the claim: packages/plugin-form/README.md, content/docs/plugins/plugin-form.mdx and the pending .changeset/10156-edit-form-writes-only-changed-fields.md each said an edit save always carries the updated_at the form read. This change made that false, so each got a prose correction (the changeset's front matter is untouched; check-changeset-overwrite reports that edit, as intended). Standard-text conflicts, noted here and not in open_questions: (1) os-dev pushes an empty branch first, while the dispatch budget allowed only a comment if there was no repro; the defect reproduced, so this did not matter. (2) The harness asked for a Co-Authored-By trailer naming a model; the dispatch and os-dev require model-free trailers, so the commits carry only Claude-Session. Assignee untouched (os-bill, the PM's).",
"tests": "MEASUREMENT (the real enforcement code; no mock enforces anything). Rig: objectstack origin/main 949e99bed9 in a scratch detached worktree. Closure built with turbo under the lock: 32 tasks plus verify and client, OS_SKIP_DTS=1. A one-object app booted with @objectstack/verify bootStack (sqlite-wasm driver, ObjectQL, REST, Hono, auth, security), served on a loopback HTTP listener. objectui side: the real ObjectStackAdapter over @objectstack/client 17.4.0. PRE-FIX (objectui e0f8202), raw HTTP: read V0, then PATCH If-Match V0 answered 200 and returned a record with a newer updated_at V1, then PATCH If-Match V0 answered 409 CONCURRENT_UPDATE with currentVersion V1. Control: PATCH If-Match V1 answered 200. Real useOccSave over the real adapter: the 2nd save sent V0, got 409, the conflict dialog opened, and the outcome was cancelled. Mounted ObjectForm in edit mode: the 2nd submit sent the first read's token, got 409, and the dialog opened. POST-FIX, same rig: the 2nd hook save sent V1 and answered 200 with no dialog. The ObjectForm 2nd submit sent the first write's version and answered 200 with no dialog. Another writer between the two saves still earned 409 and the dialog, so the guard is live. PINS: packages/plugin-form/src/occSave.secondSave.test.tsx, 10 rows. The double is shaped from the measured wire: an ISO-Z version stamped per write, the whole record returned, and the 409 body built the way @objectstack/client builds it and passed through the real normaliseClientError. GATES at HEAD 7e1e06d:
pnpm exec vitest run packages/plugin-form/(repo root) gave Test Files 122 passed (122), Tests 1309 passed and 1 skipped (1310).pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-form^...' run buildexited 0 (the 12-package closure).pnpm --filter @object-ui/plugin-form run type-checkexited 0; it echoedtsc --noEmit && tsc -p tsconfig.test.json, and tsc --listFiles on tsconfig.test.json includes the new test. ABLATION at 7e1e06d via ablation-replace.mjs (versionToSend returns the read's token): the anchor went 1 to 0, the marker 0 to 1, and the blob f0d66a02 to 02c4b75a. Over the 3 OCC suites: 5 failed, 16 passed (21). Red: the 2nd save, 3rd save, other-writer, after-Overwrite and ObjectForm rows. Green: the single-save control, 4 other new rows, and all 11 existing OCC rows. Restore: blob f0d66a02 equals HEAD, git diff HEAD is empty, marker count 0. No dist in the path: vitest aliases @object-ui/* to src, and the pins import ./occSave. Other gates: pnpm check:control-bytes OK. pnpm check:new-line-citations: 0 new. node scripts/check-changeset-presence.mjs: 1 changeset for 1 released package. check-changeset-no-major OK. check-changeset-overwrite reports the one deliberate 10156 prose edit. pnpm check:changeset-claims: the self-contradiction reading is clean, and it asked for a re-read of .changeset/6237-wizard-step-config-split.md (it names plugin-form.mdx); I read it and it is still true. check-vi-mock-override-shape OK. check-test-path-roots OK. check-governed-queue-guard --test: NOT GOVERNED (6 paths). ESLint, narrowed to the 2 touched source files, with all three proofs. (1) Population: eslint --print-config lints occSave.tsx with react-hooks/exhaustive-deps on (warn) and rules-of-hooks on (error). (2) Count: --format json reported 2 files. (3) Invariance: parserOptions has no project or projectService, so the config is not type-aware and this diff cannot move a verdict on an untouched file. Per rule, head against base: occSave.tsx @typescript-eslint/no-explicit-any 3 and 3, exhaustive-deps 0 and 0; the new test 0 findings. NOT MEASURED: the repo-wide pnpm lint and the full pnpm test (CI-owned), and check-doc-links (the docs edits are prose-only and change no link). CI is in progress and was not awaited.","mcp_calls": "0",
"api_writes": "2 — (1) pr_create through the fleet relay: POST /repos/objectstack-ai/objectstack/dispatches (204), whose run 36141795003 executed POST /repos/objectstack-ai/objectui/pulls with draft=true as objectstack-fleet[bot], giving PR 10641; (2) this os-dev-report comment through post-stamped.mjs: POST /repos//issues/10565/comments. Separately, 3 git pushes: the empty branch first, then the fix commits.",
"open_questions": [],
"out_of_scope_findings": [
"observation (not a/b/c) · two saves in flight at once (a double submit before the first resolves) read the same token, so the later one can meet a 409. This predates this change and was not measured · carrier: none · noted in PR Acceptance notes, not filed",
"observation (not a/b/c) · booting objectstack's @objectstack/verify bootStack logs 'Port 0 is in use, using port N instead' from the Hono server plugin, which is only a misleading log line · carrier: none · noted in PR Acceptance notes, not filed"
]
}
Generated by Claude Code
objectstack-fleet commentedon Sep 25, 2026
✅ ACCEPT — PR objectui#10641 at
7e1e06d0f· entering the merge queue once CI is greendomain:uiseat #1,session_01BA3nKVUwKQJf8DBxrSVtNC. The seat read the dev report and the diff against the triage5831289536and the claim5832865538. No review-tier record is owed, becauseClause-②: noholds:occSave.tsxis not re-exported from@object-ui/plugin-form's entry (index.tsxnames it 0 times), and neither the payload nor any export moves.main·Fixes #10565·Clause-②: noat line start · 6 files (+391 / −8) · merges clean ontomainorigin/main949e99bed9(@objectstack/verifybootStack, with ObjectQL, REST, Hono, auth and security) and drove it with objectui's realObjectStackAdapterover@objectstack/client17.4.0. ⛔ No mock enforced anything. Pre-fix: readV0, thenPATCH If-Match V0answered 200 and returnedV1, thenPATCH If-Match V0answered 409CONCURRENT_UPDATE(currentVersion V1). Control:If-Match V1answered 200. The realuseOccSaveand a mountedObjectFormin edit mode both sentV0on the second save, got 409, and opened the conflict dialog. ⇒ the premise holds, and the first write's response carries the new versionuseOccSaveonly. PerobjectName+recordId, the hook remembers the version its last successful write returned (the guarded save and the Overwrite retry alike), paired with the read that write superseded. It sends that version only while the form still holds the SAME read, so a newer read wins. A read withoutupdated_atstays unguarded, and a result without a version falls back to the read. The seat read every non-comment line:recordKey,versionToSendandrememberare module-private, and the sixbaseRecordcall sites andObjectForm.tsxare untouched, so there is no overlap with open PR objectui#10620V1and answered 200 with no dialog, as did theObjectFormsecond submit. Another writer between the two saves still earns 409 and the dialog, so the guard is liveoccSave.secondSave.test.tsx, 10 rows, over a double shaped from the measured wire (per-write ISO-Z version, the whole record returned, and the 409 body passed through the realnormaliseClientError). Ablation (versionToSendreturns the read's token): 5 red / 16 green across the three OCC suites, red exactly on the second save, third save, other writer, after Overwrite andObjectFormrows. The single-save control and the 11 existing OCC rows stayed green. Restored by blobpackages/plugin-form/README.md,plugin-form.mdxand the pending objectui#10156 changeset each said an edit save always carries theupdated_atthe form read. Each got a prose correction, with the changeset's frontmatter untouched (check-changeset-overwritecase 2)packages/plugin-form/122 files, 1309 tests pass. The type-check passes after the closure build. eslint per rule matches base (exhaustive-deps0 → 0). Control bytes, new line citations, changeset presence / no-major / overwrite / claims (the6237flag read and still true), vi-mock shape, test-path roots and the governed guard (NOT GOVERNED) exit 0. Changeset:patchon@object-ui/plugin-formDev notes — routed
bootStacklogs 「Port 0 is in use, using port N instead」 from the Hono server plugin, a misleading log line in the platform repo ⇒ PR Acceptance notes. 承接者:无.domain:uiseat #1 · review · 2026-09-25T13:48Zfix(plugin-form): an open edit form's second save sends the version i…