perf(template-engine): read-only staleness/comparison paths skip Expression-trigger compiles — deploy gate remains the authoritative check (plan R2-05 T4)
This commit is contained in:
@@ -97,11 +97,16 @@ public class ValidationService
|
||||
/// </param>
|
||||
/// <param name="validateScriptCompilation">
|
||||
/// <c>true</c> (default) runs the authoritative Roslyn <see cref="ValidateScriptCompilation"/>
|
||||
/// stage — the single most expensive check (a non-collectible assembly load per script).
|
||||
/// <c>false</c> skips ONLY that stage; every other structural/semantic check still runs.
|
||||
/// Read-only staleness/comparison callers (DeploymentManager's FlatteningPipeline on its
|
||||
/// comparison/probe paths) pass <c>false</c> because they need only the flattened config and
|
||||
/// revision hash, not a compile. The deploy gate keeps the default (<c>true</c>).
|
||||
/// stage — the single most expensive check (a non-collectible assembly load per script) —
|
||||
/// AND the Expression-trigger syntax/compile check
|
||||
/// (<see cref="CheckExpressionSyntax"/>, a forbidden-API verdict plus a real compile of every
|
||||
/// Expression-triggered script/alarm body against <see cref="TriggerCompileSurface"/>).
|
||||
/// <c>false</c> skips ONLY those two compile stages; every other structural/semantic check
|
||||
/// still runs — including, for Expression triggers, the blank-expression check and the
|
||||
/// cheap attribute-reference scan. Read-only staleness/comparison callers (DeploymentManager's
|
||||
/// FlatteningPipeline on its comparison/probe paths) pass <c>false</c> because they need only
|
||||
/// the flattened config and revision hash, not a compile. The deploy gate keeps the default
|
||||
/// (<c>true</c>) — it is the authoritative check for both stages.
|
||||
/// </param>
|
||||
/// <returns>A merged <see cref="ValidationResult"/> aggregating all pipeline stage outcomes.</returns>
|
||||
public ValidationResult Validate(
|
||||
@@ -128,7 +133,7 @@ public class ValidationService
|
||||
validateScriptCompilation ? ValidateScriptCompilation(configuration) : ValidationResult.Success(),
|
||||
ValidateAlarmTriggerReferences(configuration),
|
||||
ValidateScriptTriggerReferences(configuration),
|
||||
ValidateExpressionTriggers(configuration),
|
||||
ValidateExpressionTriggers(configuration, validateScriptCompilation),
|
||||
ValidateConnectionBindingCompleteness(configuration, enforceConnectionBindings, siteConnectionNames),
|
||||
ValidateSchemaReferences(configuration, sharedScripts, resolveSchemaRef),
|
||||
_semanticValidator.Validate(configuration, sharedScripts, alarmCapableConnectionNames)
|
||||
@@ -366,8 +371,16 @@ public class ValidationService
|
||||
/// </list>
|
||||
/// </summary>
|
||||
/// <param name="configuration">The flattened configuration to validate.</param>
|
||||
/// <param name="validateExpressionSyntax">
|
||||
/// <c>true</c> (default) runs the authoritative <see cref="CheckExpressionSyntax"/>
|
||||
/// forbidden-API + compile stage for each Expression trigger. <c>false</c> skips ONLY
|
||||
/// that stage — the blank-expression check and the attribute-reference scan still run —
|
||||
/// so read-only staleness/comparison callers do not pay the per-expression compile.
|
||||
/// </param>
|
||||
/// <returns>A <see cref="ValidationResult"/> with errors and warnings from all expression trigger checks.</returns>
|
||||
public static ValidationResult ValidateExpressionTriggers(FlattenedConfiguration configuration)
|
||||
public static ValidationResult ValidateExpressionTriggers(
|
||||
FlattenedConfiguration configuration,
|
||||
bool validateExpressionSyntax = true)
|
||||
{
|
||||
var errors = new List<ValidationEntry>();
|
||||
var warnings = new List<ValidationEntry>();
|
||||
@@ -382,7 +395,7 @@ public class ValidationService
|
||||
CheckExpressionTrigger(
|
||||
ValidationCategory.ScriptTriggerReference, "script",
|
||||
script.CanonicalName, script.TriggerConfiguration,
|
||||
attributeNames, errors, warnings);
|
||||
attributeNames, errors, warnings, validateExpressionSyntax);
|
||||
}
|
||||
|
||||
foreach (var alarm in configuration.Alarms)
|
||||
@@ -393,7 +406,7 @@ public class ValidationService
|
||||
CheckExpressionTrigger(
|
||||
ValidationCategory.AlarmTriggerReference, "alarm",
|
||||
alarm.CanonicalName, alarm.TriggerConfiguration,
|
||||
attributeNames, errors, warnings);
|
||||
attributeNames, errors, warnings, validateExpressionSyntax);
|
||||
}
|
||||
|
||||
return new ValidationResult { Errors = errors, Warnings = warnings };
|
||||
@@ -424,7 +437,8 @@ public class ValidationService
|
||||
string? triggerConfigJson,
|
||||
HashSet<string> attributeNames,
|
||||
List<ValidationEntry> errors,
|
||||
List<ValidationEntry> warnings)
|
||||
List<ValidationEntry> warnings,
|
||||
bool validateExpressionSyntax = true)
|
||||
{
|
||||
var expression = ExtractExpressionFromTriggerConfig(triggerConfigJson);
|
||||
var strict = IsStrictAnalysis(triggerConfigJson);
|
||||
@@ -443,12 +457,20 @@ public class ValidationService
|
||||
return;
|
||||
}
|
||||
|
||||
var syntaxError = CheckExpressionSyntax(expression);
|
||||
if (syntaxError != null)
|
||||
// The syntax/compile stage is the expensive one (a forbidden-API verdict + a
|
||||
// real Roslyn compile of the expression). Read-only staleness/comparison
|
||||
// callers pass validateExpressionSyntax: false to skip ONLY this stage; the
|
||||
// blank-expression check above and the attribute-reference scan below still run.
|
||||
// The deploy gate keeps the default (true) — the authoritative check.
|
||||
if (validateExpressionSyntax)
|
||||
{
|
||||
errors.Add(ValidationEntry.Error(category,
|
||||
$"The {entityLabel} '{entityName}' expression trigger failed validation: {syntaxError}",
|
||||
entityName));
|
||||
var syntaxError = CheckExpressionSyntax(expression);
|
||||
if (syntaxError != null)
|
||||
{
|
||||
errors.Add(ValidationEntry.Error(category,
|
||||
$"The {entityLabel} '{entityName}' expression trigger failed validation: {syntaxError}",
|
||||
entityName));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var attrName in ExtractAttributeReferences(expression))
|
||||
|
||||
Reference in New Issue
Block a user