Skip to content

Commit 6e5ad07

Browse files
Claudeclaude
authored andcommitted
fix: replace hardcoded dates in thread tests with relative helpers
aggregateThreads uses maxAgeDays=14 to filter sessions. Tests with hardcoded dates (2026-02-08/09) aged out of the window, causing 6 CI failures. Replaced with daysAgo() helpers that stay within range. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9fc8fbb commit 6e5ad07

2 files changed

Lines changed: 55 additions & 29 deletions

File tree

tests/unit/services/thread-manager.test.ts

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -313,22 +313,35 @@ describe("resolveThread — duplicate cascade detection", () => {
313313
});
314314

315315
describe("aggregateThreads", () => {
316+
// Use relative dates so tests don't age out of the 14-day window
317+
const today = new Date();
318+
const daysAgo = (n: number) => {
319+
const d = new Date(today);
320+
d.setDate(d.getDate() - n);
321+
return d.toISOString().split("T")[0];
322+
};
323+
const daysAgoISO = (n: number) => {
324+
const d = new Date(today);
325+
d.setDate(d.getDate() - n);
326+
return d.toISOString();
327+
};
328+
316329
it("deduplicates threads across sessions by text", () => {
317330
const sessions = [
318331
{
319332
id: "s1",
320-
session_date: "2026-02-09",
333+
session_date: daysAgo(1),
321334
close_compliance: { close_type: "standard" },
322335
open_threads: [
323-
{ id: "t-aaa", text: "Shared thread", status: "open" as const, created_at: "2026-02-08T00:00:00Z" },
336+
{ id: "t-aaa", text: "Shared thread", status: "open" as const, created_at: daysAgoISO(2) },
324337
],
325338
},
326339
{
327340
id: "s2",
328-
session_date: "2026-02-08",
341+
session_date: daysAgo(2),
329342
close_compliance: { close_type: "standard" },
330343
open_threads: [
331-
{ id: "t-bbb", text: "Shared thread", status: "open" as const, created_at: "2026-02-07T00:00:00Z" },
344+
{ id: "t-bbb", text: "Shared thread", status: "open" as const, created_at: daysAgoISO(3) },
332345
],
333346
},
334347
];
@@ -342,10 +355,10 @@ describe("aggregateThreads", () => {
342355
const sessions = [
343356
{
344357
id: "s1",
345-
session_date: "2026-02-09",
358+
session_date: daysAgo(1),
346359
close_compliance: null,
347360
open_threads: [
348-
{ id: "t-aaa", text: "Should be skipped", status: "open" as const, created_at: "2026-02-09T00:00:00Z" },
361+
{ id: "t-aaa", text: "Should be skipped", status: "open" as const, created_at: daysAgoISO(1) },
349362
],
350363
},
351364
];
@@ -357,18 +370,18 @@ describe("aggregateThreads", () => {
357370
const sessions = [
358371
{
359372
id: "s1",
360-
session_date: "2026-02-09",
373+
session_date: daysAgo(1),
361374
close_compliance: { close_type: "standard" },
362375
open_threads: [
363-
{ id: "t-aaa", text: "Phase 2 GitMem public npm release still pending", status: "open" as const, created_at: "2026-02-08T00:00:00Z" },
376+
{ id: "t-aaa", text: "Phase 2 GitMem public npm release still pending", status: "open" as const, created_at: daysAgoISO(2) },
364377
],
365378
},
366379
{
367380
id: "s2",
368-
session_date: "2026-02-08",
381+
session_date: daysAgo(2),
369382
close_compliance: { close_type: "standard" },
370383
open_threads: [
371-
{ id: "t-aaa", text: "Phase 2 issues (GitMem public npm release) still ready to execute", status: "open" as const, created_at: "2026-02-07T00:00:00Z" },
384+
{ id: "t-aaa", text: "Phase 2 issues (GitMem public npm release) still ready to execute", status: "open" as const, created_at: daysAgoISO(3) },
372385
],
373386
},
374387
];
@@ -382,11 +395,11 @@ describe("aggregateThreads", () => {
382395
const sessions = [
383396
{
384397
id: "s1",
385-
session_date: "2026-02-09",
398+
session_date: daysAgo(1),
386399
close_compliance: { close_type: "standard" },
387400
open_threads: [
388-
{ id: "t-aaa", text: "Still open", status: "open" as const, created_at: "2026-02-09T00:00:00Z" },
389-
{ id: "t-bbb", text: "Was resolved", status: "resolved" as const, created_at: "2026-02-08T00:00:00Z" },
401+
{ id: "t-aaa", text: "Still open", status: "open" as const, created_at: daysAgoISO(1) },
402+
{ id: "t-bbb", text: "Was resolved", status: "resolved" as const, created_at: daysAgoISO(2) },
390403
],
391404
},
392405
];

tests/unit/services/thread-supabase.test.ts

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,26 @@ import type { ThreadObject } from "../../../src/types/index.js";
5656
// Helpers
5757
// ---------------------------------------------------------------------------
5858

59+
/** Relative date helpers to avoid hardcoded dates aging out of aggregateThreads' maxAgeDays window */
60+
const today = new Date();
61+
const daysAgo = (n: number) => {
62+
const d = new Date(today);
63+
d.setDate(d.getDate() - n);
64+
return d.toISOString().split("T")[0];
65+
};
66+
const daysAgoISO = (n: number) => {
67+
const d = new Date(today);
68+
d.setDate(d.getDate() - n);
69+
return d.toISOString();
70+
};
71+
5972
/** Build a minimal ThreadObject with sensible defaults */
6073
function makeThread(overrides: Partial<ThreadObject> = {}): ThreadObject {
6174
return {
6275
id: overrides.id ?? generateThreadId(),
6376
text: overrides.text ?? "Test thread text",
6477
status: overrides.status ?? "open",
65-
created_at: overrides.created_at ?? "2026-02-09T00:00:00.000Z",
78+
created_at: overrides.created_at ?? daysAgoISO(1),
6679
...(overrides.resolved_at && { resolved_at: overrides.resolved_at }),
6780
...(overrides.source_session && { source_session: overrides.source_session }),
6881
...(overrides.resolved_by_session && { resolved_by_session: overrides.resolved_by_session }),
@@ -83,10 +96,10 @@ function makeSupabaseThreadRow(overrides: Record<string, unknown> = {}) {
8396
status: overrides.status ?? "active",
8497
thread_class: overrides.thread_class ?? "backlog",
8598
vitality_score: overrides.vitality_score ?? 1.0,
86-
last_touched_at: overrides.last_touched_at ?? "2026-02-09T00:00:00.000Z",
99+
last_touched_at: overrides.last_touched_at ?? daysAgoISO(1),
87100
touch_count: overrides.touch_count ?? 1,
88-
created_at: overrides.created_at ?? "2026-02-09T00:00:00.000Z",
89-
updated_at: overrides.updated_at ?? "2026-02-09T00:00:00.000Z",
101+
created_at: overrides.created_at ?? daysAgoISO(1),
102+
updated_at: overrides.updated_at ?? daysAgoISO(1),
90103
resolved_at: overrides.resolved_at ?? null,
91104
resolution_note: overrides.resolution_note ?? null,
92105
source_session: overrides.source_session ?? null,
@@ -379,7 +392,7 @@ describe("Cache Sync: local cache used when Supabase offline", () => {
379392
const sessions = [
380393
{
381394
id: "s1",
382-
session_date: "2026-02-09",
395+
session_date: daysAgo(1),
383396
close_compliance: { close_type: "standard" },
384397
open_threads: localThreads,
385398
},
@@ -400,7 +413,7 @@ describe("Format Compat: list_threads returns same format as file-only version",
400413
thread_id: "t-compat01",
401414
text: "Compat check thread",
402415
status: "active",
403-
created_at: "2026-02-08T12:00:00.000Z",
416+
created_at: daysAgoISO(2),
404417
}),
405418
];
406419

@@ -452,7 +465,7 @@ describe("Format Compat: mixed format threads normalized before Supabase write",
452465
id: "t-existing",
453466
text: "Already a ThreadObject",
454467
status: "open",
455-
created_at: "2026-02-09T00:00:00.000Z",
468+
created_at: daysAgoISO(1),
456469
};
457470

458471
const raw: (string | ThreadObject)[] = [plainString, jsonNoteFormat, threadObject];
@@ -486,7 +499,7 @@ describe("Format Compat: resolved threads stay resolved across sessions (zombie
486499
id: "t-zombie01",
487500
text: "Was resolved",
488501
status: "resolved",
489-
resolved_at: "2026-02-08T12:00:00.000Z",
502+
resolved_at: daysAgoISO(2),
490503
}),
491504
];
492505

@@ -504,22 +517,22 @@ describe("Format Compat: resolved threads stay resolved across sessions (zombie
504517

505518
expect(merged).toHaveLength(1);
506519
expect(merged[0].status).toBe("resolved");
507-
expect(merged[0].resolved_at).toBe("2026-02-08T12:00:00.000Z");
520+
expect(merged[0].resolved_at).toBe(daysAgoISO(2));
508521
});
509522

510523
it("should also prevent zombies via aggregateThreads deduplication", () => {
511524
const sessions = [
512525
{
513526
id: "s-recent",
514-
session_date: "2026-02-09",
527+
session_date: daysAgo(1),
515528
close_compliance: { close_type: "standard" },
516529
open_threads: [
517-
makeThread({ id: "t-zombie02", text: "Resolved thread", status: "resolved", resolved_at: "2026-02-09T00:00:00.000Z" }),
530+
makeThread({ id: "t-zombie02", text: "Resolved thread", status: "resolved", resolved_at: daysAgoISO(1) }),
518531
],
519532
},
520533
{
521534
id: "s-older",
522-
session_date: "2026-02-08",
535+
session_date: daysAgo(2),
523536
close_compliance: { close_type: "standard" },
524537
open_threads: [
525538
makeThread({ id: "t-zombie02", text: "Resolved thread", status: "open" }),
@@ -545,15 +558,15 @@ describe("Edge Case: concurrent create_thread with same text deduplicates", () =
545558
const sessions = [
546559
{
547560
id: "s1",
548-
session_date: "2026-02-09",
561+
session_date: daysAgo(1),
549562
close_compliance: { close_type: "standard" },
550563
open_threads: [
551564
makeThread({ id: "t-dup0001", text: "Investigate auth timeout issue" }),
552565
],
553566
},
554567
{
555568
id: "s2",
556-
session_date: "2026-02-08",
569+
session_date: daysAgo(2),
557570
close_compliance: { close_type: "standard" },
558571
open_threads: [
559572
makeThread({ id: "t-dup0002", text: "Investigate auth timeout issue" }),
@@ -782,7 +795,7 @@ describe("Local file persistence roundtrip with Supabase-sourced data", () => {
782795
id: "t-round002",
783796
text: "Resolved roundtrip thread",
784797
status: "resolved",
785-
resolved_at: "2026-02-09T10:00:00.000Z",
798+
resolved_at: daysAgoISO(1),
786799
resolution_note: "Done",
787800
resolved_by_session: "session-rt-2",
788801
}),
@@ -795,7 +808,7 @@ describe("Local file persistence roundtrip with Supabase-sourced data", () => {
795808
expect(loaded[0].id).toBe("t-round001");
796809
expect(loaded[0].source_session).toBe("session-rt-1");
797810
expect(loaded[1].status).toBe("resolved");
798-
expect(loaded[1].resolved_at).toBe("2026-02-09T10:00:00.000Z");
811+
expect(loaded[1].resolved_at).toBe(daysAgoISO(1));
799812
expect(loaded[1].resolution_note).toBe("Done");
800813
});
801814
});

0 commit comments

Comments
 (0)