Files
codex-game-studio/tests/workflow-catalog.test.ts
T
f3365d2613 feat: close CCGS parity gaps (#12)
* docs: remove implemented OpenSpec change

Remove the completed eval framework OpenSpec change documents and add a CCGS gap task reference based on the parity reports and upstream CCGS surfaces.

* feat: generate CCGS gap report

Add an OpenSpec-backed implementation for deterministic remaining-gap reporting from the CCGS parity matrix, including tests and regenerated references.

* feat: deepen accessibility role parity

Add OpenSpec-backed CCGS-depth coverage for the accessibility specialist role, including role contract tests, parity regression tests, and regenerated gap reports.

* feat: close direct role depth gaps

Add OpenSpec-backed CCGS-depth contracts for the remaining direct role package gaps, plus parity tests and regenerated remaining-gap reports. Stop before engine sub-specialist, workflow, template, and rule work.

* feat: add engine sub-specialist roles

Add OpenSpec-backed CCGS engine sub-specialist parity, selected-engine role sets, wrong-engine gating, focused engine references, generated custom-agent surfaces, tests, and regenerated parity reports.

* feat: close first workflow parity batch

* feat: close remaining workflow parity gaps

* feat: close final CCGS parity gaps

* chore: remove implemented OpenSpec changes

---------

Co-authored-by: MerlinH <merlinh221@gmail.com>
2026-07-07 14:09:47 +10:00

105 lines
5.4 KiB
TypeScript

import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { describe, test } from "node:test";
import { expect } from "expect";
import { artifactStatus, workflowCatalog, workflowCatalogSummary } from "../src/workflow-catalog.js";
import { initProject, statusProject } from "../src/projects.js";
import { workflowRegistry } from "../src/workflows.js";
const firstBatchWorkflowGapIds = [
"engine-setup",
"game-concept",
"design-review-concept",
"art-bible",
"map-systems",
"design-system",
"design-review",
"review-all-gdds",
"consistency-check",
"create-architecture",
"control-manifest",
"accessibility-doc"
] as const;
const secondBatchWorkflowGapIds = [
"entity-inventory",
"asset-spec",
"ux-design",
"ux-review",
"test-setup",
"implement",
"code-review",
"bug-report",
"retrospective",
"team-feature",
"scope-check",
"balance-check",
"asset-audit",
"playtest-polish",
"team-polish",
"patch-notes",
"changelog",
"launch-checklist"
] as const;
describe("workflow catalog", () => {
test("represents CCGS-style phases with required and repeatable artifact checks", () => {
expect(workflowCatalog.phases[0]).toEqual(expect.objectContaining({ id: "concept", nextPhase: "systems-design" }));
const concept = workflowCatalog.phases.find((phase) => phase.id === "concept");
expect(concept?.steps).toContainEqual(expect.objectContaining({ id: "game-concept", required: true, artifact: expect.objectContaining({ path: "design/gdd.md" }) }));
const systems = workflowCatalog.phases.find((phase) => phase.id === "systems-design");
expect(systems?.steps).toContainEqual(expect.objectContaining({ id: "design-system", repeatable: true }));
});
test("first CCGS workflow-step parity batch is registry-backed and catalog-aligned", () => {
for (const id of firstBatchWorkflowGapIds) {
expect(workflowRegistry[id]).toEqual(expect.objectContaining({ id, file: `.codex/workflows/${id}.md` }));
}
const catalogIds = workflowCatalog.phases.flatMap((phase) => phase.steps.map((step) => step.id));
expect(catalogIds).toEqual(expect.arrayContaining([...firstBatchWorkflowGapIds]));
expect(catalogIds).not.toContain("setup-engine");
const engineSetup = workflowCatalog.phases.flatMap((phase) => phase.steps).find((step) => step.id === "engine-setup");
expect(engineSetup).toEqual(expect.objectContaining({ required: true, artifact: expect.objectContaining({ path: ".codex/studio.json" }) }));
const designSystem = workflowCatalog.phases.flatMap((phase) => phase.steps).find((step) => step.id === "design-system");
expect(designSystem).toEqual(expect.objectContaining({ repeatable: true }));
});
test("second CCGS workflow-step parity batch is registry-backed and catalog-aligned", () => {
for (const id of secondBatchWorkflowGapIds) {
expect(workflowRegistry[id]).toEqual(expect.objectContaining({ id, file: `.codex/workflows/${id}.md` }));
}
const catalogIds = workflowCatalog.phases.flatMap((phase) => phase.steps.map((step) => step.id));
expect(catalogIds).toEqual(expect.arrayContaining([...secondBatchWorkflowGapIds]));
const steps = workflowCatalog.phases.flatMap((phase) => phase.steps);
expect(steps.find((step) => step.id === "entity-inventory")).toEqual(expect.objectContaining({ required: true, repeatable: true, artifact: expect.objectContaining({ path: "design/entities/entity-inventory.md" }) }));
expect(steps.find((step) => step.id === "implement")).toEqual(expect.objectContaining({ required: true, repeatable: true, artifact: expect.objectContaining({ path: "production/session-state/active.md" }) }));
expect(steps.find((step) => step.id === "launch-checklist")).toEqual(expect.objectContaining({ required: true, artifact: expect.objectContaining({ path: "production/launch-checklist.md" }) }));
});
test("artifact checks report complete, invalid-pattern, and missing workflow prerequisites", () => {
const root = mkdtempSync(path.join(tmpdir(), "ogs-workflow-catalog-"));
mkdirSync(path.join(root, "design"), { recursive: true });
writeFileSync(path.join(root, "design", "gdd.md"), "# Test GDD\n");
expect(artifactStatus(root, { path: "design/gdd.md", pattern: "# Test" })).toEqual(expect.objectContaining({ status: "complete" }));
expect(artifactStatus(root, { path: "docs/architecture/README.md" })).toEqual(expect.objectContaining({ status: "missing" }));
expect(artifactStatus(root, { path: "design/gdd.md", pattern: "[" })).toEqual(expect.objectContaining({ status: "incomplete", reason: expect.stringMatching(/invalid pattern/) }));
expect(artifactStatus(root, { path: "design/gdd.md", pattern: "Nope" })).toEqual(expect.objectContaining({ status: "incomplete" }));
});
test("status output includes the next incomplete workflow catalog phase", () => {
const cwd = mkdtempSync(path.join(tmpdir(), "ogs-workflow-status-"));
initProject({ name: "Workflow Status Game", engine: "godot", mode: "prototype", nonInteractive: true }, cwd);
expect(statusProject(undefined, cwd)).toContain("workflow phase: concept");
expect(workflowCatalogSummary(cwd)).toContain("map-systems");
writeFileSync(path.join(cwd, "design", "gdd.md"), "# Test GDD\n\n## System Map\nSystem dependencies are listed.\n");
expect(workflowCatalogSummary(cwd)).toContain("workflow phase: pre-production");
expect(workflowCatalogSummary(cwd)).toContain("vertical-slice");
});
});