Summary
registerRenderer(format, renderer, ownership?) takes host-enforced ownership metadata — commands and resultDiscriminator — and the host does enforce it at call time, exactly as RendererOverrideOwnership documents ("An unrelated command never reaches the callback").
The collision check ignores that metadata completely. It groups renderer overrides by format alone, so two extensions that own strictly disjoint commands still report extension_renderer_collision and still leave pm health at ok: false.
The consequence is worse than a spurious warning: the check emits the same code, byte for byte, for a correctly scoped override and for an unscoped one that silently destroys the output of every command in the CLI. The warning that should catch a catastrophe is indistinguishable from the warning that means "working as designed".
Reproduction
Two minimal extensions, both registering a json renderer, owning disjoint commands with mutually exclusive result discriminators:
// coll-ext-a/index.js (coll-ext-b is identical with b for a)
export function activate(api) {
api.registerRenderer(
"json",
() => JSON.stringify({ from: "a" }),
{
commands: ["coll-a"],
resultDiscriminator: (result) =>
Boolean(result && typeof result === "object" && "colla" in result),
},
);
}
pm init colltest
pm install ./ext-a --project # ok: true, activated: true
pm install ./ext-b --project # ok: true, activated: true
pm health --json
Result — both activate cleanly (activation_failure_count: 0), and:
ok: false
extension_renderer_collision:json:project:coll-ext-b:project:coll-ext-a
There is no overlap to contend. coll-a and coll-b are disjoint, the discriminators are mutually exclusive, and the host is enforcing both.
The control: identical warning, catastrophic behaviour
Same two extensions, ownership argument removed:
export function activate(api) {
api.registerRenderer("json", () => JSON.stringify({ from: "b" }));
}
pm health --json
{"from":"b"}
The unscoped renderer replaced the entire output of every --json command in the CLI. pm health no longer reports on anything; it returns the extension's literal.
And the warning it produces is:
extension_renderer_collision:json:project:coll-ext-b:project:coll-ext-a
The same string. One configuration is safe by construction; the other has silently broken every machine-readable output path in the tool. The health check cannot tell them apart.
Where it comes from
The renderer collision detector groups solely on format:
function ds(e){
let n = new Map;
for (let t of e.overrides) { let o = n.get(t.format) ?? []; o.push(t); n.set(t.format, o); }
// ... if (o.length <= 1) continue;
// ... else emit `extension_renderer_collision:${format}:${winner}:${displaced}` for every non-winner
}
t.commands and t.resultDiscriminator are on those override records — registerRenderer validates them (ownership.commands must contain non-empty command paths, ownership.resultDiscriminator must be a function when provided) and stores them, and the extension report already surfaces result_discriminator as a boolean. The collision check simply never reads them.
Compare the command-override detector immediately below it, which groups by t.command and is therefore correct for its surface. Renderers are the one surface where the discriminating key was available and not used.
Why this matters beyond one warning
A user installing the published pm package catalog into one project reaches pm health ok: false with 20 collisions, of which 9 are renderer collisions between packages that already self-scope. We audited these: they are benign in effect, because each renderer declines results it does not own.
That audit is the problem. Establishing "benign" required reading the source of six packages. The health check is the tool that is supposed to answer it, and it reports the safe case and the output-destroying case identically. So the honest options available to an ecosystem today are:
- Ship with
pm health ok: false permanently, training everyone to ignore the check — including on the day it reports the real thing.
- Delete correct, defensive registrations to silence a warning about scoping the host is already enforcing.
Neither is a good outcome, and no amount of care on the package side reaches ok: true.
Suggested fix
Group renderer overrides by format plus declared ownership, and only report a collision when two overrides can actually contend:
- Both declare
commands and the sets intersect → real collision, report it (this is the us() logic already used for command overrides).
- Either declares no ownership → it claims the whole format; report the collision, ideally with a distinct, louder code, since the reproduction above shows this case can destroy all output.
- Both declare disjoint
commands → no collision. The host has already guaranteed they cannot both run.
A resultDiscriminator cannot be statically compared, so treating "both declare one" as non-contending would be unsound. But it is a strong signal that the author scoped deliberately, and it would be reasonable to downgrade the severity rather than clear it — the current behaviour gives an author who did everything right no way to express it.
Related: #890 (collision warnings name contenders but not the winner) is closed and complementary — that was about reporting a real collision better; this is about a collision being reported where none exists, while a genuinely dangerous one gets the same wording.
Environment
- pm CLI
2026.8.3, Node 22, Linux.
- Both extensions activate cleanly;
load_failure_count: 0, activation_failure_count: 0.
Summary
registerRenderer(format, renderer, ownership?)takes host-enforced ownership metadata —commandsandresultDiscriminator— and the host does enforce it at call time, exactly asRendererOverrideOwnershipdocuments ("An unrelated command never reaches the callback").The collision check ignores that metadata completely. It groups renderer overrides by format alone, so two extensions that own strictly disjoint commands still report
extension_renderer_collisionand still leavepm healthatok: false.The consequence is worse than a spurious warning: the check emits the same code, byte for byte, for a correctly scoped override and for an unscoped one that silently destroys the output of every command in the CLI. The warning that should catch a catastrophe is indistinguishable from the warning that means "working as designed".
Reproduction
Two minimal extensions, both registering a
jsonrenderer, owning disjoint commands with mutually exclusive result discriminators:Result — both activate cleanly (
activation_failure_count: 0), and:There is no overlap to contend.
coll-aandcoll-bare disjoint, the discriminators are mutually exclusive, and the host is enforcing both.The control: identical warning, catastrophic behaviour
Same two extensions, ownership argument removed:
pm health --json {"from":"b"}The unscoped renderer replaced the entire output of every
--jsoncommand in the CLI.pm healthno longer reports on anything; it returns the extension's literal.And the warning it produces is:
The same string. One configuration is safe by construction; the other has silently broken every machine-readable output path in the tool. The health check cannot tell them apart.
Where it comes from
The renderer collision detector groups solely on
format:t.commandsandt.resultDiscriminatorare on those override records —registerRenderervalidates them (ownership.commands must contain non-empty command paths,ownership.resultDiscriminator must be a function when provided) and stores them, and the extension report already surfacesresult_discriminatoras a boolean. The collision check simply never reads them.Compare the command-override detector immediately below it, which groups by
t.commandand is therefore correct for its surface. Renderers are the one surface where the discriminating key was available and not used.Why this matters beyond one warning
A user installing the published pm package catalog into one project reaches
pm health ok: falsewith 20 collisions, of which 9 are renderer collisions between packages that already self-scope. We audited these: they are benign in effect, because each renderer declines results it does not own.That audit is the problem. Establishing "benign" required reading the source of six packages. The health check is the tool that is supposed to answer it, and it reports the safe case and the output-destroying case identically. So the honest options available to an ecosystem today are:
pm health ok: falsepermanently, training everyone to ignore the check — including on the day it reports the real thing.Neither is a good outcome, and no amount of care on the package side reaches
ok: true.Suggested fix
Group renderer overrides by format plus declared ownership, and only report a collision when two overrides can actually contend:
commandsand the sets intersect → real collision, report it (this is theus()logic already used for command overrides).commands→ no collision. The host has already guaranteed they cannot both run.A
resultDiscriminatorcannot be statically compared, so treating "both declare one" as non-contending would be unsound. But it is a strong signal that the author scoped deliberately, and it would be reasonable to downgrade the severity rather than clear it — the current behaviour gives an author who did everything right no way to express it.Related: #890 (collision warnings name contenders but not the winner) is closed and complementary — that was about reporting a real collision better; this is about a collision being reported where none exists, while a genuinely dangerous one gets the same wording.
Environment
2026.8.3, Node 22, Linux.load_failure_count: 0,activation_failure_count: 0.