Skip to content

cloud-connection: install-local's own uninstall door (DELETE /marketplace/install-local/:id) bypasses the uninstall verb, so it asks no uninstall guard and writes no package audit row #31283

Closed

Description

@objectstack-fleet

domain:server#4 · marchtian · session_017ihL2dLQEXWGsE2SZ3Qn5F

Filing gate: ① product defect, from the deliveries of #31232 (PR #31280, dev report 6713593306, finding 3) and #31186 (seat ruling A, dev note in its card thread). Read from code, not run. ⛔ Not a claim. Triage sets the grade and the lane.
Reader: the seat that owns packages/cloud-connection/src/marketplace-install-local-plugin.ts (handleUninstall, ~l.3004).
Dedupe (open AND closed): install-local uninstall deletePackage, install-local handleUninstall → #31023 / #31183 (it already calls protocol.runUninstallCleanups), none on this gap.
reach: every uninstall through install-local's own door (DELETE /marketplace/install-local/:id); read from code.
class: a · type: Bug

维护者速读

本地安装的包有自己的卸载入口,它不走平台统一的卸载动作(deletePackage),只单独调用卸载后的清理。所以 #31232 加的“有规则依赖就拒绝卸载”的守卫和 #31186 加的“卸载写审计记录”对这个入口都不生效。

What is wrong

Expected

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    domain:serverDomain lane — seat card indexed by label:pm:seat
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Nov 7, 2026
  2. objectstack-fleet commented on Nov 7, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p2 · domain:server · 2026-11-07T22:52Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-project-manager · session_01FEkQ5o8PE7ZtVjcor51wBZ

    Claim: PM loop round 1 · 2026-11-08T06:43Z
    Session: session_01FEkQ5ktJb5rQ5n2GUXSQMR (card thread, dev) · seat session_01FEkQ5o8PE7ZtVjcor51wBZ
    Account: os-project-manager
    Branch: claude/project-thread-f6p2x0
    Worktree: objectstack-issue-31296 (reused, reset to fresh origin/main 405a78e)
    Domain: domain:server
    Seat: domain:server#5
    File surface: packages/cloud-connection/src/marketplace-install-local-plugin.ts (handleUninstall), possibly packages/metadata-protocol (a public guard / audit entry point beside runUninstallCleanups) + tests, root .changeset/
    Container & model: M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: thread default
    Clause-②: no (narrowing) — an install-local uninstall the door accepted today is refused with the verb's dependent-rule 409; one contract-review-tier review owed before the queue (the dev re-declares from the real diff)
    Metadata-protocol: none
    Responsibility: cloud-connection install-local uninstall door (objectstack) | handleUninstall calls runUninstallCleanups but never deletePackage, so the verb's pre-uninstall guards (#31232) and its package_uninstall audit row (#31186) are skipped | every DELETE /marketplace/install-local/:id
    Thread-read: 6714111917
    Premise: holds (read, not run): on origin/main 405a78e handleUninstall still withdraws through registry.uninstallPackage + runUninstallCleanups only; the dev measures red first
    Serial constraints cleared: cleared — #31296 / PR #31388 merged (3a0aa91). Open PRs #31402 and #31398 touch the same file outside the uninstall door: merge origin/main after whichever lands first, keep both sides

    Scope: Fixes #31283. One verdict and one writer (delegate to deletePackage, or public entry points), never a copy in the door; a missing published protocol member is needs_decision. Order: /mnt/project-files/pm-orders/server/order-31296-31283.md (PR 2). Summons: the maintainer's 「server 再开两个座位」「并发都是5」 (this project, 2026-11-07); grading per 「定级你可以自己决定」 is triage's here (graded on the card).

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

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-project-manager · session_01FEkQ5ktJb5rQ5n2GUXSQMR
    os-dev-report
    {
    "issue": 31283,
    "status": "done",
    "branch": "claude/project-thread-f6p2x0",
    "pr": "#31439",
    "session": "session_01FEkQ5ktJb5rQ5n2GUXSQMR",
    "premise_still_valid": true,
    "summary": "Premise measured red on main 405a78e: install-local's uninstall of a package whose objectExtensions field another package's active rule reads answered 200, and no package_uninstall event was written. Delegating to deletePackage does not keep the door's semantics (success false with no stored rows, sys_packages delete, table drops), so @objectstack/metadata-protocol now exposes the one guard runner (runUninstallGuards) and the one audit writer (recordPackageUninstall) as class members beside runUninstallCleanups; deletePackage itself now calls both, so there is one verdict and one writer. The door asks the guards before its first write (coded 4xx answered as the guard spelled it, other throws propagate) and records the row once after a completed uninstall. No packages/spec member was needed, so no needs_decision. Clause-② re-declared from the diff: yes (narrowing), since the class gains two public members and one exported type.",
    "tests": "New packages/cloud-connection/src/marketplace-install-local-uninstall-guards-audit.test.ts (real ObjectKernel + ObjectQLPlugin protocol + runtime AppPlugin's real dependent-rule guard, audit slot recorder): 409 PACKAGE_DISABLE_RESTRICTED_BY_VALIDATION_RULE with formatPackageDisableDependents' exact sentence, nothing moved (ledger, registration, served field, no cleanup, no audit); CONTROL 200 + exactly one package_uninstall event. RED on 405a78e: 'expected 200 to be 409', 'expected [] to deeply equal [ { …(6) } ]', 'Tests 2 failed (2)'. Four new cases in packages/metadata-protocol/src/protocol.uninstall-guards.test.ts (runner refuses/resolves, writer writes with environment / no slot); with protocol.package-delete-refusal.test.ts 'Tests 30 passed (30)'. ABLATIONS via scripts/ablation-replace.mjs on fix ef3daa6 (src-relative import, no build): (1) guard ask removed: 'ok mutation landed: anchor 1 -> 0, blob e9f4cc22a5db -> 2e788c35b432', 'Tests 1 failed | 1 passed (2)', 'ok restored: blob == HEAD (e9f4cc22a5db)'; (2) audit write removed: 'blob e9f4cc22a5db -> 1a0037367d2a', 'Tests 1 failed | 1 passed (2)', restored == HEAD. Head 645c951: cloud-connection 'Test Files 75 passed (75) Tests 975 passed (975)' VERDICT 0; metadata-protocol '326 passed | 4 skipped (330)', '22563 passed | 26 skipped (22589)' VERDICT 0; typecheck both exit 0.",
    "gates": "Head 645c951, after pnpm turbo run build --concurrency=2 (VERDICT 0). dispatch-gates --commands --repo objectstack-ai/objectstack: 102 families, all exit 0 on first run (record /mnt/project-files/pm-orders/server/31283-gates-ran.txt); check:type-check-debt also rerun after dogfood: exit 0. --ran: '102 derived famil(ies) accounted for — 102 run, 0 NOT-MEASURED (a DERIVED zero — all 102 recorded an exit code and none of them is 3)'. eslint --no-inline-config on the seven touched .ts files exit 0. CI families: PR #31439 check-runs in_progress at report time, read by the seat.",
    "dogfood_battery": "645c9512 · os-verify-lock: VERDICT command-exit 0 (held 34m56s) · Test Files 438 passed | 3 skipped (441) · Tests 3622 passed | 41 skipped (3663) · no failures",
    "mcp_calls": "0",
    "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches, fleet-write run 42460976215, read-back identical, PR #31439) and this report comment via post-stamped.mjs; git push is not a REST write",
    "open_questions": [],
    "security_findings": "none",
    "out_of_scope_findings": [],
    "deviations": "One file outside the order's expected surface: content/docs/deployment/marketplace-handbook.mdx (Uninstalling, one paragraph: the refusal and the audit row), declared on the Skills-docs line. Expected surface otherwise: marketplace-install-local-plugin.ts, metadata-protocol (protocol.ts, protocol-package-uninstall.ts, protocol-package-lifecycle-types.ts, index.ts), two test files, one changeset. Clause-② moved from the claim's 'no (narrowing)' to 'yes (narrowing)' for the two new public members and the exported type. Merged origin/main once (645c951); #31402 and #31398 had not landed; main moved 11 commits after, not re-merged."
    }


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions