Skip to content

Commit d3c1071

Browse files
committed
fix(spec): declare what the expression author helpers actually emit
`expression()` and `cel()` (hence `F` and `P`) always set a non-blank `source`, but were declared as returning `Expression`, whose `source` is optional. Harmless while no slot required `source`; once the field-rule triad did, a `P` template written straight into `visibleWhen` became a TS2322 — the recommended authoring form for a predicate stopped type-checking in the one place predicates are written (caught by `check:skill-examples` on the docs and skills corpus, and by the examples typecheck on app-showcase). Fixed at the producer, not the call sites: the return type now states what the helper emits. Narrowing a return type removes nothing from a caller — `EvaluatedExpression` is assignable to `Expression`. Claude-Session: https://claude.ai/code/session_019srGWGCBBCBHqcDoRZpQRh Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4f9d0cf commit d3c1071

1 file changed

Lines changed: 21 additions & 3 deletions

File tree

‎packages/spec/src/shared/expression.zod.ts‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,11 @@ export type PredicateInput = z.input<typeof PredicateInputSchema>;
469469
* Construct an Expression literal from a CEL source string. Used by DX
470470
* shorthand (`cel\`...\``) and by codegen tools.
471471
*/
472-
export function expression(source: string, dialect: ExpressionDialect = 'cel', meta?: ExpressionMeta): Expression {
472+
export function expression(
473+
source: string,
474+
dialect: ExpressionDialect = 'cel',
475+
meta?: ExpressionMeta,
476+
): EvaluatedExpression {
473477
return { dialect, source, ...(meta ? { meta } : {}) };
474478
}
475479

@@ -508,8 +512,22 @@ function renderTemplate(strings: TemplateStringsArray, values: readonly unknown[
508512
return out;
509513
}
510514

511-
/** Tagged template — produces a CEL Expression envelope. */
512-
export function cel(strings: TemplateStringsArray, ...values: unknown[]): Expression {
515+
/**
516+
* Tagged template — produces a CEL Expression envelope.
517+
*
518+
* Returns {@link EvaluatedExpression}, not {@link Expression}: this helper
519+
* ALWAYS sets `source`, so the wider return type was a declaration of
520+
* something the function cannot produce. It was harmless only while no slot
521+
* required `source` — once the field-rule triad did (ADR-0136 D1), a
522+
* ``P`record.status == 'paid'` `` written straight into `visibleWhen` became a
523+
* TS2322, and the recommended authoring form for a predicate stopped
524+
* type-checking in the one place predicates are written. Fixed at the PRODUCER
525+
* (Prime Directive #12) rather than by rewriting the call sites: the return
526+
* type now states what the helper emits. Narrowing a return type removes
527+
* nothing from a caller — `EvaluatedExpression` is assignable to `Expression`
528+
* — so every existing consumer still compiles.
529+
*/
530+
export function cel(strings: TemplateStringsArray, ...values: unknown[]): EvaluatedExpression {
513531
return { dialect: 'cel', source: renderTemplate(strings, values) };
514532
}
515533

0 commit comments

Comments
 (0)