mirror of
https://github.com/merlinhu1/codex-game-studio.git
synced 2026-08-25 07:54:34 +02:00
- add CCGS surface inventory and parity matrix reporting\n- expand Codex-native roles, skills, and workflow catalog coverage\n- remove nested init compatibility and align root project docs\n- migrate tests from Vitest to node:test with standalone expect
173 lines
6.0 KiB
TypeScript
173 lines
6.0 KiB
TypeScript
import { describe, test } from "node:test";
|
|
import { expect } from "expect";
|
|
import {
|
|
codexPermissionForWritePolicy,
|
|
defaultApprovalPolicyForStudioMode,
|
|
defaultWritePolicyForStudioMode,
|
|
evaluateStudioRunEligibility,
|
|
type ProjectStage,
|
|
type StudioMode
|
|
} from "../src/studio-policy.js";
|
|
|
|
describe("studio policy primitives", () => {
|
|
test("project stage and studio mode are independent policy axes", () => {
|
|
const stages: ProjectStage[] = ["design", "prototype", "development"];
|
|
const modes: StudioMode[] = ["fast-prototype", "guided-studio", "strict-studio"];
|
|
|
|
for (const projectStage of stages) {
|
|
expect(defaultApprovalPolicyForStudioMode("guided-studio")).toBe("approval-or-override");
|
|
expect(
|
|
evaluateStudioRunEligibility({
|
|
projectStage,
|
|
studioMode: "guided-studio",
|
|
phase: "implement",
|
|
hasMatchingApproval: true
|
|
})
|
|
).toMatchObject({
|
|
allowed: true,
|
|
writePolicy: "approved-write",
|
|
metadata: {
|
|
projectStage,
|
|
studioMode: "guided-studio",
|
|
approvalPolicy: "approval-or-override"
|
|
}
|
|
});
|
|
}
|
|
|
|
for (const studioMode of modes) {
|
|
expect(
|
|
evaluateStudioRunEligibility({
|
|
projectStage: "prototype",
|
|
studioMode,
|
|
phase: "plan"
|
|
})
|
|
).toMatchObject({
|
|
allowed: true,
|
|
writePolicy: "read-only",
|
|
metadata: {
|
|
projectStage: "prototype",
|
|
studioMode
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
test("studio modes define approval policy defaults", () => {
|
|
expect(defaultApprovalPolicyForStudioMode("fast-prototype")).toBe("advisory");
|
|
expect(defaultApprovalPolicyForStudioMode("guided-studio")).toBe("approval-or-override");
|
|
expect(defaultApprovalPolicyForStudioMode("strict-studio")).toBe("approval-required");
|
|
});
|
|
|
|
test("plan, review, and ship phases are read-only in every studio mode", () => {
|
|
for (const studioMode of ["fast-prototype", "guided-studio", "strict-studio"] satisfies StudioMode[]) {
|
|
for (const phase of ["plan", "review", "ship"] as const) {
|
|
expect(defaultWritePolicyForStudioMode(studioMode, phase, { hasMatchingApproval: true, approvedByUser: true })).toBe("read-only");
|
|
expect(
|
|
evaluateStudioRunEligibility({
|
|
projectStage: "development",
|
|
studioMode,
|
|
phase,
|
|
hasMatchingApproval: true,
|
|
approvedByUser: true
|
|
})
|
|
).toMatchObject({
|
|
allowed: true,
|
|
writePolicy: "read-only",
|
|
allowFileEdits: false,
|
|
codexSandbox: "read-only"
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
test("implementation and fix eligibility follows studio-mode approval rules", () => {
|
|
for (const phase of ["implement", "fix"] as const) {
|
|
expect(defaultWritePolicyForStudioMode("fast-prototype", phase)).toBe("advisory-write");
|
|
expect(evaluateStudioRunEligibility({ projectStage: "prototype", studioMode: "fast-prototype", phase })).toMatchObject({
|
|
allowed: true,
|
|
writePolicy: "advisory-write",
|
|
allowFileEdits: true,
|
|
codexSandbox: "danger-full-access",
|
|
metadata: {
|
|
provenance: "advisory"
|
|
}
|
|
});
|
|
|
|
expect(evaluateStudioRunEligibility({ projectStage: "prototype", studioMode: "guided-studio", phase })).toMatchObject({
|
|
allowed: false,
|
|
writePolicy: "read-only",
|
|
allowFileEdits: false,
|
|
codexSandbox: "read-only",
|
|
requiredApproval: {
|
|
approvalPolicy: "approval-or-override",
|
|
studioMode: "guided-studio",
|
|
phase
|
|
}
|
|
});
|
|
expect(evaluateStudioRunEligibility({ projectStage: "prototype", studioMode: "guided-studio", phase, hasMatchingApproval: true })).toMatchObject({
|
|
allowed: true,
|
|
writePolicy: "approved-write",
|
|
allowFileEdits: true,
|
|
codexSandbox: "danger-full-access",
|
|
metadata: {
|
|
provenance: "approval"
|
|
}
|
|
});
|
|
expect(evaluateStudioRunEligibility({ projectStage: "prototype", studioMode: "guided-studio", phase, approvedByUser: true })).toMatchObject({
|
|
allowed: true,
|
|
writePolicy: "override-write",
|
|
allowFileEdits: true,
|
|
codexSandbox: "danger-full-access",
|
|
metadata: {
|
|
provenance: "override"
|
|
}
|
|
});
|
|
|
|
expect(evaluateStudioRunEligibility({ projectStage: "development", studioMode: "strict-studio", phase })).toMatchObject({
|
|
allowed: false,
|
|
writePolicy: "read-only",
|
|
allowFileEdits: false,
|
|
codexSandbox: "read-only",
|
|
requiredApproval: {
|
|
approvalPolicy: "approval-required",
|
|
studioMode: "strict-studio",
|
|
phase
|
|
}
|
|
});
|
|
expect(evaluateStudioRunEligibility({ projectStage: "development", studioMode: "strict-studio", phase, approvedByUser: true })).toMatchObject({
|
|
allowed: false,
|
|
writePolicy: "read-only",
|
|
allowFileEdits: false,
|
|
codexSandbox: "read-only"
|
|
});
|
|
expect(evaluateStudioRunEligibility({ projectStage: "development", studioMode: "strict-studio", phase, hasMatchingApproval: true })).toMatchObject({
|
|
allowed: true,
|
|
writePolicy: "approved-write",
|
|
allowFileEdits: true,
|
|
codexSandbox: "danger-full-access",
|
|
metadata: {
|
|
provenance: "approval"
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
test("mutating write policies default to danger-full-access unless constrained explicitly", () => {
|
|
for (const writePolicy of ["advisory-write", "approved-write", "override-write"] as const) {
|
|
expect(codexPermissionForWritePolicy(writePolicy)).toEqual({
|
|
allowFileEdits: true,
|
|
codexSandbox: "danger-full-access"
|
|
});
|
|
expect(codexPermissionForWritePolicy(writePolicy, { constrainedSandbox: true })).toEqual({
|
|
allowFileEdits: true,
|
|
codexSandbox: "workspace-write"
|
|
});
|
|
}
|
|
|
|
expect(codexPermissionForWritePolicy("read-only", { constrainedSandbox: true })).toEqual({
|
|
allowFileEdits: false,
|
|
codexSandbox: "read-only"
|
|
});
|
|
});
|
|
});
|