Found while censusing predicate-fault reporting for #6038. Filed unassigned; out of that card's scope (it is not a node gate).
The defect
packages/core/src/evaluator/ExpressionEvaluator.ts, evaluate() — both fault paths log unconditionally and are not deduped:
// per-part catch, multi-part templateconsole.warn(`Expression evaluation failed for: ${expr}`,error);// outer catchconsole.warn(`Failed to evaluate expression: ${expression}`,error);Every sibling reporter in this area IS rate limited, and each records why:
fieldRules.tswarnPredicateFailure — deduped per (dialect, source): "a broken predicate is re-evaluated on every render/keystroke, and the point is one loud line, not a scrolling wall."visibilityDiagnostic.ts — deduped per (type, key, source), for the same reason.
evaluate() is the odd one out, and it is on the hottest path of the three: SchemaRenderer calls it for every properties.* value, every props.* value and content, for every node, on every render.
Measured
On the built evaluator, evaluateCondition('${nosuchroot.x > 1}') three times in a row produced 3console.warn lines (the CEL envelope, by contrast, produced 1 for the same three calls). A single broken ${…} in a prop of a 200-row list is therefore 200 lines, and 200 more on the next render — the exact "一个列表里几百行会淹没控制台" hazard #6038's ruling names as the reason its own warning had to be rate limited.
Note on what #6038 did and did not change here
#6038 added EvaluationOptions.onFault; when a caller supplies it, these two console.warns are replaced by the passback, so the node-gate path is now deduped by the caller's reporter. Every other caller — props, content, properties — passes no onFault and still floods. The fix is to give these two sites the same one-per-source rate limit the two sibling reporters already have.
One thing to decide rather than assume: whether the dedupe should be keyed on the source text alone (matching warnPredicateFailure) — an interpolated string evaluated against many different scopes is one authoring mistake, but it is also the case that the same text can be genuinely broken in one scope and fine in another.
Related: #6038 (the onFault seam), #5926.
Generated by Claude Code
Found while censusing predicate-fault reporting for #6038. Filed unassigned; out of that card's scope (it is not a node gate).
The defect
packages/core/src/evaluator/ExpressionEvaluator.ts,evaluate()— both fault paths log unconditionally and are not deduped:Every sibling reporter in this area IS rate limited, and each records why:
fieldRules.tswarnPredicateFailure— deduped per (dialect, source): "a broken predicate is re-evaluated on every render/keystroke, and the point is one loud line, not a scrolling wall."visibilityDiagnostic.ts— deduped per (type, key, source), for the same reason.evaluate()is the odd one out, and it is on the hottest path of the three:SchemaRenderercalls it for everyproperties.*value, everyprops.*value andcontent, for every node, on every render.Measured
On the built evaluator,
evaluateCondition('${nosuchroot.x > 1}')three times in a row produced 3console.warnlines (the CEL envelope, by contrast, produced 1 for the same three calls). A single broken${…}in a prop of a 200-row list is therefore 200 lines, and 200 more on the next render — the exact "一个列表里几百行会淹没控制台" hazard #6038's ruling names as the reason its own warning had to be rate limited.Note on what #6038 did and did not change here
#6038 added
EvaluationOptions.onFault; when a caller supplies it, these twoconsole.warns are replaced by the passback, so the node-gate path is now deduped by the caller's reporter. Every other caller — props, content,properties— passes noonFaultand still floods. The fix is to give these two sites the same one-per-source rate limit the two sibling reporters already have.One thing to decide rather than assume: whether the dedupe should be keyed on the source text alone (matching
warnPredicateFailure) — an interpolated string evaluated against many different scopes is one authoring mistake, but it is also the case that the same text can be genuinely broken in one scope and fine in another.Related: #6038 (the
onFaultseam), #5926.Generated by Claude Code