@@ -61,13 +61,15 @@ import {
6161 resolveDiscordThreadTitleBadges ,
6262 resolveDiscordTitlePrEvidence ,
6363 resolveSettledDiscordThreadTitleUpgrade ,
64+ resolveSilentDiscordThreadPrBadge ,
6465 resolveTemporaryDiscordThreadTitleBadge ,
6566 resolveThreadChangeRequestLookupCwds ,
6667 mergeStickyTitlePr ,
6768 nextMirroredThreadTitleAfterApply ,
6869 planDiscordThreadTitleApply ,
6970 shouldApplyDiscordThreadPrBadge ,
7071 shouldApplyDiscordThreadTitleBadge ,
72+ shouldDeferInitializedPrWhileBusy ,
7173 shouldConvertWorkingTipsToWakeUp ,
7274 summarizeExternalUserInput ,
7375 threadTitleChangeRequestState ,
@@ -2095,6 +2097,143 @@ describe("resolveSettledDiscordThreadTitleUpgrade", () => {
20952097 } ) ,
20962098 ) . toBe ( "🔀 ⏳ Empasa pickup carrier rollout" ) ;
20972099 } ) ;
2100+
2101+ it ( "does not thrash-rename ⏳ → ▫️ ⏳ while still busy after no-PR is confirmed" , ( ) => {
2102+ // Turn start painted activity-only; VCS later confirms no PR. Second rename to
2103+ // ▫️ ⏳ is pure channel noise — settle will paint ▫️ when busy clears.
2104+ expect (
2105+ resolveSettledDiscordThreadTitleUpgrade ( {
2106+ thread : {
2107+ title : "for pr 2101, i wish we could push freely to draft PRs" ,
2108+ branch : "t3-discord/pr-2101-draft-pushes" ,
2109+ worktreePath : "/var/lib/t3/worktrees/t3code/t3-discord-6c17cdca" ,
2110+ messages : [ assistantMessage ( ) ] ,
2111+ session : { status : "running" , activeTurnId : "turn-1" } as never ,
2112+ latestTurn : {
2113+ turnId : "turn-1" as never ,
2114+ state : "running" ,
2115+ completedAt : null ,
2116+ } as never ,
2117+ } ,
2118+ mirroredThreadTitle : "⏳ for pr 2101, i wish we could push freely to draft PRs" ,
2119+ attemptedThreadTitle : "⏳ for pr 2101, i wish we could push freely to draft PRs" ,
2120+ cachedPr : null ,
2121+ canApplyNoPrBadge : true ,
2122+ } ) ,
2123+ ) . toBeNull ( ) ;
2124+ } ) ;
2125+
2126+ it ( "still paints ▫️ ⏳ in one shot when busy starts on a plain title with no-PR known" , ( ) => {
2127+ expect (
2128+ resolveSettledDiscordThreadTitleUpgrade ( {
2129+ thread : {
2130+ title : "for pr 2101, i wish we could push freely to draft PRs" ,
2131+ branch : "t3-discord/pr-2101-draft-pushes" ,
2132+ worktreePath : "/var/lib/t3/worktrees/t3code/t3-discord-6c17cdca" ,
2133+ messages : [ assistantMessage ( ) ] ,
2134+ session : { status : "running" , activeTurnId : "turn-1" } as never ,
2135+ latestTurn : {
2136+ turnId : "turn-1" as never ,
2137+ state : "running" ,
2138+ completedAt : null ,
2139+ } as never ,
2140+ } ,
2141+ mirroredThreadTitle : "for pr 2101, i wish we could push freely to draft PRs" ,
2142+ attemptedThreadTitle : "for pr 2101, i wish we could push freely to draft PRs" ,
2143+ cachedPr : null ,
2144+ canApplyNoPrBadge : true ,
2145+ } ) ,
2146+ ) . toBe ( "▫️ ⏳ for pr 2101, i wish we could push freely to draft PRs" ) ;
2147+ } ) ;
2148+
2149+ it ( "still upgrades ⏳ → 🔀 ⏳ mid-turn when a real PR appears" , ( ) => {
2150+ expect (
2151+ resolveSettledDiscordThreadTitleUpgrade ( {
2152+ thread : {
2153+ title : "Empasa pickup carrier rollout" ,
2154+ branch : "t3-discord/empasa-pickup-carrier" ,
2155+ worktreePath : "/var/lib/t3/worktrees/scanner/t3-discord-c434b753" ,
2156+ messages : [ assistantMessage ( ) ] ,
2157+ session : { status : "running" , activeTurnId : "turn-1" } as never ,
2158+ latestTurn : {
2159+ turnId : "turn-1" as never ,
2160+ state : "running" ,
2161+ completedAt : null ,
2162+ } as never ,
2163+ } ,
2164+ mirroredThreadTitle : "⏳ Empasa pickup carrier rollout" ,
2165+ attemptedThreadTitle : "⏳ Empasa pickup carrier rollout" ,
2166+ cachedPr : { state : "open" , hasFailingChecks : false } ,
2167+ } ) ,
2168+ ) . toBe ( "🔀 ⏳ Empasa pickup carrier rollout" ) ;
2169+ } ) ;
2170+ } ) ;
2171+
2172+ describe ( "shouldDeferInitializedPrWhileBusy / resolveSilentDiscordThreadPrBadge" , ( ) => {
2173+ it ( "defers only the no-PR badge while busy is unchanged" , ( ) => {
2174+ expect (
2175+ shouldDeferInitializedPrWhileBusy ( {
2176+ currentPr : null ,
2177+ nextPr : "initialized" ,
2178+ currentActivity : "busy" ,
2179+ nextActivity : "busy" ,
2180+ } ) ,
2181+ ) . toBe ( true ) ;
2182+ expect (
2183+ resolveSilentDiscordThreadPrBadge ( {
2184+ currentPr : null ,
2185+ nextPr : "initialized" ,
2186+ currentActivity : "busy" ,
2187+ nextActivity : "busy" ,
2188+ } ) ,
2189+ ) . toBeNull ( ) ;
2190+ } ) ;
2191+
2192+ it ( "does not defer when painting dual badges from a plain title" , ( ) => {
2193+ expect (
2194+ shouldDeferInitializedPrWhileBusy ( {
2195+ currentPr : null ,
2196+ nextPr : "initialized" ,
2197+ currentActivity : null ,
2198+ nextActivity : "busy" ,
2199+ } ) ,
2200+ ) . toBe ( false ) ;
2201+ expect (
2202+ resolveSilentDiscordThreadPrBadge ( {
2203+ currentPr : null ,
2204+ nextPr : "initialized" ,
2205+ currentActivity : null ,
2206+ nextActivity : "busy" ,
2207+ } ) ,
2208+ ) . toBe ( "initialized" ) ;
2209+ } ) ;
2210+
2211+ it ( "does not defer real PR upgrades or settle (busy → idle)" , ( ) => {
2212+ expect (
2213+ shouldDeferInitializedPrWhileBusy ( {
2214+ currentPr : null ,
2215+ nextPr : "open" ,
2216+ currentActivity : "busy" ,
2217+ nextActivity : "busy" ,
2218+ } ) ,
2219+ ) . toBe ( false ) ;
2220+ expect (
2221+ shouldDeferInitializedPrWhileBusy ( {
2222+ currentPr : null ,
2223+ nextPr : "initialized" ,
2224+ currentActivity : "busy" ,
2225+ nextActivity : null ,
2226+ } ) ,
2227+ ) . toBe ( false ) ;
2228+ expect (
2229+ resolveSilentDiscordThreadPrBadge ( {
2230+ currentPr : null ,
2231+ nextPr : "initialized" ,
2232+ currentActivity : "busy" ,
2233+ nextActivity : null ,
2234+ } ) ,
2235+ ) . toBe ( "initialized" ) ;
2236+ } ) ;
20982237} ) ;
20992238
21002239describe ( "planDiscordThreadTitleApply" , ( ) => {
0 commit comments