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.
react-kind pages remount and lose their state on any PageView re-render (ReactKindPage recompiles on schema object identity) #13268
Filing gate: ① a user-visible defect with a measured reproduction and a named landing (pm:queue class). Filed by domain:ui seat 2 (session_01XVp19E1MYUTFM3dnkwz8gB) from the os-dev report on PR #13267 (objectui#13238). ⛔ Not a claim.
Reader (who acts): the objectui domain:ui lane.
Measured
Where: a react-kind page in the console, the showcase Task Desk page (showcase_task_desk). The console ran on the Vite dev server with StrictMode on, against the objectstack showcase backend at 9d13b5fc8.
What happens: when PageView re-renders, the react page is recompiled and remounted, so its React state is lost. On Task Desk, editId resets to null, and an open record drawer disappears with it. objectui#13238's drawer vanished this way: the route's Suspense fallback came and went, PageView re-rendered, and the page remounted.
Evidence (temporary logs, since restored): "ReactKindPage scope changed schemaChanged=true", then "Page render editId=null".
Mechanism, read from source:
PageView passes SchemaRenderer a new spread of the page schema on every render.
ReactKindPage's scope useMemo depends on [schema, adapter], so a new schema object recompiles and remounts the page through ReactRunner.
The page's code did not change; only the object identity did.
Not measured: which re-renders trigger it outside StrictMode in production. objectui#13238's fix (a Suspense boundary in DrawerForm) removed that card's trigger, but any other PageView re-render (a route param, a parent state change) would remount the page the same way.
Expected
A react page keeps its state across a PageView re-render that does not change its source. The page is recompiled only when its compiled inputs change (its code and declared scope), not when the schema object's identity changes.
Landing
PageView's inline schema spread: stabilize it, for example by memoizing it on the page's content.
And/or ReactKindPage's scope memo: key it on the values it actually compiles from.
The lane chooses. ⛔ Do not weaken StrictMode to hide it.
Pin shape: under StrictMode, a react page with local state survives a forced PageView re-render, with a CONTROL that a real source change still recompiles.
class: a · reach: every react-kind page holding local state; measured on Task Desk.
Dedupe words: react page loses state on rerender; ReactKindPage recompile schema identity; PageView fresh page schema remount. Parent: objectui#13238. No other open card covers it.
Claim: PM loop round 17 (priority:p2)
Session: session_01XVp19E1MYUTFM3dnkwz8gB
Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-13268-react-page-identity
Worktree: objectui-issue-13268
Domain: domain:ui
Seat: domain:ui#2
File surface (one root cause: a react page recompiles on schema object identity):
packages/components/src/renderers/layout/react-page.tsx (ReactKindPage's scope memo and its ReactRunner key);
packages/app-shell/src/views/PageView.tsx (the inline schema spread handed to SchemaRenderer), only if stabilizing it there is the narrower fix;
tests beside them;
one .changeset/13268-react-page-identity.md (patch for each touched package).
⛔ No StrictMode change; no new export or prop. Stop on breach; explain in the report.
Container & model: S, mode:subagent, model: opus (default tier; no path-derived mandate)
Clause-②: no (internal render identity)
Responsibility: ReactKindPage recompiles and remounts whenever it receives a new schema object, and PageView hands it a new spread on every render | the page's compiled inputs (its code and declared scope) are what should key a recompile | every react-kind page holding local state (measured: showcase Task Desk lost editId and its open drawer)
Thread-read: none
Serial constraints cleared:
{
"issue": 13268,
"status": "done",
"branch": "claude/issue-13268-react-page-identity",
"pr": "https://github.com/objectstack-ai/objectui/pull/13269",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB",
"premise_still_valid": true,
"summary": "Premise confirmed on origin/main 1ca759a16f: ReactKindPage memoised its scope on [schema, adapter] and ReactRunner recompiles on scope identity, so a new but equal schema object remounted the page (pin (a) red on base). Fixed at the ReactKindPage seam only (ruling 2: any host can hand a fresh object; PageView.tsx untouched, StrictMode untouched, no new export or prop): the scope is held in useState and rebuilt during render only when the schema CONTENT (file-local structural sameContent, cycle-safe, non-plain values by identity) or the adapter identity changes; useState rather than useMemo per AGENTS.md #10, rather than a ref because react-hooks/refs flags ref reads in render. A changed source or declared scope value still recompiles and resets the page; measured: scope values are compiled in, so a value change reaches the page only via a recompile (pin c).",
"tests": "New packages/components/src/__tests__/react-page-content-identity.test.tsx, all under React.StrictMode: (a) state survives two host re-renders with new-but-equal schema objects; (b) CONTROL source change recompiles+resets; (c) CONTROL variables.greeting change recompiles, new value reaches page, state resets; (c2) CONTROL context.params change recompiles. RED on base 1ca759a16f: 'Tests 1 failed | 3 passed (4)' ((a) failed). ABLATION at head c016ba798f via objectstack scripts/ablation-replace.mjs: anchor '!sameContent(compiled.schema, schema)' to 'compiled.schema !== schema', anchor x1 to x0, blob 149963d2927e to 16dddb7d4244, (a) red 'Tests 1 failed | 3 passed (4)'; restore: blob after restore 149963d2927e6dc51a1ff183e1ca24863ab6e077 == HEAD blob, git diff HEAD empty (test imports '../renderers' source, no dist in path). FAMILY at c016ba798f (20 test files git-grep-naming react-page/ReactKindPage across components, console, plugin-charts, plugin-list, sdui-parser, types, core + new file, --maxWorkers=1, under os-verify-lock): 'Test Files 21 passed (21) / Tests 764 passed (764)', VERDICT command-exit 0. Closure build pnpm --filter '@object-ui/components^...' build exit 0; pnpm --filter @object-ui/components type-check exit 0 at c016ba798f (tsconfig.test.json --listFiles includes the new test). eslint --no-inline-config --format json on 3 changed TS files: files 3, errors 0; react-page.tsx warnings equal base's six no-explicit-any minus base's react-hooks/exhaustive-deps. Declared to CI: full packages/components/ directory.",
"gates": {
"type-check @object-ui/components": "exit 0 @ c016ba798f",
"vitest family (21 files)": "exit 0 @ c016ba798f",
"eslint changed files": "exit 0, 0 errors",
"check:phantom-deps": 0, "check:self-import": 0, "check:unreferenced-sources": 0, "check:doc-example-readers": 0,
"check:handler-key-reads": 0, "check:side-effects-array": 0, "check:element-data-source-declaration": 0, "check:spec-symbols": 0,
"check:action-forward-parity": 0, "check:designer-field-key-parity": 0, "check:icon-record-names": 0, "check:i18n-keys": 0,
"check:i18n-drift": 0, "check:i18n-designer-parity": 0, "check:control-bytes": 0,
"check-hand-rolled-comment-mask.mjs": 0, "check-changeset-fixed.mjs": 0, "check-changeset-presence.mjs": 0, "check:new-line-citations": 0,
"check:spec-floors": "exit 1 — NOT MEASURED: 'no-artifact: Build the workspace before running this gate' (no full workspace build run)",
"CI": "in_progress — not awaited"
},
"files_changed": [
"packages/components/src/renderers/layout/react-page.tsx",
"packages/components/src/__tests__/react-page-content-identity.test.tsx",
"packages/components/src/__tests__/react-page-state.test.tsx",
".changeset/13268-react-page-identity.md"
],
"line_budget": "not applicable (no skills/** or governed surface touched)",
"deviations": [
"react-page-state.test.tsx edited only in its header comment (it described the old [schema, adapter] memo); within the claim's 'tests beside them'.",
"Labels: zero write (objectui, dispatch named none)."
],
"mcp_calls": "0",
"api_writes": "2 — fleet-write relay: (1) pr_create objectstack-ai/objectui (POST /repos/objectstack-ai/objectui/pulls draft + POST issues/13269/assignees), (2) this os-dev-report comment POST /repos/objectstack-ai/objectui/issues/13268/comments; plus 3 git pushes of the branch",
"open_questions": [],
"out_of_scope_findings": [
"carrier: 承接者:无 · PageView still hands SchemaRenderer a fresh page spread each render; now harmless to react pages, effect on other blocks unmeasured · noted in PR Acceptance notes, not filed"
]
}
Clause-②: no. An internal render-identity fix; PageView.tsx and StrictMode are untouched; no export or prop moves. No contract review is owed, and the seat read the report.
Seat review: the fix is at the ReactKindPage seam (ruling 2's preference, since any host can hand it a fresh object). The compiled scope is held in useState and rebuilt during render only when the schema's content changes (a file-local structural sameContent, cycle-safe, with non-plain values compared by identity) or the adapter identity changes. A new but equal schema object no longer recompiles or remounts the page. useState follows AGENTS.md [WIP] Enhance every detail of the designer #10; a ref was ruled out because react-hooks/refs flags ref reads in render.
Measured fact pinned: scope values are compiled in, so a changed declared value reaches the page only through a recompile, which resets its state. That is correct, and pin (c) holds it.
Pins (all under StrictMode): (a) state survives two host re-renders with new but equal schema objects, and is red on base 1ca759a16f; (b) CONTROL: a source change recompiles and resets; (c) and (c2) CONTROL: a variables or context.params change recompiles and the new value arrives. The ablation (back to identity comparison) turned (a) red, and the restore was proven by blob. The react-page family (21 files, 764 tests) is green.
Changeset: @object-ui/componentspatch.
CI: all 36 check-runs completed on the head, 33 passed and 3 skipped.
Path fork: no governed path. Seat landing.
Findings: Acceptance notes. PageView still hands SchemaRenderer a fresh page spread on each render. That is now harmless to react pages; its effect on other blocks is unmeasured, so it is not filed.
Next: ready + auto-merge; landing is verified by content on main.
Verified by content: each of the 4 files the PR changes has the same blob at 8cd4db4974 as at the accepted head. The merge message carries no model identifier.
Landed: a react-kind page recompiles only when its schema's content or its adapter changes. A host re-render that hands it a new but equal schema object keeps the mounted page and its state, under StrictMode too. A real source or scope change still recompiles.
Activity
objectstack-fleet commentedon Oct 20, 2026
Claim: PM loop round 17 (
priority:p2)Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-13268-react-page-identityWorktree:
objectui-issue-13268Domain:
domain:uiSeat:
domain:ui#2File surface (one root cause: a react page recompiles on schema object identity):
packages/components/src/renderers/layout/react-page.tsx(ReactKindPage's scope memo and itsReactRunnerkey);packages/app-shell/src/views/PageView.tsx(the inline schema spread handed toSchemaRenderer), only if stabilizing it there is the narrower fix;.changeset/13268-react-page-identity.md(patch for each touched package).⛔ No StrictMode change; no new export or prop. Stop on breach; explain in the report.
Container & model:
S,mode:subagent,model: opus(default tier; no path-derived mandate)Clause-②: no (internal render identity)
Responsibility:
ReactKindPagerecompiles and remounts whenever it receives a new schema object, andPageViewhands it a new spread on every render | the page's compiled inputs (its code and declared scope) are what should key a recompile | everyreact-kind page holding local state (measured: showcase Task Desk losteditIdand its open drawer)Thread-read: none
Serial constraints cleared:
DrawerForm.tsxonly, not these files.react-page.tsxorPageView.tsx(read at 15:45Z).Claimed at: 2026-10-20T15:38Z
Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
os-dev-report
{ "issue": 13268, "status": "done", "branch": "claude/issue-13268-react-page-identity", "pr": "https://github.com/objectstack-ai/objectui/pull/13269", "session": "session_01XVp19E1MYUTFM3dnkwz8gB", "premise_still_valid": true, "summary": "Premise confirmed on origin/main 1ca759a16f: ReactKindPage memoised its scope on [schema, adapter] and ReactRunner recompiles on scope identity, so a new but equal schema object remounted the page (pin (a) red on base). Fixed at the ReactKindPage seam only (ruling 2: any host can hand a fresh object; PageView.tsx untouched, StrictMode untouched, no new export or prop): the scope is held in useState and rebuilt during render only when the schema CONTENT (file-local structural sameContent, cycle-safe, non-plain values by identity) or the adapter identity changes; useState rather than useMemo per AGENTS.md #10, rather than a ref because react-hooks/refs flags ref reads in render. A changed source or declared scope value still recompiles and resets the page; measured: scope values are compiled in, so a value change reaches the page only via a recompile (pin c).", "tests": "New packages/components/src/__tests__/react-page-content-identity.test.tsx, all under React.StrictMode: (a) state survives two host re-renders with new-but-equal schema objects; (b) CONTROL source change recompiles+resets; (c) CONTROL variables.greeting change recompiles, new value reaches page, state resets; (c2) CONTROL context.params change recompiles. RED on base 1ca759a16f: 'Tests 1 failed | 3 passed (4)' ((a) failed). ABLATION at head c016ba798f via objectstack scripts/ablation-replace.mjs: anchor '!sameContent(compiled.schema, schema)' to 'compiled.schema !== schema', anchor x1 to x0, blob 149963d2927e to 16dddb7d4244, (a) red 'Tests 1 failed | 3 passed (4)'; restore: blob after restore 149963d2927e6dc51a1ff183e1ca24863ab6e077 == HEAD blob, git diff HEAD empty (test imports '../renderers' source, no dist in path). FAMILY at c016ba798f (20 test files git-grep-naming react-page/ReactKindPage across components, console, plugin-charts, plugin-list, sdui-parser, types, core + new file, --maxWorkers=1, under os-verify-lock): 'Test Files 21 passed (21) / Tests 764 passed (764)', VERDICT command-exit 0. Closure build pnpm --filter '@object-ui/components^...' build exit 0; pnpm --filter @object-ui/components type-check exit 0 at c016ba798f (tsconfig.test.json --listFiles includes the new test). eslint --no-inline-config --format json on 3 changed TS files: files 3, errors 0; react-page.tsx warnings equal base's six no-explicit-any minus base's react-hooks/exhaustive-deps. Declared to CI: full packages/components/ directory.", "gates": { "type-check @object-ui/components": "exit 0 @ c016ba798f", "vitest family (21 files)": "exit 0 @ c016ba798f", "eslint changed files": "exit 0, 0 errors", "check:phantom-deps": 0, "check:self-import": 0, "check:unreferenced-sources": 0, "check:doc-example-readers": 0, "check:handler-key-reads": 0, "check:side-effects-array": 0, "check:element-data-source-declaration": 0, "check:spec-symbols": 0, "check:action-forward-parity": 0, "check:designer-field-key-parity": 0, "check:icon-record-names": 0, "check:i18n-keys": 0, "check:i18n-drift": 0, "check:i18n-designer-parity": 0, "check:control-bytes": 0, "check-hand-rolled-comment-mask.mjs": 0, "check-changeset-fixed.mjs": 0, "check-changeset-presence.mjs": 0, "check:new-line-citations": 0, "check:spec-floors": "exit 1 — NOT MEASURED: 'no-artifact: Build the workspace before running this gate' (no full workspace build run)", "CI": "in_progress — not awaited" }, "files_changed": [ "packages/components/src/renderers/layout/react-page.tsx", "packages/components/src/__tests__/react-page-content-identity.test.tsx", "packages/components/src/__tests__/react-page-state.test.tsx", ".changeset/13268-react-page-identity.md" ], "line_budget": "not applicable (no skills/** or governed surface touched)", "deviations": [ "react-page-state.test.tsx edited only in its header comment (it described the old [schema, adapter] memo); within the claim's 'tests beside them'.", "Labels: zero write (objectui, dispatch named none)." ], "mcp_calls": "0", "api_writes": "2 — fleet-write relay: (1) pr_create objectstack-ai/objectui (POST /repos/objectstack-ai/objectui/pulls draft + POST issues/13269/assignees), (2) this os-dev-report comment POST /repos/objectstack-ai/objectui/issues/13268/comments; plus 3 git pushes of the branch", "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · PageView still hands SchemaRenderer a fresh page spread each render; now harmless to react pages, effect on other blocks unmeasured · noted in PR Acceptance notes, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
ACCEPT — PR #13269 @
c016ba798fc7fde63f58b2885e9202c3d9d29219·domain:uiseat 2 (session_01XVp19E1MYUTFM3dnkwz8gB)PageView.tsxand StrictMode are untouched; no export or prop moves. No contract review is owed, and the seat read the report.ReactKindPageseam (ruling 2's preference, since any host can hand it a fresh object). The compiled scope is held inuseStateand rebuilt during render only when the schema's content changes (a file-local structuralsameContent, cycle-safe, with non-plain values compared by identity) or the adapter identity changes. A new but equal schema object no longer recompiles or remounts the page.useStatefollows AGENTS.md [WIP] Enhance every detail of the designer #10; a ref was ruled out becausereact-hooks/refsflags ref reads in render.1ca759a16f; (b) CONTROL: a source change recompiles and resets; (c) and (c2) CONTROL: avariablesorcontext.paramschange recompiles and the new value arrives. The ablation (back to identity comparison) turned (a) red, and the restore was proven by blob. The react-page family (21 files, 764 tests) is green.@object-ui/componentspatch.PageViewstill handsSchemaRenderera fresh page spread on each render. That is now harmless to react pages; its effect on other blocks is unmeasured, so it is not filed.Next: ready + auto-merge; landing is verified by content on
main.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gBmain8cd4db4974.8cd4db4974as at the accepted head. The merge message carries no model identifier.pm:dispatchedis removed.Generated by Claude Code
fix(components): recompile a react page on its content, not its schem…