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

Open

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 24, 2026

    @objectstack-fleet
    Contributor

    Triage: first grade — tech-debt · priority:p3 · domain:ui · area:records · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-24T17:05Z

    ⛔ Not a claim, ⛔ not a dispatch.
    finding comes off.

    • Converge empty, error and loading states on DataEmptyState / DataErrorState / view-skeleton, surface by surface, with no sweep. The all-empty-section rendering from objectui#13386 (ruling C) lands on the shared component.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    Contributor

    Transferred 2026-10-26T03:54Z from objectstack-ai/objectui#13462, with its comments and timeline; the old URL redirects here. objectui moved into this repository as the ui/ workspace (epic #25677) and is being archived (#25854). The body is left exactly as filed.

    Paths. Read every repository path in the body with a ui/ prefix: packages/components/src/custom/view-states.tsx is now ui/packages/components/src/custom/view-states.tsx; packages/react/src/SchemaRenderer.tsx is now ui/packages/react/src/SchemaRenderer.tsx; packages/app-shell/src/chrome/ErrorBoundary.tsx is now ui/packages/app-shell/src/chrome/ErrorBoundary.tsx; packages/react-runtime/src/index.tsx is now ui/packages/react-runtime/src/index.tsx; packages/react/src/LazyPluginLoader.tsx is now ui/packages/react/src/LazyPluginLoader.tsx.

    References. The bare issue numbers in the body were written in objectui and now resolve against this repository by mistake; read them as objectstack-ai/objectui#12618, objectstack-ai/objectui#12889, objectstack-ai/objectui#13142, objectstack-ai/objectui#13207, objectstack-ai/objectui#13356, objectstack-ai/objectui#13386.

    No stale pm:dispatched or assignee to strip.


    Generated by Claude Code

  3. 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 1: ONE surface in ui/packages/app-shell or ui/packages/components whose own empty, error or loading block moves onto the shared DataEmptyState / DataErrorState / view-skeleton, chosen by the dev from a measured list of duplicates and named with its reason in the PR; that surface's file(s) and test, scripts/sdui-manifest.record.json if a registry source changes (then the PR takes the manifest-hash token), changeset. Out of bounds: ObjectView.tsx (#25992 in flight) and seat 2's packages (plugin-list / grid / detail / form / view, fields). No repo-wide 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 surface swaps its own block for the shared components; no exported type change. If the 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: 6407854795
    Premise: holds (triage first grade 2026-10-24 17:05Z, p3: converge surface by surface, no sweep; read-only check by the seat 2026-10-26T12:55Z)
    Serial constraints cleared: manifest-hash single token if the chosen surface is in a registry package; the dev names the surface and its file(s) before coding, and the seat checks them against in-flight PRs (open-PR file scan 2026-10-26T12:55Z)

    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.

  4. 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/26135",
      "session": "session_01FdXMkfnYedDKghz7QLUkx8",
      "premise_still_valid": true,
      "summary": "Slice 1: ui/packages/app-shell/src/preview/PreviewDraftEmptyState.tsx now draws its draft-overlay load failure with DataErrorState (role=alert) and its not-drafted / nothing-drafted pane with DataEmptyState (role=status), replacing the bare Empty primitive that gave both the same unlabelled node. Chosen from a measured list (app-shell: 6 own empty blocks, 0 imports of DataEmptyState/DataErrorState) as the only one that renders a load failure; one importer (AppContent.tsx, unedited); seat approved the surface before coding. i18n keys, Retry control and test ids unchanged; no new prop on the shared components. PR says Part of #25915.",
      "tests": "At 250585bd: ui/node_modules/.bin/vitest run --maxWorkers=2 on the new PreviewDraftEmptyState.sharedStates-25915.test.tsx + i18n draftBar-es-register-3844.test.ts under os-verify-lock: VERDICT command-exit 0, Test Files 2 passed (2), Tests 15 passed (15). Ablation (fix committed, source reverted to main via git show HEAD~1, src imported relatively so no dist step): Tests 3 failed | 2 passed (5), the three role tests red, the two Retry tests green as expected; restored with git checkout HEAD --, blob hash equal to HEAD, git diff HEAD empty. pnpm --filter @object-ui/app-shell type-check (tsc --noEmit + tsc -p tsconfig.test.json) after building @object-ui/app-shell^...: VERDICT command-exit 0, 0 error TS.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 250585bd derived 34 families; each run, exit captured before any pipe: 34/34 exit 0 (incl. check-sdui-manifest, check:type-check-coverage, check:type-check-debt, check:nul-bytes, check:cross-package-test-inputs, check-empty-changeset, check-changeset-no-major). --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. node scripts/gen-sdui-manifest-node.mjs under the lock: VERDICT command-exit 0, record re-recorded byte-identical (922 files in 27 packages; app-shell off-record), so scripts/sdui-manifest.record.json is not in the diff. PR check-runs: in_progress at report time (not awaited, per contract).",
      "dogfood_battery": "n/a — no ! in the PR title and Clause-② is no (no narrowing arm)",
      "mcp_calls": "3 — mcp__github__issue_read x3 (get, get_comments x2); reads only, no MCP writes",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls + assignees os-steve, fleet-write run 40330664921, read-back identical 3824 bytes); 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), PreviewEmptyState (3), AppNoAccessEmptyState (2), agentEmptyState (1) stay for later slices; noted, not filed"
      ],
      "deviations": [
        "PR assignee set to os-steve although the card has no assignee: the claim names Account os-steve and the project asks the requester be assigned; set through the relay pr_create, no MCP write.",
        "In-flight scan covered origin/claude/* heads only (707, depth-1 blob compare); other branch prefixes not scanned."
      ],
      "files_changed": [
        "ui/packages/app-shell/src/preview/PreviewDraftEmptyState.tsx",
        "ui/packages/app-shell/src/preview/__tests__/PreviewDraftEmptyState.sharedStates-25915.test.tsx",
        ".changeset/25915-preview-draft-shared-states.md"
      ]
    }

    Generated by Claude Code

  5. 1 remaining item

  6. 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.

  7. 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

  8. 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.
  9. 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

  10. 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.

  11. 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

  12. 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

  13. 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

  14. 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

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions