feat(placements): v0.11 P5 learner placement visibility (REQ-11-005) [9/10] — wave 5-2: wire pins + the A-304 badge-honesty census (mock talent surfaces stay placement-grep-clean)
This commit is contained in:
@@ -866,3 +866,76 @@ test("wire pin: EmployerApplicationSummary carries learner_id per the G-319 supe
|
||||
"the G-319 pin split: OwnPostingSummary stays counts-only",
|
||||
);
|
||||
});
|
||||
|
||||
// v0.11 P5 (REQ-11-005, D-110): the learner status-read wire pins +
|
||||
// the A-304 badge-honesty census — no placement badge on the mock
|
||||
// talent surfaces (D-092 binding: a badge on a mock page is
|
||||
// fabricated placement); the learner's-own application surface is the
|
||||
// ONLY placement render.
|
||||
|
||||
test("wire pin: LearnerApplicationStatus mirrors the base.py learner status read (D-104)", async () => {
|
||||
const typesSrc = readFileSync(web("../../packages/types/placement.ts"), "utf8");
|
||||
const pySrc = readFileSync(
|
||||
web("../../apps/ai-service/ai_service/placements/base.py"),
|
||||
"utf8",
|
||||
);
|
||||
const summaryBlock = typesSrc.slice(
|
||||
typesSrc.indexOf("export interface LearnerApplicationSummary"),
|
||||
typesSrc.indexOf("export interface LearnerApplicationStatus"),
|
||||
);
|
||||
for (const f of ["id:", "posting_id:", "learner_id:", "status:", "created_at:"]) {
|
||||
assert.ok(summaryBlock.includes(f), `LearnerApplicationSummary missing ${f}`);
|
||||
}
|
||||
const statusBlock = typesSrc.slice(
|
||||
typesSrc.indexOf("export interface LearnerApplicationStatus"),
|
||||
);
|
||||
assert.ok(/application: LearnerApplicationSummary;/.test(statusBlock));
|
||||
assert.ok(/events: PlacementEvent\[\];/.test(statusBlock));
|
||||
assert.ok(/placement: Placement \| null;/.test(statusBlock));
|
||||
// the backend contract carries the same three arms (base.py)
|
||||
const pyBlock = pySrc.slice(pySrc.indexOf("class LearnerApplicationStatusResponse"));
|
||||
assert.ok(/application: LearnerApplicationSummary/.test(pyBlock));
|
||||
assert.ok(/events: list\[PlacementEventRead\]/.test(pyBlock));
|
||||
assert.ok(/placement: PlacementRead \| None/.test(pyBlock));
|
||||
// the mine-read contract (G-322)
|
||||
const mineBlock = typesSrc.slice(typesSrc.indexOf("export interface MineApplication"));
|
||||
assert.ok(/application_id: string;/.test(mineBlock));
|
||||
assert.ok(/status: ApplicationStatus;/.test(mineBlock));
|
||||
assert.ok(
|
||||
/class MineApplicationResponse/.test(pySrc),
|
||||
"base.py carries the mine contract",
|
||||
);
|
||||
});
|
||||
|
||||
test("pin: A-304 badge honesty — no placement badge on the mock talent surfaces (D-092/D-109)", async () => {
|
||||
const surfaces = [
|
||||
"app/(employer)/employer/talent/page.tsx",
|
||||
"app/(employer)/employer/talent/[candidateId]/page.tsx",
|
||||
"components/employer/talent-search.tsx",
|
||||
];
|
||||
for (const surface of surfaces) {
|
||||
const src = readFileSync(web(surface), "utf8");
|
||||
assert.ok(
|
||||
!/placement/i.test(src),
|
||||
`${surface}: a badge on a mock surface is fabricated placement (D-092 binding)`,
|
||||
);
|
||||
}
|
||||
// the learner's-own application surface is the ONLY placement render
|
||||
const jobDetail = readFileSync(
|
||||
web("components/marketplace/job-detail-client.tsx"),
|
||||
"utf8",
|
||||
);
|
||||
assert.ok(
|
||||
/appStatus\.placement &&/.test(jobDetail),
|
||||
"the placement confirmation renders only on the learner's-own application surface",
|
||||
);
|
||||
const placementBlock = jobDetail.slice(jobDetail.indexOf("appStatus.placement &&"));
|
||||
assert.ok(
|
||||
/Placement recorded/.test(placementBlock),
|
||||
"G-328: the placement copy says RECORDED",
|
||||
);
|
||||
assert.ok(
|
||||
!/verified/i.test(placementBlock),
|
||||
"G-328: no verification claim on the placement surface",
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user