Skip to content

Commit 437597e

Browse files
theboycoderclaude
andauthored
fix(verdict): a public suffix is not a domain (#1605)
classifyPage decides "offsite-redirect" by comparing the registrable domain of the requested host against the final one, and computed it as `parts.slice(-2)`. That reads every Brazilian host as "com.br", so a redirect from one .com.br site to an unrelated one compared EQUAL, the hop was never flagged, and a page that had moved to somebody else's business went on being judged on its own content — a false LIVE, the opposite of the false deaths this file exists to prevent. Same shape for co.uk, com.au, co.jp and the rest. src/lib/partner-project-identity.ts already carries the suffix list and its tests, so this drops the local copy and calls registrableDomain. Third place in the codebase to hit it this week; scripts/data/backfill-deployment.ts has its own correct copy, and scripts/eval/engine-b-sweeps.ts still has a naive one whose inputs I have not checked. Exposure today is small and worth stating: three directory rows sit on .com.br and none on the other multi-label suffixes. The cost of the bug is not its current blast radius — it is that the failure is silent and lands on the "still live" side. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
1 parent 043dd87 commit 437597e

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

src/lib/__tests__/page-verdict.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,33 @@ describe("classifyPage — a 200 is not a business", () => {
6060
expect(classifyPage({}).verdict).toBe("unknown");
6161
});
6262
});
63+
64+
describe("offsite redirect across a multi-label public suffix", () => {
65+
it("flags a hop between two different .com.br sites", () => {
66+
// `parts.slice(-2)` read both of these as "com.br", compared them equal,
67+
// and let a page that had moved to somebody else's business go on being
68+
// judged on its own content.
69+
const v = classifyPage({
70+
status: 200,
71+
requestedHost: "bwbi.com.br",
72+
finalHost: "someoneelse.com.br",
73+
title: "Outra empresa",
74+
metaDescription: null,
75+
bodyText: null,
76+
} as never);
77+
expect(v.verdict).toBe("offsite-redirect");
78+
expect(v.reason).toBe("bwbi.com.br → someoneelse.com.br");
79+
});
80+
81+
it("does not flag a www or subdomain hop inside one .com.br site", () => {
82+
const v = classifyPage({
83+
status: 200,
84+
requestedHost: "www.bwbi.com.br",
85+
finalHost: "app.bwbi.com.br",
86+
title: "BWB",
87+
metaDescription: null,
88+
bodyText: null,
89+
} as never);
90+
expect(v.verdict).not.toBe("offsite-redirect");
91+
});
92+
});

src/lib/page-verdict.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
* a non-product verdict, because this feeds a basis DOWNGRADE (never a
1919
* status change) and a false "parked" costs a live project its evidence.
2020
*/
21+
import { registrableDomain } from "./partner-project-identity";
2122

2223
export type PageVerdict =
2324
| "product"
@@ -48,13 +49,19 @@ const SCAFFOLD =
4849
const PLACEHOLDER =
4950
/\b(coming soon|under construction|site is under construction|we('| a)re changing home|changing home|home changing|launching soon|stay tuned|join (our|the) waitlist|waitlist only)\b/i;
5051

52+
/** The offsite-redirect test compares these, so a wrong answer here is a wrong
53+
* VERDICT. `parts.slice(-2)` read every Brazilian host as "com.br", so a
54+
* redirect from one .com.br site to an unrelated one compared EQUAL and the
55+
* hop was never flagged — a page that had moved to somebody else's business
56+
* went on being judged on its own content. Same shape for co.uk, com.au and
57+
* the rest. src/lib/partner-project-identity.ts already carries the suffix
58+
* list and its tests; three directory rows sit on .com.br today. */
5159
function registrable(host: string | null | undefined): string {
5260
const h = (host ?? "")
5361
.toLowerCase()
5462
.replace(/^www\./, "")
5563
.replace(/:\d+$/, "");
56-
const parts = h.split(".").filter(Boolean);
57-
return parts.length >= 2 ? parts.slice(-2).join(".") : h;
64+
return registrableDomain(h) || h;
5865
}
5966

6067
/** Classify what a URL served. See the file header for why this exists. */

0 commit comments

Comments
 (0)