Allow CSS declaration seams, and test the shape rather than a fixture

exp found that splitting `width:${w}px;height:${h}px` leaves the quasi
"px;height:" — a seam between two declarations, carrying the tail of one
value and the head of the next property. It has a colon but no value and no
brace, so every CSS shape here missed it. Their regex is used as written.

The semicolon is what keeps prose out, and it is load-bearing: "12 people:"
has the colon but no declaration before it, and "Pools checked; nothing
found:" has both a semicolon and a colon and still counts, because the
segments either side are not property:value pairs.

Tested on the SHAPE, not through a .vue fixture, and the first version was
wrong in a way worth recording. A seam only exists as a separate string if a
quasi is judged alone, and this gate deliberately judges a split template
literal as one string — so no fixture can produce one. The fixture version I
wrote first passed with the rule DISABLED, which is exactly the vacuous green
this file exists to refuse. Asserting at the shape fails when the rule is
removed.

Measured before adding it: exp's four upg-neighbor findings and the CSS half
of prayer-walk-planner's are already gone, fixed by the two CSS shapes that
landed after their measurement. The only seam left in either bundle is an
HTML attribute one (`" dir="`), which this does not cover. So the rule
guards against a recurrence and against callers that do judge quasis
separately, rather than clearing a live count.
This commit is contained in:
Doxa Maps 2026-09-29 09:12:34 +00:00
parent a0110a7216
commit 93fc2e1b5a

View file

@ -88,6 +88,18 @@ const ALLOW = [
test: (s) => /^[a-z-]+\($/.test(s)
|| /^[,)\s]*[a-z-]+\([^)]*\)[,)\s]*$/.test(s)
|| /^[,)\s]+$/.test(s) },
// ★ DECLARATION SEAMS, the other half of the same split (exp, I18N-EXP-PLAN). Splitting
// `width:${w}px;height:${h}px` leaves the quasi "px;height:" — a seam BETWEEN two declarations,
// carrying the tail of one value and the head of the next property. It has a colon but no value
// and no brace, so every CSS shape above misses it. exp measured these as false leaks in
// upg-neighbor and prayer-walk-planner once the gate runs over experimental bundles in report mode.
//
// ⚠ THE `;` IS WHAT KEEPS PROSE OUT, and it is load-bearing: "12 people:" and "Access in their own
// language:" have the colon but no semicolon-separated declaration before it. Verified on the case
// that worries me most — "Pools checked; nothing found:" HAS a semicolon and still stays loud,
// because the segments either side are not `property: value` pairs.
{ why: 'CSS DECLARATION SEAMS left by splitting a template literal: "px;height:", "; background:"',
test: (s) => /^[a-z%]*\s*;\s*(?:[a-z-]+\s*:\s*[^;]*;\s*)*[a-z-]+\s*:\s*$/.test(s) },
{ why: 'ID PREFIXES ending in a COLON, built by interpolation: `fam:${x}`, `dial:${x}`, and '
+ 'localStorage keys like `pgg-cards-per-row:${profile}`. The hyphen rule below covers a '
+ 'trailing separator but not a colon, so these read as prose. A prefix is not a sentence: '
@ -908,6 +920,19 @@ const a = greeting + 'Welcome to the prayer map'
</script>`
ok(scanSfc(CAT, 'concat.vue').some((f) => f.text === 'Welcome to the prayer map'),
'COUNTS a sentence built by CONCATENATION — only an equality test means "compared against data"')
// ★ exp's CSS DECLARATION SEAMS (I18N-EXP-PLAN), tested on the SHAPE rather than through a fixture.
// A seam like "px;height:" only exists as a separate string if a quasi is judged alone, and this
// gate deliberately judges a split template literal as ONE string — so a .vue fixture can never
// produce one, and an assertion written that way passes whether or not the rule exists. I wrote
// that version first and it stayed green with the rule disabled, which is the whole failure mode
// this file exists to refuse. The rule is real for any caller that does judge quasis separately;
// asserting it at the shape is the only way to prove it can fail.
ok(!!allowedBy('px;height:') && !!allowedBy('; background:'),
'a CSS declaration seam is allowed')
ok(!allowedBy('12 people:'),
'prose ending in a colon is NOT — the seam shape needs a semicolon-separated declaration')
ok(!allowedBy('Pools checked; nothing found:'),
'prose with a semicolon AND a colon is NOT — the segments must be property:value pairs')
// the catalogue-side rule, tested directly: the two facts that make a fallback safe
ok(fallbackFullyResolved('dashboard.map_loading'),
'a key present and really translated in all 11 locales counts as resolved')