Skip to content

Studio 左栏导航在 AI 副驾 apply 之后不刷新:新对象已 active 且已入 app.navigation,整页刷新才出现 #7255

Description

@hotlong

现象

2026-09-02 最新主干 rig:在 Studio 工作台内让 AI 副驾「再加一张跟进记录表」并「确认修改」,租户库 sys_metadata 里 app.navigation 已含 {"id":"nav_b2r4_follow_up_record","label":"跟进记录","type":"object",...}(无 icon),对象与默认列表视图也已 active,但工作台左栏「客户管理 · 导航」仍只有「首页仪表盘 / 客户」;整页刷新后才出现「跟进记录」。

修复要求

  1. AI apply / publish 完成后,工作台的导航与元数据树订阅变更并刷新(AI 副驾与工作台在同一页,工具结果里带 packageId/对象名,足够触发精确失效)。
  2. 顺带:AI 生成的导航项没有 icon,与前两项(layout_dashboard / building_2)不一致——确认由生产者(cloud 蓝图/apply 链路)补默认 icon 还是渲染端给缺省图标,按生产者侧修并在本卡说明。

Activity

  1. self-assigned this
    on Sep 2, 2026
  2. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    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 card

  3. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    Claim: 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 opus

  4. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    os-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."
      ]
    }
  5. hotlong commented on Sep 2, 2026

    @hotlong
    ContributorAuthor

    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 in views/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-check after the dependency closure exit 0 with --listFiles covering the new tests; FULL-repo pnpm lint 47/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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions