Skip to content

finding(i18n): the pack half of check-i18n-dead-keys applies single-segment dynamic heads its sibling corpus refuses — 196 keys held live by three of them #9126

Description

@claude

Observation-class, found while working objectui#9046 (the class-4 property-read derivation is where this surfaced). Not claimed. Deliberately not done there: objectui#9046 is fenced from widening or narrowing what either existing leg accepts, and this is a narrowing of the pack half's dynamic-head leg.

What was measured

scripts/check-i18n-dead-keys.mjs sweeps two corpora with the same mirror question. Both subtract template-head reachability before reporting, and the two halves disagree about how WIDE a head may be:

  • the designer half refuses a head with fewer than two segments of its own, deletes it from the applied set, and prints a loud Dynamic head(s) with no segment of their own, NOT applied line. Its own comment gives the reason: a head that wide would mark a whole namespace live and read as a very clean sweep.
  • the pack half applies every collected head unfiltered — a key is held live when it merely starts with some head, and nothing checks the head's own depth.

Measured on origin/main at the time of filing, by running the gate's own analyze() and collectEnKeys() over this checkout:

single-segment head collected by the pack half en leaves under it of those, with no literal call site at all
approvalsInbox. 169 164
common. 48 17
managedByBadge. 15 15

196 pack keys are held out of the candidate list by three heads that name only a top-level namespace. Each of those heads comes from one real call site building a key from a runtime value, so the head itself is genuine; what is not genuine is the conclusion that every leaf in the namespace is a possible target of that one substitution.

Why it is worth a row rather than nothing

⛔ Nothing on the tree is mis-rendered and no key is wrongly deleted — the direction of the error is recall-over-precision, which is the direction this sweep deliberately chooses. The cost is the other half of that trade, and it is the harm objectui#9046's triage names: an under-reporting gate is read as evidence of cleanliness. A reader of the report sees 365 candidates across 47 namespaces and has no way to learn that a further 196 keys were never offered, or that three of them account for it.

The asymmetry is the sharp part: the same file already decided this question for its other corpus, wrote down the reasoning, and emits an error when it triggers. The pack half neither filters nor reports. So this is not a new judgement call — it is a decision that exists, applied to one corpus and not the other.

Explicitly not claimed here

⛔ This does not argue the three heads are wrong, that the keys under them are dead, or that any of them should be deleted. ⛔ It does not propose the designer half's threshold as the right one for the packs; the pack namespaces are shaped differently and that number is a maintainer call. ⛔ No key, tier or retirement is in question. What is claimed is that the pack half applies a head class its sibling refuses, silently, and that the silence is measurable.

Dedup

Repo-scoped REST list page, state=open&per_page=100&sort=updated&direction=desc, grepped locally for dynamic head / wide head / namespace live / template head / dead-key / MIN_HEAD_SEGMENTS. Control: objectui#9046 itself is in the page, so the read is a real one and not a silent empty. The page came back with fewer than 100 rows, so it covers the whole open set at that moment rather than a recency window. One title hit, not a duplicate — objectui#9046, this finding's origin.

Filed by the os-dev seat working objectui#9046, session session_01FhBNJcLRZLe8M87VcUgpKr, with Claude Code.


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions