Repository navigation
Studio 左栏导航在 AI 副驾 apply 之后不刷新:新对象已 active 且已入 app.navigation,整页刷新才出现 #7255
Description
Activity
Claim: PM loop round 3 (epic objectstack-ai/cloud#1841)
Session:session_c5c0ce54-bb9c-478c-9e5b-cf44b80d4569
Branch:claude/issue-7255-studio-nav-refresh-after-apply
Worktree:objectui-issue-7255
Domain: domain:ui
File surface:packages/app-shell/src/views/studio-design/**(nav rail / metadata tree refresh after an AI apply), the AI copilot → workbench invalidation seam, tests (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: opus (PM judgement)
Clause-②: no
Serial constraints cleared: objectui#7366 (#7254, studio-design + i18n + tool cards) MERGED — base on current main; #7256 (PR #7372, home/logo, enqueued) and #7371 (usage indicator, in flight) own disjoint files; #7257 (merged) retired the dev metadata-events poll — a production-safe refresh channel is part of this cardClaim: dev
Session:session_c5c0ce54-bb9c-478c-9e5b-cf44b80d4569
Branch:claude/issue-7255-studio-nav-refresh-after-apply(pushed, empty)
Worktree:objectui-issue-7255
Base:20c04b232f64435e999f2205114b9a0d8966ad6a(origin/main)
File surface (planned):packages/app-shell/src/views/studio-design/**, the AI copilot to workbench invalidation seam, tests
Mode:mode:subagent, model opusos-dev-report
{ "issue": 7255, "status": "done", "branch": "claude/issue-7255-studio-nav-refresh-after-apply", "pr": "https://github.com/objectstack-ai/objectui/pull/7376", "premise_still_valid": true, "summary": "PM's mechanism guess confirmed on current main, with one correction: the apply signal is NOT read off the copilot's tool-card state. ChatPane already fires emitMetadataRefresh() on every turn whose tool results carried an authoring envelope (draftReview / replayOutcome) — the confirm-replay path in the card mints replay_* tool-call ids, so the pulse DOES fire in the reported scenario. The missing half was a subscriber: the four Studio pillar rails keyed their loads on publishNonce / draftNonce only, which the workbench's own Publish and draft-save bump and nothing the copilot does. Added useMetadataRefreshNonce(hold) and listed it in the load deps of the Interfaces (nav tree + object picker), Data, Automations and Access rails. Two non-obvious halves: the Interfaces load rehydrates appDraft, which IS the nav edit buffer, so the pulse is HELD while navDirty/navSaving and released — not dropped — once autosave settles; and that effect no longer flaps appStatus back through 'loading' on a re-read of the same package, which would have blinked the nav toolbar once per copilot turn (AGENTS.md #8). No new channel, no poll, no reload: the refresh channel is the existing assistant-bus invalidation that usePendingDrafts and MetadataProvider already converge on — production-safe by construction, nothing near the dev-only metadata-events SSE that objectui#7257 taught to stop retrying. A packageId payload on the pulse was considered and deliberately NOT added; the PR body carries the four-axis reasoning.", "tests": "All at c8534ddce (final commit). TARGETED: `pnpm exec vitest run packages/app-shell/src/views/studio-design/ packages/app-shell/src/assistant/` -> `Test Files 48 passed (48) / Tests 257 passed (257)`; the wider first pass adding `packages/app-shell/src/preview/` was `Test Files 60 passed (60) / Tests 353 passed (353)`. NEW: StudioDesignSurface.aiApplyRefresh.test.tsx (both rails grow the new entry after emitMetadataRefresh() in the SAME mounted tree — pre-existing entries asserted to survive, so a remount 'fix' fails it) and useMetadataRefreshNonce.test.tsx (hold defers + coalesces, never drops). ABLATION: committed first, then stripped metadataRefreshNonce from the two dep arrays under test; mutation confirmed ON DISK before measuring — `metadataRefreshNonce]` occurrence count 5 -> 2 and file hash b2522f25 -> ba30689f, not an editor exit code. Predicted direction RED, observed RED: `Tests 2 failed | 3 passed` (both acceptance tests failed; the three hook unit tests stayed green, the correct split — they measure the adapter, not the wiring). NO rebuild leg is claimed or needed: the test imports ./StudioDesignSurface as a sibling SOURCE module, so the mutated bytes are what ran. Restore under an EXIT/INT/TERM trap with an absolute repo root, proven by STATE not exit code: `git diff HEAD` empty, tree clean, on-disk hash back to b2522f25d375f1b7b3fc08309c3acd133a66e0c2 = the HEAD blob, count back to 5; suites re-run green on the restored tree. TYPE-CHECK: `pnpm --filter @object-ui/app-shell type-check` exit 0 AFTER `pnpm --filter '@object-ui/app-shell^...' build` (exit 0) — without the closure it was 20+ phantom TS2307. Both new test files are genuinely covered, not excluded: `tsc -p tsconfig.test.json --listFiles` names them and the first run caught a real fixture widening error. LINT: full-repo `pnpm lint` (eslint . --no-inline-config), NOT a narrowed run — `Tasks: 47 successful, 47 total` / `Cached: 0 cached, 47 total`, 0 errors (2877 pre-existing no-explicit-any warnings, none in this diff). GATES (exit code captured before any pipe, verdict lines quoted in the PR body): check:control-bytes OK (6075 files scanned); check:i18n-keys OK (no new keys); check:i18n-drift `0 en value(s) changed`; check:vi-mock-specifiers OK; check:vi-mock-inherit OK; check:self-import OK; check:phantom-deps OK; check:side-effects-array OK; check:entry-guard OK; check:icon-record-names OK; check-changeset-presence `1 source file(s) of 1 released package(s) changed ... declares 1 changeset(s)`; check-changeset-no-major OK (minor). check:eager-closure is NOT MEASURED locally — it needs apps/console/dist/eager-closure.json and reports itself a broken gauge without it; CI has the artifact. NOTE objectui has no scripts/pm/dispatch-gates.mjs (that script only lives in objectstack and answers about its own tree), so the gate family above was derived by hand from this repo's package.json check:* list against the diff's paths. CI status at report time: in_progress.", "mcp_calls": "0 — every GitHub read and write went through REST (`gh api`); the repo-scoped probe passed on the first call, so no MCP fallback was needed.", "open_questions": [], "out_of_scope_findings": [ "filed as objectstack-ai/cloud#1858 (no assignee): AI-appended nav items carry no `icon` while the same producer's blueprint-first items do (layout_dashboard / building_2). Judged producer-side per this card's ruling — BOTH objectui consumers already have a renderer default (NavigationRenderer.resolveIcon falls back to FileText; the Studio NavTree falls back node.icon -> the object's own metadata icon -> a type-generic glyph), so the defect is 'a generic glyph beside two semantic ones', and choosing a meaningful icon needs to know what the table is FOR — information only the blueprint/apply chain has. Guessing from the label in the renderer would fossilize a second de-facto contract (Commandment #0.1), so nothing was changed here. Searched objectstack-ai/cloud open issues first via one targeted REST search ('nav icon' -> 0, 'blueprint icon' -> 0) with a same-session control word ('navigation' -> 3 hits) proving the channel answers." ] }ACCEPT — reviewer of record: PM (epic objectstack-ai/cloud#1841), verified against GitHub.
- PR fix(app-shell): Studio rails converge on an AI copilot apply without a page reload #7376: draft → main,
Fixes #7255; files inviews/studio-design/**+ the assistant-bus hook + tests + changeset — inside the surface. - Ruling check: no new channel, no poll, no reload — the existing assistant-bus
emitMetadataRefresh()pulse (already fired by ChatPane on authoring envelopes, incl. the confirm-replay path) gains its missing subscriber:useMetadataRefreshNonce(hold)in the load deps of the Interfaces (nav tree + object picker), Data, Automations and Access rails; the pulse is HELD while the nav edit buffer is dirty/saving and released, not dropped; no appStatus flap on re-read. Production-safe by construction (nothing near the dev-only SSE 生产姿态下 console 持续轮询 GET /api/v1/dev/metadata-events → 404,浏览器控制台被刷红 #7257 retired). PM's "read it off the tool-card state" guess corrected — accepted. - Icon half judged producer-side per the ruling and filed as objectstack-ai/cloud#1858 (no consumer-side label guessing) — agreed; renderer defaults already exist.
- Evidence: 48 files / 257 tests on studio-design + assistant (60/353 with preview); new acceptance test asserts both rails grow the entry in the SAME mounted tree; ablation (drop the nonce from the two dep arrays) proven on disk, predicted red observed red (2 failed / 3 hook unit tests green), restore proven by state;
type-checkafter the dependency closure exit 0 with--listFilescovering the new tests; FULL-repopnpm lint47/47 uncached, 0 errors; 12 gate verdict lines quoted; eager-closure declared NOT MEASURED (needs CI artifact). - CI in progress at review time. Flipping ready; enqueuing when every check is green.
Generated by Claude Code
- PR fix(app-shell): Studio rails converge on an AI copilot apply without a page reload #7376: draft → main,
现象
2026-09-02 最新主干 rig:在 Studio 工作台内让 AI 副驾「再加一张跟进记录表」并「确认修改」,租户库
sys_metadata里 app.navigation 已含{"id":"nav_b2r4_follow_up_record","label":"跟进记录","type":"object",...}(无 icon),对象与默认列表视图也已 active,但工作台左栏「客户管理 · 导航」仍只有「首页仪表盘 / 客户」;整页刷新后才出现「跟进记录」。修复要求