@@ -171,6 +171,9 @@ const LATE_MOST_RECENT: Readonly<Record<string, 'open' | 'in_progress'>> = {
171171 'Calibration verification — Lab 1' : 'open' ,
172172} ;
173173
174+ /** How long ago each actively-chased late row was last touched. */
175+ const CHASED_DAYS_AGO = [ 2 , 6 , 10 ] as const ;
176+
174177/** Untouched since dispatch as well as late — the fourth Late row above. */
175178const STALLED_LATE = 'Calibration verification — Lab 1' ;
176179
@@ -244,6 +247,31 @@ for (const [duty, series] of byDuty) {
244247const inFlightKey = ( duty : string ) : string | undefined =>
245248 byDuty . get ( duty ) ?. find ( ( draft ) => ! isPast ( draft ) ) ?. period_key ;
246249
250+ /**
251+ * How long ago a task that is still moving was last touched.
252+ *
253+ * Two constraints, and the interesting one is the second:
254+ *
255+ * 1. **Never before the task was dispatched.** A row cannot have been worked
256+ * on before it existed. This clamps the whole band for a freshly
257+ * dispatched monthly.
258+ * 2. **Never 14 days or more.** Anything that old lands in "Not moving", and
259+ * which rows stagnate is a decision this fixture makes deliberately —
260+ * see {@link STALLED_IN_FLIGHT} — not a side effect of a spread.
261+ *
262+ * Between those, the age is spread by how long the task has BEEN open rather
263+ * than uniformly. A task dispatched five months ago and still being worked was
264+ * realistically last touched a week or two back; one dispatched on Monday was
265+ * touched this week. A uniform spread collapses to "everything was touched in
266+ * the last few days" once constraint 1 clamps it, which makes the dashboard's
267+ * nested >7d / >14d / >30d buckets read identically and look broken.
268+ */
269+ const touchedDaysAgo = ( draft : TaskDraft , dispatched : Date , index : number ) : number => {
270+ const openFor = Math . floor ( ( NOW . getTime ( ) - dispatched . getTime ( ) ) / DAY ) ;
271+ if ( openFor >= 14 ) return 8 + ( index % 5 ) ;
272+ return Math . max ( 0 , Math . min ( index % 6 , openFor ) ) ;
273+ } ;
274+
247275/**
248276 * Decide what actually happened to one dispatched task.
249277 *
@@ -268,10 +296,15 @@ const resolveDraft = (draft: TaskDraft, index: number): SeededTask => {
268296 return withNote ( {
269297 ...draft ,
270298 status : LATE_MOST_RECENT [ draft . duty ] ! ,
299+ // Chased, but at different tempos — 2, 6 and 10 days. A month-overdue
300+ // task that was last touched yesterday, every time, is not what being
301+ // chased looks like; and spreading these across the fortnight is what
302+ // puts anything at all in the dashboard's 7-to-14-day band, which would
303+ // otherwise be empty and make its >7d and >14d tiles read identically.
271304 last_update_at :
272305 draft . duty === STALLED_LATE
273306 ? untouchedSinceDispatch
274- : iso ( new Date ( NOW . getTime ( ) - ( ( index % 9 ) + 1 ) * DAY ) ) ,
307+ : iso ( new Date ( NOW . getTime ( ) - CHASED_DAYS_AGO [ index % CHASED_DAYS_AGO . length ] ! * DAY ) ) ,
275308 } ) ;
276309 }
277310 if ( isMostRecentPast && draft . duty === SKIPPED_MOST_RECENT ) {
@@ -307,12 +340,7 @@ const resolveDraft = (draft: TaskDraft, index: number): SeededTask => {
307340 return withNote ( {
308341 ...draft ,
309342 status : isInFlightHead && IN_PROGRESS_IN_FLIGHT . includes ( draft . duty ) ? 'in_progress' : 'open' ,
310- // Not stalled ⇒ touched inside the fortnight, spread across it so the
311- // Recent-activity timeline reads as a stream rather than one boot-time
312- // spike. Never earlier than the day the task was dispatched.
313- last_update_at : stalled
314- ? untouchedSinceDispatch
315- : iso ( new Date ( Math . max ( NOW . getTime ( ) - ( index % 13 ) * DAY , dispatched . getTime ( ) ) ) ) ,
343+ last_update_at : stalled ? untouchedSinceDispatch : iso ( new Date ( NOW . getTime ( ) - touchedDaysAgo ( draft , dispatched , index ) * DAY ) ) ,
316344 } ) ;
317345} ;
318346
0 commit comments