Skip to content

components, app-shell: 17 EmptyState implementations, 23 Skeletons and 5 error-boundary classes; the shared DataErrorState has one importer and ViewSkeleton none — make the shared vocabulary the only one #25915

Closed

Description

@os-zhuang

Filing gate ③: a maintainer-directed task. Maintainer, 2026-10-24, verbatim: 「同意:建议新建:与合并无关、独立成卡的产品/契约项(可现在建)」, approving the review's list of independent product / contract cards. Batch-of: 13 (this review batch; the per-fire quota is overridden by the maintainer's direction).

维护者速读

空态/错误态/加载态各自为政:17 个 *EmptyState(app-shell 9)、23 个 *Skeleton、5 个错误边界类;共享的 DataErrorState 只有 1 个导入者,ViewSkeleton / ShimmerSkeleton 导出后 0 导入者;Loader2 旋转器 155 处 vs Skeleton 108 处;toast.error 154 处(19 处英文字面量);role="alert" 68 处对 372 处 text-destructive——行内错误大多不向辅助技术播报。建议把 DataEmptyState / DataErrorState / view-skeleton 定为列表/详情/仪表盘面的唯一呈现,并与开卡 objectstack-ai/objectui#13386 / objectstack-ai/objectui#12618(全空分区怎么画)一起落到共享组件上。

Measured (2026-10-24, HEAD 7981384; script errstate.mjs in the review scratchpad)

Task

  • Declare DataEmptyState / DataErrorState / the view-skeleton family the only presentations for list, detail and dashboard surfaces; give DataErrorState role="alert" by construction.
  • Migrate app-shell's 9 EmptyState variants to DataEmptyState props (icon / title / description / action); route renderer catch paths to DataErrorState.
  • Delete ShimmerSkeleton / ViewSkeleton if still unused after the migration; land the objectui#13386 decision on the shared component.

Who acts: objectui domain:ui seat, one PR per package. Effort M. Risk: visual diffs in the console; rollback per file.

Filed by the read-only whole-repo review session https://claude.ai/code/session_01BDtwYUWhLGyWLzYQjZ95Cf on 2026-10-24, written through the maintainer's own account token (the session holds no fleet-bot credential). Evidence files: that session's scratchpad (objectui-review-report.md, findings-*.md). ⛔ Not a claim; triage grades and routes; suggested labels are suggestions only.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Landed (partial) · domain:ui seat 1 · 2026-10-26T14:14Z

    • Merged: PR fix(app-shell): draw the draft preview failure and empty panes with the shared view states #26135 landed through the merge queue at 2026-10-26T14:13Z as merge commit 601c773844e8. It carried Part of #25915, so the card stays open.

    • Landed here: slice 1. PreviewDraftEmptyState now uses DataErrorState when the overlay read fails (role="alert") and DataEmptyState when nothing is drafted (role="status").

    • Remaining, measured by the slice-1 dev on main: five app-shell blocks still draw their own empty state, which is the work left on this card:

      • InspectorEmptyState (7 importers)
      • StudioEmptyState (4)
      • PreviewEmptyState (3)
      • AppNoAccessEmptyState (2)
      • agentEmptyState (1)

      ui/packages/components was not part of that count.

    • The seat continues with slice 2 on the same card thread, under the claim that follows.

  2. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1
    Session: session_017iXjUm1rujwDk7f3KT1Pkk (seat); implementing card thread session_01FdXMkfnYedDKghz7QLUkx8
    Account: os-steve
    Branch: claude/project-thread-ztb3fw (platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)
    Worktree: the card thread's own container
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: slice 2: ONE of the remaining app-shell blocks (PreviewEmptyState, StudioEmptyState, AppNoAccessEmptyState or agentEmptyState; InspectorEmptyState only if its 7 importers stay unedited) moves onto the shared DataEmptyState / DataErrorState. The dev names the block, its file(s) and its importers before coding. Scope is that file and its test, plus importers only if a prop must change, plus a changeset. Out of bounds: ObjectView.tsx and its new objectView*.ts modules (#25992), seat 2 packages, and ui/packages/components (a registry package, which would add a manifest record). No sweep. PR says Part of #25915 (stop on breach; explain in the report). ⛔ ui/.github/** and the root .github/workflows/ci.yml are out of bounds (maintainer's word, ui-merge epic in flight). Changeset in the root .changeset/.
    Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no (one block swaps its own markup for the shared components; no exported type change. If a shared component needs a new prop, the thread reports first and the seat amends this line)
    Metadata-protocol: none
    Responsibility: n/a: renderer defect in ui/, the producing code is the cited ui file; no platform path covers it; reached through the public Console
    Thread-read: 6418225978
    Premise: holds (slice 1 landed as #26135; the remaining blocks are counted in the slice-1 report 6417210214; read-only check by the seat 2026-10-26T14:15Z)
    Serial constraints cleared: none expected: app-shell is outside the sdui registry closure. Before coding, the dev names the surface and its files, and the seat checks them against in-flight PRs (open-PR file scan 2026-10-26T14:15Z)

    Dispatch order handed to the card thread by the project coordinator (three partitions: ruling / mechanism hypotheses / suggested route); the dev does not claim, and starts only once this claim names its branch.

  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 25915,
      "status": "done",
      "branch": "claude/project-thread-ztb3fw",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26166",
      "session": "session_01FdXMkfnYedDKghz7QLUkx8",
      "premise_still_valid": true,
      "summary": "Slice 2: ui/packages/app-shell/src/console/AppNoAccessEmptyState.tsx now renders DataEmptyState (role=status) instead of the Empty primitive wrapped around a verbatim hand-copy of DataEmptyState icon-square classes. i18n keys/defaults, wrapper and link test ids unchanged; data-reason moves to the status node via DataEmptyState prop spread, so no new prop (Clause-② stays no). One importer, AppContent.tsx, unedited; the seat approved the block before coding. PR says Part of #25915.",
      "tests": "At bd0b46a6: ui/node_modules/.bin/vitest run --maxWorkers=2 on the new AppNoAccessEmptyState.sharedState-25915.test.tsx + unedited AppContent.emptyNavigationLanding-12079 + AppContent.noReadableObjectLanding-25338 under os-verify-lock: VERDICT command-exit 0, Test Files 3 passed (3), Tests 16 passed (16). Ablation (fix committed, source reverted to main via git show HEAD~1, relative src import): Tests 4 failed (4); restored with git checkout HEAD --, blob hash equal to HEAD, git diff HEAD empty. pnpm --filter @object-ui/app-shell type-check after building @object-ui/app-shell^...: VERDICT command-exit 0, 0 error TS.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at bd0b46a6 derived 35 families (slice 1 set + check:skill-identifier-liveness); each run, exit captured before any pipe: 35/35 exit 0. --ran reconciliation: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN. sdui: app-shell is outside the registry closure, record not in the diff (check-sdui-manifest exit 0). PR check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and Clause-② is no",
      "mcp_calls": "2 this slice — mcp__github__issue_read (get_comments), mcp__github__pull_request_read (get_check_runs on #26135); reads only, no MCP writes",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls + assignees os-steve, fleet-write run 40341152773, read-back identical 3584 bytes); this os-dev-report comment POST /repos/objectstack-ai/objectstack/issues/25915/comments. git push is not a REST write.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: #25915 · remaining app-shell blocks InspectorEmptyState (7 importers), StudioEmptyState (4; sentence is ReactNode, needs a DataEmptyState prop or children), PreviewEmptyState (3; warn tone has no shared equivalent), agentEmptyState (returns data, not a block); noted, not filed"
      ],
      "deviations": [
        "Branch restarted from origin/main 601c7738 after #26135 merged (remote branch had been deleted, so a plain push).",
        "PR assignee os-steve although the card has none (claim Account os-steve), set through the relay.",
        "In-flight scan covered origin/claude/* heads only (723)."
      ],
      "files_changed": [
        "ui/packages/app-shell/src/console/AppNoAccessEmptyState.tsx",
        "ui/packages/app-shell/src/console/__tests__/AppNoAccessEmptyState.sharedState-25915.test.tsx",
        ".changeset/25915-app-no-access-shared-state.md"
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Landed (partial) · domain:ui seat 1 · 2026-10-26T15:26Z · slot released

    • Merged: PR fix(app-shell): draw the app no-access screen with the shared DataEmptyState #26166 (slice 2). AppNoAccessEmptyState now renders through DataEmptyState with role="status"; data-reason stays on the status root. With slice 1 (fix(app-shell): draw the draft preview failure and empty panes with the shared view states #26135), two app-shell blocks are now on the shared view states.
    • What remains, as the slice-2 dev measured it. Each remaining item needs a choice before another move-only slice can go:
      • StudioEmptyState: its sentence is a ReactNode, but DataEmptyState.description takes a string. Converging it needs a children slot or a widened prop on DataEmptyState. That is ui/packages/components, a registry package, so it means Clause-②: yes (additive).
      • PreviewEmptyState: it has a warn tone, and the shared states have no equivalent. The same kind of components addition, or a ruling that this pane stays as it is.
      • InspectorEmptyState: it has 7 importers, so converging it means editing them or keeping a wrapper.
      • agentEmptyState: it returns { title, description } data, not a block, so it is likely out of scope.
    • Released: pm:dispatched comes off and pm:queue goes back on. The remaining items need someone to decide on the components prop (and whether the warn tone is a shared state) before a seat can dispatch slice 3. The card stays open.
  5. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    Contributor

    domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT

    Ruling: letter B · maintainer 「25915 B」 in the seat thread, 2026-10-29T02:36Z · recorded by seat domain:ui#1 · 2026-10-29T02:38Z

    The seat's question (put in the thread 2026-10-29T02:30Z): the three remaining app-shell empty states (StudioEmptyState with a ReactNode sentence, PreviewEmptyState with a warn tone, InspectorEmptyState with 7 importers) can converge only if the published DataEmptyState in @object-ui/components is widened (A), or they stay as they are (B).

    B, concretely:

    • DataEmptyState is not widened. StudioEmptyState, PreviewEmptyState, InspectorEmptyState and agentEmptyState stay as they are: they are Studio design-time panes, outside the list / detail / dashboard surfaces this card converges, and a public-API widening for three internal panes is not worth a contract review.
    • What is left on the card needs no choice and closes it: (1) the hand-drawn load-failure blocks in seat 1's area move onto DataErrorState (role="alert" by construction) — measured candidates RouteObjectReadFailed in ui/packages/app-shell/src/console/AppContent.tsx and the page load failure in ui/packages/app-shell/src/views/PageView.tsx, both an Empty with no role; (2) ViewSkeleton and ShimmerSkeleton, still 0 importers outside their own files on origin/main after 10755db2, are retired under the repo's rules for a published export.
    • objectui#13386's all-empty-section rendering stays where its own ruling put it; it is not reopened here.

    Ruling-ref: names this comment. The card stays pm:queue until the seat's next order.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    Contributor

    domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT

    Dispatch order · domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · 2026-10-29T02:39Z

    You are the os-dev developer agent for exactly ONE card: #25915, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/NNNNN" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.

    Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Dispatch the ui lane" one message with your branch name and wait. Worktree objectstack-issue-25915 on that branch from a fresh origin/main; pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).

    Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=25915 --file=F --json run ONCE with output captured to a file (timestamps only as {{NOW}} / {{WAS:…}}). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran. Changeset in the root .changeset/ when a published package changes. ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread "Dispatch the ui lane" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.

    Ruling (cannot be re-ruled)

    Maintainer letter B, recorded 6486367718: DataEmptyState is NOT widened; StudioEmptyState / PreviewEmptyState / InspectorEmptyState / agentEmptyState stay as they are (⛔ do not touch them). Triage first grade 6407850591 (p3): converge surface by surface, no sweep. This order closes the card in two PRs from one thread.

    PM mechanism assumptions (measure on origin/main after 10755db2; disproof welcome)

    • Slice 3 (PR 1, Part of #25915): two hand-drawn load-failure blocks in seat 1's area render an Empty with no role, so assistive technology hears nothing: RouteObjectReadFailed in ui/packages/app-shell/src/console/AppContent.tsx (:1869, test id route-object-read-failed) and the page record load failure in ui/packages/app-shell/src/views/PageView.tsx (:271, test id page-record-load-failed). Both move onto DataErrorState (ui/packages/components/src/custom/view-states.tsx, role="alert" by construction), keeping their i18n keys and defaults, their test ids and their Retry control. If DataErrorState cannot carry a Retry action or a test id without a new prop, STOP and tell the seat (no new prop on the shared component without an amended claim). Search ui/packages/app-shell for any other hand-drawn load-failure block outside ⛔ ObjectView*, RecordDetailView.tsx and seat 2's packages; list what you find in the report, move only these two.
    • Slice 4 (PR 2, Fixes #25915, after PR 1 merges or in parallel if the files do not overlap): ViewSkeleton (custom/view-skeleton.tsx) and ShimmerSkeleton (custom/shimmer-skeleton.tsx) are re-exported from ui/packages/components/src/custom/index.ts (:23–24) and have 0 importers outside their own files (the app-shell/src/styles.css hit is a comment). Retire both under the repo's rules for removing a published export (read AGENTS.md and ui/AGENTS.md for the retirement / tombstone / changeset-major rules; scripts/sdui-manifest.record.json if the registry closure moves). If those rules make the removal a Clause-② narrowing that owes a contract review or a Tier H path, quote the rule in the report and stop before pr_create; the seat amends.

    Scope

    File surface: slice 3 = the two files above, their tests (one new pin per block: role="alert" present, Retry still calls its handler; a control showing the success path renders no alert), one patch changeset for @object-ui/app-shell if it publishes (it is private: true now: then no changeset, say so). Slice 4 = the two skeleton files, custom/index.ts, the manifest record if moved, a changeset for @object-ui/components. Ablation per slice: revert the block to Empty ⇒ the role pin goes red. ⛔ Every Studio empty state named in the Ruling. Stay under 400 changed lines per PR.

    Tier

    Quote dispatch-gates --tier on each diff. Expected none (seat ran it on the five paths). TIER_DEFAULT, effort medium. Slice 3: Clause-②: no, Metadata-protocol: none. Slice 4: you state Clause-② from the retirement rule you read. PR 1 Part of #25915; PR 2 Fixes #25915.

  7. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    Contributor

    domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT

    Claim: PM loop round 26 · 2026-10-29T02:42Z
    Session: session_01JQwxbZeBv2y91towxasSUT (seat; implementation by card thread session session_01JQwxbZK9w6fe2Y6mGQjj6L, mode:thread)
    Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/project-thread-jplskw (the card thread's harness push branch, self-reported — the measured platform exception to claude/issue-N-slug)
    Worktree: objectstack-issue-25915 in the card thread's clone
    Domain: domain:ui
    Seat: domain:ui#1 (seat post #25966)
    File surface: slice 3 — ui/packages/app-shell/src/console/AppContent.tsx (RouteObjectReadFailed), ui/packages/app-shell/src/views/PageView.tsx (page record load failure), their tests; slice 4 — ui/packages/components/src/custom/view-skeleton.tsx, shimmer-skeleton.tsx, custom/index.ts (:23–24 only), the sdui manifest record if it moves, a changeset. ⛔ StudioEmptyState / PreviewEmptyState / InspectorEmptyState / agentEmptyState, ⛔ ObjectView*, RecordDetailView.tsx, seat 2's packages; no new prop on DataErrorState without an amended claim (stop on breach; explain in the report)
    Container & model: M, mode:thread (the maintainer's word: 3 active card threads per seat, 2026-10-28 10:00Z / 12:11Z), model: TIER_DEFAULT (seat-run dispatch-gates --tier on the five paths: no path-derived mandate), effort: medium
    Clause-②: no (slice 3); slice 4 stated by the dev from the export-retirement rule it reads, and the seat amends this line before its pr_create if that rule says a review is owed
    Metadata-protocol: none
    Responsibility: load-failure presentation in this lane's @object-ui/app-shell + unused published exports in @object-ui/components | maintainer ruling B 6486367718 | a load failure is announced (role="alert") and no dead skeleton export ships
    Thread-read: 6486381447
    Premise: holds — on origin/main after 10755db2, both load-failure blocks render an Empty with no role, and ViewSkeleton / ShimmerSkeleton have 0 importers outside their own files (the app-shell/src/styles.css hit is a comment).
    Serial constraints cleared: seat read of every open PR's file list at claim time — only draft PR #27340 touches custom/index.ts, adding two lines near the top (:10, :12), not :23–24; whichever lands second merges origin/main.
    Resume-from: none


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    Contributor

    domain:ui#1 · os-warren · session_01JQwxbZK9w6fe2Y6mGQjj6L

    os-dev-report

    {
      "issue": 25915,
      "status": "needs_decision",
      "branch": "claude/project-thread-jplskw",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27366",
      "session": "session_01JQwxbZK9w6fe2Y6mGQjj6L",
      "premise_still_valid": true,
      "summary": "Slice 3 done as draft PR #27366 (Part of #25915): RouteObjectReadFailed in AppContent.tsx and the page record-scope load failure in PageView.tsx now render DataErrorState (role=alert by construction). i18n keys and defaults, test ids and both Retry handlers are unchanged; no new prop on the shared component (test id spreads through props, Retry is passed as children, the component's documented slot for a call site's own control). Slice 4 is measured but NOT opened: retiring ViewSkeleton and ShimmerSkeleton removes symbols from the published @object-ui/components entry, which by the rules quoted in open_questions is a Clause-② (narrowing) declaration that owes a CONTRACT_REVIEW_TIER review, so per the order I stop before its pr_create for the seat to amend. Also, view-skeleton.tsx cannot be deleted as a file: GridSkeleton and ChartSkeleton in it have live importers.",
      "tests": "At head 72976b7a, under os-verify-lock: pnpm --dir ui exec vitest run --maxWorkers=2 on AppContent.disabledPackageDeepLink-13052.test.tsx and PageView.appPageRecord-12931.test.tsx (one new #25915 pin each: role=alert present and containing Retry; Retry re-reads; the success path renders no alert): VERDICT command-exit 0, Test Files 2 passed (2), Tests 23 passed (23). Ablation (fix committed; both sources reverted to origin/main, i.e. the Empty blocks; grep -c of the DataErrorState opener 0 in each, of the old Empty opener with the test id 1 in each; components resolve to src through the ui vitest alias, so no dist leg): VERDICT command-exit 1, Tests 2 failed | 21 passed (23), both #25915 pins red on toHaveAttribute role alert; restored with git checkout HEAD --, both blob hashes equal HEAD, git diff HEAD empty. All 56 app-shell test files importing AppContent or PageView: VERDICT command-exit 0, Test Files 56 passed (56), Tests 358 passed (358). pnpm --filter @object-ui/app-shell type-check after building @object-ui/app-shell^... (8m18s under the lock): VERDICT command-exit 0, 0 error TS.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 72976b7a derived 34 families; each run, exit captured before any pipe: 34/34 exit 0 (pnpm --dir ui exec vitest run scripts/ under the lock: Test Files 174 passed, 2 skipped). --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. dispatch-gates --tier: no path-derived mandate. pnpm --dir ui run check:new-line-citations: 0 new, exit 0. Changed lines 129 (+89/-40), under 3000. PR check-runs: not yet reported at report time (not awaited, per contract).",
      "line_budget": "slice 3: 129 changed lines of the 400 per-PR cap",
      "dogfood_battery": "n/a for PR #27366: no ! in the title and Clause-② is no with no arm. Slice 4 would owe one at its final head (a (narrowing) arm).",
      "mcp_calls": "1 — mcp__claude-code-remote__subscribe_pr_activity on #27366 (not a GitHub MCP tool); 0 mcp__github__ calls",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls with assignees os-warren, fleet-write run 40811604052, read-back identical 5396 bytes) and this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/25915/comments via post-stamped). git push is not a REST write.",
      "open_questions": [
        {
          "question": "Slice 4 owes a contract review: may it open as Clause-② no (narrowing), and on what file surface?",
          "rule": "AGENTS.md Post-Task Checklist step 3: '(narrowing) is BREAKING'; 'removing or renaming anything an author can write (a spec key, an export, a config field) puts the FROM → TO mapping and the one-line fix in the body'; 'A breaking changeset must also state its ADR-0087 disposition'. pm-dispatch references/contract-review.md: 'PR 正文与 changeset 行首 Clause-②: no (narrowing) 申报的收窄亦此档' (CONTRACT_REVIEW_TIER), scope the whole non-prose diff. os-dev.md: full dogfood once at the final head when Clause-② carries a (narrowing) arm. Not Tier H: no governed path is touched. ADR-0145 does not apply (it governs ?: never authoring-face tombstones, not React runtime exports).",
          "measured": "@object-ui/components exports only '.' (dist/index), which reaches custom/index.ts. Zero importers outside their own file: ViewSkeleton, ViewSkeletonVariant, ViewSkeletonDispatchProps (view-skeleton.tsx), ShimmerSkeleton, ShimmerSkeletonProps (shimmer-skeleton.tsx). Live importers in the same view-skeleton.tsx: GridSkeleton (plugin-dashboard DatasetWidget.tsx), ChartSkeleton (plugin-charts ObjectChart.tsx, plugin-dashboard DatasetWidget.tsx, pinned by chart-primitives-removed-7397.test.ts as staying exported). KanbanSkeleton, FormSkeleton, ListSkeleton: 0 importers, only ViewSkeleton dispatches to them. The app-shell styles.css comment that names ShimmerSkeleton is outside the slice-4 file surface.",
          "options": [
            "A: amend the claim to Clause-② no (narrowing), Metadata-protocol none; retire ViewSkeleton + its two types from view-skeleton.tsx (file stays for Grid/Chart/Kanban/Form/List) and delete shimmer-skeleton.tsx + its index.ts line; add ui/packages/app-shell/src/styles.css (one comment line) to the surface; patch changeset for @object-ui/components with BREAKING note, FROM → TO lines and an adr-0087 not-required (runtime-export-retired) marker; CONTRACT_REVIEW_TIER review before landing; dogfood at the final head. Cost: about 90 changed lines, one dogfood run, one review.",
            "B: same as A and also retire KanbanSkeleton, FormSkeleton and ListSkeleton, which lose their only caller (the dispatcher). Wider than ruling B names.",
            "C: keep the exports and close the card on slice 3 only. No review cost, but the dead exports stay published."
          ],
          "recommendation": "A: it is exactly what ruling B names, and the review is owed by the narrowing whichever slice-4 shape is taken."
        },
        {
          "question": "Branch sequencing: this thread can push only claude/project-thread-jplskw, so slice 4 cannot run in parallel with PR #27366.",
          "options": [
            "A: slice 4 starts from a fresh origin/main on the same branch after #27366 merges",
            "B: the seat dispatches slice 4 to another card thread now (files do not overlap)"
          ],
          "recommendation": "A, unless the seat wants slice 4 queued for review sooner."
        }
      ],
      "out_of_scope_findings": [
        "carrier: #25915 · other app-shell blocks that draw a load failure by hand, outside ObjectView*, RecordDetailView.tsx and seat 2's packages, not moved per the order: views/metadata-admin/AuditPanel.tsx (audit-error-state, an Empty), views/metadata-admin/ResourceEditPage.tsx (refs-error, an Empty), views/metadata-admin/DirectoryPage.tsx (engine.directory.loadFailed, a bare text-destructive div), chrome/ErrorBoundary.tsx (boundary fallback, an Empty); views/objectViewHeaderChrome.tsx has one but is under the ObjectView* exclusion; noted, not filed",
        "carrier: #25915 · KanbanSkeleton, FormSkeleton and ListSkeleton become uncalled exports once the ViewSkeleton dispatcher is retired (open question 1, option B); noted, not filed"
      ],
      "deviations": [
        "Changeset: the order said no changeset because @object-ui/app-shell is private. Its code ships inside the published @object-ui/console SPA, so the changeset bumps @object-ui/app-shell and @object-ui/console as patch, the same pair recent app-shell-only fixes carry.",
        "Pins added as new cases inside the two existing test files that already mount these failures (one per block), not as new files.",
        "Visual: the page block's muted AlertTriangle is replaced by DataErrorState's default destructive icon; the route block, which had no icon, now shows it. Both Retry buttons keep their own markup."
      ],
      "files_changed": [
        ".changeset/25915-load-failures-data-error-state.md",
        "ui/packages/app-shell/src/console/AppContent.tsx",
        "ui/packages/app-shell/src/console/__tests__/AppContent.disabledPackageDeepLink-13052.test.tsx",
        "ui/packages/app-shell/src/views/PageView.tsx",
        "ui/packages/app-shell/src/views/__tests__/PageView.appPageRecord-12931.test.tsx"
      ]
    }

    Generated by Claude Code

  9. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    Contributor

    domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT

    Claim amendment (slice 4) · 2026-10-29T03:23Z · amends Claim 6486419404 on the dev's open question 1 in report 6487003112

    The seat takes the dev's option A for slice 4 and sequencing A.

    File surface (slice 4): ui/packages/components/src/custom/view-skeleton.tsx (retire ViewSkeleton, ViewSkeletonVariant, ViewSkeletonDispatchProps; the file stays for GridSkeleton / ChartSkeleton / KanbanSkeleton / FormSkeleton / ListSkeleton), ui/packages/components/src/custom/shimmer-skeleton.tsx (deleted), ui/packages/components/src/custom/index.ts (its shimmer-skeleton line only), ui/packages/app-shell/src/styles.css (the one comment line naming ShimmerSkeleton), the sdui manifest record if it moves, one changeset for @object-ui/components with the BREAKING note, the FROM → TO lines and its ADR-0087 disposition. ⛔ KanbanSkeleton / FormSkeleton / ListSkeleton stay exported (option B is wider than ruling 6486367718 names; noted as an out-of-scope finding only).
    Clause-②: no (narrowing) — owes one CONTRACT_REVIEW_TIER review of the whole non-prose diff before the queue, handed to triage by the seat with a Contract-review-handoff: line on the head; the dev runs the full dogfood once at the final head. Not Tier H (no governed path).
    Metadata-protocol: none
    Sequencing: slice 4 starts from a fresh origin/main on claude/project-thread-jplskw after PR #27366 merges; Fixes #25915.

    Every other line of 6486419404 stands.


    Generated by Claude Code

  10. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    Contributor

    domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT

    Landed (partial, slice 3) · seat domain:ui#1 · 2026-10-29T03:51Z

    PR #27366 merged as c4c515ad3c (seat record 6487136546). The route object-read failure (AppContent.tsx RouteObjectReadFailed) and the custom page's record-load failure (PageView.tsx) are now drawn by the shared DataErrorState, so a failed read is announced (role="alert"); titles, copy, i18n keys, test ids and Retry are unchanged, and the shared component gained no prop. Part of #25915, so the card stays open and claimed: slice 4 (retire ViewSkeleton and ShimmerSkeleton, claim amendment 6487017457, Fixes #25915) starts now on the same branch from a fresh origin/main.


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    Contributor

    domain:ui#1 · os-warren · session_01JQwxbZK9w6fe2Y6mGQjj6L

    os-dev-report

    {
      "issue": 25915,
      "status": "done",
      "branch": "claude/project-thread-jplskw",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27388",
      "session": "session_01JQwxbZK9w6fe2Y6mGQjj6L",
      "premise_still_valid": true,
      "summary": "Slice 4, under claim amendment 6487017457 (option A): draft PR #27388 (Fixes #25915) retires ViewSkeleton, ViewSkeletonVariant and ViewSkeletonDispatchProps from view-skeleton.tsx. The file stays for Grid, Kanban, Form, List and Chart skeletons. The PR deletes shimmer-skeleton.tsx (ShimmerSkeleton, ShimmerSkeletonProps) and its custom/index.ts line, and rewords the app-shell styles.css comment. Its changeset is a @object-ui/components patch with a BREAKING note, a FROM → TO line for each of the five exports and an adr-0087 not-required (runtime-export-retired) marker naming them. Clause-② no (narrowing), Metadata-protocol none; it owes a CONTRACT_REVIEW_TIER review before the queue. The branch restarted from origin/main c4c515ad after #27366 merged; the remote branch had been deleted, so the push was plain.",
      "tests": "At head 8e055464, under os-verify-lock: pnpm --filter @object-ui/components build VERDICT 0; pnpm --filter @object-ui/components type-check VERDICT 0, 0 error TS; pnpm --dir ui exec vitest run --maxWorkers=2 packages/components/ VERDICT 0, Test Files 447 passed | 1 skipped (448), Tests 4327 passed | 24 skipped. Removal proof on the built dist: grep -cw is 0 for all five retired names in index.js and custom/view-skeleton.d.ts; custom/shimmer-skeleton.d.ts is not emitted; control GridSkeleton reads 2 in view-skeleton.d.ts and 1 in index.js. No ablation: no tested behaviour changed (a removal of uncalled exports); no permanent pin, since the claim surface names no test file.",
      "gates": "dispatch-gates --commands at 8e055464 derived 28 families; 28/28 exit 0, each exit captured before any pipe. check-adr-0087-registration verified the runtime-export-retired marker for all five operands. The ui vitest scripts/ gate first exited 1 on quick-reference-commands-4149 (apps/site): a leftover ui/apps/site dir of ignored files from this worktree's earlier install, before #27329 retired the site. After removing it, the rerun gave VERDICT 0, Test Files 169 passed | 2 skipped. --ran: 28 derived, 28 run, 0 NOT-MEASURED, 0 UNRUN. check-platform-checklist --changed-from origin/main exit 0 (no anchored file). dispatch-gates --tier: no path-derived mandate. PR check-runs: not yet reported at report time.",
      "line_budget": "slice 4: 111 changed lines (+21/-90) of the 400 per-PR cap",
      "dogfood_battery": "8e055464 · closure pnpm --filter '@objectstack/dogfood^...' build VERDICT command-exit 0 · pnpm --filter @objectstack/dogfood test VERDICT command-exit 0 (22m19s under the lock) · Test Files 348 passed | 3 skipped (351) · Tests 2806 passed | 20 skipped (2826) · no failures",
      "mcp_calls": "1 — mcp__claude-code-remote__subscribe_pr_activity on #27388 (not a GitHub MCP tool); 0 mcp__github__ calls",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls with assignees os-warren, fleet-write run 40820258602, read-back identical 5982 bytes) and this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/25915/comments via post-stamped). git push is not a REST write.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: #25915 · KanbanSkeleton, FormSkeleton and ListSkeleton are now uncalled exports of @object-ui/components (their only caller was the retired dispatcher); kept per amendment 6487017457; noted, not filed"
      ],
      "deviations": [
        "No permanent absence pin; removal proven once on the built dist instead (claim surface names no test file).",
        "The ui scripts/ gate is recorded at its rerun after removing a stale local ui/apps/site directory (ignored files only, not in the diff)."
      ],
      "files_changed": [
        ".changeset/25915-retire-view-and-shimmer-skeleton.md",
        "ui/packages/app-shell/src/styles.css",
        "ui/packages/components/src/custom/index.ts",
        "ui/packages/components/src/custom/shimmer-skeleton.tsx",
        "ui/packages/components/src/custom/view-skeleton.tsx"
      ]
    }

    Generated by Claude Code

  12. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    Contributor

    domain:ui#1 · os-warren · session_01JQwxbZeBv2y91towxasSUT

    Landed · seat domain:ui#1 · 2026-10-29T06:23Z

    PR #27388 merged as 3bfb357aa3 (contract review PASS 6489318444, seat record 6489334469); Fixes #25915 closed the card. Slice 4 retired the five unused @object-ui/components exports (ViewSkeleton, ViewSkeletonVariant, ViewSkeletonDispatchProps, ShimmerSkeleton, ShimmerSkeletonProps) with a patch changeset carrying the BREAKING note and FROM → TO lines; GridSkeleton, KanbanSkeleton, FormSkeleton, ListSkeleton and ChartSkeleton stay. With slice 3 (#27366, c4c515ad3c), ruling B 6486367718 is fully landed.

    Left on record, not filed: KanbanSkeleton / FormSkeleton / ListSkeleton have no in-workspace caller; animate-shimmer has no in-workspace consumer (kept as the host migration target); four more hand-drawn load failures (AuditPanel, ResourceEditPage, DirectoryPage, chrome ErrorBoundary) could move to DataErrorState in a later card. The seat releases the claim.


    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