diff --git a/apps/validator/src/lib/report.ts b/apps/validator/src/lib/report.ts index 179331e..5e18f7b 100644 Binary files a/apps/validator/src/lib/report.ts and b/apps/validator/src/lib/report.ts differ diff --git a/apps/validator/src/main.ts b/apps/validator/src/main.ts index 6b48202..dcfe4aa 100644 --- a/apps/validator/src/main.ts +++ b/apps/validator/src/main.ts @@ -26,6 +26,7 @@ import { excerptAt, formatPointer } from "./lib/locate.js"; import { buildReport, MAX_SOURCE_BYTES, + recommendationsBlurb, type DocumentKind, type Finding, type Report, @@ -515,7 +516,7 @@ function renderReport(report: Report, label: string): void { renderFindings( recommendationsBox, "Recommendations", - "Unmet spec recommendations (SHOULD). The document is still valid; these make it easier to find, filter and subscribe to.", + recommendationsBlurb(report.specVersion), report.recommendations, "warn", ); diff --git a/apps/validator/test/report.test.ts b/apps/validator/test/report.test.ts index 93be205..7b4b119 100644 --- a/apps/validator/test/report.test.ts +++ b/apps/validator/test/report.test.ts @@ -5,7 +5,13 @@ import { describe, expect, it } from "vitest"; import { LATEST_VERSION } from "@opentechevents/validate"; -import { buildReport, MAX_DEPTH, maxDepth, type Report } from "../src/lib/report.js"; +import { + buildReport, + MAX_DEPTH, + maxDepth, + recommendationsBlurb, + type Report, +} from "../src/lib/report.js"; /** Reuses packages/validate's fixtures: one corpus, one opinion of "valid". */ function fixture(name: string): string { @@ -215,3 +221,42 @@ describe("buildReport — spec versions", () => { expect(report.recommendations).toEqual([]); }); }); + +// D042: a 1.0 freezes validity, not the recommended profiles. Anything that +// scores or badges on this list has to know which version produced it. +describe("recommendationsBlurb", () => { + it("names the version whose profile produced the list", () => { + expect(recommendationsBlurb("0.6.0")).toContain("OTE 0.6.0's recommended profile"); + }); + + it("warns that the list is not frozen the way validity is", () => { + const blurb = recommendationsBlurb("0.6.0"); + expect(blurb).toContain("not frozen"); + expect(blurb).toMatch(/add or drop recommendations/); + }); + + // The recommendations are still SHOULD-level, and saying so is what keeps + // them from reading as errors. + it("keeps the SHOULD framing and the reassurance that the document is valid", () => { + const blurb = recommendationsBlurb("0.6.0"); + expect(blurb).toContain("(SHOULD)"); + expect(blurb).toContain("still valid"); + }); + + // Unreachable through the UI — no version checked means no recommendations, + // and the box stays hidden — but the sentence must not read "OTE null's". + it("does not invent a version when none was applied", () => { + const blurb = recommendationsBlurb(null); + expect(blurb).not.toContain("null"); + expect(blurb).toContain("the recommended profile"); + }); + + // The version shown is the one actually checked, which is not always the + // one the document declares — a hand-picked version has to win here too. + it("reports whichever version was checked", async () => { + const report = validated( + await buildReport(fixture("versioned/event-0.3.0.json"), { version: LATEST_VERSION }), + ); + expect(recommendationsBlurb(report.specVersion)).toContain(`OTE ${LATEST_VERSION}`); + }); +});