Skip to content

[finding] printMetadataStats has two more rows that say nothing: Runtime: drops at zero plugins, and stats.translations is collected but never rendered at all #11172

Description

@os-elon

Observed while implementing #10952 (extending zeroFallback to every summary section). Filed unassigned — not routed, not graded. Neither of these is in #10952's scope, and #10952 deliberately did not touch either: triage there ruled on the four summary sections (Data/UI/Logic/Security), and both rows below sit outside that array.

Measured

packages/cli/src/utils/format.tsprintMetadataStats, at #10952's head.

1. Runtime: drops its whole row at zero, exactly like the sections used to

if(stats.plugins>0||stats.devPlugins>0){// …console.log(` ${chalk.bold('Runtime:')}${chalk.dim(parts.join(', '))}`);}

A stack with no plugins and no devPlugins prints no Runtime: line at all. Confirmed against the real CLI (bin/run-dev.js validate, NO_COLOR=1) on a stack declaring nothing — the summary after #10952's fix is:

 Data: 0 Objects
UI: 0 Apps
Logic: 0 Flows
Security: 0 Positions 0 Permissions

…and no Runtime: row. This is the same "reads as never asked, not as zero" shape #10504 and #10952 removed from the sections.

Why this was NOT folded into #10952. It is not mechanically determined by that card's evidence. Runtime: is not a member of the sections array — it has no items, it renders a different fragment style (2 plugins, 1 devPlugins, comma-joined and fully dim, versus the sections' count-then-item-name fragments joined by two spaces, as in Data: 1 Objects 2 Fields), and unlike an empty Security:, a stack with zero plugins is an entirely ordinary steady state rather than an unfinished one. Whether Runtime: 0 plugins is informative or is just a row that is always there saying nothing is a fresh product-judgment call, and inventing an answer inside #10952 would have been exactly the unilateral widening #10504's brief fenced off.

2. stats.translations is counted and then never printed

MetadataStats declares translations: number (format.ts:350) and collectMetadataStats populates it (format.ts:389, count(config.translations)), but printMetadataStats never reads it — grepping the function body for translations returns 0 hits. So every os validate / os info / os compile run does the work of counting a stack's translations and then discards the number.

This one is not a zero-drop at all: the count is invisible at every value, not just 0. A stack with 40 translation bundles reports them nowhere in the summary.

Open question for triage

Both come down to one question the #10952 ruling did not reach: does "a summary section is never silently dropped" extend past the sections array — to the Runtime: row, and to a counted metric that has no row at all? Plausible answers include giving translations a home in the existing UI: or a new i18n: fragment, dropping the unused field from MetadataStats under implementation-first, or leaving Runtime: conditional on purpose.

Suggested landing

packages/cli/src/utils/format.ts — same function, same file surface as #10952, once triage decides. If translations turns out to have no intended reader, the implementation-first answer is to delete the field rather than find it a row.

Context, not a blocker: #10504 (the original UI: 0 Apps ruling) and #10952 (its generalisation to all four sections).

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions