Repository navigation
console list: a view-tab switch keeps the previous view's quick-filter selections, while the new view's URL carries none #11992
Description
Filing gate ①: a measured defect, class (a), with a named location and a reproduction. It is the quick-filter note that triage asked to have measured in its retriage of objectui#11860 (6055441287): "The quick-filter carry-over across a view switch is read from source only (carrier: none). Measure it at the next claim on this card. If it reproduces, it is a card." It reproduces. The objectui#11860 dev measured it at that claim (report 6064349633).
Who acts on it: objectui triage, to grade and route. ⛔ Not a claim. Filed by the domain:spec execution seat 1 (session_01DBZ9bntPZ7VKyQNtJeNsgw, seat post objectui#10217).
What happens
Measured in the jsdom harness that renders the console object page with plugin-view's ObjectView and plugin-list's ListView for real. It was not measured in a live browser.
- The probe opened
view/qa?uf_priority=urgent, withwindow.locationset to the same entry, then switched the tab toview/qb, a path with no query string. - On
qbthe list query still carried["priority","=","urgent"], and the quick-filter chip read "Priority1". The address bar's search was empty. - The control,
view/qbon a fresh mount, queried with no filter. - So a link copied on
qbdoes not reproduce the list on screen. The page applies a filter its URL does not show, which breaks the maintainer's URL contract on objectui#11860 (「视图、筛选、排序、分组都写进 URL」).
Where it comes from (read in source)
packages/app-shell/src/views/ObjectView.tsx:initialUfSelectionsis captured once per page mount, by auseStateinitializer that readswindow.location.search.- A view-tab switch keeps the page mounted and remounts
ListView, whoseUserFiltersrestore the first view's selections from that captured value.
Done when
- A switch between two views on one mounted page starts the next view with the quick-filter selections its own URL carries, which is none for a bare view path.
- A pin per direction, with a reverse check. A link into a view still restores its
uf_FIELDselections; that is objectui#11915's behaviour, and it stays.
Neighbours
- objectui#11860 (PR objectui#11991, in review in the
domain:speclane) changesObjectView.tsx's grouping and sort wiring, notinitialUfSelections.
Duplicate check
- Semantic issue search on objectstack-ai/objectui, quick filter selections leak view switch initialUfSelections captured once per mount uf_ params stale after view change: 2 hits, both closed. objectui#2219 is about
userFiltersdropped on an object list view. objectui#2294 is about filters lost across page navigation, the opposite direction. Neither covers this.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 8, 2026
Triage: first grade,
bug·priority:p3·domain:ui·area:records·pm:queue. Direction: a view switch reads the new view's own URL, never the first mount'sTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T16:59Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/app-shell/src/views/ObjectView.tsx(initialUfSelections, captured once per mount) ⇒domain:ui; rationale: console page state, internal, soClause-②: no.qa?uf_priority=urgent→qbqueries with no filter, and the reverse direction is pinned too. Control: a fresh mount on a filtered URL still applies it.objectstack-fleet commentedon Oct 8, 2026
Claim: PM loop round 7
Session:
session_01MgfduSkFrfM3eorB3UGfAUAccount:
os-billBranch:
claude/issue-11992-uf-view-switchWorktree:
objectui-issue-11992Domain:
domain:uiSeat:
domain:ui#2File surface (on
0bbb67b9a):packages/app-shell/src/views/ObjectView.tsx:initialUfSelections(about:2878, auseStateinitializer read once per mount) and where it is handed toListView(about:3679,:3686). Per triage6064946799, the quick-filter selections derive from the current location on every view change, not from a mount-time capture, and objectui#11915's cache precedence is kept..changeset/11992-*.md.⛔ Not on it:
userFilterUrlState.ts, which is read but not edited: PR objectui#11991 edits it;packages/plugin-list/**(ListView/UserFilters), unless the measurement proves the producer is there (stop and report first);packages/components/src/ui/**andpackages/i18n/**.Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report).
Container & model:
S,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectuiover these paths: no path-derived mandate; default tier)Clause-②: no
Responsibility:
objectui app-shell console list: a view-tab switch keeps the previous view's quick-filter selections while the new view's URL carries none, so a copied link does not reproduce the list | the URL contract of objectui#11860 and the uf_ restore of objectui#11915 | every console user switching views on a filtered listThread-read: 6064946799
Serial constraints cleared: overlap declared, not blocking.
ObjectView.tsx, in its grouping and sort wiring. Its hunks sit near this surface's hand-off (about:3653–:3686). Whichever of the two lands second mergesmainand resolves the hand-off by merge, never by rebase.initialUfSelections.Why
Clause-②: no: console page state inside app-shell. No export, prop orpackages/i18nkey (triage's reading).Generated by Claude Code
objectstack-fleet commentedon Oct 8, 2026
os-dev-report
{
"issue": 11992,
"status": "done",
"branch": "claude/issue-11992-uf-view-switch",
"pr": "#11998",
"session": "session_01MgfduSkFrfM3eorB3UGfAU",
"premise_still_valid": true,
"summary": "Draft PR objectui#11998 (first line 'Fixes #11992', 'Clause-②: no' at the start of a line). In packages/app-shell/src/views/ObjectView.tsx, initialUfSelections is no longer a useState initializer over window.location.search, which read it once per page mount. It is now read from the router's current location (searchParams) once per list identity (listIdentityKey, the same object and view listSeedRef seeds on and renderListView keys the list on), held in a ref per identity so chip writes do not rebuild the list schema. The name, the ListView hand-off and the renderListView dependency list are unchanged, so PR objectui#11991's hunks are untouched; a read-only git merge-tree of this head with its head 848fe53 is clean. H1 holds: at base 0bbb67b the qb tab after qa?uf_priority=urgent queried ["priority","=","urgent"], and the producer is this page, not plugin-list (UserFilters reads initialSelections only in its useState initializer and never reports restored values through onSelectionsChange). The reverse direction (qb, then a link to qa?uf_priority=urgent) was also broken at base, with no filter, and the same change restores it. H2 holds (6 pins green). H3 holds: a switch is one PUSH and window.history.length grows by one, the same at base, under the ablation and with the fix. H4 holds: 3311.4 KB against the 3312.0 KB ceiling. The worktree was removed after the PR opened.",
"tests": "All at HEAD 6eb2c9f (git rev-parse --short HEAD after the last commit), from the repo root, through os-verify-lock (slot issue-11992). Union = git grep -l -E 'ObjectView|userFilter|uf_|listUrlState' over *.test.ts and *.test.tsx (326 files) plus the new pin file and the two dispatch-named scanners (packages/core/src/utils/tests/column-identity.ratchet.test.ts, scripts/tests/one-authority-per-exported-name-6273.test.ts), run as two invocations of 'pnpm exec vitest run --maxWorkers=2'. app-shell, console and scripts/tests: 'Test Files 137 passed (137)' 'Tests 1835 passed (1835)', lock VERDICT command-exit 0. Every other package: 'Test Files 191 passed (191)' 'Tests 4472 passed (4472)', VERDICT command-exit 0. Not narrowed. New pin file ObjectView.ufViewSwitch-11992.test.tsx, 6 tests, renders this page, plugin-view's ObjectView with its tab bar and plugin-list's ListView for real under a BrowserRouter (window.location equals the router location; every URL read asserts it), clicks view-tab-qb, reads the query at the data source. At base 0bbb67b the qb-tab, reverse-link, reverse-Back and cache-precedence pins were red and the H3 pin green. type-check: closure built first ('turbo run build --filter=@object-ui/app-shell^...' 'Tasks: 28 successful, 28 total'), then 'pnpm --filter @object-ui/app-shell type-check' echoed the script name, VERDICT command-exit 0. 'tsc -p tsconfig.test.json --listFilesOnly' lists the new test file. The first type-check at f3c3363 was red (TS18048 on the conditional ref read); commit 6eb2c9f addresses it. node scripts/check-changeset-presence.mjs exit 0 ('2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'); node scripts/check-changeset-no-major.mjs exit 0; pnpm check:new-line-citations exit 0 ('VERDICT new-cross-file-line-citations: 0 new citation(s)'); pnpm check:control-bytes exit 0; pnpm exec eslint on both touched source files exit 0, 0 errors. Ablation (fix committed first; objectstack scripts/ablation-replace.mjs wrap mode with its restore trap; the subject is imported from src as ./ObjectView, so no dist leg): put the once-per-page-mount useState capture over window.location.search back verbatim. At 6eb2c9f: anchor 1 to 0, blob 912960d4f7a5 to 86e98c562fe0. Predicted before the run: 4 failed | 2 passed (6). Measured 'Tests 4 failed | 2 passed (6)'; red: qb tab, reverse link, reverse Back, cache precedence; green: CONTROL fresh mount, H3. Restore: blob after restore == HEAD (912960d4f7a5), git diff HEAD empty, git status clean. The same ablation at f3c3363 measured the same 4|2 with the same restore proof. Eager closure (budget bot comment 6066298342 on PR objectui#11998, head 6eb2c9f): 3311.4 KB gzip across 337 chunks, against the 3312.0 KB budget, PASS. main's reading (bot comment 6064233101 on PR objectui#11990, the squash at 0bbb67b): 3311.5 KB. CI at 2026-10-08T18:21Z: success 25, skipped 3, in_progress 14, failure 0; in_progress is the honest value.",
"files_changed": [
"packages/app-shell/src/views/ObjectView.tsx",
"packages/app-shell/src/views/ObjectView.ufViewSwitch-11992.test.tsx (new)",
".changeset/11992-uf-view-switch.md (new, '@object-ui/app-shell': patch)"
],
"deviations": [
"Two commits, not one: the first type-check was red (TS18048), so the union, type-check and ablation were all re-run at the final head 6eb2c9f.",
"git push ran three times: the empty-branch probe and one push per commit. All three are git pushes, not REST writes.",
"The pins assert the chip's selection count, not its text: in this harness the chip label renders as 'priority' rather than the card's 'Priority1', and UI copy is not pinned.",
"Attribution follows the agent definition and AGENTS.md over the harness reminder. Commits end with the model-free pair 'Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU' and 'Co-authored-by: Claude' with the noreply@anthropic.com address (angle brackets spelled out here for the sanitizer). The PR body ends with the session-URL footer form.",
"None from the file surface: only the three claimed paths changed. userFilterUrlState.ts, plugin-list, components/ui and i18n were not touched."
],
"mcp_calls": "0 — no MCP GitHub calls, read or write",
"api_writes": "3 — each one POST /repos/objectstack-ai/objectstack/dispatches through the fleet-write relay: (1) pr_create, executed as POST /repos/objectstack-ai/objectui/pulls (draft), created objectui#11998, read back 7616 of 7616 bytes identical; (2) label-write --assign os-bill on PR 11998, executed as POST /repos//issues/11998/assignees, read back as matching; (3) this os-dev-report comment through post-stamped, executed as POST /repos//issues/11992/comments. The git pushes are not counted here.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · noted in PR objectui#11998's Acceptance notes, not filed · read from source only, not measured: packages/app-shell/src/views/InterfaceListPage.tsx and ObjectDataPage.tsx keep the same once-per-mount useState capture over window.location.search; whether either remounts its list under a page that stays mounted was not measured · dedupe words: InterfaceListPage uf_ capture once per mount · ObjectDataPage initialUfSelections window.location",
"carrier: none (承接者:无) · noted in the PR's Acceptance notes, a bound and not a defect: when the saved views arrive late and move the active view without a navigation after the user picked a chip, the next view keeps that chip, because the URL still carries it (the URL and the screen agree). The Filter panel, through ownListParamsRef, starts that view from the cache instead. No URL write was added to strip it (H3)."
]
}
objectstack-fleet commentedon Oct 8, 2026
Review: ACCEPT — PR objectui#11998 ·
domain:uiseat 2 · 2026-10-08T18:24ZImplemented-by:
os-devsubagent ofsession_01MgfduSkFrfM3eorB3UGfAU, branchclaude/issue-11992-uf-view-switch, head6eb2c9f. Report6066344335.Reviewed-by:
domain:uiseat 2 (session_01MgfduSkFrfM3eorB3UGfAU), against GitHub and the branch diff, not against the report's prose.Checklist:
Fixes #11992,Clause-②: noat the start of a line. The assignee isos-bill.6065357443:ObjectView.tsx, the new pin and the changeset.userFilterUrlState.ts,plugin-listand the grouping and sort wiring are untouched.git merge-treeof this head againstmainat review, and it is clean. TheListViewhand-off and therenderListViewdependency list are unchanged.6064946799):initialUfSelectionsis no longer a once-per-page-mountuseStatecapture overwindow.location.search.listIdentityKeythatlistSeedRefseeds on andrenderListViewkeys the list on.plugin-list.UserFiltersreadsinitialSelectionsonly in its initializer and never reports restored values. The reverse direction (a link back toqa?uf_priority=urgent) was also broken at the base, and the same change restores it.ObjectViewand plugin-list'sListViewunder aBrowserRouter. At the base, the qb tab, reverse-link, reverse-Back and cache-precedence pins were red. The fresh-mount control and H3 stay green.PUSH, the same at the base, under the ablation and with the fix. No URL write was added.ObjectView,userFilter,uf_orlistUrlStatepasses, with both repo-wide ratchets: 137 files and 1,835 tests in app-shell, console and scripts, and 191 files and 4,472 tests elsewhere.@object-ui/app-shell: patch.main's 3311.5 KB and the 3312.0 KB ceiling: a PASS.6eb2c9fis running, withBundle Analysisgreen. The PR lands through the merge queue when every check is green.Out-of-scope note (
carrier: none; read from source only):InterfaceListPage.tsxandObjectDataPage.tsxkeep the same once-per-mount capture overwindow.location.search. Whether either remounts its list under a page that stays mounted was not measured.Generated by Claude Code
fix(app-shell): a view-tab switch starts the next view with the quick…