feat(m9/T28b): trigger analysis-kind selector (UI) + --trigger-kind (CLI)

Surfaces the T28a backend "analysisKind" discriminator in both authoring
surfaces: an Advisory|Strict <select> (id="alarm-trigger-kind" /
"script-trigger-kind") added to the Expression fragment of
AlarmTriggerEditor and ScriptTriggerEditor, and a --trigger-kind option
on template alarm/script add+update in the CLI.

Key/value contract: "analysisKind":"Strict" when strict; key omitted for
Advisory — exactly as ValidationService.IsStrictAnalysis reads it.
Selector only shown for Expression triggers; non-Expression triggers do
not emit the key even if IsStrictAnalysisKind is set on the model.

Both projects build 0 warnings; 101 CentralUI Trigger tests + 33 CLI
Template tests pass.
This commit is contained in:
Joseph Doherty
2026-06-18 10:44:57 -04:00
parent f618ac0322
commit dcc6f623e2
8 changed files with 684 additions and 2 deletions
@@ -339,6 +339,13 @@ public static class TemplateCommands
var hiOption = new Option<double?>("--hi") { Description = "HiLo: high setpoint" };
var hiHiOption = new Option<double?>("--hihi") { Description = "HiLo: high-high setpoint" };
var expressionOption = new Option<string?>("--expression") { Description = "Expression: boolean trigger expression" };
// M9-T28b: analysis kind for Expression triggers (advisory|strict; default advisory).
// Writes "analysisKind":"Strict" into the trigger config when set to strict.
var triggerKindOption = new Option<string?>("--trigger-kind")
{
Description = "Expression trigger analysis kind: advisory (default) or strict. " +
"Strict escalates a blank expression from a warning to a deploy-blocking error."
};
var addCmd = new Command("add") { Description = "Add an alarm to a template" };
addCmd.Add(templateIdOption);
@@ -361,6 +368,7 @@ public static class TemplateCommands
addCmd.Add(hiOption);
addCmd.Add(hiHiOption);
addCmd.Add(expressionOption);
addCmd.Add(triggerKindOption);
addCmd.SetAction(async (ParseResult result) =>
{
var triggerType = result.GetValue(triggerTypeOption)!;
@@ -372,7 +380,8 @@ public static class TemplateCommands
result.GetValue(minOption), result.GetValue(maxOption),
result.GetValue(thresholdOption), result.GetValue(windowOption), result.GetValue(directionOption),
result.GetValue(loLoOption), result.GetValue(loOption), result.GetValue(hiOption), result.GetValue(hiHiOption),
result.GetValue(expressionOption));
result.GetValue(expressionOption),
result.GetValue(triggerKindOption));
return await CommandHelpers.ExecuteCommandAsync(
result, urlOption, formatOption, usernameOption, passwordOption,
@@ -395,6 +404,11 @@ public static class TemplateCommands
var updateTriggerConfigOption = new Option<string?>("--trigger-config") { Description = "Trigger configuration JSON" };
var updateLockedOption = new Option<bool>("--locked") { Description = "Lock status" };
updateLockedOption.DefaultValueFactory = _ => false;
// M9-T28b: --trigger-kind for update (same semantics as add)
var updateTriggerKindOption = new Option<string?>("--trigger-kind")
{
Description = "Expression trigger analysis kind: advisory (default) or strict."
};
var updateCmd = new Command("update") { Description = "Update a template alarm" };
updateCmd.Add(updateIdOption);
@@ -404,6 +418,7 @@ public static class TemplateCommands
updateCmd.Add(updateDescOption);
updateCmd.Add(updateTriggerConfigOption);
updateCmd.Add(updateLockedOption);
updateCmd.Add(updateTriggerKindOption);
updateCmd.SetAction(async (ParseResult result) =>
{
return await CommandHelpers.ExecuteCommandAsync(
@@ -514,6 +529,13 @@ public static class TemplateCommands
var paramsOption = new Option<string?>("--parameters") { Description = "Parameter definitions JSON" };
var returnOption = new Option<string?>("--return-def") { Description = "Return definition JSON" };
// M9-T28b: analysis kind for Expression triggers (advisory|strict; default advisory).
var scriptTriggerKindOption = new Option<string?>("--trigger-kind")
{
Description = "Expression trigger analysis kind: advisory (default) or strict. " +
"Strict escalates a blank expression from a warning to a deploy-blocking error. " +
"Used with --trigger-config or appended to a built config when --trigger-type is Expression."
};
var addCmd = new Command("add") { Description = "Add a script to a template" };
addCmd.Add(templateIdOption);
@@ -524,6 +546,7 @@ public static class TemplateCommands
addCmd.Add(lockedOption);
addCmd.Add(paramsOption);
addCmd.Add(returnOption);
addCmd.Add(scriptTriggerKindOption);
addCmd.SetAction(async (ParseResult result) =>
{
return await CommandHelpers.ExecuteCommandAsync(
@@ -550,6 +573,11 @@ public static class TemplateCommands
var updateParamsOption = new Option<string?>("--parameters") { Description = "Parameter definitions JSON" };
var updateReturnOption = new Option<string?>("--return-def") { Description = "Return definition JSON" };
// M9-T28b: --trigger-kind for update (same semantics as add)
var updateScriptTriggerKindOption = new Option<string?>("--trigger-kind")
{
Description = "Expression trigger analysis kind: advisory (default) or strict."
};
var updateCmd = new Command("update") { Description = "Update a template script" };
updateCmd.Add(updateIdOption);
@@ -560,6 +588,7 @@ public static class TemplateCommands
updateCmd.Add(updateLockedOption);
updateCmd.Add(updateParamsOption);
updateCmd.Add(updateReturnOption);
updateCmd.Add(updateScriptTriggerKindOption);
updateCmd.SetAction(async (ParseResult result) =>
{
return await CommandHelpers.ExecuteCommandAsync(