You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
console marketplace: a soft-uninstalled package (status disabled) still shows Installed with no reinstall; listInstalledPackages drops status/enabled #28521
Filing gate ①: a product defect, measured on a local hosted-path stack (control plane plus an objectos runtime environment, with the Console built at framework fa74b489). The measurement is on the cloud side; the defect is in the Console.
What happens
After a package is uninstalled on a hosted environment, the marketplace card still says "Installed" and offers no install or reinstall button.
The cloud side behaves correctly:
Uninstall is a soft disable that keeps the installation row, for the ADR-0025 consent record and the sample-data state.
GET /cloud-connection/installation answers installed: false.
GET /cloud-connection/installed lists the row with status: 'disabled' and enabled: false. The SDK's packages.list / enable depend on that row being listed.
Reinstalling through POST /cloud-connection/install answers 200, outcome reinstalled, and re-enables the same row.
ui/packages/app-shell/src/console/marketplace/marketplaceApi.tslistInstalledPackages() (around lines 942–967) maps every row and drops status and enabled.
MarketplacePage.tsx (around lines 396–399) counts every listed row as installed.
Ask
The marketplace reads status / enabled, and does not count a disabled row as installed.
It shows either the Install button, or 已停用 with a 重新安装 action that calls the install door, which re-enables the row.
Setup → Packages reads the same list through readMarketplaceInstalls() and probably has the same gap (not measured). Please check it too.
Business reason
A customer who uninstalls an app cannot see that it is off and cannot get it back. Today the only way out is a different package.
Reader
The Console marketplace owner, through objectstack triage. No cloud change is needed. The cloud card that measured this closes when this one lands and the pin carries it.
Dedup
Searched open and closed objectstack issues for "marketplace uninstall disabled installed reinstall": no card about the disabled state on the card.
Read fresh. The cloud side is correct, as the cloud seat measured: a disabled row is listed, and reinstalling re-enables it. The defect is in the Console only. listInstalledPackages() drops status and enabled, and MarketplacePage counts every row as installed. The fix needs no cloud change, so it stays in the framework domain:ui lane. The cloud card waits on the pin.
p2 stands. The claim checks Setup → Packages (readMarketplaceInstalls()) too, as the card asks, and measures the reinstall through the install door.
Claim: PM loop round 2 · 2026-11-01T07:10Z
Session: session_01QsR2jVBzmHX5zVyRfxqBc3 (card thread, os-dev); dispatched by seat session session_01QsR2jR7ZFkpqmm4U8S1f9y
Account: zhuangjianguo
Branch: claude/project-thread-xx8o3g (platform-assigned to the card thread; it can push only this branch)
Worktree: objectstack-issue-28521
Domain: domain:ui
Seat: domain:ui#4
File surface: ui/packages/app-shell/src/console/marketplace/** and the Setup → Packages page that reads readMarketplaceInstalls() (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the Console marketplace's listInstalledPackages() drops status/enabled and MarketplacePage counts every listed row as installed | the cloud door already serves status: 'disabled' and reinstalls through POST /cloud-connection/install | any hosted customer who uninstalled a package
Thread-read: 6553639105
Premise: holds (no open PR touches the marketplace tree; last landing there is #28200, merged)
Serial constraints cleared: none
Cloud: triage 6553639105 reads this as Console-only with no cloud change. If the work needs the cloud repository, the card goes whole to the repo:cloud lane.
{
"issue": 28521,
"status": "done",
"branch": "claude/project-thread-xx8o3g",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28620",
"head": "5f3027f6",
"session": "session_01QsR2jVBzmHX5zVyRfxqBc3",
"premise_still_valid": true,
"summary": "listInstalledPackages() now reads the control-plane row's status/enabled and marks a soft-uninstalled row `disabled` (either field saying so). MarketplacePage keeps such a row out of installedIds and the org card draws Reinstall (existing key marketplace.action.reinstall) instead of the Installed badge; the click goes through the same doOrgInstall -> POST /api/v1/cloud-connection/install, which re-enables the row, and the reloaded listing then reads Installed. readMarketplaceInstalls() drops disabled rows on the cloud leg, so Setup -> Packages neither lists nor acts on them (that page did have the gap: a disabled row with no registry row was pushed as a not-loaded marketplace install with Uninstall). Public catalog grid (install-local ledger only) and the detail page (/installation already answers installed:false) needed no change.",
"tests": "New MarketplacePage.disabledInstall-28521.test.tsx, 6 cases, real listInstalledPackages/readMarketplaceInstalls/installPackage over a stubbed fetch: 6/6 passed. Ablations via ablation-replace.mjs (anchor 1->0, restored to HEAD blob, git diff HEAD empty): MarketplacePage counting every cloud row installed -> Reinstall case red (1 failed/5 passed); readMarketplaceInstalls keeping disabled rows -> Setup Packages case red (1 failed/5 passed). Narrowed set at 43425dfa: 71 ui test files naming MarketplacePage/marketplaceApi/readMarketplaceInstalls/listInstalledPackages/PackagesPage, 710 tests passed. Merged head 5f3027f6: new file + all of app-shell/src/views/metadata-admin/, 686 files, 7259 passed, 1 skipped. pnpm --filter @object-ui/app-shell run type-check exit 0.",
"gates": "dispatch-gates --commands (34 families, tree 4a3bfd1c, before the merge of main; the merge brought only packages/cli and metadata commits) -> each run, exit captured before any pipe: node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0; node scripts/check-adr-0087-registration.mjs --self-test :: exit 0; node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0; node scripts/check-closing-keyword-parity.mjs :: exit 0; node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0; node scripts/check-comment-mask-corpus.mjs :: exit 0; node scripts/check-empty-changeset.mjs --base origin/main :: exit 0; node scripts/check-empty-changeset.mjs --self-test :: exit 0; node scripts/check-sdui-manifest.mjs :: exit 0; node scripts/check-sdui-manifest.mjs --self-test :: exit 0; node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0; node scripts/release-pending-publish.mjs --self-test :: exit 0; pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0; pnpm check:changeset-gate-self-tests :: exit 0; pnpm check:closed-ceremony-text :: exit 0; pnpm check:cross-package-test-inputs :: exit 0; pnpm check:dispatcher-error-vocabulary :: exit 0; pnpm check:driver-memory-census :: exit 0; pnpm check:engine-double-contract :: exit 0; pnpm check:gitlink-declared :: exit 0; pnpm check:nul-bytes :: exit 0; pnpm check:pm-changeset-deadline-census :: exit 0; pnpm check:published-files :: exit 0; pnpm check:query-options-erasure :: exit 0; pnpm check:refd-timer-probe :: exit 0; pnpm check:skill-identifier-liveness :: exit 0; pnpm check:test-source-alias :: exit 0; pnpm check:tier-file-adoption :: exit 0; pnpm check:type-check-coverage :: exit 0; pnpm check:undeclared-dep-imports :: exit 0; pnpm check:watch-hint-literal :: exit 0; pnpm check:where-matcher :: exit 0; pnpm --dir ui exec vitest run scripts/ :: exit 0; pnpm check:type-check-debt :: exit 0. dispatch-gates --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. CI families: in_progress on PR #28620 at report time, not waited on.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"line_budget": "4 files, +241 / -3 (test file 198 lines; source +29/-3; changeset 14)",
"files_changed": [
".changeset/28521-marketplace-disabled-install.md",
"ui/packages/app-shell/src/console/marketplace/MarketplacePage.tsx",
"ui/packages/app-shell/src/console/marketplace/marketplaceApi.ts",
"ui/packages/app-shell/src/console/marketplace/__tests__/MarketplacePage.disabledInstall-28521.test.tsx"
],
"deviations": [
"No new @object-ui/i18n key: the card's 已停用 badge would widen the published catalogue (Clause-② yes); Reinstall alone uses the existing key, so the claim's Clause-②: no stands.",
"Reinstall not measured on a live hosted stack: the cloud repo is unreadable from this container; the test uses the row shape the card measured.",
"Narrowed ui test run (named-module set) declared; CI's Test UI runs the rest of app-shell."
],
"mcp_calls": "4 — github issue_read (get, get_comments x2), claude-code-remote get_session; no GitHub MCP writes",
"api_writes": "2 relay writes — pr_create (POST /repos/objectstack-ai/objectstack/pulls via fleet-write run 41288297421) and this os-dev-report comment (post-stamped); plus 2 git pushes (not REST)",
"open_questions": [],
"out_of_scope_findings": []
}
ACCEPT → PR #28620 comment 6555588105 · 2026-11-01T08:34Z · no contract-review face owed · landing through the merge queue. A live hosted-stack retest is not measured.
Activity
objectstack-fleet commentedon Nov 1, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 发布并装进一个环境 | none | P②
Triage: p2 ·
domain:ui·area:devpath·pm:queue· 2026-11-01T04:56Z⛔ Not a claim.
listInstalledPackages()dropsstatusandenabled, andMarketplacePagecounts every row as installed. The fix needs no cloud change, so it stays in the frameworkdomain:uilane. The cloud card waits on the pin.readMarketplaceInstalls()) too, as the card asks, and measures the reinstall through the install door.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Claim: PM loop round 2 · 2026-11-01T07:10Z
Session:
session_01QsR2jVBzmHX5zVyRfxqBc3(card thread, os-dev); dispatched by seat sessionsession_01QsR2jR7ZFkpqmm4U8S1f9yAccount:
zhuangjianguoBranch:
claude/project-thread-xx8o3g(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-28521Domain:
domain:uiSeat:
domain:ui#4File surface:
ui/packages/app-shell/src/console/marketplace/**and the Setup → Packages page that readsreadMarketplaceInstalls()(stop on breach; explain in the report)Container & model: M,
mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
the Console marketplace's listInstalledPackages() drops status/enabled and MarketplacePage counts every listed row as installed | the cloud door already serves status: 'disabled' and reinstalls through POST /cloud-connection/install | any hosted customer who uninstalled a packageThread-read: 6553639105
Premise: holds (no open PR touches the marketplace tree; last landing there is #28200, merged)
Serial constraints cleared: none
Cloud: triage 6553639105 reads this as Console-only with no cloud change. If the work needs the cloud repository, the card goes whole to the
repo:cloudlane.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jVBzmHX5zVyRfxqBc3
os-dev-report
{ "issue": 28521, "status": "done", "branch": "claude/project-thread-xx8o3g", "pr": "https://github.com/objectstack-ai/objectstack/pull/28620", "head": "5f3027f6", "session": "session_01QsR2jVBzmHX5zVyRfxqBc3", "premise_still_valid": true, "summary": "listInstalledPackages() now reads the control-plane row's status/enabled and marks a soft-uninstalled row `disabled` (either field saying so). MarketplacePage keeps such a row out of installedIds and the org card draws Reinstall (existing key marketplace.action.reinstall) instead of the Installed badge; the click goes through the same doOrgInstall -> POST /api/v1/cloud-connection/install, which re-enables the row, and the reloaded listing then reads Installed. readMarketplaceInstalls() drops disabled rows on the cloud leg, so Setup -> Packages neither lists nor acts on them (that page did have the gap: a disabled row with no registry row was pushed as a not-loaded marketplace install with Uninstall). Public catalog grid (install-local ledger only) and the detail page (/installation already answers installed:false) needed no change.", "tests": "New MarketplacePage.disabledInstall-28521.test.tsx, 6 cases, real listInstalledPackages/readMarketplaceInstalls/installPackage over a stubbed fetch: 6/6 passed. Ablations via ablation-replace.mjs (anchor 1->0, restored to HEAD blob, git diff HEAD empty): MarketplacePage counting every cloud row installed -> Reinstall case red (1 failed/5 passed); readMarketplaceInstalls keeping disabled rows -> Setup Packages case red (1 failed/5 passed). Narrowed set at 43425dfa: 71 ui test files naming MarketplacePage/marketplaceApi/readMarketplaceInstalls/listInstalledPackages/PackagesPage, 710 tests passed. Merged head 5f3027f6: new file + all of app-shell/src/views/metadata-admin/, 686 files, 7259 passed, 1 skipped. pnpm --filter @object-ui/app-shell run type-check exit 0.", "gates": "dispatch-gates --commands (34 families, tree 4a3bfd1c, before the merge of main; the merge brought only packages/cli and metadata commits) -> each run, exit captured before any pipe: node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0; node scripts/check-adr-0087-registration.mjs --self-test :: exit 0; node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0; node scripts/check-closing-keyword-parity.mjs :: exit 0; node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0; node scripts/check-comment-mask-corpus.mjs :: exit 0; node scripts/check-empty-changeset.mjs --base origin/main :: exit 0; node scripts/check-empty-changeset.mjs --self-test :: exit 0; node scripts/check-sdui-manifest.mjs :: exit 0; node scripts/check-sdui-manifest.mjs --self-test :: exit 0; node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0; node scripts/release-pending-publish.mjs --self-test :: exit 0; pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0; pnpm check:changeset-gate-self-tests :: exit 0; pnpm check:closed-ceremony-text :: exit 0; pnpm check:cross-package-test-inputs :: exit 0; pnpm check:dispatcher-error-vocabulary :: exit 0; pnpm check:driver-memory-census :: exit 0; pnpm check:engine-double-contract :: exit 0; pnpm check:gitlink-declared :: exit 0; pnpm check:nul-bytes :: exit 0; pnpm check:pm-changeset-deadline-census :: exit 0; pnpm check:published-files :: exit 0; pnpm check:query-options-erasure :: exit 0; pnpm check:refd-timer-probe :: exit 0; pnpm check:skill-identifier-liveness :: exit 0; pnpm check:test-source-alias :: exit 0; pnpm check:tier-file-adoption :: exit 0; pnpm check:type-check-coverage :: exit 0; pnpm check:undeclared-dep-imports :: exit 0; pnpm check:watch-hint-literal :: exit 0; pnpm check:where-matcher :: exit 0; pnpm --dir ui exec vitest run scripts/ :: exit 0; pnpm check:type-check-debt :: exit 0. dispatch-gates --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. CI families: in_progress on PR #28620 at report time, not waited on.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "line_budget": "4 files, +241 / -3 (test file 198 lines; source +29/-3; changeset 14)", "files_changed": [ ".changeset/28521-marketplace-disabled-install.md", "ui/packages/app-shell/src/console/marketplace/MarketplacePage.tsx", "ui/packages/app-shell/src/console/marketplace/marketplaceApi.ts", "ui/packages/app-shell/src/console/marketplace/__tests__/MarketplacePage.disabledInstall-28521.test.tsx" ], "deviations": [ "No new @object-ui/i18n key: the card's 已停用 badge would widen the published catalogue (Clause-② yes); Reinstall alone uses the existing key, so the claim's Clause-②: no stands.", "Reinstall not measured on a live hosted stack: the cloud repo is unreadable from this container; the test uses the row shape the card measured.", "Narrowed ui test run (named-module set) declared; CI's Test UI runs the rest of app-shell." ], "mcp_calls": "4 — github issue_read (get, get_comments x2), claude-code-remote get_session; no GitHub MCP writes", "api_writes": "2 relay writes — pr_create (POST /repos/objectstack-ai/objectstack/pulls via fleet-write run 41288297421) and this os-dev-report comment (post-stamped); plus 2 git pushes (not REST)", "open_questions": [], "out_of_scope_findings": [] }objectstack-fleet commentedon Nov 1, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
ACCEPT → PR #28620 comment 6555588105 · 2026-11-01T08:34Z · no contract-review face owed · landing through the merge queue. A live hosted-stack retest is not measured.
Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:ui#4 · zhuangjianguo · session_01QsR2jR7ZFkpqmm4U8S1f9y
Landed · 2026-11-01T08:53Z · PR #28620 merged through the merge queue as
0e78922e. Record: ACCEPT 6555588105 (at5f3027f6); no contract review owed.0e78922e~1)origin/main)disabled?: trueinapp-shell/src/console/marketplace/marketplaceApi.tsdisabledIdsinapp-shell/src/console/marketplace/MarketplacePage.tsxThe card closed through
Fixes. A live hosted-stack retest is not measured.pm:dispatchedcomes off in the same stroke as this note.Generated by Claude Code