141 lines
8.6 KiB
TypeScript
141 lines
8.6 KiB
TypeScript
import { buildServiceCurationPreview } from "../src/v1/curator/curator-store.js";
|
|
import type { CuratorIcpId } from "../src/v1/curator/icp-registry.js";
|
|
|
|
const ICP_IDS: CuratorIcpId[] = [
|
|
"student_recent_grad",
|
|
"intern",
|
|
"fresher_early_professional",
|
|
"experienced_professional",
|
|
"freelancer",
|
|
"founder",
|
|
"enterprise",
|
|
];
|
|
|
|
const LIVE_ROUTE_PREFIX: Record<string, string> = {
|
|
"courses-service": "/agents/courses",
|
|
"qscore-service": "/agents/qscore",
|
|
"resume-service": "/agents/resume",
|
|
"interview-service": "/agents/interview",
|
|
"roleplay-service": "/agents/roleplay",
|
|
"matchmaking-service": "/agents/matchmaking",
|
|
"social-branding-service": "/agents/social-branding",
|
|
};
|
|
|
|
const EXPECTED_FOCUS: Record<CuratorIcpId, string[]> = {
|
|
student_recent_grad: ["Start Your Story", "Discover Your Strengths", "Build Credibility", "Explore Opportunities", "Learn To Grow", "Grow Your Network", "Ready For Tomorrow"],
|
|
intern: ["Own Your Journey", "Show Your Growth", "Build Credibility", "Find Better Opportunities", "Strengthen Your Skills", "Expand Your Network", "Step Into Opportunity"],
|
|
fresher_early_professional: ["Start Strong", "Build Visibility", "Show Your Potential", "Find Better Opportunities", "Grow Your Skills", "Expand Your Network", "Launch Your Career"],
|
|
experienced_professional: ["Lead With Purpose", "Build Executive Presence", "Show Strategic Value", "Expand Your Influence", "Future-Proof Leadership", "Build Strategic Relationships", "Lead The Future"],
|
|
freelancer: ["Build Your Brand", "Package Your Value", "Earn Trust", "Find More Clients", "Grow Your Business", "Expand Your Network", "Scale Forward"],
|
|
founder: ["Own Your Vision", "Validate Your Idea", "Build Credibility", "Find Your Market", "Grow Smarter", "Build Your Network", "Launch Forward"],
|
|
enterprise: ["Know Your Workforce", "Measure Your Talent", "Strengthen Capability", "Build Better Hiring", "Grow Leaders", "Activate Growth", "Future Ready Enterprise"],
|
|
};
|
|
|
|
const EXPECTED_DAY_ONE_TITLES: Record<CuratorIcpId, string[]> = {
|
|
student_recent_grad: ["Claim Your Corner", "Know Your Number", "Resume Rescue", "Pitch Perfect"],
|
|
intern: ["Claim Your Corner", "Know Your Number", "Resume Reloaded", "Pitch Perfect"],
|
|
fresher_early_professional: ["Claim Your Corner", "Know Your Number", "Resume Rescue", "Pitch Perfect"],
|
|
experienced_professional: ["Own Your Executive Brand", "Know Your Number", "Executive Resume", "Executive Introduction"],
|
|
freelancer: ["Claim Your Corner", "Know Your Number", "Portfolio Rescue", "Client Pitch"],
|
|
founder: ["Build In Public", "Know Your Number", "Founder Story", "Founder Pitch"],
|
|
enterprise: ["Shape Your Story", "Know Your Workforce", "Capability Blueprint", "Leadership Kickoff"],
|
|
};
|
|
|
|
function assert(condition: unknown, message: string): asserts condition {
|
|
if (!condition) throw new Error(message);
|
|
}
|
|
|
|
function routeFor(route: string) {
|
|
return new URL(route, "https://app.sai-onchain.me");
|
|
}
|
|
|
|
async function main() {
|
|
const startDate = "2026-07-02";
|
|
const failures: string[] = [];
|
|
|
|
for (const icpId of ICP_IDS) {
|
|
const preview = await buildServiceCurationPreview({
|
|
userId: `curator-static-registry-test-${icpId}`,
|
|
startDate,
|
|
icpId,
|
|
userContext: { targetRole: "Product Manager" },
|
|
});
|
|
|
|
try {
|
|
assert(preview.version === "icp-v10-static", `${icpId}: expected static plan version`);
|
|
assert(preview.plan.days.length === 7, `${icpId}: expected 7 generated days`);
|
|
assert(preview.plan.calendarWeeks.length === 1, `${icpId}: expected one sprint-relative calendar week`);
|
|
|
|
const firstSevenFocus = preview.plan.days.slice(0, 7).map((day) => day.focus);
|
|
assert(JSON.stringify(firstSevenFocus) === JSON.stringify(EXPECTED_FOCUS[icpId]), `${icpId}: first 7 focus labels must match 7-day sprint doc`);
|
|
|
|
const dayOneTitles = preview.plan.days[0]?.tasks.map((task) => task.title);
|
|
assert(JSON.stringify(dayOneTitles) === JSON.stringify(EXPECTED_DAY_ONE_TITLES[icpId]), `${icpId}: day 1 task titles must match docs`);
|
|
|
|
for (const day of preview.plan.days) {
|
|
assert(day.generationStatus === "seeded", `${icpId} day ${day.dayIndex}: generation status must stay seeded`);
|
|
assert(!day.adaptationReason, `${icpId} day ${day.dayIndex}: adaptation reason should be absent`);
|
|
assert(day.tasks.length === 4, `${icpId} day ${day.dayIndex}: expected exactly 4 task objects`);
|
|
|
|
const taskIds = new Set(day.tasks.map((task) => task.id));
|
|
const stageIds = new Set(day.tasks.map((task) => task.stageId));
|
|
assert(taskIds.size === 4, `${icpId} day ${day.dayIndex}: task IDs must be unique`);
|
|
assert(stageIds.size === 4, `${icpId} day ${day.dayIndex}: stage IDs must be unique`);
|
|
|
|
for (const task of day.tasks) {
|
|
assert(task.missionId === "curator-sprint", `${icpId} ${task.id}: missionId mismatch`);
|
|
assert(task.missionInstanceId?.startsWith("curator-sprint:icp-v10-static:"), `${icpId} ${task.id}: missionInstanceId should use static version`);
|
|
assert(task.stageId?.includes(`${task.serviceId?.replace("-service", "")}`), `${icpId} ${task.id}: stageId should include service segment`);
|
|
assert(task.id.includes(`${task.serviceId?.replace("-service", "")}`), `${icpId} ${task.id}: taskId should include service segment`);
|
|
assert(task.actorName !== "Vera" && task.actorName !== "Kai" && task.actorName !== "Mira" && task.actorName !== "Lyra", `${icpId} ${task.id}: agent persona leaked into actorName`);
|
|
|
|
const url = routeFor(task.route);
|
|
const livePrefix = task.serviceId ? LIVE_ROUTE_PREFIX[task.serviceId] : undefined;
|
|
if (livePrefix) {
|
|
assert(url.pathname === livePrefix, `${icpId} ${task.id}: route ${url.pathname} does not match ${livePrefix}`);
|
|
} else {
|
|
assert(url.pathname === "/agents/service-unavailable", `${icpId} ${task.id}: unsupported service must use unavailable route`);
|
|
assert(url.searchParams.get("serviceId") === task.serviceId, `${icpId} ${task.id}: unavailable route must preserve serviceId`);
|
|
}
|
|
assert(url.searchParams.get("source") === "curator-v1", `${icpId} ${task.id}: route missing curator source`);
|
|
assert(url.searchParams.get("curatorTaskId") === task.id, `${icpId} ${task.id}: route curatorTaskId mismatch`);
|
|
assert(url.searchParams.get("missionId") === task.missionId, `${icpId} ${task.id}: route missionId mismatch`);
|
|
assert(url.searchParams.get("missionInstanceId") === task.missionInstanceId, `${icpId} ${task.id}: route missionInstanceId mismatch`);
|
|
assert(url.searchParams.get("stageId") === task.stageId, `${icpId} ${task.id}: route stageId mismatch`);
|
|
assert(url.searchParams.get("taskTitle") === task.title, `${icpId} ${task.id}: route taskTitle mismatch`);
|
|
assert(url.searchParams.get("taskSubtitle") === task.subtitle, `${icpId} ${task.id}: route taskSubtitle mismatch`);
|
|
assert(url.searchParams.get("taskType") === task.taskType, `${icpId} ${task.id}: route taskType mismatch`);
|
|
|
|
if (task.serviceId === "interview-service") {
|
|
const taskText = `${task.title} ${task.subtitle}`.toLowerCase();
|
|
const isIntroductionTask = /(?:60|90)[ -]?second|\bintroduction\b|\bpitch\b|\bpresentation\b/.test(taskText);
|
|
assert(url.searchParams.get("type") === (isIntroductionTask ? "warm_up" : "behavioral"), `${icpId} ${task.id}: interview type must match task intent`);
|
|
assert(url.searchParams.get("role") === (isIntroductionTask ? null : "Product Manager"), `${icpId} ${task.id}: interview role must match task intent`);
|
|
assert(url.searchParams.get("difficulty") === (isIntroductionTask ? "easy" : "medium"), `${icpId} ${task.id}: interview difficulty must match task intent`);
|
|
assert(url.searchParams.get("duration") === "5", `${icpId} ${task.id}: interview route should carry duration`);
|
|
}
|
|
|
|
if (task.serviceId === "roleplay-service") {
|
|
assert(url.searchParams.get("role") === "Product Manager", `${icpId} ${task.id}: practice route should preserve target role`);
|
|
assert(url.searchParams.get("duration") === "5", `${icpId} ${task.id}: practice route should carry duration`);
|
|
}
|
|
}
|
|
}
|
|
} catch (err) {
|
|
failures.push(err instanceof Error ? err.message : String(err));
|
|
}
|
|
}
|
|
|
|
if (failures.length) {
|
|
console.error(failures.join("\n"));
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`curator-static-registry tests passed for ${ICP_IDS.length} ICPs, 7 days each, 4 doc-backed tasks per day`);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|