diff --git a/internal/sddstatus/status.go b/internal/sddstatus/status.go index 41308539..1580deea 100644 --- a/internal/sddstatus/status.go +++ b/internal/sddstatus/status.go @@ -614,7 +614,10 @@ func reportLineHasBlocker(line string) bool { if line == "" { return false } - if reportPassNegationPattern.MatchString(line) || reportPendingPattern.MatchString(line) { + if reportPassNegationPattern.MatchString(line) { + return true + } + if reportPendingPattern.MatchString(line) && !reportLineHasPassSignal(line) { return true } if reportCriticalGlyphStatusPattern.MatchString(line) { @@ -647,6 +650,9 @@ func reportLineHasPassSignal(line string) bool { if line == "" { return false } + if strings.Contains(line, "āœ…") { + return true + } _, value, hasField := reportField(line) if hasField && reportPassValuePattern.MatchString(stripMarkdownSignal(value)) { return true diff --git a/internal/sddstatus/status_test.go b/internal/sddstatus/status_test.go index b6144e42..5c648ae1 100644 --- a/internal/sddstatus/status_test.go +++ b/internal/sddstatus/status_test.go @@ -402,6 +402,44 @@ func TestResolveApplyVerifyArchiveGates(t *testing.T) { wantNext: "verify", wantBlocked: "verify-report.md is not clearly passing.", }, + { + name: "archive ready when verify report has checkmark todo on same line", + seed: func(t *testing.T, root string) { + changeRoot := seedReadyChange(t, root, "thin", "- [x] 1.1 Work\n") + write(t, filepath.Join(changeRoot, "verify-report.md"), "# Verify\nStatus: PASS\nāœ… TODO: finish audit\nāœ… PENDING: test run\n") + }, + wantApply: ApplyAllDone, + wantApplyD: DependencyAllDone, + wantVerify: DependencyAllDone, + wantArchive: DependencyReady, + wantNext: "archive", + }, + { + name: "archive blocked when verify report has standalone todo without glyph", + seed: func(t *testing.T, root string) { + changeRoot := seedReadyChange(t, root, "thin", "- [x] 1.1 Work\n") + write(t, filepath.Join(changeRoot, "verify-report.md"), "# Verify\nStatus: PASS\ntodo: security review\n") + }, + wantApply: ApplyAllDone, + wantApplyD: DependencyAllDone, + wantVerify: DependencyReady, + wantArchive: DependencyBlocked, + wantNext: "verify", + wantBlocked: "verify-report.md is not clearly passing.", + }, + { + name: "archive blocked when verify report mixes checkmark todo and standalone todo", + seed: func(t *testing.T, root string) { + changeRoot := seedReadyChange(t, root, "thin", "- [x] 1.1 Work\n") + write(t, filepath.Join(changeRoot, "verify-report.md"), "# Verify\nStatus: PASS\nāœ… TODO: finish audit\ntodo: security review\n") + }, + wantApply: ApplyAllDone, + wantApplyD: DependencyAllDone, + wantVerify: DependencyReady, + wantArchive: DependencyBlocked, + wantNext: "verify", + wantBlocked: "verify-report.md is not clearly passing.", + }, { name: "archive blocked when verify report says status not passed", seed: func(t *testing.T, root string) {