Files
growqr-backend/scripts/matchmaking-events.test.ts

120 lines
3.7 KiB
TypeScript

import assert from "node:assert/strict";
import { extractQscoreSignals } from "../src/events/projectors/qscore-projector.js";
import { buildMatchmakingGatewayEvent } from "../src/services/matchmaking-events.js";
import type { GrowEventRow } from "../src/db/schema.js";
function event(overrides: Partial<GrowEventRow> & { type: string; payload: Record<string, unknown> }): GrowEventRow {
return {
id: `event-${overrides.type}`,
userId: "user_test",
orgId: null,
source: "matchmaking-v2",
type: overrides.type,
category: "service",
occurredAt: new Date("2026-07-09T00:00:00.000Z"),
receivedAt: new Date("2026-07-09T00:00:01.000Z"),
mission: overrides.mission ?? null,
subject: overrides.subject ?? null,
correlation: overrides.correlation ?? null,
payload: overrides.payload,
raw: {},
dedupeKey: null,
processingStatus: "pending",
processingError: null,
processedAt: null,
};
}
const saved = buildMatchmakingGatewayEvent({
userId: "user_test",
action: "mark_saved",
body: {
action: "mark_saved",
params: {
opportunity_id: "job_123",
curatorTaskId: "task_123",
missionId: "curator-sprint",
missionInstanceId: "sprint_123",
stageId: "stage_123",
source: "curator-v1",
},
},
result: { task_id: "a2a_123", status: "completed", messages: [] },
});
assert.equal(saved.type, "matchmaking.match.saved");
assert.deepEqual(saved.mission, {
missionId: "curator-sprint",
instanceId: "sprint_123",
stageId: "stage_123",
source: "curator-v1",
});
assert.deepEqual(saved.subject, {
serviceId: "matchmaking",
kind: "opportunity",
id: "job_123",
externalId: "job_123",
});
assert.equal(saved.correlation?.taskId, "task_123");
assert.equal(saved.correlation?.curatorTaskId, "task_123");
assert.equal(saved.correlation?.opportunityId, "job_123");
assert.equal(saved.payload.curatorTaskId, "task_123");
assert.equal(saved.payload.opportunityId, "job_123");
assert.equal(saved.payload.action, "mark_saved");
const generatedSignals = extractQscoreSignals(event({
type: "matchmaking.matches.generated",
payload: {
action: "run_search",
matchCount: 6,
scanned: 120,
result: { status: "completed" },
},
}));
assert.ok(
generatedSignals.some((signal) => signal.signalId === "market.matches" && signal.score > 0),
"generated matches should produce a market opportunity signal from match counts",
);
const savedSignals = extractQscoreSignals(event({
type: "matchmaking.match.saved",
payload: {
action: "mark_saved",
opportunityId: "job_123",
curatorTaskId: "task_123",
result: { status: "completed" },
},
}));
assert.ok(
savedSignals.some((signal) => signal.signalId === "networking.opportunities" && signal.score > 0),
"saved opportunities should produce an opportunity engagement signal without numeric match score",
);
const reviewed = buildMatchmakingGatewayEvent({
userId: "user_test",
action: "record_feedback",
body: {
action: "record_feedback",
params: { opportunity_id: "job_123", curatorTaskId: "task_123" },
},
result: { task_id: "a2a_456", status: "completed", messages: [] },
});
assert.equal(reviewed.type, "matchmaking.matches.reviewed");
const appliedSignals = extractQscoreSignals(event({
type: "matchmaking.match.applied",
payload: {
action: "mark_applied",
opportunityId: "job_123",
curatorTaskId: "task_123",
result: { status: "completed" },
},
}));
assert.ok(
appliedSignals.some((signal) => signal.signalId === "networking.opportunities" && signal.score >= 80),
"applied opportunities should produce a stronger opportunity signal without numeric match score",
);
console.log("matchmaking-events tests passed");
process.exit(0);