feat(resume): check categories, stable issue keys, ignores and a two-column rule

- Every live check has a category (contact details, dates, layout, section
  headings, writing). Reports score the applicable rules, per category too.
- Findings carry a key that uses entry ids instead of array indexes, so it
  survives reordering. Keys in the new metadata.check.ignored set findings
  aside without counting them against the score.
- TWO_COLUMN_LAYOUT flags a two-column template that prints a sidebar.
- Full-width pages print no sidebar, so sections placed only there are now
  reported as never printing instead of passing as main-column content.
- metadata.check also holds job-posting terms hidden as not true; public
  viewers don't receive it.
- ats-pdf exports the job-description matcher, spelling variants and the
  semantics reader for the editor's job match and parser view.
This commit is contained in:
Amruth Pillai
2026-09-28 21:33:11 +02:00
parent 0e36729b80
commit e26ce08fc5
11 changed files with 291 additions and 33 deletions
@@ -62,13 +62,21 @@ describe("redactResumeForViewer", () => {
expect(result.name).toBe("Resume");
});
it("strips metadata.notes for non-owner", () => {
it("strips metadata.notes and the author's Check choices for non-owner", () => {
const resume = {
name: "Title",
data: { ...defaultResumeData, metadata: { ...defaultResumeData.metadata, notes: "Private notes" } },
data: {
...defaultResumeData,
metadata: {
...defaultResumeData.metadata,
notes: "Private notes",
check: { ignored: ["MISSING_PHONE:/basics/phone"], hiddenTerms: ["HIPAA"] },
},
},
};
const result = redactResumeForViewer(resume, false);
expect(result.data.metadata.notes).toBe("");
expect(result.data.metadata.check).toBeUndefined();
});
it("preserves stylesheet source for an authorized non-owner", () => {
@@ -42,6 +42,8 @@ export function assertCanView(resume: Resume, viewer: Viewer): void {
* contains personal context like "Senior Eng @ Foo — final draft").
* - `resume.data.metadata.notes` — explicitly documented as "only visible
* to the author when editing" in the resume schema.
* - `resume.data.metadata.check` — the author's Check choices (ignored
* issues, job-posting terms hidden as "not true for me").
*
* Everything else (including `data.basics.name`, the person's name on the
* resume itself) is part of the public payload and is returned unchanged.
@@ -61,6 +63,7 @@ export function redactResumeForViewer<T extends { name: string; data: ResumeData
metadata: {
...resume.data.metadata,
notes: "",
check: undefined,
},
},
};