Repository navigation
metadata-protocol: uninstalling a package that shares an object with another package now leaves a half-uninstalled package (sys_packages row gone, its row of the shared object stranded) after PR #23464's per-item 409 #23473
Description
Filing gate ①, class (a): a reproducible defect with a named producer.
reach:the uninstall door (deletePackage, served atDELETE /api/v1/packages/:id).- Measured in process on the real stack: real ObjectQL and protocol, better-sqlite3 tables.
- Read through to the HTTP answer from source (
400 PACKAGE_DELETE_PARTIAL), not driven over HTTP.
This card carries the uninstall half of #23415's family. #23415 (PR #23464) keeps the metadata delete door's 409 refusal, which stops the data loss on both doors.
Filed by domain:spec seat 4 (#18917) · sunhaolin · session session_0121ooBYRmS8ziFXm9ai5YHm. Sources: #23415's dev report (os-dev-report comment on #23415, open_questions[0]) and PR #23464's contract review (6167575307, ③, which escalated it to this seat). ⛔ Not a claim. Grade and lane are triage's.
What happens
deletePackage deletes each of the package's sys_metadata rows with packageId set and, unless keepData: true, with dropStorage: true. Take a package P whose object another package Q also holds.
- Before PR fix(metadata-protocol)!: a delete with dropStorage drops an object's table only with its last stored row, refused 409 while another row remains #23464: that per-item delete dropped the object's table, so Q's records were lost.
- After PR fix(metadata-protocol)!: a delete with dropStorage drops an object's table only with its last stored row, refused 409 while another row remains #23464: the per-item delete is refused
409 RESOURCE_CONFLICT, and the uninstall collects it infailed[](success: false; the HTTP door answers400 PACKAGE_DELETE_PARTIAL). By then thesys_packagesrow is already gone (step 4, the first durable step), and the package's other rows are deleted. P's row of the shared object, its table and its records stay. - So the result is a half-uninstalled package: P is no longer installed, but a row bound to P still serves the object.
- The refusal text names
dropStorage, which an uninstall caller never sent.
What done looks like (the shape is the owner's call, possibly a decision)
Two shapes are in sight. They differ on a destructive default, so the claimant may need a ruling:
- B, refuse the whole uninstall. A pre-flight before step 4 answers
409when any of P's active object rows shares the object with another row, so a refused uninstall leaves everything as it was. The prescription would bekeepData: true, or removing the other package's row first. This is the dev's and the contract reviewer's recommendation, and [finding]uninstallPackageunregisters the namespace BEFORE the verb that can refuse — a rejected uninstall leaves the package half-mutated #7970 (closed) fixed the same "refused after the first durable step" shape foruninstallPackage. - C, uninstall P and keep the shared table. Delete P's row, drop only the tables P alone held, keep the shared one because Q still serves it, and name the kept table in the response.
- This seat's concern with B: dropping storage is the uninstall's DEFAULT, not an opt-in the caller sent.
keepData: truekeeps EVERY table P alone held, so B makes an administrator choose between orphaning all of P's private tables and deleting Q's definition. C is not the skip route metadata-protocol: a delete naming one package withdropStorage=truedrops the object table while another package row of the object remains — the remaining package object loses its data #23415 rejected, because that rejection was about ignoring an explicitdropStorage=trueat the metadata door.
Either way: a real-stack pin of the two-package uninstall, and the unchanged single-package uninstall as the control.
Dedupe
MCP search_issues on this repo, closed included: deletePackage uninstall shared object another package row stranded sys_packages deleted partial uninstall dropStorage keepData → 11 hits.
- metadata-protocol: a delete naming one package with
dropStorage=truedrops the object table while another package row of the object remains — the remaining package object loses its data #23415 (open) is the metadata delete door: this card's parent family, not this card. - [finding]
uninstallPackageunregisters the namespace BEFORE the verb that can refuse — a rejected uninstall leaves the package half-mutated #7970 (closed) isuninstallPackage's refusal after the first durable step: the same shape on another verb, already fixed. - Uninstalling a package after a kernel reboot leaves its permission set's sys_permission_set row behind (managed_by admin, package_id null) #23299, [finding] After an install-local uninstall, a later hot install of ANOTHER package re-projects the uninstalled package's permission set, which survives the restart as an orphan package-managed row #21576, [finding] An install-local uninstall (DELETE /api/v1/marketplace/install-local/:id) leaves the package's permission sets in sys_permission_set: the "no ghost grants" uninstall cleanup never runs on that door #21490,
protocol.deletePackagefinds zerosys_metadatarows the data plane finds 3 of — uninstall leaves orphaned rows (persistence half of #7557) #7705, Package disable and uninstall never reach the metadata/data layer: a disabled package's objects still serve rows, and uninstall leaves 7 orphanedsys_metadatarows #7557, Product question: an uninstall with no organizationId deletes EVERY organization's rows for that package (measured 5 of 5, including a foreign org's) #7780, Uninstalling a package orphans its tenants' bare-key ADR-0005 overlays — warned about, but nothing resolves them #7951 and runtime /packages domain 持久化不对称:enable/disable/uninstall 直写 in-memory registry,install/update 却走 protocol service 落 sys_packages #5047 are other uninstall leftovers: permission sets, overlays, organizations, registry persistence.
None is this.
Dedupe words: deletePackage shared object partial uninstall; uninstall stranded row sys_packages gone; keepData shared table uninstall refusal.
Activity
objectstack-fleet commentedon Oct 14, 2026
Triage: first grade ·
bug·priority:p1+target:v18·domain:spec·pm:queue· land with PR #23464 · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-14T11:52ZRead fresh. PR #23464 (#23415's fix, the per-item
409) is still open, somaindoes not yet carry the half-uninstall. It appears the moment that PR lands.DELETE /api/v1/packages/:id) answers. B refuses the whole uninstall up front, which is a narrowing; C changes what the uninstall does with a shared table. So it is p1 + the major-in-development'starget:label.maintrades metadata-protocol: a delete naming one package withdropStorage=truedrops the object table while another package row of the object remains — the remaining package object loses its data #23415's data loss for a half-uninstalled package. The simplest path is for metadata-protocol: a delete naming one package withdropStorage=truedrops the object table while another package row of the object remains — the remaining package object loses its data #23415's claimant to fold the pre-flight into PR fix(metadata-protocol)!: a delete with dropStorage drops an object's table only with its last stored row, refused 409 while another row remains #23464; the lane decides.domain:spec: the package-axis delete family (metadata-protocol: three package-axis gaps PR #23290's review leaves open — the registry heal after a per-package delete, the draft save's storage-order bind with two packages, and the delete_lockgate that takes no package #23297, metadata-protocol: a delete naming one package withdropStorage=truedrops the object table while another package row of the object remains — the remaining package object loses its data #23415, metadata-protocol: a save into a second package of an object a runtime-authored row owns answers 200 while the registry refuses the ownership —classifyObjectContributionprotects code owners only (ADR-0029 D9.9) #23416).uninstallPackageunregisters the namespace BEFORE the verb that can refuse — a rejected uninstall leaves the package half-mutated #7970's precedent (refuse before the first durable step). Only if the choice turns on the destructive default does it go to the decision box with the four facets; triage does not pre-rule it.objectstack-fleet commentedon Oct 14, 2026
Lane decision on this card ·
domain:specseat 4 (#18917; #23415's claimant) ·sunhaolin·session_0121ooBYRmS8ziFXm9ai5YHm· 2026-10-14T12:12Z. ⛔ Not a claim, ⛔ no label change.Order (triage
6167719509left it to the lane). PR #23464 lands as it is; it was already in the merge queue when triage graded this card. Its trade is data loss (another package's records dropped) for a stranded row that is reported infailed[]. The lane takes that trade over holding the data-loss fix. This card is dispatched by this seat as soon as PR #23464 is onmain, serial behind it onprotocol.ts.Shape: B, refuse the whole uninstall before its first durable step. Existing text decides it, so it does not go to the decision box.
deletePackage's own docblock onmain:A shared object is the same kind of stake, so it joins the same up-front refusal (#7970 is the same shape on
uninstallPackage). The refusal names the shared objects and the other holders, and prescribes the ways out: remove the other package's row first, orkeepData: true.The seat's earlier concern with B, recorded in this card's body, is answered by the step-3 precedent: an uninstall blocked by another holder's stake is the platform's existing posture, not a new one. C would be a second, quieter posture for the same condition.
objectstack-fleet commentedon Oct 14, 2026
Claim: PM loop round 2 · 2026-10-14T12:21Z
Session:
session_0121ooBYRmS8ziFXm9ai5YHmAccount:
sunhaolin(the seat's linked user asGET /useranswers it; this card's assignee)Branch:
claude/issue-23473-uninstall-shared-object-refusalWorktree:
objectstack-issue-23473Domain:
domain:specSeat:
domain:spec#4(seat post #18917)File surface:
packages/metadata-protocol/src/protocol.ts,deletePackage's steps 1–4 only (near:25803at1baf976cf9): one pre-flight before step 4, beside step 3's uninstall refusal. ⛔ Not the per-item loop after step 4: PR #23469 (another lane, draft) rewrites it near:25885. ⛔ NotdeleteMetaItem(PR #23464, landed). Also: one real-stack pin (besidepackages/rest/src/meta-delete-drop-storage-other-rows.test.ts, or the uninstall route's own tests); one.changeset/23473-*.md. Stop on a breach and explain it in the report.Container & model:
M,mode:subagent,model: default tier(dispatch-gates --tierat1baf976cf9: "no path-derived mandate"); the narrowing owes one review atCONTRACT_REVIEW_TIERbefore the queue.Clause-②: no
Responsibility:
deletePackageinpackages/metadata-protocol/src/protocol.tsproduces it (since PR #23464 it deletessys_packagesat step 4 and then meets the per-item409for a shared object, leaving the package half-uninstalled) | none: step 3's uninstall refusal covers another package EXTENDING an owned object, not two packages each holding a row | an administrator uninstalling a package whose object another package also holds, throughDELETE /api/v1/packages/:id; no live two-package object is namedThread-read: 6168058499
Ruling-ref: none from the maintainer; the lane decision is
6168058499(shape B, fromdeletePackage's own step-3 precedent and its #21276 ordering guarantee).Serial constraints cleared: PR #23464 (the metadata delete door) landed as
1baf976cf9. PR #23469 edits the per-item loop (:25885,:25990,:26171) and PR #23428 a comment near:25971; the pre-flight sits before step 4, outside those hunks (every open PR'sprotocol.tspatch read in this act). #23416 (this seat, in flight) holdsclassifyObjectContribution, a different region.objectstack-fleet commentedon Oct 14, 2026
os-dev-report
{
"issue": 23473,
"status": "done",
"branch": "claude/issue-23473-uninstall-shared-object-refusal",
"pr": "#23504",
"session": "session_0121ooBYRmS8ziFXm9ai5YHm (subagent: the dispatching PM session)",
"premise_still_valid": true,
"summary": "deletePackage now refuses the whole uninstall 409 RESOURCE_CONFLICT before step 4 (the sys_packages delete) when, without keepData: true, an active object row of the package shares its object with another stored active row (another package's or the package-less one); nothing is removed, and the message names each shared object, the rows that keep it, and two ways out (keepData, or delete a row of the object without dropStorage first). Shape B per lane decision 6168058499; premise measured true: the condition is read with deleteMetaItem's own address read (packagelessAddress, same shouldDropStorage guard and type fold), no new store surface, and keepData sends no dropStorage so it reads and drops nothing. Step 3's own refusal is code-less (door answers 500 INTERNAL_ERROR), so the per-item refusal's RESOURCE_CONFLICT/409 is reused; no code minted, Clause-② unchanged. No measured uninstall flow needs shape C: the only callers are the DELETE /api/v1/packages/:id door and rollBackUnmanagedImport, whose import refuses held names before writing; and deleting the package's own row of a shared object first gives C's outcome explicitly (pinned).",
"tests": "New pin packages/runtime/src/package-uninstall-shared-object.integration.test.ts (real ObjectQL + better-sqlite3 SqlDriver + PackageServicePlugin + protocol + HttpDispatcher.handlePackages): 5/5 passed at fee128e (refused 409 RESOURCE_CONFLICT with sys_packages row, GET 200, both rows, table, record and registry entry intact; same with the package-less row; keepData way out 200 failed:[] table+Q row+record kept, registry serves Q; own-row-first way out 200 failed:[] shared table kept, private table dropped; CONTROL single package drops its table). At 2e12695 (merge of origin/main; the only later commit edits the pin): @objectstack/metadata-protocol whole suite 236 files passed 3 skipped, 28397 tests passed 19 skipped; runtime uninstall-route sweep (all src/domains/packages-.test.ts, all src/package-uninstall-.integration.test.ts, package-duplicate-adopt-org-scope, package-list-commits-org-scope) 32 files 551 tests passed; rest uninstall-route sweep (package-door-*, package-envelope.conformance, package-routes-coded-error-mapping, package-publish-mount, direct-mount-introspection, meta-delete-drop-storage-other-rows) 12 files 236 tests passed; metadata-protocol tsc --noEmit exit 0; runtime tsc --noEmit + check:test-typecheck OK (27 files / 190 errors / 68 pinned held, no new). check:test-typecheck OK again at fee128e. packages/cli integration layer untouched, declared to CI. Ablation at 971f6e7 via scripts/ablation-replace.mjs WRAP (anchor 'if (request.keepData !== true) {' 1 to 0, blob bb8d6828 to 941fb372): rebuilt metadata-protocol, ablation-dist-preflight marker present in dist/index.js and dist/index.cjs; pin red on cases 1 and 2 with the card's defect (400 PACKAGE_DELETE_PARTIAL, registryRemoved true, per-item RESOURCE_CONFLICT in failed[]), cases 3-5 green. Restore: blob == HEAD, git diff HEAD empty, porcelain clean; rebuilt; --absent marker in 0 of 24 built files; pin 5/5 green. Direction observed: red as expected.",
"gates": "Local: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 65 families at fee128e (same list as at 2e12695); all 65 ran with exit 0 captured before any pipe (each command to its own log), incl. pnpm check:dispatcher-error-vocabulary, check:doc-authoring, check:durability-log-level, check:engine-double-contract, check:error-status-conformance, check:issue-citations, check:nul-bytes, check:test-source-alias, check:cross-package-test-inputs, check:type-check-coverage, check:type-check-debt, check:published-files, check:dts-closure, check:dual-build-cjs-loads, node scripts/check-adr-0087-registration.mjs --base origin/main (1 declared-breaking changeset with disposition not-required (no-migration-prescription)), check-changeset-no-major, check-empty-changeset. Reconciliation: dispatch-gates --ran with per-family exit codes: '65 derived famil(ies) accounted for — 65 run, 0 NOT-MEASURED (a DERIVED zero)'. Local-only families check:dev-prereqs / check:skill-frame-freshness: not triggered (no packages/spec or frame edit). CI on PR #23504 head fee128e at report time (read, not re-run): success — Auto Label, Check Documentation Links, Check PR Size, Dogfood Regression Gate, Flag docs affected by code changes, Governed Surface Queue Guard, Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, Part-of PR must not also close its card, The card this PR closes must claim this branch, filter; skipped — Build Docs, Console Pin Gate, Dogfood shards, Dogfood Verify CLI, Packed-tarball smoke (opt-in), Temporal Conformance (live PG + MySQL); in_progress — Build Core, Check Changeset, Lint · CI, release & engine gates, Lint · ESLint, Lint · docs & code guards, Lint · repo & tooling gates, Lint · scoped · query-options erasure, Lint · scoped · slot lookup & corpus, Test Core (1/6 to 6/6), Type Check · consumer gates / debt ledger / source gates / workspace. CI convergence is the seat's read.",
"mcp_calls": "0",
"api_writes": "2 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): 1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (draft, #23504) + POST /repos//issues/23504/assignees [sunhaolin]; body read back 9611/9611 bytes identical. 2) comment → POST /repos//issues/23473/comments (this report). git push is not counted. No label writes: the dispatch named no label and skip-changeset does not apply (a changeset ships).",
"files_changed": [
"packages/metadata-protocol/src/protocol.ts (deletePackage docblock step 3 + the pre-flight between step 3 and step 4; +70)",
"packages/runtime/src/package-uninstall-shared-object.integration.test.ts (new real-stack pin)",
".changeset/23473-uninstall-shared-object-refusal.md (minor, BREAKING, Clause-② no (narrowing), ADR-0087 not-required (no-migration-prescription), FROM/TO/Remedy)"
],
"deviations": [
"Two print-only scratch tests were placed in packages/runtime/src for one locked run each (the refusal text; the registry state after P's row goes) and deleted right after; never committed, git status --porcelain empty afterwards.",
"One metadata-protocol suite run outlived the 600 s foreground cap and was moved to the background by the harness; I waited on its recorded PID in the foreground (tail --pid) and read its log; verdict command-exit 0.",
"One locked call joined a runtime and a rest sweep with ; (lock verdict batch-last-exit); each part wrote its own exit (RT_EXIT=0, RS_EXIT=0) to its log, and the post-merge rerun joined them with &&.",
"ablation-dist-preflight was once invoked on a plain rebuild (not an ablation leg) and refused on the tree reading because of an untracked scratch file; read as no measurement, not a gate result."
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: domain:spec seat 4 (sunhaolin, #23415's claimant) · noted, not filed — .changeset/23415-drop-storage-other-rows.md (on main, unreleased) says an uninstall 'reports the refusal for that object in its failed[] list ... and leaves the object's row and table in place'; this PR makes that sentence false before it ships. Outside this claim's file surface, so not edited. Suggested replacement: 'An uninstall of a package holding such an object is refused whole before anything is removed; see the 23473 changeset.' Also in PR #23504's Acceptance notes.",
"noted, not filed (measured, no defect): after a keepData uninstall of P, or a metadata-door delete of P's row without dropStorage, the running registry serves Q's definition of the shared object (label of Q's row) and a data read returns the record; pinned in cases 3 and 4."
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
Collected ·
domain:specseat 4 ·session_0121ooBYRmS8ziFXm9ai5YHm· 2026-10-14T14:45Z · ⛔ Not ACCEPT yet.The dev report
6170924033is in: PR #23504, headfee128e3da,status: done, premise held (shape B).The seat read the diff: the pre-flight in
deletePackagebefore step 4, the real-stack pin, and the changeset. One patch round is owed before the seat record:.changeset/23415-drop-storage-other-rows.mdis onmainand unreleased. Its TO says an uninstall "reports the refusal for that object in itsfailed[]list … and leaves the object's row and table in place". PR fix(metadata-protocol)!: an uninstall that would drop a table another stored row still serves is refused 409 before anything is removed #23504 makes that false in the same release, so the sentence must move to the whole-uninstall refusal. This file was outside the claim's file surface. The seat extends the surface to that one changeset; it is this seat's own landing, metadata-protocol: a delete naming one package withdropStorage=truedrops the object table while another package row of the object remains — the remaining package object loses its data #23415..changeset/23473-*.mdstates FROM as400 PACKAGE_DELETE_PARTIAL. That ismain's unreleased intermediate. The last release dropped the shared table instead, as metadata-protocol: a delete naming one package withdropStorage=truedrops the object table while another package row of the object remains — the remaining package object loses its data #23415's own FROM says. FROM must state what a reader upgrading from the last release saw.Then comes the narrowing's review at
CONTRACT_REVIEW_TIERon the landing head. Both wait for a free subagent slot: #23416, the #23455 family and #23493 (mainred) are in flight.Filed from the PR's measurement: #23505 (the ADR-0029 extension refusal on the same verb answers
500 INTERNAL_ERROR).objectstack-fleet commentedon Oct 14, 2026
os-dev-report
{
"issue": 23473,
"addendum_to": "6170924033",
"round": "patch round per 6171068654 (text only)",
"status": "done",
"pr": "#23504",
"head": "7d36e8d205d783c9171b952d66dc06b16fa15ae0",
"edits": [
"Merged origin/main (10 commits; none touch packages/metadata-protocol/src/protocol.ts or the runtime packages domain, so no source re-test per AGENTS.md §10 scoped re-check).",
".changeset/23415-drop-storage-other-rows.md: the TO sentence about an uninstall now reads 'An uninstall of a package holding such an object, without
keepData, is refused whole,409 RESOURCE_CONFLICT, before anything is removed; its message names the object, the rows that keep it, and the ways out.' No tracker number in that shipped text (CHANGELOG readers never see changeset file names). FROM's 'The same held for ... an uninstall' kept.",".changeset/23473-uninstall-shared-object-refusal.md: FROM rewritten to the released behaviour: the uninstall removed the package and its rows and dropped the shared object's table with the package's row of it, while the other package's row kept the object defined and served with its records gone; its next data read answered 500. No mention of the unreleased 400 PACKAGE_DELETE_PARTIAL. The summary line's 'instead of half-uninstalling the package' became 'instead of dropping the object's table while the other row still serves it'. TO, Unchanged and Remedy re-checked against the new FROM: unchanged.",
"Docs: no edit. grep -n -i -E 'uninstall|PACKAGE_DELETE_PARTIAL|failed\[\]|keepData|dropStorage|another package|shared|drop' on content/docs/deployment/install-modes.mdx and content/docs/concepts/metadata-lifecycle.mdx: no hit says what an uninstall does to a shared object or names failed[] / PACKAGE_DELETE_PARTIAL (the hits are unmanaged-copy lock drops, objectExtensions, the overlay whitelist, the hash's dropped undefined values, and the cluster shared-database note)."
],
"gates": "dispatch-gates --commands at 7d36e8d: 65 families, the same list as before. 64 exit 0, including check-adr-0087-registration --base origin/main (1 declared-breaking changeset with a disposition), check-changeset-no-major (no major bump), check:doc-authoring, check:issue-citations (every citation this change adds resolves), and the five dist readers after a closure rebuild. 1 exit 1: check-empty-changeset --base origin/main, the DELIBERATE CORRECTION class, because this PR changes .changeset/23415-drop-storage-other-rows.md, which it did not add. That red is by design and stays: the gate and pr-automation.yml's route 0 say do NOT restore and do NOT apply skip-changeset. Instead, write a confirmation on the PR naming the note and what changed under it. 'Check Changeset' is not a required context. --ran: 65 derived, 65 run, 0 NOT-MEASURED.",
"needs_from_seat": "A written confirmation on PR #23504 (my write budget has no PR comment), for example: 'Confirmed: this PR deliberately corrects the pending note .changeset/23415-drop-storage-other-rows.md (this seat's own landing). Its uninstall sentence said a shared object is reported in failed[] and left in place; this PR refuses that uninstall whole with 409 RESOURCE_CONFLICT before anything is removed.'",
"api_writes": "1 relay stroke: comment → POST /repos//issues/23473/comments (this addendum). git push not counted.",
"mcp_calls": "0"
}
Generated by Claude Code
objectstack-fleet commentedon Oct 14, 2026
ACCEPT → PR #23504 comment 6172664218 ·
domain:specseat 4 ·session_0121ooBYRmS8ziFXm9ai5YHm· 2026-10-14T16:04ZThe review at
CONTRACT_REVIEW_TIERpassed on7d36e8d205(6172644842). Landing waits on one thing: the maintainer's confirmation of the pending-note correction (.changeset/23415-drop-storage-other-rows.md), per ruling D on #18375. It was requested in the seat's session at 2026-10-14T15:20Z. Waiting on: the maintainer, since then.5 remaining items
objectstack-fleet commentedon Oct 15, 2026
Ruling: maintainer 「确认」 · letter A · 2026-10-15T04:15Z · said to
domain:specseat 4's sessionsession_0121ooBYRmS8ziFXm9ai5YHm(sunhaolin) in its chat, in answer to the seat's explanation of PR #23504. Carried by that session with provenance under ruling D on #18375; not a director batch.6184266311records the confirmation of the.changeset/23415-drop-storage-other-rows.mdcorrection, as ruling D requires.needs-user-decision→pm:queue, with no assignee.6172644842and seat record ACCEPT6172664218, both on head7d36e8d205.domain:specseat claims the card and lands PR fix(metadata-protocol)!: an uninstall that would drop a table another stored row still serves is refused 409 before anything is removed #23504 by the hand-off steps in6183361784.maininto the head.main.git merge-treeis clean.packages/metadata-protocol/src/protocol.tschanged 9 times onmainsince the merge base, among them fix(metadata-protocol): the read naming no package serves the row the package-less save writes, beside a package-unbound row (S6) #23489 (the package-less read) and fix(metadata-protocol)!: a save into a second package of an object a runtime-authored row owns is refused (ADR-0029 D9.9) #23510.mainin, then re-reads the pre-flight againstpackagelessAddresson the merged head before arming the PR.target:v18.objectstack-fleet commentedon Oct 15, 2026
Claim: PM loop, temporary re-seat · 2026-10-15T04:30Z · landing only: PR #23504, already reviewed and confirmed
Session:
session_0121ooBYRmS8ziFXm9ai5YHmAccount:
sunhaolin(the seat's linked user asGET /useranswers it; this card's assignee)Branch:
claude/issue-23473-uninstall-shared-object-refusal(head7d36e8d205, unchanged since the seat record)Worktree: none. No dev is dispatched: the work is done.
Domain:
domain:specSeat:
domain:spec#4(seat post #18917; re-seat marker6184406254, on the maintainer's word 「临时回座把 #23504 落地」)File surface: none. This claim lands the reviewed head as it is. The merge queue builds the PR on current
mainand runs the full PR battery there. The seat readsdeletePackage's pre-flight on that merged tree before arming. If that reading finds a break, the seat stops and the card goes back with the reading.Container & model: n/a. No dev and no reviewer is needed: the narrowing's
CONTRACT_REVIEW_TIERreview PASSed on this exact head (6172644842), and a base merge would move the head off that record.Clause-②: no
Responsibility: unchanged from the first claim
6168221878.Thread-read: 6184273013
Ruling-ref:
6184273013(the maintainer's 「确认」, carried; on PR #235046184266311) under ruling D on #18375; lane decision6168058499(shape B).Serial constraints cleared: I read every open PR's file list in this act. Only PR #23469 (another lane, draft,
marchtian; already named in the first claim6168221878) touchespackages/metadata-protocol/src/protocol.ts. InsidedeletePackageit changes the step-2 row read (engine.find→findEnvironmentRows) and the per-item loop after step 4. Neither is the pre-flight that PR #23504 adds between steps 3 and 4, andgit merge-treeofmain+ PR #23504 + PR #23469 is clean. PR #23504 lands first; PR #23469 mergesmainafter it. The landing reading also covers the 9maincommits to that file since this PR's merge base.Resume-from: none (the newest
Release:,6183361784, carries none).objectstack-fleet commentedon Oct 15, 2026
Claim amended ·
domain:specseat 4 ·session_0121ooBYRmS8ziFXm9ai5YHm· claim6184449232· 2026-10-15T05:05ZWhat happened. PR #23504 left the merge queue on a CI failure.
38682506920on the queue commit5e97584201, which ismain8d05456cbeplus this PR.Test Core (6/6)failed inpackages/runtime(pnpm run testexited 1).8d05456cbealone the same shard is green, so the failure comes from this PR meetingmain.ci-failure.mjs: annotations only), so the failing test is not named yet.The landing claim becomes a dev round. Changes to
6184449232:objectstack-issue-23473.deletePackagesteps 1–4 inpackages/metadata-protocol/src/protocol.ts, this PR's pin (packages/runtime/src/package-uninstall-shared-object.integration.test.ts), the two changesets, and a merge ofmaininto the branch (merge commit, no rebase, no force). A test thatmainadded is changed only if it asserts behaviour this PR deliberately replaces, and the report must name it.M,mode:subagent, default tier.Prime suspect. It is a reading, not yet a measurement.
package-uninstall-store-refusal.integration.test.tschanged onmainwith PR #23522 (#23505). Its CONTROL case uninstalls the extending package through the same door. The new pre-flight may read the extending package's row of the extended object as a second holder, and refuse.Reviews owed. The merge moves the head, so the
CONTRACT_REVIEW_TIERreview and the seat record are re-done on the new head before the queue.objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{
"issue": 23473,
"round": "merge round after merge-queue ejection (run 38682506920); claim 6184449232 amended by 6184860304",
"status": "done",
"branch": "claude/issue-23473-uninstall-shared-object-refusal",
"pr": "#23504",
"head": "addcca0cf5fc63ba01412d211c8c93dc8dbf8941",
"merge_commit": "192d2051daaf74b40f9f5727449000f60c99646c (git merge origin/main at 8d05456; no conflict, protocol.ts auto-merged; no rebase, no amend, no force)",
"session": "session_0121ooBYRmS8ziFXm9ai5YHm (subagent: the dispatching PM session)",
"premise_still_valid": true,
"summary": "The queue failure was the PR's own pin meeting main's #23510 (222293f, ADR-0029 D9.9), not the pre-flight: on the merge commit 192d205 the three P-and-Q cases of package-uninstall-shared-object.integration.test.ts ('without keepData: refused 409 ...', 'the way out, keepData: ...', 'the way out, P's own row first: ...') failed in setup at h.publish(Q, SHARED) with "Error: Cannot layer object 'probe_ticket': the overlay is bound to package 'com.probe.q', but the object is owned by package 'com.probe.p'. An object has exactly one registry entry ..." (OBJECT_OVERLAY_PACKAGE_MISMATCH / 422 at the save door). The prime suspect is falsified: package-uninstall-store-refusal.integration.test.ts, CONTROL included, passes on the merged tree. Premise measured: the shared state still arises, through today's doors (a draft saved into Q before P's row exists and promoted after it, by publishMetaItem or POST /packages/Q/publish-drafts: rows [P, Q], registry P; a package-less save first, then P and Q: rows [P, Q, package-less]) and as rows stored before D9.9, which boot leaves at rest; on each door-reached state the uninstall of P without keepData answered 409 RESOURCE_CONFLICT and removed nothing. Fix, inside the claim's surface: the pin's twoPackageObject saves P's row through the door and seeds Q's row straight into the store as a row stored before ADR-0029 D9.9 (the save's shape, checksum by hashSpec), as #23510 re-seeded its two sibling fixtures; every case assertion, the package-less case and the CONTROL are unchanged. protocol.ts and both changesets are byte-identical to the reviewed head's delta (the 23415 TO sentence untouched). I seeded rather than use the draft-promotion door because that door is a D9.9 gap and a fixture built on it would break again when the gap closes; the seat may prefer the door path.",
"fix": "packages/runtime/src/package-uninstall-shared-object.integration.test.ts only (commit addcca0): new seedStoredRow(name, packageId) helper; seedUnboundRow now calls it (same id, label and body as before); twoPackageObject seeds Q's row instead of publish(Q). No protocol.ts change, no new error code, no route change, no Clause-② change.",
"producers_measured": [
"save door, P then Q: Q refused 422 OBJECT_OVERLAY_PACKAGE_MISMATCH; rows [P]",
"save door, P then a save naming no package: addressed to P's row; rows [P]",
"save door, a save naming no package first, then P, then Q: all succeed, registry owner the sys_metadata sentinel; rows [P, Q, package-less]; uninstall P without keepData 409, nothing removed",
"Q draft saved before P's row, P publishes, Q promotes via publishMetaItem (package Q): success; rows [P, Q], registry P; uninstall P 409, nothing removed",
"same, promoted via POST /api/v1/packages/com.probe.q/publish-drafts at HttpDispatcher.handlePackages: 200, outcome published, failed []; rows [P, Q], registry serves P",
"same, via publishPackageDrafts in process: outcome published; rows [P, Q]",
"duplicatePackage P to Q with targetNamespace qq: copy renamed qq_probe_ticket; rows [P] (the kept-name case is #23510's reading: failed with the D9.9 text; not re-measured here)",
"installPackage writes no object sys_metadata row (code reading); importUnmanagedPackage refuses a name an environment row holds before writing (409, code reading); loadMetaFromDb counts a mismatched stored row in errors and leaves it stored (code reading)"
],
"tests": "All at addcca0 unless named, --maxWorkers=2, each under scripts/pm/os-verify-lock.sh, verdict from its VERDICT command-exit line. RED BEFORE at 192d205: pin + two sibling uninstall integration files: 'Tests 3 failed | 13 passed (16)', VERDICT command-exit 1 (the three P-and-Q cases, setup error quoted in summary). AFTER: pin 'Tests 5 passed (5)' exit 0. Runtime uninstall sweep (every src/package-uninstall-.integration.test.ts + every src/domains/packages-.test.ts): 'Test Files 30 passed (30) / Tests 542 passed (542)' exit 0. Runtime local project whole: one-shot run hit the ~10 min foreground cap (exit 124, no verdict, not a measurement), then 4 vitest shards: 96/96/96/96 files passed, tests 1517 + 1234 (4 skipped) + 1694 (15 skipped) + 1332, all exit 0. Runtime typecheck (tsc --noEmit + check:test-typecheck) exit 0, 'OK — ... 27 file(s) / 190 error(s) / 68 pinned signature(s) held'. Metadata-protocol whole suite (3 shards): 80 + 78 (2 skipped) + 78 (1 skipped) files passed; tests 1483 + 25547 (12 skipped) + 1391 (7 skipped), all exit 0; typecheck exit 0. CLI (for the Test Core 2/6 reading): unit tier 2 shards 145 + 145 files, 2416 + 1908 tests, exit 0; integration tier 131 files in 9 slices, all exit 0 (one slice first killed by my own 290 s timeout, exit 124, re-run green); CI's exact slice OS_TEST_SHARD=1/3 both tiers: 'Test Files 141 passed (141) / Tests 1956 passed | 1 skipped', exit 0. ABLATION at addcca0 via scripts/ablation-replace.mjs WRAP mode: anchor 'if (others.length === 0 && !at.unbound) continue;' 1 -> 0, blob 04eee5b790 -> e70c5d7193, replacement adds a marker condition so no row refuses; metadata-protocol rebuilt; ablation-dist-preflight: marker in dist/index.js and dist/index.cjs; predicted 2 red / 3 green, observed 'Tests 2 failed | 3 passed (5)': cases 1 and 2 answered 400 PACKAGE_DELETE_PARTIAL, registryRemoved true, the object in failed[] with the per-item RESOURCE_CONFLICT text (so the pre-flight refuses the same rows the per-item delete refuses). Restore: blob == HEAD 04eee5b7906ebe40733101d3f8815a5b5ececa30, git diff HEAD empty, whole-tree git status --porcelain empty, rebuilt, --absent: marker in none of 24 built files, pin 5/5 green. A first mutation spelling was refused by the tool (replacement contained the anchor, count could not drop) and restored at once: a no-op, nothing measured. The red-before leg of 'revert the fix' is the merge-commit reading above, since the fix is fixture-only.",
"gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at addcca0: 65 commands (stderr: tree of objectstack-ai/objectstack at addcca0; 4 paths vs merge base 8d05456). Each run with its exit captured before any pipe: 63 exit 0; 'node scripts/check-empty-changeset.mjs --base origin/main' exit 1 on .changeset/23415-drop-storage-other-rows.md, the maintainer-confirmed deliberate correction (6184266311), red by design; 'pnpm check:dual-build-cjs-loads' first exit 3 (PREREQUISITE NOT MET, packages without dist/), re-run exit 0 ('110 published require entry point(s) across 68 package(s) load'). --ran: 'Run reconciliation — 65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. CI check-runs on addcca0: 31 success, 6 skipped, 3 failure. Green: Build Core, TypeScript Type Check (+ four Type Check lanes), Lint & Repo Gates (+ its lint lanes), Governed Surface Queue Guard, Dogfood Regression Gate, Test Core (1/6), (3/6), (4/6), (5/6), (6/6) (6/6 is runtime + metadata-protocol, the queue's failing shard). Failure: Check Changeset (same 23415 note, red on 7d36e8d too, expected); Test Core (2/6) (CLI slice 1/3, run 38686154595) and the Test Core rollup. Test Core (2/6) NOT REPRODUCED: the job log is unreadable from this container (gh run view --log-failed: run in progress then; the log download host productionresultssa10.blob.core.windows.net is refused by the egress proxy; ci-failure.mjs: annotations only, 'command (.../packages/cli) pnpm run test exited (1)'), so the failing test is not named. Evidence it is not this PR: CI's exact slice passes locally (above); the whole CLI suite passes locally; the same shard was green on 7d36e8d; the queue run on 5e97584 had Test Core (2/6) success, and 5e97584 differs from addcca0 only in the runtime pin file, which no CLI test reads (git grep: no hit); the locally computed PR partition puts '@objectstack/cli 1/3' on shard 2/6. Nothing was changed for it. Rerunning that failed job is a write outside my budget: left to the seat.",
"mergeable_state": "blocked (read after the push: draft=false, mergeable=true, head addcca0)",
"pr_body": "Not PATCHed. The current body is stale (its first acceptance note says the 23415 note is not edited; it is, with the maintainer's confirmation) and predates this round. Replacement body: /tmp/claude-0/-home-user/a2360ed0-e03c-558a-9d23-40c33afc0152/scratchpad/issue-23473/pr-body-replacement.md",
"mcp_calls": "0",
"api_writes": "1 — POST /repos//issues/23473/comments (this report, via scripts/pm/post-stamped.mjs). Plus two git pushes (not REST): 192d205, addcca0. No label write: the PR's labels were not in this dispatch's scope.",
"deviations": [
"Ablation target: the dispatch asked to revert the fix and see red. The fix is fixture-only, so that red is the merge-commit reproduction; the one ablation instead disabled the pre-flight to prove the re-seeded fixture still bites (os-dev: ablate only tested behaviour).",
"origin/main moved to be48c5e after the merge; not merged again (AGENTS.md §10: merge only on conflict, main-caused red or queue removal).",
"The re-review owed on the new head (claim amendment 6184860304) is the seat's; nothing was readied, queued or labelled."
],
"open_questions": [
{
"question": "Fixture shape for the P-and-Q cases: seeded legacy row (as landed) or the door path that still reaches the state today (Q's draft saved before P's row, promoted after)?",
"options": [
"A keep the seeded row: robust to the D9.9 gap being closed, same as #23510's two sibling fixtures",
"B build Q's row through draft-then-promote: a real door today, but the fixture breaks again when D9.9 closes that gap"
],
"recommendation": "A, because the pin's subject is the uninstall, not how the row got in, and the door-reach is recorded in the PR body as a measurement"
}
],
"out_of_scope_findings": [
"class: b · reach: public door — POST /api/v1/packages/com.probe.q/publish-drafts at HttpDispatcher.handlePackages answered 200 (outcome published, failed []) and stored an active row bound to com.probe.q of an object a runtime-authored row of com.probe.p owns; registry still serves P · evidence: draft saved into Q (saveMetaItem mode draft) before P's row existed, then P saved, then Q promoted; publishMetaItem with package Q does the same; the save door refuses that same row 422 OBJECT_OVERLAY_PACKAGE_MISMATCH · Seam: spec:ADR-0029 D9.9 overlayPackageMismatchError → runtime:promoteDraftForPublish / publishPackageDrafts (packages/metadata-protocol/src/protocol.ts), registry write-through then refused in applyObjectRegistryMutation · same family as the D9.9 close-out named in #23510's acceptance notes: fold into it, not a single-point card · dedupe words: D9.9 draft promote second package; publish-drafts OBJECT_OVERLAY_PACKAGE_MISMATCH; runtime-authored owner draft; promoteDraftForPublish classifyObjectContribution",
"carrier: #23510's acceptance notes (D9.9 family close-out, the seat) · the package-less-owner case re-measured on 192d205: a save naming no package, then saves into P and Q, all succeed, rows [P, Q, package-less], registry owner sys_metadata · noted, not filed"
]
}
objectstack-fleet commentedon Oct 15, 2026
ACCEPT → PR #23504 comment 6187493234 ·
domain:specseat 4 (temporary re-seat) ·session_0121ooBYRmS8ziFXm9ai5YHm· 2026-10-15T08:06ZThis round was the queue failure. The PR's own fixture met
main's ADR-0029 D9.9 refusal. The pre-flight did not cause it.mainwas merged in, and Q's row is now seeded as a row stored before D9.9. The new head isaddcca0cf5. TheCONTRACT_REVIEW_TIERreview PASSed on it (6187465541).Test Core (2/6)CLI failure passed on its single re-run.The seat arms the PR now.
objectstack-fleet commentedon Oct 15, 2026
os-dev-report
{
"issue": 23473,
"round": "second merge round after merge-queue ejection (queue run 38703520759, queue commit 75e7900); claim 6184449232 amended by 6184860304",
"addendum_to": "6187145964",
"status": "done",
"branch": "claude/issue-23473-uninstall-shared-object-refusal",
"pr": "#23504",
"head": "4f639e56b06075f522098437d04b08dc06075c11",
"merge_commit": "ce7a65df2c (git merge origin/main at 23e689d; no conflict; protocol.ts auto-merged; this PR's delta to protocol.ts byte-identical before and after the merge; no rebase, no amend, no force)",
"session": "session_0121ooBYRmS8ziFXm9ai5YHm (subagent: the dispatching PM session)",
"premise_still_valid": true,
"summary": "Reproduced on merge commit ce7a65d: 4 of the pin's 5 cases failed in setup. These are every case that seeds a stored row: 'without keepData: refused 409 ...', 'a package-less row of the object counts as another holder', 'the way out, keepData: ...' and 'the way out, P's own row first: ...'. The error was "Error: Unknown field 'organization_id' on object 'sys_metadata'" at seedStoredRow (package-uninstall-shared-object.integration.test.ts:156). The CONTROL passed. Cause: #23469 (dd29bbe, ADR-0131 D6/D7) dropped the organization column from the sys_metadata family, and with it organization_id: null from the sibling pin's seed. Fix in commit 4f639e5: the pin's seed follows main's row shape (meta-delete-drop-storage-other-rows.test.ts on main) and no longer writes the column. Nothing else changed: the pre-flight, protocol.ts and both changesets are as reviewed, and the 23415 TO sentence is untouched. Address-read comparison on the merged tree: the pre-flight and deleteMetaItem both still call the one packagelessAddress. The pre-flight passes (type, name, undefined, 'active'); deleteMetaItem passes (singularTypeForRepo, name, member, targetState). #23469 changed only that function's body: its where clause was { type, name, state, organization_id: null, ...member } via engine.find, and is now { type, name, state, ...member } via findEnvironmentRows, the seam that drops a legacy organization's rows. Both callers therefore moved together. deletePackage's step-2 read now goes through the same seam, and its per-item loop lost the legacy-organization branch, so the pre-flight's input rows and the per-item delete's rows are the same set.",
"fix": "packages/runtime/src/package-uninstall-shared-object.integration.test.ts only (commit 4f639e5): organization_id: null removed from seedStoredRow's insert. No protocol.ts change, no new error code, no route change, no Clause-② change.",
"tests": "All at 4f639e5 unless named, --maxWorkers=2, each under scripts/pm/os-verify-lock.sh, verdict from its VERDICT command-exit line. RED BEFORE at ce7a65d: pin 'Tests 4 failed | 1 passed (5)', VERDICT command-exit 1 (error quoted in summary). AFTER: pin 'Tests 5 passed (5)', exit 0. Runtime uninstall sweep (every src/package-uninstall-.integration.test.ts + every src/domains/packages-.test.ts): 'Test Files 30 passed (30) / Tests 542 passed (542)', exit 0. Runtime local project, whole, in 4 vitest shards (the queue's failing package): 97/97/97/96 files passed; tests 1568 + 1247 (4 skipped) + 1696 (15 skipped) + 1332; all exit 0. Runtime typecheck (tsc --noEmit + check:test-typecheck) exit 0, 'OK — ... 27 file(s) / 190 error(s) / 68 pinned signature(s) held'. Metadata-protocol whole suite, 3 shards: 80 + 78 (2 skipped) + 78 (1 skipped) files passed; tests 1330 + 17832 (12 skipped) + 1388 (7 skipped); all exit 0. Metadata-protocol typecheck exit 0. ABLATION at 4f639e5, via scripts/ablation-replace.mjs WRAP mode: anchor 'if (others.length === 0 && !at.unbound) continue;' 1 -> 0, blob 498517e78a -> 4bee71e85b. A marker condition was added so no row refuses. Metadata-protocol was rebuilt; ablation-dist-preflight found the marker in dist/index.js and dist/index.cjs. Predicted 2 red / 3 green; observed 'Tests 2 failed | 3 passed (5)'. Cases 1 and 2 answered 400 PACKAGE_DELETE_PARTIAL, with the object in failed[] carrying the per-item RESOURCE_CONFLICT text. Restore: HEAD blob = disk blob = 498517e78a682bcb5a82432490f55bd39c91661c, git diff HEAD empty, whole-tree git status --porcelain empty; rebuilt; --absent found the marker in none of 24 built files; pin 5/5 green.",
"gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 4f639e5: 65 commands, the same 65 as at addcca0 (stderr: tree of objectstack-ai/objectstack at 4f639e5; 4 paths vs merge base 23e689d). Each ran with its exit code captured before any pipe; 63 exited 0. 'node scripts/check-empty-changeset.mjs --base origin/main' exited 1 on .changeset/23415-drop-storage-other-rows.md: the maintainer-confirmed deliberate correction (6184266311), red by design. 'pnpm check:dual-build-cjs-loads' first exited 3 (PREREQUISITE NOT MET: 40 packages without dist/ at that moment); after later gates had built them it re-ran with exit 0 ('110 published require entry point(s) across 68 package(s) load'). --ran: 'Run reconciliation — 65 derived, 65 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. CI check-runs on 4f639e5, read once after the push: 33 success, 6 skipped, 1 failure. All five required contexts are green: Build Core, TypeScript Type Check, Lint & Repo Gates, Governed Surface Queue Guard, and Test Core with all six shards. That includes (6/6), the queue's failing shard, and (2/6), the CLI slice that failed once on addcca0. The one failure is Check Changeset (the 23415 note; expected, the same on every head of this PR).",
"mergeable_state": "unstable (re-read after the push: draft=false, mergeable=true, auto_merge off, head 4f639e5; the first read right after the push answered unknown)",
"pr_body": "Not PATCHed. Replacement body with a 'Second merge round' section, readings at 4f639e5, the address-read comparison and the new ablation: /tmp/claude-0/-home-user/a2360ed0-e03c-558a-9d23-40c33afc0152/scratchpad/issue-23473/pr-body-replacement.md",
"mcp_calls": "0",
"api_writes": "1 — POST /repos//issues/23473/comments (this report, via scripts/pm/post-stamped.mjs over the fleet-write relay). Also two git pushes, which are not REST writes: ce7a65d and 4f639e5.",
"deviations": [
"Beyond the dispatch's list, I also ran the whole runtime local project (4 shards), because the queue's failing package was packages/runtime.",
"The re-review owed on the new head belongs to the seat. Nothing was readied, queued, armed or labelled."
],
"open_questions": [],
"out_of_scope_findings": [
"unchanged from report 6187145964: the D9.9 draft-promotion gap (class b, public door POST /packages/:id/publish-drafts) and the package-less-owner case, both for the D9.9 family close-out; not re-measured on this head"
]
}
objectstack-fleet commentedon Oct 15, 2026
ACCEPT → PR #23504 comment 6189155982 ·
domain:specseat 4 (temporary re-seat) ·session_0121ooBYRmS8ziFXm9ai5YHm· 2026-10-15T09:43ZThe second queue ejection came from the PR's own pin meeting
main's #23469: its seed still wrote the retiredorganization_idcolumn. The dev's second round fixed it.mainwas merged in, and the pin's seed now followsmain's row shape; the pre-flight is unchanged.4f639e56b0. TheCONTRACT_REVIEW_TIERreview PASSed on it (6189137865).#23641, the queue's anchor issue for this file, carries the diagnosis (
6187991639). The seat arms the PR now.objectstack-fleet commentedon Oct 15, 2026
Landed · PR #23504 ·
domain:specseat 4 (temporary re-seat6184406254) ·session_0121ooBYRmS8ziFXm9ai5YHm· 2026-10-15T10:10Z7cb33cfefe, on the third enqueueorigin/main7cb33cfefe.deletePackage's shared-object pre-flight is inpackages/metadata-protocol/src/protocol.tsthere, and.changeset/23415-drop-storage-other-rows.mdcarries the confirmed TO sentence ("refused whole,409 RESOURCE_CONFLICT")gh-readonly-queue/main/pr-23504-*ref remainsCONTRACT_REVIEW_TIERPASS on the landed head4f639e56b0(6189137865); seat record6189155982State change:
Fixes #23473closes this card ascompleted, andpm:dispatchedis removed in this act.The two queue ejections, both the PR's own pin meeting a newer
main, never the pre-flight:main's fix(metadata-protocol)!: a save into a second package of an object a runtime-authored row owns is refused (ADR-0029 D9.9) #23510 (ADR-0029 D9.9) refused the pin's door-saved second-package row. The row is now seeded as one stored before D9.9.main's feat(metadata-core,metadata-protocol)!: the sys_metadata family declares no organization column; indexes re-keyed (ADR-0131 D6/D7, C7b S2) #23469 retiredorganization_idfromsys_metadata, and the pin's seed still wrote it. The seed now followsmain's row shape.Diagnosis for the queue's anchor issue #23641:
6187991639. With the pin onmain, that anchor has nothing left to count.Carried elsewhere:
maincomments that PR fix(objectql): an uninstall refused because another package extends one of its objects answers 409 RESOURCE_CONFLICT with the way out, not 500 INTERNAL_ERROR #23522 left stale:protocol.tsabove step 3, andpackages/runtime/src/domains/packages.ts:2301. Both still say step 3's refusal answers500. Acceptance note, no card; the carrier is the next edit of either file.