fix(release): withhold unqualified CV review and record gates
This commit is contained in:
@@ -128,3 +128,58 @@ test("bound CV proposals use real owned saves and reject fabricated or stale out
|
||||
expect(state.calls.some((call: { path: string; body: { output_mode?: string } }) => call.path === "/cv/rewrite" && call.body.output_mode === "cv_blocks_json")).toBe(true);
|
||||
await testInfo.attach("synthetic-provider-contract-calls", { body: JSON.stringify(state, null, 2), contentType: "application/json" });
|
||||
});
|
||||
|
||||
test("Production withholds CV review before provider calls or content writes while existing AI remains available", async ({ request, playwright }) => {
|
||||
const productionUrl = `${process.env.CV_AI_READINESS_PRODUCTION_API_URL}/api`;
|
||||
const api = await playwright.request.newContext();
|
||||
try {
|
||||
const login = await api.post(`${productionUrl}/auth/login`, { data: { email: "cv-ai-readiness@example.test", password } });
|
||||
expect(login.status()).toBe(200);
|
||||
// This is an isolated loopback API behind an HTTPS canonical origin. Keep its Secure cookies
|
||||
// unchanged and explicitly transport them across the test-only internal HTTP connection.
|
||||
const cookies = login.headersArray().filter(header => header.name.toLowerCase() === "set-cookie").map(header => header.value.split(";")[0]);
|
||||
const headers: Record<string, string> = { Cookie: cookies.join("; "), "X-CSRF-TOKEN": cookies.find(cookie => cookie.startsWith("XSRF-TOKEN="))!.slice("XSRF-TOKEN=".length) };
|
||||
const me = await api.get(`${productionUrl}/auth/me`, { headers });
|
||||
expect(me.status()).toBe(200);
|
||||
const account = await me.json();
|
||||
expect(account.entitlements.ai).toBe(true);
|
||||
headers["X-Session-Context"] = account.sessionContext;
|
||||
expect((await request.post(`${providerUrl}/fixture/reset`)).status()).toBe(200);
|
||||
|
||||
const profile = { version: "1", contact: { fullName: "Production Gate Fixture", headline: source }, summary: [source] };
|
||||
expect((await api.put(`${productionUrl}/career/profile`, { headers, data: { profile } })).status()).toBe(200);
|
||||
const created = await api.post(`${productionUrl}/cv/variants`, { headers, data: { name: "Withheld AI review", settings: { themeId: "minimal", language: "en", sections: [{ key: "summary" }] } } });
|
||||
expect(created.status()).toBe(200);
|
||||
const cv = await created.json();
|
||||
const snapshot = async () => {
|
||||
const responses = await Promise.all([
|
||||
api.get(`${productionUrl}/cv/variants/${cv.id}`, { headers }), api.get(`${productionUrl}/cv/variants/${cv.id}/versions`, { headers }),
|
||||
api.get(`${productionUrl}/career/profile`, { headers }), api.get(`${productionUrl}/career/profile/versions`, { headers }),
|
||||
]);
|
||||
for (const response of responses) expect(response.status()).toBe(200);
|
||||
return Promise.all(responses.map(response => response.json()));
|
||||
};
|
||||
const before = await snapshot();
|
||||
for (const action of ["improve", "document-improve"]) {
|
||||
const response = await api.post(`${productionUrl}/cv/ai/assist`, { headers, data: {
|
||||
variantId: cv.id, expectedVersion: cv.version, action, language: "en",
|
||||
...(action.startsWith("document-") ? {} : { targetId: "section:summary", text: source }),
|
||||
} });
|
||||
expect(response.status()).toBe(503);
|
||||
expect(await response.json()).toEqual({ code: "cv_ai_unavailable" });
|
||||
}
|
||||
const applied = await api.post(`${productionUrl}/cv/variants/${cv.id}/ai/apply`, { headers, data: { proposalToken: "unused-proposal", result: rewrite } });
|
||||
expect(applied.status()).toBe(503);
|
||||
expect(await applied.json()).toEqual({ code: "cv_ai_unavailable" });
|
||||
expect(await snapshot()).toEqual(before);
|
||||
expect(await (await request.get(`${providerUrl}/fixture/state`)).json()).toEqual({ mode: "supported", counts: { rewrite: 0, evaluate: 0 }, calls: [] });
|
||||
|
||||
expect((await api.get(`${productionUrl}/jobapplications/1/ai/modules`, { headers })).status()).toBe(200);
|
||||
const legacy = await api.post(`${productionUrl}/profile-cv/rewrite-section`, { headers, data: { sourceText: source, language: "en" } });
|
||||
expect(legacy.status()).toBe(200);
|
||||
expect((await legacy.json()).text).toBe(rewrite);
|
||||
expect(await snapshot()).toEqual(before);
|
||||
const state = await (await request.get(`${providerUrl}/fixture/state`)).json();
|
||||
expect(state.counts).toEqual({ rewrite: 1, evaluate: 0 });
|
||||
} finally { await api.dispose(); }
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user