From 0950437921beb33db59ef834367e56b5b9d17dbb Mon Sep 17 00:00:00 2001 From: NoisemakerJon <139656120+Noisemaker111@users.noreply.github.com> Date: Fri, 4 Sep 2026 23:06:28 -0400 Subject: [PATCH] Separate SDK publication from external game quality gates --- .claude/skills/workflow/SKILL.md | 2 +- .github/workflows/publish.yml | 7 ++----- CHANGELOG.md | 2 ++ package.json | 1 + scripts/run-stages.ts | 14 +++++++++++++ scripts/runStages.test.ts | 36 ++++++++++++++++++++++++++++++++ 6 files changed, 56 insertions(+), 6 deletions(-) diff --git a/.claude/skills/workflow/SKILL.md b/.claude/skills/workflow/SKILL.md index 3b7a1b34..a60e6bd7 100644 --- a/.claude/skills/workflow/SKILL.md +++ b/.claude/skills/workflow/SKILL.md @@ -38,7 +38,7 @@ Implement the underlying seam and update the owning skill/reference plus generat ## Verify -Run checks proportional to risk while iterating. Before shipping, run supported generators, then `bun run gate`. Immediately before commit/push, run `bun run ship:preflight`. Use `jgengine-verify` for scene, UI, or gameplay evidence. PRs touching a rendered surface include the ten-category visual scorecard table. +Run checks proportional to risk while iterating. Before shipping, run supported generators, then `bun run gate`. SDK publication runs `check-types:sdk` and package tests. Full local and main-branch CI gates retain external Games checks; game-quality failures do not gate registry publication. Immediately before commit/push, run `bun run ship:preflight`. Use `jgengine-verify` for scene, UI, or gameplay evidence. PRs touching a rendered surface include the ten-category visual scorecard table. Inspect `git status`, the full diff, and acceptance criteria before staging. Stage only the intended files and commit once the cohesive change is complete. diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 9e94cdb4..5b5fa31d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -43,11 +43,8 @@ jobs: run: bun run stage-skills - run: bun run check-artifacts - run: bun run build - - run: bun run games:clone - env: - GAMES_CLONE_TOKEN: ${{ secrets.GAMES_CLONE_TOKEN }} - - run: bun run check-types - - run: bun test packages Games + - run: bun run check-types:sdk + - run: bun test packages - name: Publish unpublished packages in dependency order env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index a3e5209c..6dc9e588 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ between (`--json` for structured output). ### Fixed +- Separate SDK publication validation from external Games quality checks while retaining the full local and main-branch gates. + - Correct foot-IK endpoint recomputation after hip rotation; verify reachable targets and clamping without changing bone lengths. - Restore release CI prerequisites and make catalog-loader tests independent of the external Games checkout. diff --git a/package.json b/package.json index 7af1ff06..3ac00b9a 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "check-hud-tokens": "bun scripts/check-hud-tokens.ts", "check-street-rule-parity": "bun scripts/check-street-rule-parity.ts", "check-types": "bun scripts/guard.ts 900 'bun scripts/run-stages.ts check-types'", + "check-types:sdk": "bun scripts/guard.ts 900 'bun scripts/run-stages.ts check-types:sdk'", "build:registry": "bun scripts/build-registry.ts", "stage-skills": "bun scripts/stage-skills.ts", "check-stage-skills": "bun scripts/stage-skills.ts --check", diff --git a/scripts/run-stages.ts b/scripts/run-stages.ts index bbede732..4992d09a 100644 --- a/scripts/run-stages.ts +++ b/scripts/run-stages.ts @@ -85,6 +85,19 @@ const CHECK_TYPES_STAGES: readonly Stage[] = [ }, ]; +// External game content has its own Games gate; SDK publication retains every package validator. +const EXTERNAL_GAME_CHECKS = new Set([ + "check-module-globals", + "check-game-determinism", + "check-game-front-end", + "check-game-feel", + "check-art-direction", + "check-game-shape", + "check-content-gate", + "check-asset-availability", +]); +const CHECK_TYPES_SDK_STAGES = CHECK_TYPES_STAGES.filter((stage) => !EXTERNAL_GAME_CHECKS.has(stage.name)); + /** * `gate` is the full local verdict. Preflight keeps its old first slot — it is * seconds of work and catches lockfile drift before anything expensive — but it @@ -117,6 +130,7 @@ const GEN_STAGES: readonly Stage[] = [ export const PLANS: Readonly> = { gate: GATE_STAGES, "check-types": CHECK_TYPES_STAGES, + "check-types:sdk": CHECK_TYPES_SDK_STAGES, gen: GEN_STAGES, }; diff --git a/scripts/runStages.test.ts b/scripts/runStages.test.ts index 884740a4..dab4c496 100644 --- a/scripts/runStages.test.ts +++ b/scripts/runStages.test.ts @@ -141,3 +141,39 @@ describe("generated-artifact drift", () => { for (const stage of (PLANS.gen ?? []).slice(2)) expect(stage.needs).toEqual(["gen:barrels"]); }); }); + + +describe("SDK validation ownership", () => { + const externalGameChecks = [ + "check-module-globals", "check-game-determinism", "check-game-front-end", "check-game-feel", + "check-art-direction", "check-game-shape", "check-content-gate", "check-asset-availability", + ]; + + test("SDK retains every non-game validator and the full plan retains all game validators", () => { + const full = PLANS["check-types"]!; + const sdk = PLANS["check-types:sdk"]!; + for (const name of externalGameChecks) expect(full.some((stage) => stage.name === name)).toBe(true); + expect(sdk).toEqual(full.filter((stage) => !externalGameChecks.includes(stage.name))); + expect(sdk.map((stage) => stage.name)).toEqual([ + "ensure-ready", "check-artifacts", "check-skills", "check-skill-api", "check-orphan-ratchet", + "check-stateful-ratchet", "check-capabilities", "check-pack-texture-layout", "check-recipes", + "check-doc-symbols", "check-hud-tokens", "check-street-rule-parity", "check-types-all", + ]); + }); + + test("SDK reports package failures and still runs remaining independent validators", () => { + const stages = PLANS["check-types:sdk"]!; + const results = runPlan(stages, (stage) => stage.name !== "check-skills"); + expect(results.find((result) => result.name === "check-skills")?.state).toBe("failed"); + expect(results.find((result) => result.name === "check-types-all")?.state).toBe("passed"); + expect(formatSummary("check-types:sdk", stages, results)).toContain("check-types:sdk failed"); + }); + + test("SDK prerequisite failures remain skipped and never masquerade as successful checks", () => { + const stages = PLANS["check-types:sdk"]!; + const results = runPlan(stages, (stage) => stage.name !== "ensure-ready"); + expect(results[0]?.state).toBe("failed"); + expect(results.slice(1).every((result) => result.state === "skipped")).toBe(true); + expect(formatSummary("check-types:sdk", stages, results)).toContain("NOT known-good"); + }); +});