From c6e0994c6e67b349b749a4f0f6f4cf3f90430dfa Mon Sep 17 00:00:00 2001 From: iza <59828082+izadoesdev@users.noreply.github.com> Date: Wed, 9 Sep 2026 03:11:00 +0300 Subject: [PATCH] fix(insights): preserve canonical replies before public pages --- apps/insights/src/business-context.test.ts | 32 ++++++++++++++++++++++ apps/insights/src/business-context.ts | 5 ++++ 2 files changed, 37 insertions(+) diff --git a/apps/insights/src/business-context.test.ts b/apps/insights/src/business-context.test.ts index 21786fdd6..50a21f619 100644 --- a/apps/insights/src/business-context.test.ts +++ b/apps/insights/src/business-context.test.ts @@ -425,6 +425,38 @@ describe("saved organization business context", () => { }; const input = { scope, asOf, allowRefresh: false }; + it("keeps canonical replies ahead of extra public pages before selection", async () => { + const pages = Array.from({ length: 4 }, (_, index) => ({ + ...page, + id: `page-${index}`, + url: `https://example.com/${index || ""}`, + content: "Public background. ".padEnd(4000, "."), + })); + const result = await loadWebsiteBusinessProfile( + input, + dependencies({ + loadProfile: async () => context(pages), + readReplies: async () => [statement], + readOrganization: async () => ({ profile, generation: null }), + }) + ); + + expect(result.sources).toContainEqual(statement); + expect(result.sources[0]).toMatchObject({ + kind: "organization_profile", + content: profile.content, + }); + expect(result.sources[1]).toEqual(statement); + expect(result.sources.filter((source) => source.kind === "website")).toEqual( + pages.slice(0, 3) + ); + expect( + result.sources.reduce((total, source) => total + source.content.length, 0) + ).toBeLessThanOrEqual(16_000); + expect(result.status).toBe("partial"); + expect(businessContextSchema.parse(result)).toEqual(result); + }); + it("keeps the complete 12k saved profile and canonical correction ahead of a full homepage", async () => { const content = "A".repeat(4000) + "B".repeat(4000) + "C".repeat(4000); const result = await loadWebsiteBusinessProfile( diff --git a/apps/insights/src/business-context.ts b/apps/insights/src/business-context.ts index a4ebace40..3e0a30f8c 100644 --- a/apps/insights/src/business-context.ts +++ b/apps/insights/src/business-context.ts @@ -300,6 +300,11 @@ async function reconcileReplies( sources: eligible, issues: issue ? [issue] : [], }; + // Shared pages must not consume the budget before canonical replies. + // Exact-subject recall still keeps relevance ahead of recent replies below. + if (!input.subjectKey) { + return mergeBusinessContext(context, raw); + } const canonical = new Map(eligible.map((reply) => [reply.id, reply])); return mergeBusinessContext(raw, { ...context,