|
|
|
@@ -23,8 +23,8 @@ test("research revisions share the authentication database and preserve replay l
|
|
|
|
|
for (let i = 0; i < 20; i++) consumeCode(config, "invalid");
|
|
|
|
|
assert.equal(consumeCode(config, "invalid"), "limited");
|
|
|
|
|
const initial = readResearchSnapshot();
|
|
|
|
|
assert.equal(initial.companies.length, 1021);
|
|
|
|
|
assert.equal(initial.evidence.length, 1215);
|
|
|
|
|
assert.equal(initial.companies.length, 1023);
|
|
|
|
|
assert.equal(initial.evidence.length, 1318);
|
|
|
|
|
assert.equal(initial.observations.length, 189);
|
|
|
|
|
assert.deepEqual(initial.candidateBatches, seed.candidateBatches, "candidate gaps persist in the same database metadata");
|
|
|
|
|
assert.deepEqual(initial.directoryRechecks, seed.directoryRechecks, "follow-up classifications persist without rewriting the discovery audit");
|
|
|
|
@@ -64,9 +64,9 @@ test("research validation rejects broken evidence and unsafe source links", () =
|
|
|
|
|
|
|
|
|
|
test("reviews link explicit companies without turning global or excluded cases into companies", () => {
|
|
|
|
|
const snapshot = structuredClone(seed) as ResearchSnapshot;
|
|
|
|
|
assert.equal(snapshot.reviews.filter((r) => r.scope === "companies").length, 54);
|
|
|
|
|
assert.equal(snapshot.reviews.filter((r) => r.scope === "dataset").length, 8);
|
|
|
|
|
assert.equal(snapshot.reviews.filter((r) => r.scope === "excluded-candidate").length, 16);
|
|
|
|
|
assert.equal(snapshot.reviews.filter((r) => r.scope === "companies").length, 60);
|
|
|
|
|
assert.equal(snapshot.reviews.filter((r) => r.scope === "dataset").length, 10);
|
|
|
|
|
assert.equal(snapshot.reviews.filter((r) => r.scope === "excluded-candidate").length, 31);
|
|
|
|
|
const review = snapshot.reviews.find((r) => r.id === "R4")!;
|
|
|
|
|
assert.deepEqual(reviewCompanyIds(snapshot, review), ["AI007", "AI013", "AI021", "AI034"]);
|
|
|
|
|
assert.deepEqual(reviewCompanyIds(snapshot, snapshot.reviews.find((r) => r.id === "CN-R-PSI")!), []);
|
|
|
|
@@ -85,11 +85,11 @@ test("reviews link explicit companies without turning global or excluded cases i
|
|
|
|
|
test("disclosure counts exclude client income, biographies, targets and duplicate milestones", () => {
|
|
|
|
|
const snapshot = seed as ResearchSnapshot;
|
|
|
|
|
const summary = categorySummary(snapshot);
|
|
|
|
|
assert.equal(summary.reduce((n, c) => n + c.count, 0), 1021);
|
|
|
|
|
assert.equal(summary.reduce((n, c) => n + c.count, 0), 1023);
|
|
|
|
|
assert.equal(summary.reduce((n, c) => n + c.self, 0), 26);
|
|
|
|
|
assert.equal(summary.reduce((n, c) => n + c.estimate, 0), 1);
|
|
|
|
|
assert.equal(summary.reduce((n, c) => n + c.platform, 0), 16);
|
|
|
|
|
assert.equal(summary.reduce((n, c) => n + c.unknown, 0), 978);
|
|
|
|
|
assert.equal(summary.reduce((n, c) => n + c.unknown, 0), 980);
|
|
|
|
|
assert.equal(snapshot.companies.find((c) => c.name === "Rork")?.revenueStatus, "unknown");
|
|
|
|
|
assert.equal(snapshot.companies.find((c) => c.name === "Result")?.revenueStatus, "unknown");
|
|
|
|
|
assert.ok(snapshot.observations.filter((o) => o.selection === "signal").every((o) => o.scope === "公司整体"));
|
|
|
|
@@ -97,7 +97,7 @@ test("disclosure counts exclude client income, biographies, targets and duplicat
|
|
|
|
|
|
|
|
|
|
test("technical reviews keep accessible materials separate from tested capabilities", () => {
|
|
|
|
|
const snapshot = structuredClone(seed) as ResearchSnapshot;
|
|
|
|
|
assert.equal(snapshot.companies.filter((c) => c.technicalReview).length, 14);
|
|
|
|
|
assert.equal(snapshot.companies.filter((c) => c.technicalReview).length, 16);
|
|
|
|
|
assert.equal(snapshot.companies.filter((c) => c.technicalReview?.level === "public-artifact").length, 6);
|
|
|
|
|
assert.equal(snapshot.companies.filter((c) => c.technicalReview?.level === "independent-test").length, 1);
|
|
|
|
|
assert.equal(snapshot.companies.find((c) => c.id === "AI051")?.revenueStatus, "unknown");
|
|
|
|
@@ -151,7 +151,14 @@ test("retracted ARR and projected margins remain excluded", () => {
|
|
|
|
|
const forecast = snapshot.observations.find((o) => o.kind === "非GAAP毛利率预期")!;
|
|
|
|
|
assert.equal(forecast.selection, "excluded");
|
|
|
|
|
const peec = snapshot.companies.find((c) => c.name === "Peec AI")!;
|
|
|
|
|
assert.equal(peec.teamBound, ">");
|
|
|
|
|
assert.equal(peec.team, 100);
|
|
|
|
|
assert.equal(peec.teamBound, "≥");
|
|
|
|
|
const currentTeam = snapshot.observations.find((o) => o.id === "PEEC-JOB-TEAM")!;
|
|
|
|
|
assert.equal(currentTeam.value, peec.team);
|
|
|
|
|
assert.equal(currentTeam.bound, peec.teamBound);
|
|
|
|
|
const historicalTeam = snapshot.observations.find((o) => o.id === "O067")!;
|
|
|
|
|
assert.equal(historicalTeam.value, 70);
|
|
|
|
|
assert.equal(historicalTeam.bound, ">");
|
|
|
|
|
assert.equal(snapshot.observations.filter((o) => o.company === peec.id && o.selection === "signal").length, 1);
|
|
|
|
|
assert.ok(snapshot.observations.some((o) => o.company === peec.id && o.selection === "historical-estimate"));
|
|
|
|
|
});
|
|
|
|
@@ -279,7 +286,7 @@ test("annual launch archives exclude older companies only with evidence and reus
|
|
|
|
|
assert.equal(batch.complete, false);
|
|
|
|
|
assert.equal(batch.records.length, 19);
|
|
|
|
|
const older = batch.records.filter((r) => r.status === "outside-cohort");
|
|
|
|
|
assert.equal(older.length, 10);
|
|
|
|
|
assert.equal(older.length, 16);
|
|
|
|
|
assert.ok(older.every((r) => !r.companyId && r.evidenceIds?.length));
|
|
|
|
|
assert.equal(batch.records.find((r) => r.name === "Trace")?.companyId, "YC30687");
|
|
|
|
|
const trace = snapshot.companies.find((c) => c.id === "YC30687")!;
|
|
|
|
@@ -300,7 +307,7 @@ test("unreconciled directory financials remain source reviews instead of income
|
|
|
|
|
assert.ok(review.evidenceIds.includes("PH-TANA-DR"));
|
|
|
|
|
assert.equal(reviewCompanyIds(snapshot, review).length, 0);
|
|
|
|
|
assert.ok(!snapshot.observations.some((o) => o.evidence === "PH-TANA-DR"));
|
|
|
|
|
assert.equal(snapshot.candidateBatches!.flatMap((b) => b.records).filter((r) => r.status === "pending-year").length, 17);
|
|
|
|
|
assert.equal(snapshot.candidateBatches!.flatMap((b) => b.records).filter((r) => r.status === "pending-year").length, 11);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("product pivots and founder histories do not become new company years or current revenue", () => {
|
|
|
|
@@ -335,7 +342,7 @@ test("Chinese discovery entries preserve unread articles and use separate primar
|
|
|
|
|
assert.equal(batch.records.length, 4);
|
|
|
|
|
assert.ok(batch.records.every((row) => row.kind === "company" && row.profileStatus === "unavailable"));
|
|
|
|
|
assert.equal(batch.records.filter((row) => row.status === "linked").length, 2);
|
|
|
|
|
assert.equal(batch.records.find((row) => row.name === "Utopai")?.status, "pending-year");
|
|
|
|
|
assert.equal(batch.records.find((row) => row.name === "Utopai")?.status, "outside-cohort");
|
|
|
|
|
assert.ok(!snapshot.observations.some((o) => ["PS-CODE", "SG-START", "SG-APR", "SSI-HISTORY"].includes(o.evidence)), "task costs, investment, capacity and financing are not revenue");
|
|
|
|
|
const prism = snapshot.companies.find((c) => c.id === "AI075")!;
|
|
|
|
|
assert.equal(prism.team, null, "a team range or linked employees must not become exact headcount");
|
|
|
|
|