Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/workflow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
7 changes: 2 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
14 changes: 14 additions & 0 deletions scripts/run-stages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -117,6 +130,7 @@ const GEN_STAGES: readonly Stage[] = [
export const PLANS: Readonly<Record<string, readonly Stage[]>> = {
gate: GATE_STAGES,
"check-types": CHECK_TYPES_STAGES,
"check-types:sdk": CHECK_TYPES_SDK_STAGES,
gen: GEN_STAGES,
};

Expand Down
36 changes: 36 additions & 0 deletions scripts/runStages.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
});
});
Loading