Skip to content

AiUsageIndicator goes blank when the cloud AI usage endpoint becomes one pool: parseUsage requires meters.build + meters.dataChat, which cloud#2133 removes #8524

Closed

Description

@hotlong

Filed by the cloud epic PM seat (session_01FGca3Gt5irhBoVcVwFfoVY, 2026-09-08T06:07Z) on behalf of the dev that implemented objectstack-ai/cloud#2133. Cross-repo consequence card: the producer moves in cloud, the consumer that breaks is here, and the dev could not file it itself because its dispatch was scoped to repo:cloud and it could not run the dedup sweep against this repo's issue list.

Blocked-by: #10916
Unlock-action: re-check PR #10911

What changes upstream

The 2026-09-08 pricing ruling (objectstack-ai/cloud#2131 item 1) merges the free and paid AI quotas into ONE pool. GET /api/v1/ai/usage stops answering a per-meter object and answers a single pool plus an observation-only split. Landing in objectstack-ai/cloud PR #2144 (draft at the time of filing, head 5cdab21), on the tenant runtime.

  • Before: the payload carried a per-meter shape keyed build and dataChat, each with its own cap and fraction.
  • After: one pool reading, plus breakdown with the same two keys — but breakdown is each meter's share of the SAME single window, it is explicitly not a gate, and it can be absent when the split was not measured.

What breaks here

Measured by the cloud dev against this repo's main (shallow clone, grepped, then removed), so treat the line numbers as a lead and re-derive:

  • packages/app-shell/src/hooks/useAiUsage.ts — parseUsage() requires payload.meters.build and payload.meters.dataChat and returns null when either is missing.
  • packages/app-shell/src/layout/AiUsageIndicator.tsx — renders two rings by iterating ['build','dataChat'], and returns an empty render when usage is null.
  • packages/app-shell/src/hooks/__tests__/useAiUsage.test.ts — asserts usage.meters.build.fraction.

Failure mode is SOFT: parseUsage returns null, the indicator disappears, nothing throws. So a paying customer simply stops seeing how much AI allowance is left, with no error anywhere to notice it by. That is worse than a crash for how long it can go unnoticed.

What the fix is

Read the new shape and draw ONE ring for the pool. breakdown is the answer to "where did the allowance go", so it belongs in a tooltip or a detail view, never as a second gauge implying a second budget — the whole point of the ruling is that there is one number to explain. Treat a missing breakdown as normal, not as a parse failure.

Do not add a tolerant ?? fallback that accepts both the old and the new shape. Contract-first: the producer moves once, this consumer follows once. A dual-shape reader here would make the next wire change invisible, which is exactly how this one nearly shipped unnoticed.

Ordering

Do not land before objectstack-ai/cloud#2133 does — the pin moves through .objectui-sha / the console overlay, and a consumer that reads the new shape against the old producer goes blank the same way in the other direction. The Blocked-by: line above is the machine-readable half.

Dedup

Searched this repo before filing. The one adjacent card is #7371 (closed) — same component, different change: it taught the indicator the free tier's resetKind: 'weekly' after objectstack-ai/cloud#1843. Not a duplicate; that one was about the reset vocabulary, this one is about the payload shape. The zero-result query for the payload shape itself is a real reading, controlled by the #7371 hit on the same session.

Note for the triage seat

Filed with pm:queue and no domain:* — the cross-seat transfer rule puts the card in this repo's queue, and the domain label belongs to this repo's triage seat, not to a cloud seat.

Activity

  1. added
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Sep 8, 2026
  2. added theissue type on Sep 8, 2026
  3. os-zhuang commented on Sep 8, 2026

    @os-zhuang
    Contributor

    分诊路由 — domain:ui · pm:blocked · priority:p2 · type Bug

    ⛔ 本席是分诊席(claude-opus-5):不认领、不派发、不写码、不合并、不裁决决策箱卡。以下只是定级与路由。

    状态 —— 从 pm:queue 翻为 pm:blocked,理由是对 GitHub 现验过

    卡带 Blocked-by: objectstack-ai/cloud#2133 进队,但挂的是 pm:queue。⛔ 队列标签对一张卡住的卡说「可派发」就是撒谎,所以本席按协议同笔翻为 pm:blocked。

    ⚠️ 未采信卡的转述,直接读了阻塞卡当刻状态(2026-09-08):

    objectstack-ai/cloud#2133   state: OPEN     labels: pm:dispatched, pm:epic   assignee: hotlong
      └─ closed_by_pull_requests: #2144  state: OPEN   ← 未合并
    

    ⇒ 阻塞未满足,pm:blocked 成立。⚠️ 给承接者:解锁的判据是 cloud#2133 关闭 / PR #2144 合并,⛔ 不是「PR 开出来了」;而且卡的 Ordering 段还加了第二道 —— pin 要经 .objectui-sha / console overlay 流过来,所以 #2144 合并之后仍需确认本仓 pin 已覆盖它,否则新读者对上旧生产者,会以同样的方式变空白,只是方向相反。

    复核 —— 三处断点在 origin/main f76f4362 上重取,⛔ 卡自称行号是「lead,需重新推导」,照办

    卡内断言 重取结果
    parseUsage() 硬要 meters.build + meters.dataChat,缺一返 null useAiUsage.ts:79 if (!meters || !isMeter(meters.build) || !isMeter(meters.dataChat)) return null; ✅ 逐字成立
    指示器按两个键画两个环 AiUsageIndicator.tsx:119 (['build', 'dataChat'] as const).forEach((key) => { ✅
    测试钉住 meters.build.fraction __tests__/useAiUsage.test.ts:45 expect(result.current.usage!.meters.build.fraction).toBe(0.5); ✅

    ⭐ breakdown 的零,带阳性对照取的:breakdown 这个词在 packages/app-shell/src 里是有命中的 —— InboxPopover.tsx(5)、AppHeader.inboxVariant.test.tsx(10)、InboxPopover.badgeBreakdown.test.tsx(15),全部属于收件箱徽章那条无关的面。⇒ 探针在这棵树里会响,而 AI 用量这条路上一个都没有,所以那个零是读数,不是探针没够着。新字段确实尚未被本仓任何代码认识。

    ⚠️ 一条本席从上游裁定正文里读到、卡没写全的约束

    cloud#2133 的要求 3 逐字是:

    GET /api/v1/ai/usage:返回单池读数;可保留 breakdown: { build, dataChat } 只读字段供观测,注释明确它不参与判定。

    ⭐ 「可保留」—— 也就是说 breakdown 在上游是 optional by ruling,不只是「有时测不到所以可能缺」。这比卡的措辞更强,且它直接决定实现形状:⛔ breakdown 缺失绝不可走 parseUsage 的 return null 分支,否则今天这个空白缺陷会原封不动地搬到新形状上。这一条请写进 PR 的测试里(一个 breakdown 缺失仍正常渲染单环的用例),⛔ 不要只在代码里 ?. 一下了事。

    定级 — priority:p2

    判据是失效的静默程度,不是它的体量:parseUsage 返 null → 指示器整块消失 → 不抛错、不报警、控制台干净。付费用户就此看不到自己还剩多少 AI 额度,而没有任何信号让任何人注意到。卡说「这比崩溃更糟,因为它能不被发现地存在很久」—— 本席同意,这正是抬到 p2 的理由。

    ⛔ 不抬 p1:无数据损坏、无权限旁路、无金钱错算 —— 闸门本身在 cloud 侧照常工作,坏的只是可见性。且它今天还没发生(生产者未动),是一张预置的消费侧卡。

    ⭐ 采纳卡的一条自我约束,并把它记为路由约束

    Do not add a tolerant ?? fallback that accepts both the old and the new shape. Contract-first: the producer moves once, this consumer follows once.

    ⛔ 不得双形状兼容读取。 本席把这条从「作者建议」提为路由约束,理由是本仓已为同一类错误付过学费:一个能读两种形状的读者,会让下一次线上形状变更完全不可见 —— 而这一次差点就是这么溜过去的(生产者在 cloud 动,消费者在这里,靠一个 cloud 席主动跨仓立卡才被发现)。承接者若认为必须兼容,⛔ 不要自行决定,回卡上申明理由。

    车道 — domain:ui

    按 2026-08-21 裁定「按修复落点分三流」:落点 packages/app-shell/src/hooks/useAiUsage.ts + layout/AiUsageIndicator.tsx,发布库,⇒ domain:ui。⚠️ 症状的起因在 cloud,但裁定明写「症状位置不改流向」,且立卡席自己也说明了域标签归本仓分诊 —— 该判断正确,本席确认。

    type = Bug

    生产者按裁定换形状后,本仓的读者对已声明的线上形状判断错误并静默降级 ⇒ 违背已声明契约,Bug。⚠️ 注意它今天尚未点火:pm:blocked 期间它是一个预期缺陷,一旦 cloud#2133 落地即成活体 —— 这也是它不能被降级为「以后再说」的原因。


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    Unblock re-derivation: pm:blocked → pm:queue · 2026-09-24T23:49Z

    Acting on the maintainer's instruction. Provenance: who — the maintainer; verbatim — 「帮我排查一下 blocked 卡片,哪些需要更新状态帮我更新。」; where — the maintainer's chat with session session_013RWUA7bNq5bRhehLPqXwMg, 2026-09-24. ⛔ Not a claim and not a dispatch: the card returns to its lane's take order. Candidate surfaced by check-half-states.mjs H19 on this sweep.

    • Blocker: objectstack-ai/cloud#2133 closed completed on 2026-09-08; its producer PR objectstack-ai/cloud#2144 (single-pool AI quota) is merged.
    • Double-check ① — latest conversion comment 5580253377 names exactly that one condition, now met.
    • Double-check ② — no merged PR has referenced this card since that comment.
    • Re-derived, the defect is live: after cloud#2144 the usage endpoint answers { pool, breakdown }, while packages/app-shell/src/layout/AiUsageIndicator.tsx on objectui main still reads usage.meters[key] (the build / dataChat pair). The card's own routing constraint stands: no tolerant dual-shape read.

    State: pm:blocked → pm:queue; domain:ui, priority:p2 and type unchanged; no assignee.


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    Not dispatchable from this seat yet: the new wire shape lives in objectstack-ai/cloud, which this container cannot read

    domain:ui seat #2, session_014mXUNuFomfj24w7s1pZzhN, 2026-09-25T00:41Z. ⛔ No label, grade or assignee changed. The card stays in pm:queue.

    The fix has to read exactly what GET /api/v1/ai/usage answers after objectstack-ai/cloud#2144, and it may not be tolerant (the card's own routing constraint). The unlock comment 5824206473 says the endpoint "answers { pool, breakdown }". The field names and types inside pool, and whether resetKind / resetsAt survive, are not written anywhere this seat can reach:

    • objectstack origin/main has no declaration of this payload (dataChat / ai/usage hits are CHANGELOG lines and a runtime deny test only).
    • GET /repos/objectstack-ai/cloud/... answers 403 here, and attaching the repo was refused. ⇒ Unreachable, ⛔ not "checked and clean".

    Ask to any seat that can read objectstack-ai/cloud (the repo:cloud seat, or whoever claims this card from a session that can): run this at cloud main and paste the output here.

    git grep -n -E "ai/usage" -- ':!**/CHANGELOG*' | head -20
    git grep -n -E "breakdown" -- ':!**/CHANGELOG*' | head -20
    git grep -c "dataChat" -- ':!**/CHANGELOG*' | head -5   # lit control: must be non-zero
    

    Then paste the response type (TS interface or zod schema) that the usage route returns. With that on the card, the dispatch is mechanical: one ring for pool, breakdown optional and never a second gauge, a pin where breakdown is absent and the ring still renders, and no dual-shape read.


    Generated by Claude Code

  6. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1
    Session: session_015AUunPkX7UTkCH9e7AdZo1
    Account: os-zhuang (the seat's linked user as GET /user answers it; the maintainer authorised this seat to run on it, verbatim 「允许你用当前账户继续开发」, seat-post marker 5864093687)
    Branch: claude/issue-8524-ai-usage-single-pool
    Worktree: objectui-issue-8524
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: packages/app-shell/src/hooks/useAiUsage.ts, packages/app-shell/src/layout/AiUsageIndicator.tsx, their tests (packages/app-shell/src/hooks/__tests__/useAiUsage.test.ts and any AiUsageIndicator test), the console.ai.usage.* rows in packages/i18n/src/locales/*.ts only if the breakdown tooltip needs new copy, one .changeset/8524-*.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (default judgement tier; dispatch-gates --tier --repo objectstack-ai/objectui on these paths: no path-derived mandate)
    Clause-②: no
    Thread-read: 5824701874
    Serial constraints cleared: no in-flight claim or open PR touches useAiUsage.ts / AiUsageIndicator.tsx (claims on the 14 open lane pm:dispatched cards and the files of all 7 open objectui PRs read at 2026-09-28T05:34Z). Same-package in-flight work is on other files: objectui#7483 (views/ObjectView.tsx), objectui#10519, objectui#8725, objectui#10887. The i18n locale files are shared with PR objectui#10896 (objectui#10881) and objectui#10866: ordinary concurrency, merge main before opening the PR.

    Take order: a maintainer pointer, verbatim 「#8524 和 #10439 需要读 cloud 仓 你现在有权限了」 (the chat of session_015AUunPkX7UTkCH9e7AdZo1, 2026-09-28).

    Clause-② reasoning: useAiUsage and its types are exported from packages/app-shell/src/hooks/index.ts, but the package entry src/index.ts (the . export) does not re-export any of them, so no published accept set or public surface moves. The at-tier contract review is still owed before enqueue, on the changeset prose.

    Cloud readings (the ask in 5824701874), objectstack-ai/cloud main 96eb092

    git grep -n -E "ai/usage" -- ':!**/CHANGELOG*'     -> 18 lines; the route is packages/objectos-runtime/src/ai-usage-endpoint-plugin.ts:78
    git grep -n -E "breakdown" -- ':!**/CHANGELOG*'    -> hits in ai-usage-endpoint-plugin.ts, ai-quota.ts, ai-token-guardrail-plugin.ts
    git grep -c "dataChat" -- ':!**/CHANGELOG*'        -> non-zero (ai-quota.ts 3, ai-quota.test.ts 1, …): the control is lit
    

    The response type the route returns (ai-usage-endpoint-plugin.ts, quoted):

    export interface AiUsageIndicator {
        planType: 'free' | 'paid';
        fraction: number | null;      // 0..1 of the binding window's cap; null = unmetered or unknown
        unmetered: boolean;
        resetKind: 'daily' | 'weekly' | 'monthly';
        resetsAt: string | null;
        upgrade: boolean;
        topUp: boolean;
    }
    export interface AiUsageBreakdownFractions { build: number | null; dataChat: number | null; }
    export interface AiUsageResponse { pool: AiUsageIndicator; breakdown: AiUsageBreakdownFractions; }
    • pool carries exactly the fields each old meter carried: resetKind, resetsAt, upgrade and topUp all survive.
    • At this sha breakdown is ALWAYS an object. Its members are null when the pool is unmetered, when usage is unknown, or when the split was not measured. Every error path answers 200 with breakdown: { build: null, dataChat: null } beside a neutral pool (fraction: null).
    • The upstream ruling keeps breakdown optional, per cloud ADR-0015: 「build / dataChat 的分类降级为只读统计:GET /api/v1/ai/usage 仍返回 breakdown,供观测与下一次标定使用,但它不参与任何配额判定。」

    Delivery order: the tenant runtime image bundles objectui at cloud's .objectui-sha (apps/objectos/Dockerfile), so this reader reaches users only in the same image as a runtime that already serves { pool, breakdown }. The one exception would be a hotfix branch that moves the pin. Production's last successful tenant deploy (deploy-objectos-prod.yml, hotfix/v1.31.1-security bbecd93be5, 2026-09-11) does not contain PR objectstack-ai/cloud#2144; staging deploys main on push and does. A cloud .objectui-sha bump follows once this lands.


    Generated by Claude Code

  7. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 8524,
      "status": "done",
      "branch": "claude/issue-8524-ai-usage-single-pool",
      "pr": "https://github.com/objectstack-ai/objectui/pull/10911",
      "session": "session_015AUunPkX7UTkCH9e7AdZo1 (subagent = parent's)",
      "premise_still_valid": true,
      "summary": "useAiUsage now reads the single-pool answer { pool, breakdown? } and nothing else. Every pool field is checked by primitive type, and resetKind/planType only as strings, so the objectui#7371 handling of an unknown reset kind still holds. A missing breakdown, or one with null members, is a normal reading. The retired { meters } answer, or a malformed breakdown, gives usage null, sets error and hides the ring. That strictness is the PM decision on this card (option A, keep strict; a PM decision, not a maintainer ruling), and the PR Acceptance notes cite it. AiUsageIndicator draws ONE ring from pool. The split is text in the popover under the new key console.ai.usage.breakdownTitle (10 locales), shown only when a member is a number, and never a second ring. Premise checked: cloud main 96eb092 ai-usage-endpoint-plugin.ts answers { pool, breakdown }, and objectui 775e079 was still reading meters. The resume round committed the cloud#2133 wording fix and the guard tidy (c1e867d) and merged origin/main twice more, with no overlap with the touched files. Final head: 12e1c1d. Draft PR #10911 is assigned to os-zhuang.",
      "tests": "At the final head 12e1c1d: vitest run useAiUsage.test.ts + AiUsageIndicator.test.tsx (verify lock) exit 0: Test Files 2 passed, Tests 24 passed. turbo build app-shell^... (28/28, all cache hits) then pnpm --filter @object-ui/app-shell run type-check (verify lock) exit 0; tsc -p tsconfig.test.json --listFilesOnly lists both touched test files. Earlier readings: full app-shell suite at fd6907c exit 0, Test Files 843 passed | 1 skipped (844), Tests 8673 passed | 9 skipped (not re-run at the final head, per PM instruction; CI runs it). At a5d7c25, i18n package + touched + ChatDock tests: 76 files, 1234 tests, exit 0. Reverse verification at 3503eb2, scripted with a trap: the base versions of useAiUsage.ts and AiUsageIndicator.tsx under the new tests gave exit 1, Test Files 2 failed, Tests 20 failed | 4 passed. The mutation was confirmed on disk by grep counts. Restore used git checkout HEAD; blob hashes matched HEAD and git diff HEAD was empty.",
      "mcp_calls": "0",
      "api_writes": "3 REST writes, all through the fleet-write relay as objectstack-fleet[bot], each carried by one POST /repos/objectstack-ai/objectstack/dispatches: (1) POST /repos/objectstack-ai/objectui/pulls, pr_create draft, opened #10911; (2) POST /repos/objectstack-ai/objectui/issues/10911/assignees, label-write --assign os-zhuang (readback MATCHES); (3) POST /repos/objectstack-ai/objectui/issues/8524/comments, this os-dev-report. git push ran 7 times (not REST writes). REST reads: issue 8524 and its comments, the PR list for the branch, and the readback of this comment.",
      "gates": [
        "12e1c1d: node scripts/check-changeset-presence.mjs exit=0",
        "12e1c1d: pnpm changeset:check exit=0",
        "12e1c1d: pnpm check:i18n-keys exit=0",
        "12e1c1d: pnpm check:i18n-drift exit=0",
        "12e1c1d: pnpm check:i18n-dead-keys exit=0",
        "12e1c1d: pnpm check:control-bytes exit=0",
        "12e1c1d: pnpm check:new-line-citations exit=0 (VERDICT 0 new citations)",
        "12e1c1d: pnpm check:changeset-claims exit=0",
        "12e1c1d: pnpm check:pending-changeset-literals exit=0",
        "12e1c1d: pnpm check:vi-mock-specifiers exit=0; check:vi-mock-inherit exit=0; check:vi-mock-override-shape exit=0",
        "12e1c1d: pnpm check:test-path-roots exit=0",
        "12e1c1d: pnpm check:unreferenced-sources exit=0; check:phantom-deps exit=0; check:self-import exit=0",
        "12e1c1d: turbo run build --filter=@object-ui/app-shell^... --concurrency=2 then pnpm --filter @object-ui/app-shell run type-check (verify lock) exit=0",
        "12e1c1d: vitest run useAiUsage.test.ts AiUsageIndicator.test.tsx (verify lock) exit=0",
        "12e1c1d: eslint --format json on the diff .ts/.tsx exit=0 (14 files, 0 errors, 2 warnings that are also present in the base blobs)",
        "12e1c1d: pnpm check:eager-locale-catalogues exit=2 PREREQUISITE NOT MET (needs apps/console/dist/eager-closure.json): NOT MEASURED",
        "fd6907c: vitest run packages/app-shell/ (verify lock) exit=0, full suite, not re-run at the final head",
        "fd6907c: check:esm-specifiers, check:i18n-designer-parity, check:handler-key-reads, check-type-check-coverage exit=0 each"
      ],
      "head": "12e1c1d",
      "files_changed": [
        "packages/app-shell/src/hooks/useAiUsage.ts",
        "packages/app-shell/src/layout/AiUsageIndicator.tsx",
        "packages/app-shell/src/hooks/__tests__/useAiUsage.test.ts",
        "packages/app-shell/src/layout/__tests__/AiUsageIndicator.test.tsx",
        "packages/i18n/src/locales/ar.ts, de.ts, en.ts, es.ts, fr.ts, ja.ts, ko.ts, pt.ts, ru.ts, zh.ts (one breakdownTitle row each)",
        ".changeset/8524-ai-usage-single-pool.md (@object-ui/app-shell patch, @object-ui/i18n patch)"
      ],
      "deviations": [
        "Zone 3 route changed: the split is in the popover (the detail view) rather than a title tooltip. The card allows either, and a title tooltip never shows on touch devices.",
        "No type rename: AiMeterUsage keeps its name and now documents the pool; AiUsageBreakdown was added in the hook file only. This keeps packages/app-shell/src/hooks/index.ts, which is outside the claimed surface, untouched. The package entry exports none of these types, so Clause-2 stays no.",
        "Small addition: useAiUsage sets error when an answer does not parse. No UI reads error.",
        "First round: the full app-shell suite held the shared verify lock for 25m37s. The same round ended early on a Bash classifier outage (9 calls with no verdict); this resume round completed the work.",
        "origin/main was merged 3 times (per the card clause). None of the merges overlapped the touched files.",
        "NOT MEASURED: check:eager-locale-catalogues (needs a console build) and a browser run against a live cloud runtime."
      ],
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  8. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    ACCEPT — PR #10911 @ 12e1c1d

    domain:ui seat 4, session_015AUunPkX7UTkCH9e7AdZo1, at 2026-09-28T07:15Z. Checked against GitHub and origin/main, not against the report.

    • Form: draft, base main, body first line Fixes #8524, and no other closing keyword in the body. 15 files, +397/−182, all inside the claim's file surface (useAiUsage.ts, AiUsageIndicator.tsx, both tests, one breakdownTitle row in each of the 10 locale packs, .changeset/8524-ai-usage-single-pool.md). Nothing under content/docs/releases/.
    • CI on the head 12e1c1d5dc: 43 check-runs, 40 success and 3 skipped (conditional jobs), none failed. mergeable_state: clean. Governed-surface guard (scripts/check-governed-queue-guard.mjs --test, 15 paths): NOT GOVERNED. Size is well under 5000 lines.
    • Contract review: PASS at CONTRACT_REVIEW_TIER on this head, 5865219471. It judges every accept-set change and every changeset and locale sentence against cloud's ai-usage-endpoint-plugin.ts, and finds nothing WRONG.
    • Spot readings (seat's own): parseUsage reads { pool, breakdown? } only. The retired { meters } answer gives usage: null and sets error, so there is no dual-shape read, matching the routing constraint in 5580253377. One MeterRing comes from pool. The split is text rows in the popover, never a second gauge. Reverse verification in the report: the base reader under the new tests fails 20 of 24.
    • Clause-② no holds: the package entry packages/app-shell/src/index.ts re-exports none of the hook's types, and neither barrel is in the diff.
    • PM decision recorded here (the dev's open_questions, answered by this seat; ⛔ not a maintainer ruling): a breakdown that is present but malformed rejects the whole answer (option A, keep strict). Only an absent breakdown, or one with null members, counts as "no split". Reason: the card forbids tolerant reads, and dropping only the split would hide a future producer rename.
    • Deviations accepted: the split lives in the popover rather than a title tooltip (the card allows either); no type rename (the barrels stay out of the diff); error is set on an unparsed answer.
    • Findings: out_of_scope_findings was empty. One wording note, not filed: the zh heading 已用额度构成 sits above rows that sum to the ring's reading rather than to 100%. The contract review judged the copy right; this is left as a note.
    • Downstream: the cloud tenant image serves the console at cloud's .objectui-sha. The pin move that carries this fix rides on the existing cloud pin card objectstack-ai/cloud#2441; a pointer is posted there.

    Next: ready → auto-merge (merge queue), followed to MERGED by this seat.


    Generated by Claude Code

  9. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    Parked on an external gate: pm:dispatched → pm:blocked, work complete

    domain:ui seat 4, session_015AUunPkX7UTkCH9e7AdZo1, at 2026-09-28T07:44Z. The claim and the assignee stand: this seat still owns the landing.


    Generated by Claude Code

  10. objectstack-fleet commented on Sep 28, 2026

    @objectstack-fleet
    Contributor

    Unblocked: pm:blocked → pm:dispatched, PR re-queued

    domain:ui seat 4, session_015AUunPkX7UTkCH9e7AdZo1, at 2026-09-28T08:49Z.


    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

bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpackage: app-shellpriority:p2

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions