feat(check): opt-in --layout proseCoverageFloor (#2834)

* feat(check): opt-in --layout proseCoverageFloor for text_occluded

Keep the default prose coverage floor at 0.15 for all callers, and allow
stricter agents (e.g. Zephyr) to lower it via --layout "proseCoverageFloor=0.05"
without changing other layout gates.

Co-authored-by: Cursor <cursoragent@cursor.com>

* style(check): collapse --layout comments and docs to one line

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(check): strict proseCoverageFloor parse + pin 0.07 floor tests

Reject trailing-garbage fractions that Number.parseFloat would accept, and
pin the existing ~0.07 coverage fixture for default vs floor=0.05 (atomic
labels unchanged) plus a collectLayout forwarding assertion.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(check): share parseNumberStrict across layout and frame-check

Sweep the sibling --frame-check tol parser (and caption fractions) onto the
same strict Number() helper so trailing garbage cannot prefix-parse.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Xuanru Li
2026-07-27 16:27:09 -07:00
committed by GitHub
co-authored by Cursor
parent 37295b341f
commit 209e6e0148
7 changed files with 177 additions and 23 deletions
+51
View File
@@ -1141,6 +1141,57 @@ describe("frame-check flag grammar", () => {
});
expect(() => parseFrameCheck("bogus=1")).toThrow("Invalid --frame-check");
expect(() => parseFrameCheck("tol=-2")).toThrow("Invalid --frame-check");
expect(() => parseFrameCheck("tol=4px")).toThrow("Invalid --frame-check");
expect(() => parseFrameCheck("tol=2garbage")).toThrow("Invalid --frame-check");
});
});
describe("layout flag grammar", () => {
it("parses proseCoverageFloor and rejects malformed specs", async () => {
const { parseLayout } = await import("./check.js");
expect(parseLayout(undefined)).toBeUndefined();
expect(parseLayout("proseCoverageFloor=0.05")).toEqual({ proseCoverageFloor: 0.05 });
expect(parseLayout("proseCoverageFloor=0")).toEqual({ proseCoverageFloor: 0 });
expect(parseLayout("proseCoverageFloor=1")).toEqual({ proseCoverageFloor: 1 });
expect(() => parseLayout(true)).toThrow("Invalid --layout");
expect(() => parseLayout("")).toThrow("Invalid --layout");
expect(() => parseLayout("bogus=1")).toThrow("Invalid --layout");
expect(() => parseLayout("proseCoverageFloor=-0.1")).toThrow("Invalid --layout");
expect(() => parseLayout("proseCoverageFloor=1.1")).toThrow("Invalid --layout");
expect(() => parseLayout("proseCoverageFloor=0.05garbage")).toThrow("Invalid --layout");
expect(() => parseLayout("proseCoverageFloor=0.1%")).toThrow("Invalid --layout");
expect(() => parseLayout("proseCoverageFloor=")).toThrow("Invalid --layout");
});
it("threads --layout into the check pipeline options", async () => {
const { report } = await runScenario(fakeDriver());
const runPipeline = vi.fn(async (_project: ProjectDir, _options: CheckOptions) => report);
vi.spyOn(console, "log").mockImplementation(() => undefined);
const command = createCheckCommand({
resolveProject: () => PROJECT,
runPipeline,
withMeta: (value) => value,
});
await runCommand(command, {
rawArgs: ["--json", "--layout", "proseCoverageFloor=0.05"],
});
expect(runPipeline).toHaveBeenCalledWith(
PROJECT,
expect.objectContaining({
layout: { proseCoverageFloor: 0.05 },
}),
);
});
it("forwards layout options into driver.collectLayout", async () => {
const collectLayout = vi.fn(async (_time: number, _tolerance: number, _layout?: unknown) => []);
await runScenario(fakeDriver({ collectLayout }), { layout: { proseCoverageFloor: 0.05 } });
expect(collectLayout).toHaveBeenCalled();
expect(collectLayout).toHaveBeenCalledWith(expect.any(Number), expect.any(Number), {
proseCoverageFloor: 0.05,
});
});
});