From b107bf7d50ca7cb3c3b9c704802fa2b46c7fa068 Mon Sep 17 00:00:00 2001 From: protosphinx <133899485+protosphinx@users.noreply.github.com> Date: Tue, 1 Sep 2026 00:12:37 +0800 Subject: [PATCH] feat(checks): recognise Bedrock/Vertex regional prefixes in model-unknown Model IDs used via cross-region inference endpoints are prefixed with a two-letter region code: us., eu., or ap. (e.g. us.claude-sonnet-4-6). The model-unknown check compared the raw string against KNOWN_CLAUDE_MODELS, so all prefixed IDs produced a spurious warning. Strip any known regional prefix before the lookup so that Bedrock users do not need to suppress this warning or maintain their own allowlist. Unrecognised base models still warn, and the diagnostic message always shows the original (prefixed) ID for clarity. Five new tests cover the happy paths for all three prefixes, the rejection of an unrecognised prefixed model, and the message content. --- src/checks.ts | 12 +++++++++++ test/checks.test.ts | 51 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/src/checks.ts b/src/checks.ts index 8f77e5d..836438f 100644 --- a/src/checks.ts +++ b/src/checks.ts @@ -41,6 +41,11 @@ const KNOWN_EFFORT_LEVELS: ReadonlySet = new Set([ "max", ]); +// Regional prefixes used by cross-region inference endpoints (Bedrock, Vertex). +// Strip these before looking up in KNOWN_CLAUDE_MODELS so that IDs like +// `us.claude-sonnet-4-6` are recognised without enumerating every combination. +const REGIONAL_PREFIXES: ReadonlyArray = ["us.", "eu.", "ap."]; + export function runChecks( parsed: ParsedSkill[], config: SkillcheckConfig, @@ -298,12 +303,19 @@ function checkNameDrift(v: ValidatedSkill): Diagnostic[] { ]; } +function stripRegionalPrefix(model: string): string { + for (const prefix of REGIONAL_PREFIXES) { + if (model.startsWith(prefix)) return model.slice(prefix.length); + } + return model; +} function checkModelUnknown(v: ValidatedSkill): Diagnostic[] { const model = v.frontmatter.model; if (model === undefined) return []; if (typeof model !== "string" || model.length === 0) return []; if (KNOWN_CLAUDE_MODELS.has(model)) return []; + if (KNOWN_CLAUDE_MODELS.has(stripRegionalPrefix(model))) return []; return [ { severity: "warn", diff --git a/test/checks.test.ts b/test/checks.test.ts index cd5a723..ede5ccc 100644 --- a/test/checks.test.ts +++ b/test/checks.test.ts @@ -1114,6 +1114,57 @@ describe("runChecks", () => { const ds = runChecks([a, b], config); expect(ds.filter((d) => d.rule === "description-collision").length).toBe(2); }); + + it("does not warn model-unknown for us. prefixed Bedrock model when base is known", () => { + const s = mkSkill("/test/foo/SKILL.md", { + name: "foo", + description: "do the foo thing", + model: "us.claude-sonnet-4-6", + }); + const ds = runChecks([s], config); + expect(ds.find((d) => d.rule === "model-unknown")).toBeUndefined(); + }); + + it("does not warn model-unknown for eu. prefixed Bedrock model when base is known", () => { + const s = mkSkill("/test/foo/SKILL.md", { + name: "foo", + description: "do the foo thing", + model: "eu.claude-opus-5", + }); + const ds = runChecks([s], config); + expect(ds.find((d) => d.rule === "model-unknown")).toBeUndefined(); + }); + + it("does not warn model-unknown for ap. prefixed Bedrock model when base is known", () => { + const s = mkSkill("/test/foo/SKILL.md", { + name: "foo", + description: "do the foo thing", + model: "ap.claude-fable-5", + }); + const ds = runChecks([s], config); + expect(ds.find((d) => d.rule === "model-unknown")).toBeUndefined(); + }); + + it("still warns model-unknown when a regional prefix precedes an unrecognised base model", () => { + const s = mkSkill("/test/foo/SKILL.md", { + name: "foo", + description: "do the foo thing", + model: "us.claude-fable-6", + }); + const ds = runChecks([s], config); + expect(ds.some((d) => d.rule === "model-unknown")).toBe(true); + }); + + it("model-unknown message includes the full prefixed model id when regional prefix is used", () => { + const s = mkSkill("/test/foo/SKILL.md", { + name: "foo", + description: "do the foo thing", + model: "us.claude-fable-6", + }); + const ds = runChecks([s], config); + const d = ds.find((d) => d.rule === "model-unknown"); + expect(d?.message).toContain("us.claude-fable-6"); + }); }); describe("buildValidated", () => {