Merge pull request '扩展 AI 公司研究并修复收入统计表布局' (#31) from codex/ai-research-cn-sme into main
Verify and deploy Tabularium / verify-and-deploy (push) Successful in 9m0s
Verify and deploy Tabularium / verify-and-deploy (push) Successful in 9m0s
Reviewed-on: #31
This commit was merged in pull request #31.
This commit is contained in:
@@ -23,9 +23,9 @@ 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, 1029);
|
||||
assert.equal(initial.evidence.length, 1412);
|
||||
assert.equal(initial.observations.length, 192);
|
||||
assert.equal(initial.companies.length, 1051);
|
||||
assert.equal(initial.evidence.length, 1858);
|
||||
assert.equal(initial.observations.length, 237);
|
||||
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");
|
||||
assert.deepEqual(readResearchSnapshot(), initial, "reopening does not duplicate records");
|
||||
@@ -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, 74);
|
||||
assert.equal(snapshot.reviews.filter((r) => r.scope === "dataset").length, 10);
|
||||
assert.equal(snapshot.reviews.filter((r) => r.scope === "excluded-candidate").length, 37);
|
||||
assert.equal(snapshot.reviews.filter((r) => r.scope === "companies").length, 115);
|
||||
assert.equal(snapshot.reviews.filter((r) => r.scope === "dataset").length, 12);
|
||||
assert.equal(snapshot.reviews.filter((r) => r.scope === "excluded-candidate").length, 44);
|
||||
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,20 +85,24 @@ 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), 1029);
|
||||
assert.equal(summary.reduce((n, c) => n + c.self, 0), 28);
|
||||
assert.equal(summary.reduce((n, c) => n + c.count, 0), 1051);
|
||||
assert.equal(summary.reduce((n, c) => n + c.self, 0), 43);
|
||||
assert.equal(summary.reduce((n, c) => n + c.estimate, 0), 2);
|
||||
assert.equal(summary.reduce((n, c) => n + c.platform, 0), 16);
|
||||
assert.equal(summary.reduce((n, c) => n + c.unknown, 0), 983);
|
||||
assert.equal(summary.reduce((n, c) => n + c.platform, 0), 19);
|
||||
assert.equal(summary.reduce((n, c) => n + c.unknown, 0), 987);
|
||||
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 === "公司整体"));
|
||||
const arena = snapshot.observations.find((o) => o.id === "COARENA-O-CUMULATIVE")!;
|
||||
assert.equal(arena.selection, "historical", "cumulative launch revenue is not a recurring company-wide signal");
|
||||
assert.equal(arena.comparisonGroup, null);
|
||||
assert.ok(arena.metric !== "mrr" && arena.metric !== "arr", "a two-week cumulative figure cannot become MRR or ARR");
|
||||
});
|
||||
|
||||
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, 28);
|
||||
assert.equal(snapshot.companies.filter((c) => c.technicalReview?.level === "public-artifact").length, 7);
|
||||
assert.equal(snapshot.companies.filter((c) => c.technicalReview).length, 59);
|
||||
assert.equal(snapshot.companies.filter((c) => c.technicalReview?.level === "public-artifact").length, 9);
|
||||
assert.equal(snapshot.companies.filter((c) => c.technicalReview?.level === "independent-test").length, 1);
|
||||
assert.equal(snapshot.companies.find((c) => c.id === "AI051")?.revenueStatus, "unknown");
|
||||
assert.match(snapshot.companies.find((c) => c.id === "AI051")!.technicalReview!.testScope!, /Sep 2026/);
|
||||
@@ -137,6 +141,43 @@ test("ambiguous ARR claims retain currency, precision and attribution limits", (
|
||||
assert.equal(snapshot.companies.find((c) => c.id === "AI070")?.revenueStatus, "unknown");
|
||||
assert.equal(snapshot.observations.filter((o) => o.company === "AI070").length, 0,
|
||||
"unreadable announcement summaries do not become numeric ARR");
|
||||
const waitlist = snapshot.observations.find((o) => o.id === "SR25-O-OMI-WAITLIST")!;
|
||||
assert.equal(waitlist.selection, "excluded", "waitlist conversions are not paid recurring revenue");
|
||||
assert.equal(snapshot.companies.find((c) => c.id === waitlist.company)?.revenueStatus, "unknown");
|
||||
const bluma = snapshot.observations.find((o) => o.id === "BLUMA-O-HISTORICAL-MRR")!;
|
||||
assert.equal(bluma.selection, "historical");
|
||||
assert.ok(bluma.unit !== "USD" && !bluma.observedAt && bluma.comparisonGroup === null);
|
||||
const native = snapshot.observations.find((o) => o.id === "NATIVE-O-ARR-CLAIM")!;
|
||||
assert.equal(native.selection, "crosscheck");
|
||||
assert.ok(!native.metric && !native.observedAt && native.comparisonGroup === null);
|
||||
const marketVolume = snapshot.observations.find((o) => o.id === "PALISADE-O-GMV")!;
|
||||
assert.equal(marketVolume.selection, "excluded", "customer GMV must not establish company revenue or ARR");
|
||||
assert.equal(snapshot.companies.find((c) => c.id === marketVolume.company)?.revenueStatus, "unknown");
|
||||
const pingo = snapshot.observations.find((o) => o.id === "PINGO-O-MRR-JUL25")!;
|
||||
assert.equal(pingo.selection, "historical", "a July 2025 self-report is not a current payment-platform sample");
|
||||
assert.ok(pingo.unit !== "USD" && !pingo.observedAt && pingo.comparisonGroup === null);
|
||||
const designService = snapshot.observations.find((o) => o.id === "SEMIOTIC-O-LAUNCH-REVENUE")!;
|
||||
assert.equal(designService.selection, "historical");
|
||||
assert.ok(!designService.metric && designService.comparisonGroup === null, "four-week service revenue is not MRR or ARR");
|
||||
const restaurantAdoption = snapshot.observations.filter((o) => o.company === "YC32815");
|
||||
assert.ok(restaurantAdoption.length > 0 && restaurantAdoption.every((o) => o.selection === "adoption" && !o.metric),
|
||||
"restaurant count and list price must not produce an invented MRR observation");
|
||||
const fishPilot = snapshot.observations.find((o) => o.id === "OCTAPULSE-O-CONTRACT")!;
|
||||
assert.equal(fishPilot.selection, "excluded", "a paid pilot or annual contract does not establish recognized recurring revenue");
|
||||
assert.equal(snapshot.companies.find((c) => c.id === fishPilot.company)?.revenueStatus, "unknown");
|
||||
assert.equal(fishPilot.comparisonGroup, null);
|
||||
assert.notEqual(fishPilot.unit, "USD", "six-figure wording does not establish the currency");
|
||||
assert.ok(!fishPilot.metric && !fishPilot.observedAt, "the publication date is not the financial reporting date");
|
||||
const cedar = snapshot.observations.filter((o) => o.company === "AI102");
|
||||
assert.ok(cedar.every((o) => o.selection !== "signal" && o.comparisonGroup === null),
|
||||
"closed and contracted amounts without recognition or period do not establish ARR");
|
||||
assert.equal(snapshot.observations.find((o) => o.id === "SR25-O-LOOPS-CUSTOMER-SALES")?.selection, "excluded");
|
||||
const portfolio = snapshot.observations.filter((o) => o.company === "AI100");
|
||||
assert.deepEqual(portfolio.filter((o) => o.selection === "signal").map((o) => o.id), ["SR25-O-DRS-PORTFOLIO"],
|
||||
"a product milestone must not be added to its company portfolio as another company");
|
||||
assert.ok(snapshot.observations.filter((o) => o.id.startsWith("SR25-O-")).every((o) =>
|
||||
o.unit !== "USD" && !o.metric && !o.observedAt && o.comparisonGroup === null),
|
||||
"access dates and dollar symbols must not invent dated USD income samples");
|
||||
});
|
||||
|
||||
// Retractions and forecasts must stay visible for review without becoming revenue signals.
|
||||
@@ -179,8 +220,18 @@ test("directory coverage reconciles every candidate and keeps profile-only incom
|
||||
assert.ok(company.profileOnly || company.directoryOrigin === "yc-2025-2026");
|
||||
assert.equal(company.url, row.source);
|
||||
if (company.profileOnly) assert.equal(company.revenueStatus, "unknown");
|
||||
assert.equal(company.year, row.foundedYear);
|
||||
assert.ok([2025, 2026].includes(company.year!));
|
||||
if (company.id === "YC31370") {
|
||||
assert.equal(row.foundedYear, 2025, "original discovery remains unchanged");
|
||||
assert.equal(company.year, null, "a pivot year cannot settle the company founding year");
|
||||
assert.ok(snapshot.reviews.some((review) => review.id === "DAYJOB-R-COHORT" && review.companyIds?.includes(company.id)));
|
||||
} else if (company.id === "YC36279") {
|
||||
assert.equal(row.foundedYear, 2026, "original Native discovery remains unchanged");
|
||||
assert.equal(company.year, null, "a model launch and YC date cannot settle the older business founding year");
|
||||
assert.ok(snapshot.reviews.some((review) => review.id === "NATIVE-R-COHORT" && review.companyIds?.includes(company.id)));
|
||||
} else {
|
||||
assert.equal(company.year, row.foundedYear);
|
||||
assert.ok([2025, 2026].includes(company.year!));
|
||||
}
|
||||
}
|
||||
const invalid = structuredClone(snapshot);
|
||||
invalid.coverage!.newProfiles += 1;
|
||||
@@ -194,6 +245,20 @@ test("directory coverage reconciles every candidate and keeps profile-only incom
|
||||
assert.throws(() => validateResearch(lostOrigin), /coverage accounting/);
|
||||
});
|
||||
|
||||
test("business pivots and procurement volume do not become comparable startup ARR", () => {
|
||||
const snapshot = seed as ResearchSnapshot;
|
||||
const dayjob = snapshot.companies.find((company) => company.id === "YC31370")!;
|
||||
assert.equal(dayjob.year, null);
|
||||
assert.equal(dayjob.directoryOrigin, "yc-2025-2026");
|
||||
const milestones = snapshot.observations.filter((observation) => observation.company === dayjob.id);
|
||||
assert.deepEqual(milestones.filter((observation) => observation.selection === "crosscheck").map((observation) => observation.value).sort(), [496000, 653000]);
|
||||
assert.ok(milestones.every((observation) => observation.comparisonGroup === null && !observation.metric && !observation.observedAt));
|
||||
assert.ok(milestones.filter((observation) => [150000, 800000].includes(observation.value)).every((observation) => observation.selection === "excluded"));
|
||||
const procurement = snapshot.observations.find((observation) => observation.id === "SAUDARA-O-SOURCING")!;
|
||||
assert.equal(procurement.selection, "excluded");
|
||||
assert.equal(procurement.comparisonGroup, null);
|
||||
});
|
||||
|
||||
test("income descriptions report sample dispersion and maximum-value sensitivity", () => {
|
||||
const stats = describeIncome([100, 200, 300])!;
|
||||
assert.equal(stats.mean, 200);
|
||||
@@ -215,14 +280,21 @@ test("income descriptions report sample dispersion and maximum-value sensitivity
|
||||
test("platform samples exclude stale data and keep ARR, estimates and collections separate", () => {
|
||||
const snapshot = seed as ResearchSnapshot;
|
||||
const recent = platformIncomeSample(snapshot, { windowDays: 7 });
|
||||
assert.equal(recent.points.length, 14);
|
||||
assert.equal(recent.excluded.length, 3);
|
||||
assert.equal(recent.points.length, 16);
|
||||
assert.equal(recent.excluded.length, 4);
|
||||
assert.ok(recent.points.every((p) => p.observation.metric === "mrr" && p.observation.selection === "platform"));
|
||||
assert.deepEqual(new Set(recent.excluded.map((p) => p.observation.company)), new Set(["AI016", "MR013", "MR014"]));
|
||||
assert.deepEqual(new Set(recent.excluded.map((p) => p.observation.company)), new Set(["AI016", "MR013", "MR014", "MR017"]));
|
||||
assert.ok(recent.points.some((p) => p.company.name === "TrackAI" && p.observation.connectionExpired), "dated recent value is not a claim of active connection");
|
||||
const older = platformIncomeSample(snapshot, { windowDays: 90 });
|
||||
assert.equal(older.points.length, 15);
|
||||
assert.equal(older.points.length, 18);
|
||||
assert.ok(older.points.some((p) => p.company.id === "AI016"));
|
||||
assert.ok(!recent.points.some((p) => p.company.id === "MR017"));
|
||||
assert.ok(older.points.some((p) => p.company.id === "MR017" && p.observation.connectionExpired),
|
||||
"an expired connection retains its historical observation date in the wider window");
|
||||
assert.equal(recent.points.find((p) => p.company.id === "MR018")?.value, 67864,
|
||||
"an older Markdown cache must not replace or duplicate the later web snapshot");
|
||||
assert.equal(recent.points.find((p) => p.company.id === "MR019")?.value, 65431,
|
||||
"period-table revenue and revenue snapshots must not replace MRR");
|
||||
const scaled = platformIncomeSample(snapshot, { windowDays: 7, annualize: true });
|
||||
const monthlyGroups = groupIncome(recent.points);
|
||||
const annualGroups = groupIncome(scaled.points);
|
||||
@@ -307,7 +379,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, 10);
|
||||
assert.equal(snapshot.candidateBatches!.flatMap((b) => b.records).filter((r) => r.status === "pending-year").length, 18);
|
||||
});
|
||||
|
||||
test("product pivots and founder histories do not become new company years or current revenue", () => {
|
||||
@@ -320,6 +392,15 @@ test("product pivots and founder histories do not become new company years or cu
|
||||
assert.equal(candidate.companyId, pivot.id);
|
||||
assert.ok(!platformIncomeSample(snapshot, { windowDays: null }).points.some((point) => point.company.id === pivot.id));
|
||||
assert.ok(!snapshot.observations.some((o) => ["PH-FUNDRAISLY-ABOUT", "LF-PIVOT", "LF-HISTORY"].includes(o.evidence)), "other ventures' ARR, users and funding must not transfer");
|
||||
const candidates = snapshot.candidateBatches!.flatMap((b) => b.records);
|
||||
assert.equal(candidates.find((r) => r.id === "PH26-12")?.status, "outside-cohort",
|
||||
"a brand iteration with an earlier business chain is not a new company");
|
||||
const happycapy = candidates.find((r) => r.id === "PH26-04")!;
|
||||
assert.ok(happycapy.evidenceIds?.includes("FOLLOWUP-CAPY-ACRA"));
|
||||
assert.equal(happycapy.status, "pending-year", "a seller's registration does not establish a new global business");
|
||||
assert.equal(happycapy.companyId, undefined);
|
||||
assert.ok(!snapshot.observations.some((o) => o.evidence.startsWith("FOLLOWUP-")),
|
||||
"registration, funding, app-store prices and client amounts are not company income");
|
||||
});
|
||||
|
||||
test("follow-up evidence can admit an uncertain directory candidate without rewriting its original status", () => {
|
||||
|
||||
Reference in New Issue
Block a user