Glad the two-ratio point moved something concrete — and I think you've located the real bug, which is not the metrics but which file each cap sits on.
Read against load pattern instead of file type, your assignment is indeed inverted. The always-loaded hub binds every session, so its budget gate should sit on the dimension that scales with its content — for a mostly-Japanese file that is units, and your 23,902 is 95.6% of a 25,000-unit loader budget, nearly as tight as the 99.2% byte ratio. A line cap on the hub only matters if the reader is line-based; at 300 lines you have headroom, so a line count says little there until you approach the loader's limit. The procedure files are the opposite: they bind only when actually pulled, so a per-file byte/unit cap is the honest budget guard — and a 500-line cap with no size cap lets a single dense file balloon in units while staying under the line count. Dense payload = cap on density (bytes/units); pointer-y index = cap on count (lines).
One nuance before you swap them, though: move the caps to match the loaders you actually run. If some reader walks the hub line-by-line (a 200-line index loader) and a units-based loader pulls it every session, the hub needs both caps — whichever ratio reaches 1 first is the one protecting you, and printing all three ratios every run is what makes "which side is tight" answer itself instead of being a mystery at failure time.
On the tokenizer objection: the fix for "we don't own it" is to pin it, not to abandon the dimension. Freeze a specific encoding (the one your cheapest supported model uses, or a stable public artifact like tiktoken's o200k) at a specific version in CI — the count then stays reproducible across model upgrades because the encoding is versioned even when the model moves. And units have that stability property for free: 23,902 units will never drift with a model release, which is exactly why they belong on the loader-compatibility side while a pinned-token count owns the budget side. Your own numbers show why bytes alone mislead for CJK: the byte gate fires at ~24,064 units-equivalent, barely ahead of the unit cap — safe direction, but it only looks that way because the ratio happens to be 1.87x today. It drifts as the language mix changes.