Skip to content

Setup Packages is the one list of what is installed: Source column, marketplace row actions, and the "Installed Apps" entry opens Packages filtered to Source = marketplace (ruling B, objectstack-ai/objectstack#23892) #12675

Closed

Description

@objectstack-fleet

Filing gate: ④ a ruled execution card — ruling B on objectstack-ai/objectstack#23892 (batch #356 item 2, the maintainer's 「同意」; the record's id is the first line of that card's body), item 2 of objectstack-ai/objectstack#23803 (the 2026-10-16 Setup review). Filed by the director seat (summon #43, session_01QJC7i981TSs9L1CGJK59Ax). ⛔ Not a claim. Facts were read at objectui origin/main f78efdd1e3 and objectstack origin/main d5666be876.

The work (the objectui half; the cloud-connection half is the objectstack card whose Blocked-by: names this one — both numbers are in the ruling record on objectstack-ai/objectstack#23892)

  1. Source column. The console component developer:packages (packages/app-shell/src/services/builtinComponents.tsx:130, contributed by objectstack's setup-nav.contributions.ts as nav_packages) gains a Source column with the closed values code / marketplace / authored, one per loaded package.
  2. Marketplace row actions. The actions the Installed Apps page carries today (update, uninstall, the install-local reseed / purge menu under packages/app-shell/src/console/marketplace/) move onto the Packages rows whose Source is marketplace, rendered only when the marketplace capability (MarketplaceInstallLocalPlugin) is present.
  3. The filtered view. Packages accepts a Source filter preset so that the plugin's "Installed Apps" entry (MARKETPLACE_INSTALLED_UI_BUNDLE in objectstack's packages/cloud-connection) can open it filtered to Source = marketplace. The route or query spelling it needs is this card's to define and to name in its changeset, because the cloud-connection card retargets the entry to it.
  4. Retirement. MarketplaceInstalledPage / InstalledListWidget retire once the filtered view serves their actions — in this PR if the component holds row actions, else in the follow-up this card's report names.

Measure first (the ruling's carried confidence gap)

Whether developer:packages can host row actions without a redesign. If it cannot, report premise_still_valid: false with the reading: the ruling's fallback is letter C (two labelled lists — rename Installed Apps to "Marketplace installs" with one explanatory sentence; Packages still gains the Source column) and it takes effect without a new box visit.

Pins

  • Plugin present: Packages lists every loaded package with its Source; marketplace rows carry the actions; the "Installed Apps" entry opens Packages filtered to Source = marketplace.
  • Plugin absent: no entry and no marketplace actions; Packages still lists every loaded package with its Source.
  • The Source column is a closed enumeration; an unknown origin is refused at the boundary, never shown blank.

Order

This card lands first. The objectstack cloud-connection card (the entry's target) is Blocked-by: this card and moves only when the objectui pin makes this view installable. objectstack-ai/objectstack#23803 item 4's count (39 entries) is checked by whichever lands last.

Governing text

cloud ADR-0009 as restated in objectstack packages/cloud-connection/src/marketplace-ui.ts (the nav entry lives and dies with the capability); the ruling on objectstack-ai/objectstack#23892.

Dedupe

Open objectui issues whose title names marketplace, Installed Apps or Packages at filing (REST, first 100 open): #12615; none carries the Source column or the merge of the two pages (the marketplace defect cards named on the decision card are not this work). Dedupe words: Setup Packages Installed Apps Source column marketplace filter preset row actions MarketplaceInstalledPage retire.

Activity

  1. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 4 (priority:p2; ruled execution card, letter B at objectstack-ai/objectstack#23892 6216295104)
    Session: session_011K9g23W67dy2zwnyzaoB6o
    Account: os-tesla
    Branch: claude/issue-12675-packages-source
    Worktree: objectui-issue-12675 (in the cloud session's own container)
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: Setup Packages as the one installed list, plus the marketplace slice of it.

    • packages/app-shell/src/views/metadata-admin/PackagesPage.tsx, its list body only: the Source column, the Source filter preset, and the marketplace row actions;
    • packages/app-shell/src/console/marketplace/**, where the update / uninstall / reseed / purge actions and the Installed Apps list live today;
    • the developer:packages registration in services/builtinComponents.tsx;
    • the system/marketplace/installed routes in console/AppContent.tsx and the MarketplaceInstalledPage export in src/index.ts, only if this PR retires them;
    • the engine.packages.* / marketplace.* locale keys in all ten packs;
    • tests beside, and one .changeset/12675-*.md.

    Outside the surface:

    A route outside the surface stops and reports (stop on breach; explain in the report).
    Container & model: M, mode:cloud, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui over the six planned paths: no path-derived mandate)
    Clause-②: yes
    Clause-② reason: Packages gains a public Source filter preset spelling, which objectstack-ai/objectstack#23933 retargets the "Installed Apps" entry to, and a Source column. That widens the console's public surface. If this PR also retires a published export or a registered widget (the MarketplaceInstalledPage export, the marketplace:installed-list widget that objectstack's served marketplace_installed page renders), that part is a narrowing and owes one CONTRACT_REVIEW_TIER review before ready.
    Responsibility: n/a — not a defect card
    Thread-read: none
    The card has no comments. The ruling's thread on objectstack-ai/objectstack#23892 was read through 6216323384.
    Serial constraints cleared: read at objectui main efa9cb4fa3.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 12675,
      "status": "done",
      "branch": "claude/issue-12675-packages-source",
      "pr": "https://github.com/objectstack-ai/objectui/pull/12722",
      "session": "session_01L1BStZ37S5WzHGfEgk5NQJ — this run's harness-stamped id (commit Claude-Session trailer); dispatched by seat session_011K9g23W67dy2zwnyzaoB6o",
      "premise_still_valid": true,
      "summary": "H1 holds: PackagesPage's list body is a plain Table, so the marketplace actions sit in one added Actions cell (clicks stopPropagation so the row's detail sheet does not open), with no redesign. Packages now has a Source column with the closed set code / marketplace / authored. The value comes from two existing reads joined. The served row's `writable` verdict decides authored: true means authored. For a non-writable row, the marketplace slice's own list decides marketplace (listed) or code (not listed); that is the read InstalledList used, cloud-connected list first, otherwise the strict install-local ledger. A row with no boolean `writable`, a writable row the marketplace also lists, and an unreadable marketplace list (capability on) are each refused by name and no rows are drawn. H2, measured: the Installed Apps surface offered Details and Uninstall (local list only), and only those moved. They now live in `console/marketplace/MarketplaceRowActions.tsx`, which reuses `uninstallLocal` and the same pack sentences, with an in-app confirm. Update and Re-seed / Purge were never on Installed Apps; they stay on the package page that Details opens, so no second copy exists. H4: the InstalledList body is gone. The `marketplace:installed-list` widget and the legacy `system/marketplace/installed` route now redirect to Packages filtered to marketplace; the registration, the routes and the `MarketplaceInstalledPage` export stay until objectstack#23933 lands. H5: one spelling, `?source=code|marketplace|authored` on `/apps/APP/component/developer/packages`. A nav item reaches it with `{ type: 'component', componentRef: 'developer:packages', params: { source: 'marketplace' } }`, because ComponentNavView receives a component item's params as the query string. Unknown, empty or repeated values are refused. H6: the capability signal is `features.installLocal`, the one MarketplacePackagePage reads. With it off, Source still renders, no marketplace read is made and no Actions column appears. Actions also require `useWorkspaceAdminStatus().isAdmin`, the gate Installed Apps had. Seven `marketplace.*` pack keys that only InstalledList read were removed from all ten packs. The page header was not touched (left to #12662). origin/main was merged once, cleanly. The worktree `../objectui-issue-12675` is left in place (clean, pushed) because no PR exists for it yet.",
      "tests": "At final head 681c066 (after the merge with origin/main f8267df93), one locked run: `pnpm --filter @object-ui/app-shell type-check && pnpm exec vitest run --maxWorkers=2` over the PackagesPage tests, EditPackageDialog, the whole console/marketplace/ dir, UnifiedSidebar.studioNoHome-12113, AppContent.studioRootLanding-12113, AppContent.pseudoRouteSegments, spec-symbol-parity, product-neutral-renderer.ratchet, packages/i18n/, apps/console registry-inputs-spec-parity and AppContent.systemHubRoutes → `VERDICT command-exit 0`, `Test Files 133 passed (133)`, `Tests 2025 passed | 13 skipped (2038)`. New pins: PackagesPage.source-12675.test.tsx (14 tests) and MarketplaceRowActions.installedAppsPins.test.tsx (27 tests; the InstalledList pins for 11645, 12610 and the 7611 uninstall case, carried onto the Packages rows). The two InstalledListWidget test files were deleted; the 10331 InstalledList date face and the 7611 InstalledList case were removed from their files. Fixture triage: two PackagesPage fixtures gained `writable: true` (served rows always carry it). Ablations: tests import src directly with no dist in the path, so there was no build leg. Each leg went through objectstack's `scripts/ablation-replace.mjs`, with a trap that restores with `git checkout HEAD`, a `hash-object` check that the blob equals HEAD, and an empty `git diff HEAD`. A1 drop the unknown-writable refusal → 1 failed (row with no writable), restored blob 9b8d01d5d75a == HEAD. A2 actions gate without the capability → 1 failed (capability absent), ce7d2ebd26ed == HEAD. A3 drop the source filter → 1 failed (?source=marketplace); the first try with an empty replacement was refused by the tool as a no-op and re-run with a comment marker. A4 accept unknown filter → 2 failed. A5 widget renders null → 2 failed (widget, legacy route), 507736667a1b == HEAD. A6 tolerant ledger read → 1 failed (unreadable listing), 3cd140a2f5c7 == HEAD. A7 drop the conflict refusal → 1 failed; also a no-op on the first try, re-run with a marker. A8 drop the not-loaded rows → 8 failed in installedAppsPins. Every leg restored to the HEAD blob.",
      "gates": "Local, exit codes captured before any pipe. Closure `pnpm --filter '@object-ui/app-shell^...' build` + app-shell build: 0 (post-merge). `pnpm --filter '@object-ui/console^...' build`: 0. `VITE_BASE_PATH=/console/ pnpm --filter @object-ui/console exec vite build`: 0. app-shell type-check (tsc and tsconfig.test.json): 0. check:i18n-keys 0, check:i18n-drift 0, check:i18n-dead-keys 0 (report-only; the 7 keys this change orphaned were removed), check:i18n-designer-parity 0, check:changeset-claims 0, changeset:check 0, check:test-path-roots 0, check:spec-symbols 0, check:new-line-citations 0 (VERDICT 0 new citations), scripts/check-changeset-presence.mjs 0 (2 released packages, 2 changesets). eslint on the changed files: 0 errors, warnings only. Control-byte grep over the changed files: no hits. NOT RUN (MODULE_NOT_FOUND, not a red gate): check-nul-bytes.mjs and check-half-states.mjs, which do not exist in objectui. No `--ran` reconciliation: objectui has no dispatch-gates.mjs, so the local list was derived by hand from package.json and ci.yml. CI families: no PR exists yet, so no check-runs to cite; CI runs the full set.",
      "mcp_calls": "2 — mcp__github__issue_read (get, get_comments); no write tool",
      "api_writes": "0 — no REST writes. git pushes: the PR branch (empty probe, three commits, then the merge) and one push of claude/issue-12675-evidence",
      "open_questions": [
        {
          "question": "Source signal contract. `writable` is served on every /api/v1/packages row (objectstack#14375) and pinned by objectstack's packages-serializable-response.test.ts, but it is not declared on the spec's response schema, and InstalledPackageSchema declares no source or origin key. The join is exact today: install-local registers through registerApp, so marketplace rows are in engine.manifests and come back writable:false. Even so, the Source value rests on an undeclared wire key plus a second request. Should objectstack declare it?",
          "options": [
            "A — objectstack declares a closed `source` enum (code / marketplace / authored) on the served installed-package row, set where the package is registered; objectui reads it and drops the join",
            "B — objectstack declares `writable` on the response schema and objectui keeps the join",
            "C — leave it as is"
          ],
          "recommendation": "A. Business need: the Source column is a real surface (this card), and today it costs a second request plus a join. Long-term: contract-first, because the producer knows the origin at registration and the console should not reconstruct it. Preventing AI errors: a declared closed enum, refused when unknown, is harder to misread than a join of two reads. Startup scope: one key on one served row, pulled by a shipped consumer, not speculative. The seat files the objectstack half; objectui then switches to the declared key and stays strict."
        },
        {
          "question": "Ruling item 1 lists update, uninstall and reseed / purge as row actions. Measured at main: the Installed Apps surface offered only Details and Uninstall. Update (an install dialog with version, mode and notes) and Re-seed / Purge live inline in the roughly 1600-line MarketplacePackagePage, reached from the row's Details. Should they also become row controls?",
          "options": [
            "A — keep them where they are, reached from the row's Details (this PR)",
            "B — pull the update dialog and the sample-data handlers out into components the row renders"
          ],
          "recommendation": "A. Business need: the operator reaches all four from the marketplace row with one click. Long-term: no second copy and no split of the install dialog. Preventing AI errors: one owner per action. Startup scope: B is a redesign of the package page that nobody has asked for. If the maintainer wants B, it is a follow-up card."
        },
        {
          "question": "Follow-up after objectstack#23933 retargets the plugin's Installed Apps entry to `?source=marketplace`: retire the `marketplace:installed-list` registration, InstalledListWidget.tsx, both `system/marketplace/installed` routes in AppContent.tsx and the `MarketplaceInstalledPage` export in src/index.ts, and point MarketplacePage's Installed (N) button straight at the Packages URL. That button is in the file #12662 is editing, so this PR left it alone; it reaches Packages through the redirect.",
          "options": [
            "A — one objectui follow-up card, Blocked-by objectstack#23933",
            "B — fold it into #23933's landing"
          ],
          "recommendation": "A, because the retirement is objectui's surface and #23933 is objectstack's. Per the startup-scope axis it retires immediately once the entry is retargeted, with no staged window."
        },
        {
          "question": "Narrowing declared plainly, so it gets contract-review: this PR removes seven published `marketplace.*` keys from all ten packs of @object-ui/i18n (installedTitle, installedSubtitle, installedEmpty, installedAt, installedBy, installedPackageId, cachedAs). It also changes what the published `marketplace:installed-list` widget and the `MarketplaceInstalledPage` export render: they redirect to Packages instead of drawing a list. No export, widget registration or route is removed. Also, the Packages rows do not show the install date, installer or cache path that the old list showed.",
          "options": [
            "A — accept as is: the keys had no reader after the list body left, and the date and installer stay readable on the package page",
            "B — add install date and installer columns to the marketplace rows"
          ],
          "recommendation": "A. Under the startup-scope axis, dead keys and a retired view go immediately. Under the business-need axis there is no measured demand for those columns in Packages. The contract-review-tier review is owed before ready."
        },
        {
          "question": "Edge case: a cloud environment whose runtime reports features.installLocal false would not read the control plane's installed list, so control-plane installs there would read Code. Measured: a local runtime reports installLocal true when the plugin is mounted. Whether a cloud env ever runs with installLocal false is not measured.",
          "options": [
            "A — leave it; option A of the first question (a declared source key) removes the case",
            "B — also read /api/v1/cloud-connection/installed when installLocal is off"
          ],
          "recommendation": "A. B adds a request on every Packages load for a case not measured to exist, which fails the startup-scope axis."
        }
      ],
      "out_of_scope_findings": [
        "class: a · reach: public door, Setup → Packages at origin/main f8267df93 (live: published @objectstack 18.0.0-next.2 showcase, com.example.demo-todo installed through POST /api/v1/marketplace/install-local) shows the Scope badge 'Writable' for that marketplace install, while GET /api/v1/packages serves writable:false for it · evidence: evidence/12675/before-packages.png and after-packages.png on branch claude/issue-12675-evidence. PackagesPage's ScopeBadge draws any row without a scope as 'Writable' and ignores the served verdict. This PR does not touch the Scope column; after it, the Source column says Marketplace beside it · dedupe words: Packages Scope badge Writable marketplace install scopeless writable verdict ScopeBadge",
        "carrier: none · noted, not filed: listLocalInstalls still reads any failure as an empty list for MarketplacePage and MarketplacePackagePage. This PR added a strict sibling (fetchLocalInstalls) for the Source read only. Recorded in the PR's Acceptance notes."
      ]
    }

    Posted by the domain:ui seat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message, because a cloud session cannot comment from its container. The seat filled pr with the draft PR it opened, #12722.

    The seat's answers:

    1. Source signal contract: A. The seat files the objectstack half: a closed source key declared on the served installed-package row. Until it lands, the join of writable (served on every row and pinned by objectstack's own test) with the marketplace list stands, because each value traces to one named signal and unknowns are refused.
    2. Update and Re-seed / Purge: A. They stay on the package page that the row's Details opens; one owner per action.
    3. Retirement follow-up: A. The seat files one objectui card at ACCEPT, Blocked-by: cloud-connection: the "Installed Apps" entry opens Setup Packages filtered to Source = marketplace (ruling B on #23892; after the objectui card lands and the pin moves) objectstack#23933.
    4. Narrowing: declared. The seven pack keys and the widget redirect are a narrowing of published surfaces, so a CONTRACT_REVIEW_TIER review runs on this PR before ready, once CI is green.
    5. installLocal-off edge: A. Answer 1's declared key removes the case.

    The class-a finding (the Scope badge reads Writable for a marketplace install the server marks not writable) has reach at a public door, so the seat files it as its own card.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report (delta, REWORK round 1 on PR #12722)

    {
      "issue": 12675,
      "status": "done",
      "round": "rework 1 (record 6219343416 on PR #12722; contract review 6219326691)",
      "branch": "claude/issue-12675-packages-source",
      "head": "e712c8e276321dbddc96b7c13bab5e1acdfdea88",
      "previous_head": "681c066b5c387e776ad4930071e966a7db48a566",
      "pr": "https://github.com/objectstack-ai/objectui/pull/12722",
      "session": "session_01L1BStZ37S5WzHGfEgk5NQJ",
      "summary": "One commit on top of 681c066, changeset text only; no merge of main, no rebase, amend or force-push. (1) The line `Clause-②: yes (narrowing)` is added at the start of a line in both .changeset/12675-installed-apps-keys.md and .changeset/12675-packages-source.md; frontmatter is unchanged. (2) 12675-installed-apps-keys.md gains the fix for a host that still reads one of the seven removed keys: carry the sentence in the host's own bundle, or drop the read. (3) 12675-packages-source.md gains one sentence: with `features.installLocal` off no row reads Marketplace, so control-plane installs read Code there, and the declared key objectstack#23972 adds removes that case. The container had been recycled, so the worktree was re-created on the pushed tip 681c066 before editing.",
      "gates": "On head e712c8e, exit codes captured before any pipe: `pnpm check:changeset-claims` exit=0; `pnpm changeset:check` exit=0; `node scripts/check-changeset-presence.mjs` exit=0 (it reports 25 source files of 2 released packages changed and 2 changesets declared: 12675-installed-apps-keys.md and 12675-packages-source.md).",
      "tests": "No code changed this round, so no tests were re-run; the code readings of round 0 at 681c066 stand.",
      "mcp_calls": "0 GitHub MCP calls this round",
      "api_writes": "0 REST writes; 1 git push (681c066 → e712c8e)",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Posted by the domain:ui seat 1 PM (session_011K9g23W67dy2zwnyzaoB6o) verbatim from the cloud session's final message. The PR body's own line 2 already reads Clause-②: yes (narrowing) (seat edit). Next: CI on e712c8e, then the CONTRACT_REVIEW_TIER record re-rendered on the new head.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #12722 comment 6219915801 · contract review 6219892363 (CONTRACT_REVIEW_TIER PASS on e712c8e) · domain:ui seat 1 · session_011K9g23W67dy2zwnyzaoB6o · 2026-10-16T16:25Z


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 1 · session_011K9g23W67dy2zwnyzaoB6o · 2026-10-16T16:45Z


    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

domain: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