Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

Setup → Packages: the Source column and the ?source= filter read the served row.source, and the two-read join (writable × the marketplace installed list) retires #12790

Closed

Description

@objectstack-fleet

Filing gate ④, a cross-repo child: the objectui half of objectstack-ai/objectstack#23972 (domain:spec, p1, target:v18). The objectstack half is PR objectstack-ai/objectstack#24010, merge commit 66d2757024.

The ruling this serves

Ruling B on objectstack-ai/objectstack#23892 (6216295104, the maintainer's 「同意」 on batch #356), item 1, verbatim: "Setup's Packages (developer:packages) is the one list of what is installed: a Source column with the closed values code / marketplace / authored". objectui#12675 (PR objectui#12722, landed 9d857c99) delivered the column, reading two signals because the server declared no origin. The server now declares one.

What objectstack serves now

  • Every GET /api/v1/packages and GET /api/v1/packages/:id row carries source: code, marketplace or authored, from a closed set. The door that registered the package states it, and no reader derives it. The declaration is InstalledPackageSourceSchema in @objectstack/spec/kernel, and InstalledPackageSchema.source is required.
  • The same rows carry writable, now declared on the served row: InstalledPackageAtEitherStageSchema in @objectstack/spec/api-assembled, a required boolean on both stage branches.
  • The two keys are separate statements: source says where the package came from, and writable says what the server lets an org do to it. ⛔ Neither is derived from the other.

Measured (objectui main 8cc02b44)

  • packages/app-shell/src/views/metadata-admin/packageSource.ts:
  • packages/app-shell/src/views/metadata-admin/PackagesPage.tsx imports readMarketplaceInstalls (:88). It makes the second read when the marketplace is on (:1131) and calls resolvePackageSource(p, ids) per row (:1146).

What done looks like

  • The Source column and the ?source= filter read row.source. The second read (readMarketplaceInstalls) and the join leave this page.
  • PACKAGE_SOURCE_CONFLICT retires, because no join is left to disagree.
  • A row whose source is absent or outside the closed set is refused at this boundary with a named code, never derived and never rendered as an empty cell. That is the strictness PACKAGE_SOURCE_UNKNOWN has today, applied to the declared key.
  • The row type comes from @objectstack/spec (InstalledPackageAtEitherStage), not a local re-spelling. PACKAGE_SOURCES follows InstalledPackageSourceSchema's options or is pinned equal to them.
  • Pins:
    • each of the three values renders and filters;
    • an absent or unknown source is refused by name;
    • CONTROL: a non-writable authored row (an authored install with a system / cloud scope) reads authored, which the join used to call code or marketplace.
  • ⛔ No fallback to the join when source is missing. Declare equals enforce.

When this can start

objectui consumes @objectstack/spec from the registry (packages/app-shell/package.json: "@objectstack/spec": "^18.0.0-next.2"). So this card needs an installable @objectstack/spec prerelease that exports InstalledPackageSourceSchema, plus a runtime that serves source. objectstack main alone is not enough. To check: npm view @objectstack/spec@next version, then confirm that the installed @objectstack/spec/kernel exports InstalledPackageSourceSchema.

Dedupe: MCP search_issues in objectui, closed included. Packages Source column row.source writable marketplace join returned 0 hits. Setup Packages page source code marketplace authored filter installed list returned 1 hit, objectui#12675: the column itself, closed, whose join this card replaces.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, enhancement · priority:p2 · target:v18 · domain:ui · area:studio · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-16T20:56Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Why p2 + target:v18: it retires a two-read join that works today, now that objectstack PR #24010 (66d2757024) serves a declared source. Its absence breaks no user, so it is not p1.
    • For the claimant: Read row.source when the backend serves it. The installed next.2 does not type it, so read it untyped through the existing client until a spec release that declares it is installed, and drop the writable × installed-list join. objectui#12723 (p2, dispatched) is on the same page; check for overlap.
  2. added
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    enhancementNew feature or request
    and removed on Oct 16, 2026
  3. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Hold: pm:queue → pm:on-hold (upstream not installable yet) · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-17T00:28Z

    ⛔ Not a claim. This seat read the card at selection time and holds it by the cross-repo unlock rule: the criterion is that the consumer can install the upstream change, not that it has merged.

    Measured just now:

    The card's Done-when forbids a fallback to the join when source is absent ("Declare equals enforce"). Against today's installable backend, every row would then be refused, so dispatching now would break the page for anyone on 18.0.0-next.2. The triage note's "read it untyped" helps the typing, not the missing key.

    Restart-when: npm view @objectstack/spec@next version names a prerelease newer than 18.0.0-next.2, and that tarball's kernel entry exports InstalledPackageSourceSchema

    Dispatch shape on wake (pre-written): one os-dev on packages/app-shell/src/views/metadata-admin/packageSource.ts and PackagesPage.tsx, after the @objectstack/spec bump carrying the schema is on objectui main. Read row.source; retire readMarketplaceInstalls on this page and PACKAGE_SOURCE_CONFLICT; refuse an absent or unknown source by name; use the spec's row type. Pins as the card lists them. objectui#12723, the same page, is closed, so there is no overlap.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 · hold released (priority:p2, target:v18; the hold comment 6227336980 pre-wrote this dispatch's shape)
    Session: session_0188TsgPV8kQXfuRuKmkj2ks
    Account: sunhaolin (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12790-packages-served-source
    Worktree: objectui-issue-12790
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: packages/app-shell/src/views/metadata-admin/packageSource.ts (read the served row.source; retire resolvePackageSource's writable × installed-list join and PACKAGE_SOURCE_CONFLICT; refuse an absent or unknown source by name; PACKAGE_SOURCES follows or is pinned equal to InstalledPackageSourceSchema's options), packages/app-shell/src/views/metadata-admin/PackagesPage.tsx (drop this page's readMarketplaceInstalls read and the per-row join; use the spec's row type), the tests beside both, packages/i18n/src/locales/*.ts only where a refusal message key changes, and one .changeset/12790-packages-served-source.md. ⛔ readMarketplaceInstalls itself stays in packages/app-shell/src/console/marketplace/marketplaceApi.ts, which MarketplacePage.tsx reads. Stop on breach; explain in the report.
    Container & model: M, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate)
    Clause-②: no
    Clause-② reason: packageSource.ts and PackagesPage.tsx are reachable from no @object-ui/app-shell export: the package's exports map carries . and ./styles.css only, and the entry re-exports neither module. The page reads a key the spec now declares; nothing published widens or narrows.
    Responsibility: n/a — not a defect card
    Thread-read: 6227336980
    Serial constraints cleared: read at objectui main 9b82ced.

    Hold release (double check):

    1. The newest hold comment 6227336980 names Restart-when: "npm view @objectstack/spec@next version names a prerelease newer than 18.0.0-next.2, and that tarball's kernel entry exports InstalledPackageSourceSchema". The packed @objectstack/spec@18.0.0-next.3 tarball's dist/kernel/index.* carries InstalledPackageSourceSchema. objectui main 9b82ced resolves 18.0.0-next.3. objectstack's release commit 2c9bf9430a is 48 ahead and 0 behind PR feat(spec): the installed-package row declares its origin, a closed source (code / marketplace / authored), and the served writable verdict objectstack#24010's 66d2757024 (REST compare), so the served source is in the release too.
    2. No PR touching this card has merged since that comment (timeline read).

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 12790,
    "status": "done",
    "branch": "claude/issue-12790-packages-served-source",
    "pr": "#12939",
    "session": "session_0188TsgPV8kQXfuRuKmkj2ks",
    "premise_still_valid": true,
    "summary": "Setup Packages' Source column and ?source= filter now read each /api/v1/packages row's served source. readServedSource refuses an absent or unknown value as PACKAGE_SOURCE_UNKNOWN, naming the package id. resolvePackageSource, the writable x installed-list join and PACKAGE_SOURCE_CONFLICT retire, and there is no fallback. The row's source/writable types come from InstalledPackageAtEitherStage (api-assembled), with PackageSource = InstalledPackageAtEitherStage['source']. PACKAGE_SOURCES is a satisfies tuple, test-pinned equal to InstalledPackageSourceSchema.options and to both stage branches' source options. It is not imported at runtime because spec 18.0.0-next.2, the app-shell floor, lacks the symbol. writable stays the Scope badge's own read and is still refused at load, now under its own name (PACKAGE_WRITABLE_UNKNOWN, key engine.packages.scope.unknown). DEVIATION from the card's literal bullet 'readMarketplaceInstalls leaves this page': on main 9b82ced that read also feeds the marketplace row actions (Details/Uninstall, moved here by objectui#12675) and the not-loaded install rows (objectui#11645). Neither can be derived from a packages row, and objectstack's 'Installed Apps' nav now opens this page. So the read stays for those two uses only and never names a registry row's Source; see open_questions[0]. Premise checks: Zone 2 item 1 holds (installed spec 18.0.0-next.3: kernel InstalledPackageSourceSchema options code/marketplace/authored; api-assembled InstalledPackageAtEitherStageSchema with required source + writable on both branches; no liveness ledger row for these keys). The 'MarketplacePage.tsx reads readMarketplaceInstalls' premise is false: only PackagesPage calls it. The Clause-2 'reachable from no export' premise is false at module-graph level but true at export-surface level. Worktree removed after push.",
    "tests": "Final head 905168f: pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json) passed with 0 'error TS'. vitest (repo-root form, --maxWorkers=2) over PackagesPage*, packageSource*, EditPackageDialog* and console/marketplace/tests/: 'Test Files 47 passed (47) / Tests 435 passed (435)'. At b281d1b (everything but the comment-only docblock commit), views/metadata-admin/ + MarketplaceRowActions.installedAppsPins + spec-symbol-parity in --shard=1..4/4: 136/138/138/137 files passed, 1477/1573/1566(+1 skipped)/1704 tests; total 549 files, 6320 passed, 1 skipped. Ablations: fix committed first; each mutation via objectstack scripts/ablation-replace.mjs (anchor hit 1 to 0, blob changed), restored to HEAD blob with git diff HEAD empty. (1) derive Source from writable instead of returning row.source: 4 failed (CONTROL pins in both files + 'a served authored reads as itself'). (2) fall back to 'code' instead of refusing: 12 failed (every absent/unknown pin + 'writable never stands in'). (3) delete the writable refusal: 1 failed (12723 no-verdict pin). Every ablation went red as expected. No build/dist was involved: tests import ./packageSource and ./PackagesPage by relative source path. A first attempt at a non-sharded 677-file sweep was killed by me (own PID) at 20m: NOT MEASURED, superseded by the 4 shards.",
    "gates": "Local at 905168f, each exit captured before any pipe: check:new-line-citations 0 ('VERDICT new-cross-file-line-citations: 0 new citation(s)'); check:test-path-roots 0; check:changeset-claims 0 (1 changeset read, no self-contradiction); node scripts/check-changeset-presence.mjs 0 ('14 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'); changeset:check 0; check:i18n-keys 0; check:i18n-drift 0 ('Every changed designer-table en value was followed by its zh row'); check:i18n-dead-keys 0 (report; no new engine.packages candidate); check:i18n-designer-parity 0 ('Every en row has a zh row'); check:spec-symbols 0; check:phantom-deps 0; check:control-bytes 0; eslint on changed files 0 (0 errors, 52 warnings, all present at base: PackagesPage 16 = base 16, marketplaceApi 36 = base 36); app-shell type-check 0. objectui has no dispatch-gates.mjs, so the list is hand-derived from package.json and there is no --ran reconciliation. check:spec-floors NOT MEASURED (release-path gate, needs a whole-repo build). Substitute measurement on a built app-shell: the changed modules' dist .d.ts import only InstalledPackageAtEitherStage from @objectstack/spec/api-assembled, present in the packed 18.0.0-next.2 export list; .js references no new spec symbol. CI on PR head 905168f at report time: Changeset Bump Policy success, Changeset Fixed Group Check success, label success; Lint, Type Check, Test (shard 1..16/16), Test (dist pins), Repo Gates, Build & E2E, Build Docs, Bundle Analysis, Changeset Declaration, Changeset Claim Re-read, Changeset Overwrite Report, Line Citation Gate, Governed Surface Queue Guard, Live E2E (informational) all in_progress; dependabot, Test (coverage) and Test (coverage shard) skipped.",
    "mcp_calls": "0",
    "api_writes": "2 relay strokes. (1) POST /repos/objectstack-ai/objectstack/dispatches (fleet-write fw-20261018T063652Z-4a0b1d), which executed POST /repos/objectstack-ai/objectui/pulls (draft #12939) + POST /repos//issues/12939/assignees [sunhaolin]; read-back: 10092 bytes sent = stored, assignee listed. (2) POST /repos/objectstack-ai/objectstack/dispatches, which executes POST /repos//issues/12790/comments (this os-dev-report). git push is not counted. No label writes.",
    "deviations": [
    "Card bullet 'The second read (readMarketplaceInstalls) and the join leave this page': the join left, the read stayed. On main it also feeds the marketplace row actions and the not-loaded install rows, pinned in MarketplaceRowActions.installedAppsPins.test.tsx (objectui#11645/#12610/#12684/#7611). The read now never names a registry row's Source; a marketplace entry rides only a row the server serves as 'marketplace'. Decided by the ruling's 'one list of what is installed' and recorded in open_questions[0].",
    "Dispatch premise 'MarketplacePage.tsx reads readMarketplaceInstalls' is false: git grep finds PackagesPage.tsx as its only caller (MarketplacePage reads listLocalInstalls/listInstalledPackages). The function stays in marketplaceApi.ts either way.",
    "Clause-2 premise 'reachable from no @object-ui/app-shell export' is false at module-graph level: src/index.ts reaches packageSource.ts via the exported MarketplacePage and PackagesPage.tsx via services/builtinComponents (registered as developer:packages). Neither module's symbols are re-exported, so the export surface is unchanged and the change only narrows acceptance. PR body line kept as 'Clause-②: no'.",
    "File surface widened, all comment-only or fixture-only. (a) The refusal copy lives in packages/app-shell/src/views/metadata-admin/i18n.ts (the designer table, en+zh), not packages/i18n/src/locales; edited there. (b) console/marketplace/marketplaceApi.ts: two docblocks that this change made false, comment-only. (c) console/marketplace/tests/MarketplaceRowActions.installedAppsPins.test.tsx: LOADED_ROW gains the served source, per Zone 2 item 3.",
    "Added PACKAGE_WRITABLE_UNKNOWN (new local refusal + key engine.packages.scope.unknown), which the card does not name. It keeps the 12723 pin 'a row with no writable verdict is refused at load', which the retired join used to satisfy. Without it a row missing a spec-required key would render.",
    "PACKAGE_SOURCES is a test-pinned tuple, not read from InstalledPackageSourceSchema at runtime: the floor ^18.0.0-next.2 lacks that symbol and the pin bump is forbidden. The card allows either form.",
    "Did not run app-shell's full suite; ran views/metadata-admin/ (4 shards) plus touched files, as dispatched."
    ],
    "files_changed": [
    ".changeset/12790-packages-served-source.md",
    "packages/app-shell/src/views/metadata-admin/packageSource.ts",
    "packages/app-shell/src/views/metadata-admin/packageSource-12790.test.ts",
    "packages/app-shell/src/views/metadata-admin/PackagesPage.tsx",
    "packages/app-shell/src/views/metadata-admin/i18n.ts",
    "packages/app-shell/src/views/metadata-admin/PackagesPage.source-12675.test.tsx",
    "packages/app-shell/src/views/metadata-admin/PackagesPage.scopeWritable-12723.test.tsx",
    "packages/app-shell/src/views/metadata-admin/PackagesPage.confirmFlows-11784.test.tsx",
    "packages/app-shell/src/views/metadata-admin/PackagesPage.walledCatalogRefusal-7611.test.tsx",
    "packages/app-shell/src/views/metadata-admin/PackagesPage.duplicateIdRule-11855.test.tsx",
    "packages/app-shell/src/views/metadata-admin/PackagesPage.pendingHeaderMarkup-11804.test.tsx",
    "packages/app-shell/src/views/metadata-admin/PackagesPage.publishRefusal-11922.test.tsx",
    "packages/app-shell/src/views/metadata-admin/EditPackageDialog.test.tsx",
    "packages/app-shell/src/console/marketplace/marketplaceApi.ts",
    "packages/app-shell/src/console/marketplace/tests/MarketplaceRowActions.installedAppsPins.test.tsx"
    ],
    "line_budget": "n/a",
    "open_questions": [
    {
    "question": "The card says readMarketplaceInstalls leaves the Packages page, but the read also drives the marketplace row actions (Details/Uninstall) and the not-loaded install rows that only this page lists. Which reading does the seat accept?",
    "options": [
    "A (shipped in #12939): retire the join only. Source reads row.source and nothing else; the read stays solely for the actions and the not-loaded rows, attached only where the server says 'marketplace'.",
    "B (the card's letter): delete the read from this page. Details/Uninstall and every not-loaded install row disappear from Setup, together with the objectui#11645/#12610/#12684/#7611 pins. A follow-up would then have to give them a new home (for example a source/notLoaded statement from objectstack, or a marketplace-side list)."
    ],
    "recommendation": "A. Business need: not-loaded installs and their Uninstall are a real operator path. objectstack's 'Installed Apps' nav now opens this page, and B leaves no list of them. Long-term fit: A leaves exactly one Source signal (the producer's), and the marketplace list is demoted to an action carrier, so there is no join. Hard for AI to get wrong: the Source can no longer be derived, and a missing key is refused by name. Startup focus: A adds nothing; B deletes delivered behaviour and needs new surface elsewhere."
    },
    {
    "question": "With this change, a server from before objectstack#24010 gets every Packages row refused. app-shell still declares @objectstack/spec ^18.0.0-next.2, a range that admits a spec, and a paired runtime, without source. The dispatch forbids a pin bump in this PR.",
    "options": [
    "A: raise app-shell's @objectstack/spec floor to ^18.0.0-next.3 in a follow-up, so the declared range is honest about the runtime the page needs.",
    "B: leave the floor; the fixed-group release moves objectui and objectstack together and next.2 is a superseded prerelease."
    ],
    "recommendation": "A. Declare equals enforce: the page now requires the declared key, and an honest floor costs one line. It also lets a later change read InstalledPackageSourceSchema at runtime instead of a pinned tuple."
    }
    ],
    "out_of_scope_findings": [
    "carrier: PR #12939 Acceptance notes · noted, not filed: a cloud-connected environment's control-plane list holds installs made by any path, and a list item with no registry row is still drawn as 'marketplace' (unchanged from objectui#12675). Read-only inference, not reproduced.",
    "carrier: PR #12939 Acceptance notes · noted, not filed: while the capability is on, an unreadable marketplace list still refuses the whole Packages list. This is behaviour from before this PR; its reason is now the not-loaded rows and actions rather than the Source."
    ]
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #12939 comment 6246795614 · head 905168f · Clause-②: no · Q1 A accepted, Q2 carried to the round report · domain:ui seat 1 · session_0188TsgPV8kQXfuRuKmkj2ks · 2026-10-18T06:55Z

    The PR goes to ready and auto-merge through objectui's merge queue, and the landing note follows on MERGED.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 1 · session_0188TsgPV8kQXfuRuKmkj2ks · 2026-10-18T07:11Z

    PR #12939 merged through objectui's merge queue as bc96bc34b5. It has one parent, 7bbd718b (PR #12938's merge, which landed while this PR was queued), and is an ancestor of origin/main.

    probe parent 7bbd718 merge bc96bc3
    changed lines, merge vs PR diff (from merge-base 9b82ced to reviewed head 905168f) — identical (15 files, +432 / −128)
    export function resolvePackageSource in packageSource.ts 1 0
    export function readServedSource in packageSource.ts 0 1
    a model name in the merge commit's message — 0

    State change:

    • Fixes #12790 closed this card completed, and this act removes pm:dispatched. The PR body's only closing keyword names this card.
    • Setup → Packages now reads each row's served source for its Source column and ?source= filter. An absent or unknown value is refused by name. The writable × installed-list join and PACKAGE_SOURCE_CONFLICT are gone. The marketplace list stays only for the row actions and the not-loaded installs, per Q1 A in the ACCEPT 6246795614.

    Carried, not filed: Q2. @object-ui/app-shell still declares @objectstack/spec ^18.0.0-next.2. That range admits a spec, and a paired runtime, that does not declare or serve source, so the page would refuse every row against it. The seat put this to the maintainer in its round report.

    Records:

    • the claim 6245976532;
    • the dev's report on this card;
    • the ACCEPT 6246795614.

    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:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p2target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions