Skip to content

Commit ec0eaed

Browse files
committed
fix(spec): keep the blank-source refusal out of check:doc-authoring's sink closure
Interpolating the composed gate into the refusal put `featureGatePredicate` — and through it the whole `PUBLIC_AUTH_FEATURES` registry — in a customer-facing `message:` position, and that gate's per-module fixed point then swept the registry's internal `notes` / `exempt.reason` prose as customer-facing text. Measured: `pnpm check:doc-authoring` is green at the base commit and flagged three pre-existing strings with the interpolation in. The sentence now names the composed shape without interpolating the gate, which is also how the two refusals beside it are written. No test pinned the wording. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1c5b902 commit ec0eaed

1 file changed

Lines changed: 15 additions & 6 deletions

File tree

packages/spec/src/kernel/public-auth-features.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -389,14 +389,23 @@ export function lowerRequiresFeature<T extends WithRequiresFeature>(
389389
ctx.addIssue({
390390
code: 'custom',
391391
path: ['requiresFeature'],
392+
// ⚠ Deliberately does NOT interpolate `gate`. Doing so puts
393+
// `featureGatePredicate` — and through it the whole
394+
// `PUBLIC_AUTH_FEATURES` registry — in a customer-facing message
395+
// position, and `check:doc-authoring`'s per-module fixed point then
396+
// sweeps that registry's INTERNAL `notes` / `exempt.reason` prose as
397+
// customer-facing text (measured: green at the base commit, three
398+
// pre-existing strings flagged with the interpolation in). The concrete
399+
// gate is one `featureGatePredicate` call away for anyone who wants it.
392400
message:
393401
'`requiresFeature` composes only with a CEL `visible` carrying a NON-BLANK `source`; this '
394-
+ '`source` is blank after trimming, so the composition would parenthesise nothing — '
395-
+ `\`( ) && ${gate}\` — which no CEL parse accepts on any scope. The gate would fault at `
396-
+ 'evaluation instead of gating: shown regardless of the flag where the surface is fail-soft, '
397-
+ 'hidden regardless of it where it is fail-closed. Either way the flag decides nothing, which '
398-
+ 'is the inert arrival ADR-0078 rejects. Drop the blank `visible` and `requiresFeature` emits '
399-
+ `\`${gate}\` alone, or put the predicate the gate should compose with in \`source\`.`,
402+
+ '`source` is blank after trimming, so composing the feature gate onto it would parenthesise '
403+
+ 'nothing — the predicate would read `( ) && ` followed by the gate — which no CEL parse '
404+
+ 'accepts on any scope. The gate would fault at evaluation instead of gating: the element is '
405+
+ 'shown regardless of the flag where the consuming surface is fail-soft and hidden regardless '
406+
+ 'of it where it is fail-closed, so the flag decides nothing — the inert arrival ADR-0078 '
407+
+ 'rejects. Drop the blank `visible` and `requiresFeature` emits the gate alone, or put the '
408+
+ 'predicate the gate should compose with in `source`.',
400409
});
401410
return rest as Omit<T, 'requiresFeature'>;
402411
}

0 commit comments

Comments
 (0)