Skip to content

Studio: the landing card of each installed base says "n customized, m switched off", read from the per-package customization read #28566

Closed

Description

@objectstack-fleet

epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848

Filing gate: ④ child of epic #28236 (P2, cut 2026-11-01 on the maintainer's 「四项提速措施全部按推荐执行」, schedule reviewed) · plan of record: ADR-0146 Rollout P2 "N-24 landing counts"; Q8 makes it one of the two conditions for retiring Setup › Packaged automation (N-28). ⛔ Not a claim.

Blocked-by: #28411

Part of #28236 (P2, child N-24) · governs: ADR-0146 D3 ("Upgrade and audit": one line per package, "n customized, m switched off"), D4 / Q8 (Packaged automation retires after the ledger switch and this card) · lane: domain:ui · size: S.

Why it waits. The numbers are the server's: N-15 (#28411) serves, per base, the overrides, extensions and switched-off items with their counts. This card draws them and computes none.

Business reason. Before an upgrade, or just to check, an administrator wants to see at a glance which installed apps they have changed and what they have switched off. Studio's landing should say it on each app's card ("HotCRM — 4 customized, 2 switched off"). Today the only deployment-wide view is Setup's Packaged automation page, which covers flows and actions only.

Measured (35b178bd0a).

  • Studio's landing is ui/packages/app-shell/src/views/studio-design/BuilderLanding.tsx. Read-only packages get one card each (:369–402): name, id, a "read-only" chip, and a link out to Setup (studio-landing-overlay, :389). No card carries a count.
  • Package rows come from fetchPackages() (packages-io.ts), with writable as the server's verdict.
  • packages/spec/src/kernel/customization-package.ts: isCustomizationPackage (:119) and customizationBasePackageId (:111) recognize a pair id.
  • N-15's route and response field names: not landed, not verified.

Wanted.

  1. Each read-only base card carries one line: "n customized, m switched off" (zh 「已定制 n 项,已停用 m 项」). The numbers are N-15's served counts for that base, as served. n covers overrides and extensions, as N-15 counts them.
  2. Zero is shown as zero only when N-15 answered. While loading, the line shows no number. On a failed read it shows a muted "couldn't read customizations", with the server's sentence in the title, never "0".
  3. When the base has a pair, the line links to it in Studio (the pair's Studio URL, /studio/hotcrm.custom/data for HotCRM; N-19 later folds this into the base). The switched-off part links to the base's Automations pillar, where N-04's switch lives.
  4. No line on a writable package or on a pair (isCustomizationPackage). A pair id is never sent to N-15, which refuses it.
  5. One read per read-only base, capped by the cards drawn, or one batched read if N-15 offers one. The landing renders before the counts arrive.

Tests. Stubbed N-15 answers:

  • a base with 3 overrides, 1 extension and 2 switched off reads "4 customized, 2 switched off" and links to <base>.custom;
  • a base with no pair reads "0 customized, 0 switched off" with no pair link;
  • a failed read shows no number;
  • a writable package and a pair draw no line and send no request;
  • the landing paints before the counts resolve.

Release safety. Safe on its own: read-only drawing of a served read (Blocked-by: #28411). Packaged automation is not touched here. Its retirement is N-28.

Not here. The read itself (N-15). Rail marks and the "only customizations" filter (N-19). Retiring Packaged automation and the landing's Setup link (N-28). Directory marks (N-26b).

Dedupe. Searched studio landing customized switched off, landing counts customization: only #28411 (the read) and closed history.

Links back: #28236, #28411, ADR-0146 D3, D4, Q8.


Generated by Claude Code

Activity

  1. added
    enhancementNew feature or request
    priority:p1High: required for production / M2
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    on Nov 1, 2026
  2. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

    Correction to the unblock note 6555740870 · 2026-11-01T09:04Z

    The read this card draws is ledgered but not mounted on main: #28622 (p0 main red, domain:server) measures GET /api/v1/packages/:id/customizations answering nothing at runtime since 519089e1. The card stays claimed and the work goes on against the response contract (GetPackageCustomizationsResponseSchema) with stubbed answers, as its Tests section already asks. The seat does not land the PR until #28622 is fixed, so a live probe can show the line drawing real counts and not the "couldn't read customizations" state.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jRL4qcnwHDD4M1e4wx
    os-dev-report

    Delivered 2026-11-01T09:44Z: draft PR #28634 on claude/project-thread-9g21fi, head 3d90f3d4.

    {
      "issue": 28566,
      "status": "done",
      "branch": "claude/project-thread-9g21fi",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28634",
      "session": "session_01QsR2jRL4qcnwHDD4M1e4wx",
      "premise_still_valid": true,
      "summary": "Each read-only base card on the Studio landing now reads GET /api/v1/packages/:id/customizations once and draws 'n customized, m switched off' (zh 已定制 n 项,已停用 m 项): n = served counts.overrides + counts.extensions, m = served counts.switchedOff, judged by GetPackageCustomizationsResponseSchema. Pending shows no number; a failed or off-contract read shows a muted 'Couldn't read customizations' with the server sentence as title. The pair link (/studio/BASE.custom/data) appears only when the package list holds the pair; the switched-off part links /studio/BASE/automations. Writable packages and pairs draw no line and send no request. Live runtime shows the failed state until #28622 mounts the route.",
      "tests": "head 7b294065 (code), final head 3d90f3d4 = 7b294065 + merge of main d77dc07a (ui/e2e/live only, no overlap). New BuilderLanding.customizationCounts-28566.test.tsx: 1 file, 6/6. Ablations via ablation-replace.mjs, tree restored each time (git diff HEAD empty): (1) drop the extensions term → 1 failed (the 4-customized case); (2) drop only the landing pair filter → 6/6 green, the reader's own pair guard holds; (3) drop reader guard + landing filter together → 1 failed (no-line/no-request case). Every ui test naming BuilderLanding or the reader (git grep, 22 files): 120/120; before stubbing four older landing tests they were 4 failed with the network-escape guard. Route-level landing consumers: 4 files 16/16. app-shell type-check exit 0. packages/i18n/ 94 files, 1438 passed, 13 skipped. Narrowing declared: full app-shell suite left to CI Test UI.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 7b294065: 34 derived, all exit 0 (incl. check-sdui-manifest.mjs and --self-test, check:type-check-debt under lock, vitest run scripts/ 169 files / 4900 tests). --ran reconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. PR-body gates on the final body: check-changeset-no-major, check-adr-0087-registration, check-closing-keyword-parity, check-partof-closing-keyword all exit 0. check:new-line-citations: 0 new. CI check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "line_budget": "S card: +450 / -3 over 10 files (code 188 = BuilderLanding.tsx 117 + reader 71; tests 231; strings 16; changeset 18)",
      "files_changed": [
        ".changeset/28566-studio-landing-customization-counts.md",
        "ui/packages/app-shell/src/views/studio-design/packageCustomizations-io.ts",
        "ui/packages/app-shell/src/views/studio-design/BuilderLanding.tsx",
        "ui/packages/app-shell/src/views/studio-design/BuilderLanding.customizationCounts-28566.test.tsx",
        "ui/packages/app-shell/src/views/studio-design/BuilderLanding.accessibleNames-12510.test.tsx",
        "ui/packages/app-shell/src/views/studio-design/BuilderLanding.orgScope-11553.test.tsx",
        "ui/packages/app-shell/src/views/studio-design/BuilderLanding.recentPackages-11863.test.tsx",
        "ui/packages/app-shell/src/views/studio-design/BuilderLanding.setupExit-12513.test.tsx",
        "ui/packages/i18n/src/namespaces/studio/en.ts",
        "ui/packages/i18n/src/namespaces/studio/zh.ts"
      ],
      "deviations": [
        "Declaration line written in the closed-arm form 'Clause-②: yes (widening)' (precedent #28552 / PR #28606) in PR body and changeset; the claim's parenthetical reason is not copied into it.",
        "Four existing landing tests outside the new file got a 5-line vi.mock of the new reader (pending promise): the new read otherwise hit a real socket and the ui network-escape guard failed them. Within the claim's 'their tests' surface.",
        "Reader uses fetch like its packages-io neighbours rather than @objectstack/client packages.customizations (ui/AGENTS.md section 7 prefers the client); noted in Acceptance notes.",
        "Harness asked for PR assignee/reviewer via GitHub MCP; skipped per lane rule 3/10. The relay pr_create read back as UNCONFIRMED (exit 6, no run seen within 90 s); a PR list read then showed #28634 created by objectstack-fleet[bot], body read back intact, so no second dispatch was sent.",
        "The 'other locale packs' are not separate files: the studio namespace ships en and zh only, other languages fall back to en by design."
      ],
      "mcp_calls": "6 — reads only: issue_read x4 (get, get_comments x3), list_pull_requests x1, pull_request_read get x1, plus non-GitHub get_session/subscribe_pr_activity; 0 MCP writes",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls via fleet-write dispatch), this os-dev-report comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/28566/comments)",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: #28622 · the customizations route is in the route ledger but not mounted on main; this PR shows the failed state live until it lands · noted, not filed"
      ]
    }
  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

    Unblocked · 2026-11-01T08:50Z · pm:blocked → pm:queue


    Generated by Claude Code

  5. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

    Claim: PM loop round 3 · 2026-11-01T08:55Z
    Session: session_01QsR2jRL4qcnwHDD4M1e4wx (card thread, os-dev); dispatched by seat session session_01QsR2jR7ZFkpqmm4U8S1f9y
    Account: zhuangjianguo
    Branch: claude/project-thread-9g21fi (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-28566
    Domain: domain:ui
    Seat: domain:ui#4
    File surface: ui/packages/app-shell/src/views/studio-design/BuilderLanding.tsx, packages-io.ts or a small read helper beside it, their tests, and the locale packs for the new landing strings (stop on breach; explain in the report)
    Container & model: S, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: yes (widening: new @object-ui/i18n landing keys; owes this seat's TIER_DEFAULT review)
    Metadata-protocol: none
    Responsibility: Studio's landing draws read-only base cards with no customization count | GET /packages/:id/customizations (PR #28595, 519089e1) serves overrides, extensions, switched-off items and counts per base | an administrator checking what they changed before an upgrade
    Thread-read: 6555740870
    Premise: holds (BuilderLanding's read-only cards carry no count at origin/main; client.packages.customizations is served)
    Serial constraints cleared: #28561 (claimed by this seat, branch claude/project-thread-ddww6q, PR not yet open) also edits BuilderLanding.tsx (button grid) and the studio i18n packs; whichever lands second merges main and resolves


    Generated by Claude Code

  6. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

    ACCEPT → PR #28634 comment 6557136505 · 2026-11-01T11:10Z · contract review TIER_DEFAULT PASS 6557127021 · live probe drew the counts after #28622 landed (28ef35e0) · landing through the merge queue.


    Generated by Claude Code

  7. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y

    Landed · 2026-11-01T11:27Z · PR #28634 merged through the merge queue as 5e879eab. Records: contract review TIER_DEFAULT PASS 6557127021 and ACCEPT 6557136505, both at 1c9ccf15.

    probe before (5e879eab~1) now (origin/main)
    fetchPackageCustomizationCounts in studio-design/BuilderLanding.tsx 0 2
    GetPackageCustomizationsResponseSchema in studio-design/packageCustomizations-io.ts 0 (no file) 3
    landing.customizations keys in i18n/src/namespaces/studio/zh.ts 0 7

    The live probe at 1c9ccf15 (after #28622 landed) drew "0 customized, 1 switched off" from one 200 read. The card closed through Fixes. pm:dispatched comes off in the same stroke as this note.


    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

area:studioChanging a running app without code — authoring, publish, docs and the portaldomain:uienhancementNew feature or requestpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions