From 420ac8a28e1b8009465a3f8e5707b9a241423aed Mon Sep 17 00:00:00 2001 From: Gilbert Sanchez Date: Thu, 7 May 2026 13:23:11 -0700 Subject: [PATCH 1/2] fix(evaluation): use labeled break to exit foreach on Allow/Deny (closes #9) break inside switch only exits the switch block, not the enclosing foreach. Added :ruleLoop label to the foreach and changed break to break ruleLoop in the Allow and Deny cases so evaluation stops after the first terminal rule. Co-Authored-By: Claude Sonnet 4.6 --- Gatekeeper/Public/Test-FeatureFlag.ps1 | 6 +++--- trackers/p0-bugs-tracker.jsonl | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 trackers/p0-bugs-tracker.jsonl diff --git a/Gatekeeper/Public/Test-FeatureFlag.ps1 b/Gatekeeper/Public/Test-FeatureFlag.ps1 index 06f1327..6816791 100644 --- a/Gatekeeper/Public/Test-FeatureFlag.ps1 +++ b/Gatekeeper/Public/Test-FeatureFlag.ps1 @@ -44,7 +44,7 @@ process { # Process each feature Write-Verbose "Processing Feature $($FeatureFlag.Name) with ($($FeatureFlag.Rules.Count)) rules" - foreach ($rule in $FeatureFlag.Rules) { + :ruleLoop foreach ($rule in $FeatureFlag.Rules) { Write-Verbose "Processing Rule $($rule.Name)" $testConditionSplat = @{ Context = $Context @@ -58,12 +58,12 @@ 'Allow' { Invoke-Logging -Effect 'Allow' -Rule $rule $finalResult = $true - break + break ruleLoop } 'Deny' { Invoke-Logging -Effect 'Deny' -Rule $rule $finalResult = $false - break + break ruleLoop } 'Audit' { Invoke-Logging -Effect 'Audit' -Rule $rule diff --git a/trackers/p0-bugs-tracker.jsonl b/trackers/p0-bugs-tracker.jsonl new file mode 100644 index 0000000..c03bc26 --- /dev/null +++ b/trackers/p0-bugs-tracker.jsonl @@ -0,0 +1,13 @@ +{"id":1,"workstream":"evaluation","scope":"Test-FeatureFlag.ps1 — break inside switch exits switch not foreach","status":"DONE","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #9","evidence":"Added :ruleLoop label to foreach; changed break to break ruleLoop in Allow and Deny cases. Tests: 257 passed, 0 failed."} +{"id":2,"workstream":"evaluation","scope":"Test-FeatureFlag.ps1 — DefaultEffect only consulted when no terminal rule fired","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #10","evidence":""} +{"id":3,"workstream":"classes","scope":"PropertySet.AddProperty — missing hashtable key argument","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #11","evidence":""} +{"id":4,"workstream":"classes","scope":"ConditionGroup — missing FromJson static factory method","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #12","evidence":""} +{"id":5,"workstream":"classes","scope":"ConditionGroup constructor — two-group guard allows multiple group keys","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #13","evidence":""} +{"id":6,"workstream":"classes","scope":"PropertySet.FromFile — Name set from FilePath object not string","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #14","evidence":""} +{"id":7,"workstream":"config","scope":"Configuration.psd1 — Logging key 'Warning' should be 'Warn'; fix guides/logging.md example","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #15","evidence":""} +{"id":8,"workstream":"cleanup","scope":"Dead variable assignments — remove $config in Test-FeatureFlag.ps1 begin{} and $validation in Test-Condition.ps1","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #33","evidence":""} +{"id":9,"workstream":"public-api","scope":"New-FeatureFlag.ps1 — $Rules parameter must not be Mandatory","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #35","evidence":""} +{"id":10,"workstream":"private","scope":"Rename Convert-ToTypeValue → Convert-ToTypedValue (file + function + dot-source)","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #34","evidence":""} +{"id":11,"workstream":"classes","scope":"ConditionGroup.IsValid() misleading name — rename to IsLeaf() and update callers","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #31","evidence":""} +{"id":12,"workstream":"cmdlets","scope":"Missing [CmdletBinding()] on Test-Condition, Test-TypedValue, Invoke-Logging, Convert-ToTypedValue","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #32","evidence":""} +{"id":13,"workstream":"private","scope":"Convert-ToTypedValue.ps1 — boolean coercion via -as [bool] is too permissive","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #28","evidence":""} From 8de3b92c194c6541952bf99c1daa982f25214731 Mon Sep 17 00:00:00 2001 From: Gilbert Sanchez Date: Thu, 7 May 2026 14:05:54 -0700 Subject: [PATCH 2/2] Delete trackers/p0-bugs-tracker.jsonl Signed-off-by: Gilbert Sanchez --- trackers/p0-bugs-tracker.jsonl | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 trackers/p0-bugs-tracker.jsonl diff --git a/trackers/p0-bugs-tracker.jsonl b/trackers/p0-bugs-tracker.jsonl deleted file mode 100644 index c03bc26..0000000 --- a/trackers/p0-bugs-tracker.jsonl +++ /dev/null @@ -1,13 +0,0 @@ -{"id":1,"workstream":"evaluation","scope":"Test-FeatureFlag.ps1 — break inside switch exits switch not foreach","status":"DONE","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #9","evidence":"Added :ruleLoop label to foreach; changed break to break ruleLoop in Allow and Deny cases. Tests: 257 passed, 0 failed."} -{"id":2,"workstream":"evaluation","scope":"Test-FeatureFlag.ps1 — DefaultEffect only consulted when no terminal rule fired","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #10","evidence":""} -{"id":3,"workstream":"classes","scope":"PropertySet.AddProperty — missing hashtable key argument","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #11","evidence":""} -{"id":4,"workstream":"classes","scope":"ConditionGroup — missing FromJson static factory method","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #12","evidence":""} -{"id":5,"workstream":"classes","scope":"ConditionGroup constructor — two-group guard allows multiple group keys","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #13","evidence":""} -{"id":6,"workstream":"classes","scope":"PropertySet.FromFile — Name set from FilePath object not string","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #14","evidence":""} -{"id":7,"workstream":"config","scope":"Configuration.psd1 — Logging key 'Warning' should be 'Warn'; fix guides/logging.md example","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #15","evidence":""} -{"id":8,"workstream":"cleanup","scope":"Dead variable assignments — remove $config in Test-FeatureFlag.ps1 begin{} and $validation in Test-Condition.ps1","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #33","evidence":""} -{"id":9,"workstream":"public-api","scope":"New-FeatureFlag.ps1 — $Rules parameter must not be Mandatory","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #35","evidence":""} -{"id":10,"workstream":"private","scope":"Rename Convert-ToTypeValue → Convert-ToTypedValue (file + function + dot-source)","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #34","evidence":""} -{"id":11,"workstream":"classes","scope":"ConditionGroup.IsValid() misleading name — rename to IsLeaf() and update callers","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #31","evidence":""} -{"id":12,"workstream":"cmdlets","scope":"Missing [CmdletBinding()] on Test-Condition, Test-TypedValue, Invoke-Logging, Convert-ToTypedValue","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #32","evidence":""} -{"id":13,"workstream":"private","scope":"Convert-ToTypedValue.ps1 — boolean coercion via -as [bool] is too permissive","status":"PENDING","model":"claude-sonnet-4-6","effort":"low","reason":"Issue #28","evidence":""}