test(workboard): align matrix with real normalizeBoundedString consumers

ClawSweeper flagged that the prior matrix at line 31-48 tested
labels/title/notes by manually invoking normalizeBoundedString, even
though those fields use the independent normalizeTitle, normalizeNotes,
and normalizeLabels functions (each with its own generic message).
A regression that drops the (got N) suffix from normalizeBoundedString
would not be caught for those three surfaces — operators would still
see the old opaque error.

This commit narrows the matrix to only the consumers of the shared
helper (comment body, link title, link target, link URL, card id) and
restores the exact labels gateway assertion that should match the
unchanged normalizeLabels error.

Verification: 9/9 inline Node 18 AST harness (node /tmp/verify-pr-118888-v77.mjs);
parent-commit proof-gate (pre-PR helper without the got suffix) fails
4/9 of the post-fix expected messages.

Closes ClawSweeper review on PR #118888 (P2 + P3).
This commit is contained in:
Kailigithub
2026-08-14 03:11:54 +08:00
committed by Shakker
parent f990fb777a
commit 8f174ceca2
2 changed files with 17 additions and 9 deletions
+1 -1
View File
@@ -339,7 +339,7 @@ describe("workboard gateway methods", () => {
expect(respond.mock.calls[0]?.[0]).toBe(false);
expect(respond.mock.calls[0]?.[2]).toMatchObject({
message: expect.stringMatching(/^labels must be 40 characters or fewer(?: \(got 41\))?\.$/),
message: "labels must be 40 characters or fewer.",
});
});
@@ -1,7 +1,10 @@
// Regression coverage for the bounded-string normalizer used across Workboard
// input validators. The helper is shared by comment, label, title, url, and
// other bounded fields; an opaque error message blocks agents that overshoot
// the limit because they cannot tell how far over they are.
// input validators. The helper is shared by comment body, card id, link
// target, link URL, and link title; an opaque error message blocks agents
// that overshoot the limit because they cannot tell how far over they are.
// Title / notes / labels use their own independent validators and emit
// generic error messages that are intentionally out of scope for this
// helper.
import { describe, expect, it } from "vitest";
import { normalizeBoundedString } from "./store-normalizers.js";
@@ -26,19 +29,24 @@ describe("normalizeBoundedString", () => {
});
it("keeps the error message length-aware for every bounded field", () => {
// title/notes/labels/targetCardId/url/title are bounded through the same
// helper. A regression that drops the (got N) suffix will fail here.
// The `normalizeBoundedString` helper is the shared diagnostic owner for
// comment body, card id, link target, link URL, and link title. A
// regression that drops the (got N) suffix will fail here.
//
// Note: `normalizeTitle`, `normalizeNotes`, and `normalizeLabels` are
// independent validators with their own generic error messages, not
// consumers of this helper, so they are intentionally excluded from
// this matrix. Closes the false-confidence gap that ClawSweeper
// flagged on the prior matrix.
const cases: ReadonlyArray<{
readonly field: string;
readonly limit: number;
readonly actual: number;
}> = [
{ field: "labels", limit: 40, actual: 41 },
{ field: "link title", limit: 180, actual: 181 },
{ field: "title", limit: 180, actual: 9999 },
{ field: "notes", limit: 4000, actual: 4001 },
{ field: "link target", limit: 120, actual: 121 },
{ field: "link URL", limit: 2000, actual: 2001 },
{ field: "card id", limit: 120, actual: 121 },
];
for (const c of cases) {
const overlong = "x".repeat(c.actual);