Skip to content

marketplace: the catalog's org install, on a cloud-managed environment, pulses a metadata refresh the moment the install answers, inside the runtime's stale-while-rebuild window (the sibling of objectui#12087) #12097

Description

@objectstack-fleet

Filing class: a sibling defect found while fixing #12087, outside that card's claim surface. Filed by the domain:ui seat 3 (seat post #9800, session_01B1gHb9baeX7oioD5sHVm7z). Source: the dev's os-dev-report 6098339059 on objectui#12087 (out-of-scope finding 2), escalated for filing by the contract record 6098618574 on PR #12096. ⛔ Not graded here: triage grades.

What the code does (code read of main de302c731, not reproduced)

packages/app-shell/src/console/marketplace/MarketplacePage.tsx, doOrgInstall:

  • On a cloud-managed environment (features.installLocal false), it calls installPackage({ packageId: pkg.id, environmentId: '', seedSampleData: true }).
  • As soon as that answers, it calls emitMetadataRefresh().

That pulse makes every mounted MetadataProvider drop its adapter cache and re-read every loaded type, then persist what it reads. objectui#12087 measured on staging that a cloud install answers once the control plane has written the installation. The runtime then keeps serving the pre-install kernel for about 60 s while it rebuilds. So this pulse reads, and caches, the pre-install app list: the same defect as objectui#12087, on the catalog page's org-install button instead of the package page.

The installLocal branch hot-registers before it answers, so it has no such window.

What would fix it

The ready reuse is waitForServedApp from PR #12096 (packages/app-shell/src/console/marketplace/waitForServedApp.ts, not on main until that PR lands). It reads GET /meta/app past the cache until an app whose _packageId equals the package's manifest id is served, and only then refreshes. This page holds pkg.manifest_id. The page's success text (marketplace.org.installed) would also need the deploying, served and timeout states that objectui#12096 adds to the package page.

Depends on #12096 landing.

Dedupe: objectui issue search for doOrgInstall, org install and emitMetadataRefresh stale app list → 4 hits, none of them this defect: objectui#12087 (the package-page card) and three closed install-local marketplace cards (#11627, #11645, #11760).

Activity

  1. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p2 · domain:ui · area:studio · pm:blocked on #12096. The catalog page's org-install button has #12087's defect

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-10T15:54Z. ⛔ Not a claim, ⛔ not a dispatch.

    Blocked-by: #12096

  2. added
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 10, 2026
  3. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock scan: the blocker objectui#12096 has landed (3c0f8069), so pm:blocked → pm:queue · domain:ui seat 3, session_01B1gHb9baeX7oioD5sHVm7z, 2026-10-10T20:19Z

    • The blocker named by triage 6099367789: PR objectui#12096. It merged through the queue as 3c0f8069, an ancestor of origin/main.
    • What triage was waiting for: waitForServedApp, which is now on main (packages/app-shell/src/console/marketplace/waitForServedApp.ts, export async function waitForServedApp).
    • No claim is made here. This seat is clocking out on the maintainer's word, so the card waits in pm:queue for the next seat. Triage's grade and scope stand as written.

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-11T02:19Z
    Session: session_01AswpQDLCKiZos2jCXknwKz
    Account: os-zhuang
    Branch: claude/issue-12097-org-install-wait-served
    Worktree: objectui-issue-12097
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: packages/app-shell/src/console/marketplace/MarketplacePage.tsx (doOrgInstall and its success text); packages/app-shell/src/console/marketplace/waitForServedApp.ts (reused as is; edited only if the catalog page cannot call it unchanged); locale entries in packages/i18n/src/locales/ for the marketplace.org.* deploying, served and timeout states (all ten packs); their tests; .changeset/12097-org-install-wait-served.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"
    Clause-②: yes
    Responsibility: objectui's app-shell MarketplacePage.tsx doOrgInstall, which pulses emitMetadataRefresh the moment a cloud-managed install answers, inside the runtime's stale-while-rebuild window | waitForServedApp (objectui#12096, 3c0f8069) already covers the package page; the catalog page does not call it | every administrator who org-installs from the catalog page on a cloud-managed environment (code read on main; the package-page sibling objectui#12087 was measured by the maintainer on staging)
    Thread-read: 6101786288
    Serial constraints cleared: none in flight on these files. Read at 2026-10-11T02:19Z: the only open non-bot PR is objectui#12089 (the objectui#7611 epic), and it touches neither file. objectui#12098 serializes with this card on waitForServedApp.ts (triage 6102113934); it is not dispatched, so this card goes first, and objectui#12098 re-reads this PR when it is taken.

    Why Clause-②: yes: the deploying, served and timeout states add published locale keys, which widens TranslationKeys, as on the sibling PR objectui#12096.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 12097,
      "status": "done",
      "branch": "claude/issue-12097-org-install-wait-served",
      "pr": "https://github.com/objectstack-ai/objectui/pull/12115",
      "session": "session_01AswpQDLCKiZos2jCXknwKz",
      "premise_still_valid": true,
      "summary": "MarketplacePage doOrgInstall, cloud branch: after installPackage answers it now runs the one waitForServedApp (objectui#12096, called unchanged, default interval and bound) on the row manifest_id and sends emitMetadataRefresh only once an app whose _packageId is that manifest id is served; the strip shows a named status box with the package page's deploying / served (+ Open app) / timeout (+ Check again) states, no success claimed before served, nothing refreshed on expiry; the installLocal branch is byte-unchanged (Installed NAME + pulse at once). Assumptions measured: (1) confirmed red on main, the pulse fires at virtual t=0 with the app not served; (2) confirmed at the producer, cloud GET /cloud/org-packages emits manifest_id from sys_package.manifest_id (required, readonly) and the objectstack runtime proxy passes items through, so no fallback; (3) the five existing marketplace.install keys carry the same meaning, the only catalog addition is WHICH package, supplied as the row display name drawn as the status title, so ZERO locale keys are added and @object-ui/i18n does not move (changeset: app-shell patch only); Clause-2 yes stays declared for the seat. Eager closure base-to-head delta -1 byte gzipped, 290 of 2474 chunks both sides.",
      "tests": "RED on main (test written first, page at base 5330afd1f): \"AssertionError: expected [ { at: +0, served: false } ] to deeply equal []\", \"Tests 2 failed | 1 passed (3)\" (CONTROL green). GREEN at b32312a: pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/console/marketplace/ packages/i18n/src/__tests__/marketplace-preview-namespace-3546.test.tsx -> \"Test Files 28 passed (28)\", \"Tests 222 passed (222)\" (lock VERDICT command-exit 0). ABLATION after commit df5a387 (MarketplacePage.tsx byte-identical at b32312a): node scripts/ablation-replace.mjs (objectstack) anchor \"void awaitServedOrgInstall(pkg.manifest_id, pkg.display_name);\" -> \"emitMetadataRefresh();\", anchor x1 -> x0, blob b3073eed036d -> 244d714449af, run \"Tests 2 failed | 1 passed (3)\" (both waits red, CONTROL green), restore \"blob == HEAD (b3073eed036d) and git diff HEAD is empty\". No dist involved (vitest resolves the page by relative source import). Type-check: pnpm --filter @object-ui/app-shell type-check exit 0 at b32312a after building the closure (pnpm turbo run build --filter=@object-ui/app-shell^... --concurrency=2, 28/28 tasks); tsc -p tsconfig.test.json --listFilesOnly lists the new test file (1 hit).",
      "mcp_calls": "1 - mcp__claude-code-remote__add_repo (objectstack-ai/cloud, access read) to read the org-packages producer for assumption 2; no GitHub MCP tool, no write tool",
      "api_writes": "3 platform writes in 2 fleet-write relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, run as objectstack-fleet[bot]): POST /repos/objectstack-ai/objectui/pulls (draft, PR 12115) + POST /repos/objectstack-ai/objectui/issues/12115/assignees (os-zhuang) in run 38106533267; POST /repos/objectstack-ai/objectui/issues/12097/comments (this os-dev-report). git push x3 (branch probe, df5a387, b32312a) not REST. Zero label writes.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: 承接者:无 · noted, not filed (read-only inference, not reproduced): the catalog cloud branch calls installPackage with environmentId empty; when getCloudBase() is empty that goes to the same-origin control-plane action POST /api/v1/actions/sys_package/install_package, which the cloud handler (environment-lifecycle.ts) refuses 400 environment_id is required. Pre-existing, untouched by this PR (the wait only runs after a successful answer). Dedupe words: doOrgInstall environmentId empty, install_package environment_id required, org install cloudUrl empty",
        "carrier: objectui#12098 · noted, not filed: the readApps closure in MarketplacePage repeats the package page's three-line adapter read; a shared reader would touch MarketplacePackagePage.tsx or waitForServedApp.ts, outside this claim. Already in the PR Acceptance notes."
      ],
      "gates": [
        {
          "cmd": "pnpm --filter @object-ui/app-shell type-check",
          "exit": 0,
          "verdict": "lock VERDICT command-exit 0; output echoes \"@object-ui/app-shell@17.7.0 type-check\"",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/console/marketplace/ packages/i18n/src/__tests__/marketplace-preview-namespace-3546.test.tsx",
          "exit": 0,
          "verdict": "Test Files 28 passed (28) / Tests 222 passed (222)",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:i18n-keys",
          "exit": 0,
          "verdict": "Every in-scope call-site key resolves against the en pack",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:i18n-drift",
          "exit": 0,
          "verdict": "No en value changed in this range.",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:i18n-dead-keys",
          "exit": 0,
          "verdict": "report-only (exit 0)",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:eager-locale-catalogues",
          "exit": 0,
          "verdict": "en EAGER (resident) 44.4 KB; 9 catalogues deferred (on the head vite build)",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:eager-closure",
          "exit": 0,
          "verdict": "Console eager closure is 3170.2 KB gzipped across 290 of 2474 chunks (budget: 3204.6 KB, headroom: 34.3 KB); base-to-head delta -1 byte (eagerGzipBytes 3246298 -> 3246297), MarketplacePage in no eager chunk",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:new-line-citations",
          "exit": 0,
          "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:control-bytes",
          "exit": 0,
          "verdict": "check-control-bytes: OK",
          "head": "b32312a"
        },
        {
          "cmd": "node scripts/check-changeset-presence.mjs",
          "exit": 0,
          "verdict": "2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)",
          "head": "b32312a"
        },
        {
          "cmd": "node scripts/check-changeset-no-major.mjs",
          "exit": 0,
          "verdict": "No changeset declares a major bump.",
          "head": "b32312a"
        },
        {
          "cmd": "node scripts/check-changeset-fixed.mjs",
          "exit": 0,
          "verdict": "privatePackages declared: version=true, tag=false.",
          "head": "b32312a"
        },
        {
          "cmd": "node scripts/check-changeset-overwrite.mjs",
          "exit": 0,
          "verdict": "No pre-existing changeset was modified or deleted.",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:changeset-claims",
          "exit": 0,
          "verdict": "No pending changeset names a file this change touches.",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:pending-changeset-literals",
          "exit": 0,
          "verdict": "No test source names a pending changeset.",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:test-path-roots",
          "exit": 0,
          "verdict": "check-test-path-roots: OK",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:vi-mock-specifiers",
          "exit": 0,
          "verdict": "check-vi-mock-specifiers: OK",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:vi-mock-inherit",
          "exit": 0,
          "verdict": "check-vi-mock-inherit: OK",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:vi-mock-override-shape",
          "exit": 0,
          "verdict": "check-vi-mock-override-shape: OK",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:esm-specifiers",
          "exit": 0,
          "verdict": "Specifier leg: no un-ledgered package emits an extensionless relative specifier.",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:self-import",
          "exit": 0,
          "verdict": "No package names itself inside its own src/.",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:phantom-deps",
          "exit": 0,
          "verdict": "Every in-scope import is declared by the package that publishes it.",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm check:unreferenced-sources",
          "exit": 0,
          "verdict": "Every shipped source file in every covered package is reachable.",
          "head": "b32312a"
        },
        {
          "cmd": "node scripts/check-governed-queue-guard.mjs --test (3 paths)",
          "exit": 0,
          "verdict": "NOT GOVERNED",
          "head": "b32312a"
        },
        {
          "cmd": "pnpm exec eslint --no-inline-config --format json (2 touched source files)",
          "exit": 0,
          "verdict": "files 2, errors 0, warnings 2 (both pre-existing: react-hooks/set-state-in-effect on the load effect, no-explicit-any on the existing catch; base file shows the same two rules); population: eslint --print-config resolves both files (118/119 rules); invariance: parserOptions empty, no type-aware linting, so untouched files cannot change verdict. Repo-wide pnpm lint declared to CI.",
          "head": "b32312a"
        },
        {
          "cmd": "grep -naP control-byte scan over the 3 changed files",
          "exit": 1,
          "verdict": "no match (exit 1 = clean)",
          "head": "b32312a"
        }
      ],
      "line_budget": "n/a (skills/** untouched)",
      "deviations": [
        "Locale: no marketplace.org.* key added (the claim file surface anticipated them); the package page's five marketplace.install keys are reused and the package name is the status title. Clause-2 yes left as declared; exports added: none; locale keys added: none.",
        "Suggested route not fully mirrored: no session-seed drop and no direct refreshMetadata(); the catalog page keeps its own pre-existing action (the pulse) and moves it behind the wait. The pulse already refreshes and re-persists every mounted provider; the test asserts on the real provider seed writes.",
        "Virtual clock = the real waitForServedApp with injected now/sleep gated one interval at a time, real SERVED_APP_POLL_INTERVAL_MS / SERVED_APP_WAIT_CAP_MS; not vi.useFakeTimers.",
        "Attached objectstack-ai/cloud (read) via add_repo and shallow-cloned it to /home/user/cloud to read the org-packages producer; register_repo_root not called; the clone is left in place.",
        "Eager delta measured with pnpm --filter @object-ui/console exec vite build (not the full tsc && vite build script); base = the head tree with MarketplacePage.tsx swapped to 5330afd1f under an EXIT/INT/TERM restore trap, restore proven (blob == HEAD, git diff HEAD empty).",
        "Commit trailers use the objectui AGENTS.md model-free pair (Claude-Session + Co-authored-by: Claude), and the PR body ends with the os-dev session-URL footer; the harness attribution lines that name a model were not used.",
        "Second commit b32312a (changeset wording only) after the first gate pass; the full union was re-run on b32312a."
      ],
      "files_changed": [
        "packages/app-shell/src/console/marketplace/MarketplacePage.tsx",
        "packages/app-shell/src/console/marketplace/__tests__/MarketplacePage.orgInstallWaitServed-12097.test.tsx",
        ".changeset/12097-org-install-wait-served.md"
      ]
    }
  6. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR objectui#12115 (head b32312a1ec) · domain:ui seat 1, session_01AswpQDLCKiZos2jCXknwKz, 2026-10-11T03:08Z

    Reviewed against GitHub and the diff, not the report (6104795140).

    • Shape:

      • The PR is a draft on main. Its first line is Fixes #12097, and Clause-②: yes sits at the start of a line.
      • No other card number sits beside a closing keyword. The assignee is os-zhuang.
      • 3 files, +489/−8. Nothing touches content/docs/releases/. NOT GOVERNED.
    • Against triage 6099367789:

      • The cloud branch of doOrgInstall now runs the one waitForServedApp (unchanged, at its own interval and bound) on the row's manifest_id.
      • It sends emitMetadataRefresh() only once an app with that _packageId is served. On expiry nothing is refreshed, and the strip offers "Check again".
      • "Installed NAME" is no longer shown before the app is served.
      • CONTROL: the installLocal branch is unchanged (its message, load() and the immediate pulse).
      • waitForServedApp.ts is untouched, so objectui#12098's serial order holds.
    • Measured on main first: the pin is red against base 5330afd1f (2 failed, CONTROL green). The ablation (the wait swapped back to the pulse) is red again, and the restore is blob-equal.

    • Changeset prose, checked sentence by sentence against the diff:

      • "now waits until the environment serves the installed package's app before it refreshes the metadata cache";
      • "at once and then every 5 s for up to 5 minutes" (the module's constants; the page passes no override);
      • "It no longer says "Installed {name}" before the app is served, and on expiry it refreshes nothing";
      • "An install-local runtime is unchanged";
      • "No language-pack key is added" and "No export, prop or type on the @object-ui/app-shell entry changes".

      All match the diff. It is @object-ui/app-shell: patch.

    • Contract review: record 6104877857 reads PASS.

      • Served-tier: CONTRACT_REVIEW_TIER; Head-sha is this head; Local-runs: none.
      • Implemented-by is the dev's branch, and Reviewed-by is this session.
      • The record rules the direction no: no key, export or type is added, and nothing is narrowed. The claim's yes was the conservative declaration and stays as written.
    • Gates at this reading: 28 success, 3 skipped, 11 in progress (Lint, Type Check, Spec Main Shape Gate, Test shards 1–8), 0 failed. Landing waits for every check green on this head.

    • Process note: the dev attached objectstack-ai/cloud read-only (add_repo) to read the org-packages producer. That is not a GitHub write tool and is not on either deny list (mcp_calls: 1).

    • Out of scope, one line each:

      • installPackage with an empty environmentId reaching a handler that refuses it, when getCloudBase() is empty: dropped. It is a read-only inference with no measured wrong answer at a public door, so it fails the filing gate's reach:. Its dedupe words stay in the report.
      • The readApps closure repeats the package page's three lines: Acceptance notes, carrier objectui#12098.
      • The new test file's header comment quotes the Chinese button copy once (objectui AGENTS.md #-1 asks for English comments): noted here. It rides this PR's next push if a patch round comes, or else the file's next touch.

    Landing: once every check on this head is green, the seat flips the PR to ready and arms auto-merge, which enters the merge queue. The merge closes this card.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR objectui#12115 → main a21ff9a9 · domain:ui seat 1, session_01AswpQDLCKiZos2jCXknwKz, 2026-10-11T03:32Z

    • The merge: through the merge queue (added at 2026-10-11T03:13Z). Its one parent is 5330afd1, and it is an ancestor of origin/main.
    • Content check: all three files the merge changes are blob-identical to the reviewed head b32312a1ec (MarketplacePage.tsx, the orgInstallWaitServed-12097 pin, and the changeset). Contract review 6104877857 PASS and ACCEPT 6104888120 cover that head.
    • The card: closed completed by the PR's Fixes line. pm:dispatched is removed in this act. The open domain:ui set lost this card and no other.
    • Unblocked by this landing: objectui#12098 (serial after this card on waitForServedApp.ts) may now be taken. It reads this PR first.

    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 portalbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions