Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions lib/daemon/__tests__/branch-enrich-heal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,22 @@ describe("branch:enrich heals an entry whose ticket never resolved", () => {
expect(res.source).toBe("cache");
});

test("healing forces a refresh, since enrichBranches also short-circuits on a cached branch", async () => {
let opts: any = null;
const ctx = makeCtx({
b: { linearId: "ACME-1", ticket: null, mr: null, fetchedAt: Date.now() - HOUR },
});
await createCacheHandlers(ctx)["branch:enrich"]!({
branch: "b",
repoPath: "/tmp/x",
enrich: async (_b: unknown, _r: unknown, o: unknown) => {
opts = o;
ctx.cache.entries.b.ticket = { identifier: "ACME-1" };
},
});
expect(opts?.forceRefresh).toBe(true);
});

test("an id resolved but no ticket is INCOMPLETE, and re-enriches", async () => {
const ctx = makeCtx({
b: { linearId: "ACME-1", ticket: null, mr: null, fetchedAt: Date.now() - HOUR },
Expand Down
14 changes: 11 additions & 3 deletions lib/daemon/handlers/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,23 +70,31 @@ export function createCacheHandlers(ctx: HandlerContext): HandlerMap {
const repoPath = payload?.repoPath as string;
const remoteUrl = payload?.remoteUrl as string | undefined;
// Test seam: the enricher, so a test never reaches Linear or the forge.
const inject = payload?.enrich as (() => Promise<void>) | undefined;
const inject = payload?.enrich as
| ((b: unknown, r: unknown, o: unknown) => Promise<void>)
| undefined;

if (!branch) return { ok: false, error: "missing branch" };

const cached = ctx.cache.entries[branch];
const healing = !!cached;
if (cached && !isIncomplete(cached)) {
return { ok: true, data: cached, source: "cache" };
}

if (!repoPath) return { ok: false, error: "missing repoPath for cold enrichment" };

try {
// `forceRefresh` is load-bearing when healing: enrichBranches has its
// own all-cached short-circuit keyed on mere presence, so without it
// a re-enrich of a branch already in the store returns the same
// incomplete entry and never reaches the ticket lookup.
const opts = { silent: true, forceRefresh: healing };
if (inject) {
await inject();
await inject([{ path: repoPath, branch }], remoteUrl, opts);
} else {
const { enrichBranches } = await import("../../enrich.ts");
await enrichBranches([{ path: repoPath, branch }], remoteUrl, { silent: true });
await enrichBranches([{ path: repoPath, branch }], remoteUrl, opts);
}

// enrichBranches wrote through the same singleton store in this
Expand Down
Loading