fix(release): withhold unqualified CV review and record gates

This commit is contained in:
cesnimda
2026-10-08 18:40:07 +02:00
parent 9c91575079
commit fe045b9e01
11 changed files with 544 additions and 5 deletions
@@ -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(); }
});