fix(roleplay): hydrate qscore with canonical identity
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { buildPersonalizedRoleplayConfigurePayload } from "../src/routes/services.js";
|
||||
import { toQscoreUserId } from "../src/services/qscore-proxy.js";
|
||||
|
||||
const clerkUserId = "user_3GTcs6PBFcUrXUP6bH6U8dcwXBq";
|
||||
const originalFetch = globalThis.fetch;
|
||||
const requests: Request[] = [];
|
||||
|
||||
globalThis.fetch = (async (input, init) => {
|
||||
const request = new Request(input, init);
|
||||
requests.push(request);
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
org_id: "growqr",
|
||||
user_id: toQscoreUserId(clerkUserId),
|
||||
rq_score: 61,
|
||||
iq_score: 60,
|
||||
eq_score: 62,
|
||||
sq_score: 61,
|
||||
profession: "General",
|
||||
formula_version: "v1",
|
||||
formula_id: "default",
|
||||
calculated_at: "2026-07-14T00:00:00Z",
|
||||
quotients: {},
|
||||
breakdown: {},
|
||||
ledger_seq_from: null,
|
||||
ledger_seq_to: null,
|
||||
}),
|
||||
{ status: 200, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}) as typeof fetch;
|
||||
|
||||
try {
|
||||
const payload = await buildPersonalizedRoleplayConfigurePayload(
|
||||
new Request("http://backend.test/roleplay/preview"),
|
||||
{
|
||||
scenario_type: "salary-negotiation",
|
||||
metadata: { difficulty: "medium" },
|
||||
},
|
||||
clerkUserId,
|
||||
{
|
||||
resolveUserContext: async () => ({ clerk_id: clerkUserId }),
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(requests.length, 1);
|
||||
const qscoreUrl = new URL(requests[0]!.url);
|
||||
assert.equal(qscoreUrl.pathname, `/v1/qscore/${toQscoreUserId(clerkUserId)}`);
|
||||
assert.equal(qscoreUrl.searchParams.get("org_id"), "growqr");
|
||||
assert.equal((payload.qscore as Record<string, unknown>).rq_score, 61);
|
||||
assert.equal(payload.user_id, clerkUserId);
|
||||
|
||||
requests.length = 0;
|
||||
const suppliedPayload = await buildPersonalizedRoleplayConfigurePayload(
|
||||
new Request("http://backend.test/roleplay/preview"),
|
||||
{
|
||||
qscore: { rq_score: 74, source: "caller" },
|
||||
metadata: {},
|
||||
},
|
||||
clerkUserId,
|
||||
{
|
||||
resolveUserContext: async () => ({
|
||||
clerk_id: clerkUserId,
|
||||
qscore: { rq_score: 68, source: "context" },
|
||||
}),
|
||||
},
|
||||
);
|
||||
assert.equal(requests.length, 0);
|
||||
assert.deepEqual(suppliedPayload.qscore, { rq_score: 74, source: "caller" });
|
||||
|
||||
console.log("roleplay QScore identity: all assertions passed");
|
||||
} finally {
|
||||
globalThis.fetch = originalFetch;
|
||||
}
|
||||
+20
-7
@@ -668,9 +668,17 @@ async function buildPersonalizedConfigurePayload(req: Request, body: JsonObject,
|
||||
};
|
||||
}
|
||||
|
||||
async function buildPersonalizedRoleplayConfigurePayload(req: Request, body: JsonObject, userId: string): Promise<JsonObject> {
|
||||
export async function buildPersonalizedRoleplayConfigurePayload(
|
||||
req: Request,
|
||||
body: JsonObject,
|
||||
userId: string,
|
||||
dependencies: {
|
||||
resolveUserContext?: typeof resolveGrowUserContext;
|
||||
loadQscore?: typeof getQscoreFromService;
|
||||
} = {},
|
||||
): Promise<JsonObject> {
|
||||
const { mission: _mission, ...rest } = body;
|
||||
const userContext = await resolveGrowUserContext(req, userId).catch((err) => {
|
||||
const userContext = await (dependencies.resolveUserContext ?? resolveGrowUserContext)(req, userId).catch((err) => {
|
||||
log.warn({ err, userId }, "failed to resolve Grow user context for roleplay configure");
|
||||
return {} as Record<string, unknown>;
|
||||
});
|
||||
@@ -692,14 +700,19 @@ async function buildPersonalizedRoleplayConfigurePayload(req: Request, body: Jso
|
||||
metadata.context_notes = getString(incomingMetadata.context_notes) ?? candidateProfile;
|
||||
}
|
||||
|
||||
const orgId = String(rest.org_id ?? "growqr");
|
||||
const suppliedQscore = isRecord(rest.qscore)
|
||||
? rest.qscore
|
||||
: isRecord(userContext.qscore)
|
||||
? userContext.qscore
|
||||
: undefined;
|
||||
const qscore = suppliedQscore ?? await (dependencies.loadQscore ?? getQscoreFromService)(userId, orgId);
|
||||
|
||||
return {
|
||||
...rest,
|
||||
user_id: String(rest.user_id ?? userId),
|
||||
org_id: String(rest.org_id ?? "growqr"),
|
||||
metadata,
|
||||
...((rest.qscore as JsonObject | undefined) ?? (isRecord(userContext.qscore) ? userContext.qscore : undefined)
|
||||
? { qscore: (rest.qscore as JsonObject | undefined) ?? userContext.qscore }
|
||||
: {}),
|
||||
org_id: orgId,
|
||||
...(qscore ? { qscore } : {}),
|
||||
user_context: userContext,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user