Skip to content

chore(objectql, plugin-sharing): one PackageScopedNameRefusedError class for the 409 a package-scoped by-name read refuses with #31852

Closed

Description

@objectstack-fleet

domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

Found in the contract review of E8 #31680 (PR #31847, record 6734365312, nits N1, N2 and N4). Nothing here blocks E8. All three are follow-ups.

What is split

  • N2: after PR feat(objectql)!: by-name readers of apps, pages, dashboards, reports, books, cubes, tools, skills and agents consult (package, name) #31847, PackageScopedNameRefusedError exists twice: in packages/plugins/plugin-sharing/src/package-scoped-declarations.ts (around line 229, from E4) and in the new packages/objectql/src/package-scoped-read.ts. Both have the same name and the same 409 RESOURCE_CONFLICT envelope, but instanceof against one never matches the other. No cross-package catcher exists today, so nothing is wrong yet. But the next caller that catches "the package-scoped refusal" has to pick one, and it will be the wrong one half the time.
  • N4: the lean entry @objectstack/objectql/core exports SchemaRegistry, whose getApp now throws that class, but not the class itself, so a lean consumer can only match it by code and status.
  • N1: packages/cli/scripts/check-app-nav-i18n.mjs:909 calls engine.registry.getApp(app.name) with no package and no catch. A first-party app-name clash would now throw 409 out of the script instead of being reported. It cannot happen today (every first-party app has one holder).

Ask

  1. One class, declared once at the lowest package both use (@objectstack/core, beside resolvePackageScopedHolders, unless the reader finds a better home). objectql and plugin-sharing import it, and both keep exporting the name, so existing imports keep resolving.
  2. The class is exported from @objectstack/objectql/core as well.
  3. check-app-nav-i18n.mjs reads the app with its package (it has the manifest), or reports a refused read as a finding instead of throwing.
  4. Pin: an error thrown by the objectql reader is instanceof the class plugin-sharing exports, and the other way round.

Clause-②: yes (widening) (a new export on core and on the lean entry), Metadata-protocol: none, patch.

Blocked-by: #31680 (PR #31847).

Activity

  1. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: confirmed p3 · pm:queue → pm:blocked on #31680 · 2026-11-09T07:55Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 9, 2026
  3. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

    Claim: PM loop round 19 · 2026-11-09T07:57Z
    Session: session_01ADHkmQHXhv9SKTU1qQ9CNC (card thread, dev) · seat session_01ADHkmQKZzp4DLtqiCkZZRM
    Account: os-steve
    Branch: claude/project-thread-mvgczn
    Worktree: objectstack-issue-31852
    Domain: domain:server
    Seat: domain:server#2
    File surface: packages/core/src/package-scoped-resolution.ts (and core's barrel), packages/objectql/src/package-scoped-read.ts, the objectql lean entry, packages/plugins/plugin-sharing/src/package-scoped-declarations.ts, packages/cli/scripts/check-app-nav-i18n.mjs, their tests, root .changeset/. ⛔ No packages/spec/**, no ui/**
    Container & model: S, mode:thread, model: default tier, effort: medium
    Clause-②: yes (widening) — @objectstack/core and the lean entry @objectstack/objectql/core gain PackageScopedNameRefusedError
    Metadata-protocol: none
    Responsibility: nits N1, N2 and N4 of E8's contract review (6734365312), filed by this seat
    Thread-read: none
    Premise: holds as filed, read at claim on origin/main 074a014c: the class is declared in both objectql/src/package-scoped-read.ts and plugin-sharing/src/package-scoped-declarations.ts
    Serial constraints cleared: Blocked-by #31680 is closed (PR #31847 merged cfe3563)

    Scope: Fixes #31852. One PackageScopedNameRefusedError in core, re-exported unchanged by objectql (including its lean entry) and plugin-sharing; check-app-nav-i18n.mjs never throws a refused read out of the script. No behaviour change at any door. Order: /mnt/project-files/server-seat2/standard-order.md + /mnt/project-files/server-seat2/31852-delta.md. Summons: the maintainer's 「server 任务很多,你应该跟进并发5」 (project chat, 2026-11-09T02:28Z).

  4. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: correction · back to pm:queue · 2026-11-09T07:58Z

    ⛔ Not a claim.


    Generated by Claude Code

  5. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Nov 9, 2026
  6. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQHXhv9SKTU1qQ9CNC
    os-dev-report

    {
      "issue": 31852,
      "status": "done",
      "branch": "claude/project-thread-mvgczn",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/31876",
      "session": "session_01ADHkmQHXhv9SKTU1qQ9CNC",
      "premise_still_valid": true,
      "summary": "PackageScopedNameRefusedError is declared once in @objectstack/core package-scoped-resolution.ts (code RESOURCE_CONFLICT, status 409, httpStatus 409, refusal; message = the refusal's sentence). objectql package-scoped-read.ts and plugin-sharing package-scoped-declarations.ts re-export that binding under the same name, and the lean entry @objectstack/objectql/core exports it too. check-app-nav-i18n.mjs reads each app through a new pure readMergedApp: a refused getApp becomes a composition finding naming the app and every candidate; any other error is rethrown. No door changes its answer; plugin-sharing refusals gain httpStatus 409.",
      "tests": "Red first on origin/main 074a014c: core package-scoped-resolution.test.ts 1 failed | 23 passed; objectql package-scoped-e8-readers.test.ts 2 failed | 71 passed; plugin-sharing package-scoped-declarations.test.ts 3 failed | 23 passed. Green at 02e922a7 (one lock run, VERDICT command-exit 0): typecheck core+objectql+plugin-sharing; core test 139 files / 3207 tests; plugin-sharing 72 / 1496; objectql 580 / 11936. At 3bb5c3e6 after merging origin/main: rebuild of the three, typecheck, the three changed files plus core-boundary.ratchet.test.ts 24/24, 75/75, 26/26, VERDICT command-exit 0. Ablation via scripts/ablation-replace.mjs: plugin-sharing re-export replaced by a local class, anchor 1 -> 0, 3 failed | 23 passed (all three new cross-package pins), restored blob == HEAD 339e4de5b597; objectql re-export replaced by a local class, anchor 1 -> 0, 1 failed | 72 passed (identity pin), restored blob == HEAD 45f07d0a11c9. check-app-nav-i18n --self-test six new cases, exit 0; live pnpm check:app-nav-i18n exit 0 (setup 57 ids, account 13 ids).",
      "gates": "dispatch-gates --commands: 73 commands, each with its exit code captured before any pipe; all exit 0 at 02e922a7 and again at head 3bb5c3e6. --ran: 73 derived, 73 run, 0 NOT-MEASURED (a DERIVED zero, all 73 recorded an exit code, none 3). eslint --no-inline-config on packages/core/src, packages/objectql/src, packages/plugins/plugin-sharing/src and the script: exit 0. Full turbo build of packages/** at 02e922a7: 81/81. PR check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "line_budget": "9 files, +235 / -44 against origin/main before the merge",
      "files_changed": [
        ".changeset/31852-one-package-scoped-refusal-class.md",
        "packages/core/src/package-scoped-resolution.ts",
        "packages/core/src/package-scoped-resolution.test.ts",
        "packages/objectql/src/package-scoped-read.ts",
        "packages/objectql/src/core.ts",
        "packages/objectql/src/package-scoped-e8-readers.test.ts",
        "packages/plugins/plugin-sharing/src/package-scoped-declarations.ts",
        "packages/plugins/plugin-sharing/src/package-scoped-declarations.test.ts",
        "packages/cli/scripts/check-app-nav-i18n.mjs"
      ],
      "deviations": "none. @objectstack/cli takes no changeset: its files[] is dist, README.md and CHANGELOG.md, so scripts/ does not publish. No existing test edited.",
      "mcp_calls": "3 — mcp__github__issue_read (get, get_comments x2), all reads",
      "api_writes": "2 — relay pr_create (POST /pulls + assignees os-steve, PR #31876, body read back identical 8894 bytes); this os-dev-report comment via post-stamped.mjs",
      "open_questions": [
        { "question": "N1: catch the refused read, or read the app by its shell package?", "options": ["A catch and report as a composition finding naming every candidate (done)", "B read getApp(name, shellManifestId)"], "recommendation": "A, because B would silently pick the shell's app and hide a real app-name clash from the gate" }
      ],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: PR #31825 (plugin-email) · adds a third class for the same refusal family, EmailTemplateAmbiguousError in plugin-email/src/template-loader.ts (409 RESOURCE_CONFLICT, extra template and candidates fields) · left to that PR's seat per delta ruling 1 · noted, not filed"
      ]
    }
  7. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

    ACCEPT → PR #31876 comment 6736399559 · head 3bb5c3e6 · 2026-11-09T09:14Z · landing: pr_ready + automerge_enable

  8. objectstack-fleet commented on Nov 9, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-steve · session_01ADHkmQKZzp4DLtqiCkZZRM

    落地 · 2026-11-09T09:54Z

    reading value
    PR #31876 MERGED 2026-11-09T09:39Z, merge commit 1a66fcfed (ACCEPT 6736399559; TIER_DEFAULT PASS 6736388931)
    #31852 closed by the PR's Fixes #31852

    Landed:

    • PackageScopedNameRefusedError is declared once, in @objectstack/core. objectql and plugin-sharing re-export the same class under the same name, so one instanceof matches a refusal from either. The lean entry @objectstack/objectql/core exports it too.
    • check-app-nav-i18n reports a refused app read as a composition finding naming every candidate, instead of stopping on the 409.
    • Every door still answers 409 RESOURCE_CONFLICT with the same sentence.

    Carried:

  9. added a commit that references this issue on Nov 10, 2026
    1a66fcf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions