Found while implementing ADR-0130 D1+D3 (#14163 / PR #14354). Out of that card's scope, filed rather than fixed.
The site
SchemaRegistry.registerObject refuses a second code package claiming an object name another package already owns:
// packages/objectql/src/registry.ts — registerObject, ownership: 'own'thrownewError(`Object "${fqn}" is already owned by package "${existingOwner.packageId}". `+`Package "${packageId}" cannot claim ownership. Use 'extend' to add fields.`);It is a real refusal on a real path — the metadata load path reaches it through registerApp — but it carries no code and no status, so it is not an ADR-0112 envelope like the sibling refusals around it (resolveArtifactPackageOrder's DUPLICATE_ARTIFACT_PACKAGE / INVALID_ARTIFACT_PACKAGE_ENTRY, and the DUPLICATE_ARTIFACT_OBJECT_NAME refusal PR #14354 adds one layer up).
Why it matters, measured rather than argued
While reverse-verifying #14163 I ablated the new install-time object-name check and re-ran the pairing suite. The assertion expect(refused).toBeDefined()stayed green through that ablation — because this bare Error fires one step later and looks, to a throw-shaped assertion, exactly like the refusal that had just been deleted. Only the envelope assertion (code + status) went red.
So any rejection test written against this ownership rule today can only be a bare toThrow(), which is precisely the assertion ADR-0112 and ADR-0130 D3 rule out by name: it stays green against an unrelated Error from anywhere else in the path.
Suggested shape (not prescriptive)
Give the refusal an envelope — an error class with code (SCREAMING_SNAKE, registered in the dispatcher error-code vocabulary with a reachability verdict, the way DUPLICATE_ARTIFACT_OBJECT_NAME is) and status: 422 — keeping the message text as-is so existing message-substring assertions are unaffected. Worth checking at the same time whether any current test asserts only that this path throws.
Note the neighbouring late-install branch (ADR-0029 D9 §6.1, tenant-authored sitting owner) is not a refusal and is not part of this.
Found while implementing ADR-0130 D1+D3 (#14163 / PR #14354). Out of that card's scope, filed rather than fixed.
The site
SchemaRegistry.registerObjectrefuses a second code package claiming an object name another package already owns:It is a real refusal on a real path — the metadata load path reaches it through
registerApp— but it carries nocodeand nostatus, so it is not an ADR-0112 envelope like the sibling refusals around it (resolveArtifactPackageOrder'sDUPLICATE_ARTIFACT_PACKAGE/INVALID_ARTIFACT_PACKAGE_ENTRY, and theDUPLICATE_ARTIFACT_OBJECT_NAMErefusal PR #14354 adds one layer up).Why it matters, measured rather than argued
While reverse-verifying #14163 I ablated the new install-time object-name check and re-ran the pairing suite. The assertion
expect(refused).toBeDefined()stayed green through that ablation — because this bareErrorfires one step later and looks, to a throw-shaped assertion, exactly like the refusal that had just been deleted. Only the envelope assertion (code+status) went red.So any rejection test written against this ownership rule today can only be a bare
toThrow(), which is precisely the assertion ADR-0112 and ADR-0130 D3 rule out by name: it stays green against an unrelatedErrorfrom anywhere else in the path.Suggested shape (not prescriptive)
Give the refusal an envelope — an error class with
code(SCREAMING_SNAKE, registered in the dispatcher error-code vocabulary with a reachability verdict, the wayDUPLICATE_ARTIFACT_OBJECT_NAMEis) andstatus: 422— keeping the message text as-is so existing message-substring assertions are unaffected. Worth checking at the same time whether any current test asserts only that this path throws.Note the neighbouring late-install branch (ADR-0029 D9 §6.1, tenant-authored sitting owner) is not a refusal and is not part of this.