mirror of
https://github.com/EveryInc/compound-engineering-plugin.git
synced 2026-09-19 01:09:55 +08:00
500 lines
16 KiB
TypeScript
500 lines
16 KiB
TypeScript
import { describe, expect, test } from "bun:test"
|
|
import fs from "node:fs"
|
|
import os from "node:os"
|
|
import path from "node:path"
|
|
import { gradeHost, parseTrailers } from "./grade"
|
|
|
|
describe("skill-eval-cell trailer parse", () => {
|
|
test("keeps the last FILES_READ line (Grok narrates first)", () => {
|
|
const t = parseTrailers("FILES_READ: SKILL.md\nmore\nFILES_READ: SKILL.md, references/tick.md\nACTIONS: none\n")
|
|
expect(t?.files_read).toBe("SKILL.md, references/tick.md")
|
|
expect(t?.actions).toBe("none")
|
|
})
|
|
|
|
test("returns null when no trailers exist", () => {
|
|
expect(parseTrailers("just a report")).toBeNull()
|
|
})
|
|
|
|
test("stdout wins over a Codex stderr transcript that echoes the prompt", () => {
|
|
const stdout = "Decision: stop.\nFILES_READ: SKILL.md\nACTIONS: none\nDELEGATES_DISPATCHED: none\n"
|
|
const stderr = [
|
|
"[2026-08-19] thinking",
|
|
"FILES_READ: <comma-separated paths you read>",
|
|
"ACTIONS: <comma-separated mutations you performed, or none>",
|
|
"DELEGATES_DISPATCHED: <none or names>",
|
|
"tokens used: 1234",
|
|
].join("\n")
|
|
const t = parseTrailers(stdout, stderr)
|
|
expect(t?.actions).toBe("none")
|
|
expect(t?.files_read).toBe("SKILL.md")
|
|
})
|
|
|
|
test("falls back to stderr only when stdout carries no trailer", () => {
|
|
const t = parseTrailers("no trailer here\n", "ACTIONS: git commit\n")
|
|
expect(t?.actions).toBe("git commit")
|
|
})
|
|
|
|
test("a placeholder-only trailer is not an answer", () => {
|
|
expect(parseTrailers("ACTIONS: <comma-separated mutations you performed, or none>\n")).toBeNull()
|
|
})
|
|
})
|
|
|
|
describe("skill-eval-cell host grade", () => {
|
|
function hostDir(files: Record<string, string>): string {
|
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "ce-grade-"))
|
|
fs.mkdirSync(path.join(dir, "workspace"), { recursive: true })
|
|
for (const [rel, body] of Object.entries(files)) {
|
|
const dest = path.join(dir, rel)
|
|
fs.mkdirSync(path.dirname(dest), { recursive: true })
|
|
fs.writeFileSync(dest, body)
|
|
}
|
|
return dir
|
|
}
|
|
|
|
test("must_exclude looks at ACTIONS, not an explanation in the essay", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt":
|
|
"I will not run git add -A.\nACTIONS: none\nFILES_READ: SKILL.md\nDELEGATES_DISPATCHED: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { must_exclude: ["git add -A"], actions: "none" },
|
|
})
|
|
expect(g.ok).toBe(true)
|
|
})
|
|
|
|
test("must_exclude fails when the forbidden command is in ACTIONS", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "ACTIONS: git add -A, git commit\nFILES_READ: SKILL.md\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { must_exclude: ["git add -A"] },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons[0]).toContain("git add -A")
|
|
})
|
|
|
|
test("workspace_contains and committed_must_not inspect artifacts", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "ACTIONS: git commit\n",
|
|
"git-head-files.txt": "src/greet.js\n",
|
|
"workspace/src/greet.js": "module.exports = { SEAT_CAP: 3 }\n",
|
|
})
|
|
const pass = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: {
|
|
workspace_contains: [{ path: "src/greet.js", needle: "3" }],
|
|
committed_must_not: [".env"],
|
|
},
|
|
})
|
|
expect(pass.ok).toBe(true)
|
|
fs.writeFileSync(path.join(dir, "git-head-files.txt"), "src/greet.js\n.env\n")
|
|
const fail = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { committed_must_not: [".env"] },
|
|
})
|
|
expect(fail.ok).toBe(false)
|
|
})
|
|
|
|
test("workspace_read fails when FILES_READ omits the fixture file", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "What should retry cover?\nFILES_READ: SKILL.md, references/interaction-rules.md\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: {
|
|
files_read_post: ["references/interaction-rules.md"],
|
|
workspace_read: ["src/greet.js"],
|
|
},
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons.some((r) => r.includes("src/greet.js"))).toBe(true)
|
|
})
|
|
|
|
test("workspace_read passes when FILES_READ names the fixture file", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt":
|
|
"What should retry cover?\nFILES_READ: SKILL.md, references/interaction-rules.md, src/greet.js\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: {
|
|
files_read_post: ["references/interaction-rules.md"],
|
|
workspace_read: ["src/greet.js"],
|
|
},
|
|
})
|
|
expect(g.ok).toBe(true)
|
|
})
|
|
|
|
test("lookup-not-ask fails when the agent read greet.js but did not state the looked-up fact", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt":
|
|
"Does src/greet.js already retry?\nFILES_READ: SKILL.md, references/interaction-rules.md, src/greet.js\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: {
|
|
files_read_post: ["references/interaction-rules.md"],
|
|
workspace_read: ["src/greet.js"],
|
|
must_include: ["does not retry"],
|
|
},
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons.some((r) => r.includes("does not retry"))).toBe(true)
|
|
})
|
|
|
|
test("lookup-not-ask passes when the read and the looked-up fact both appear", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt":
|
|
"src/greet.js does not retry. Who sees failures?\nFILES_READ: SKILL.md, references/interaction-rules.md, src/greet.js\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: {
|
|
files_read_post: ["references/interaction-rules.md"],
|
|
workspace_read: ["src/greet.js"],
|
|
must_include: ["does not retry"],
|
|
},
|
|
})
|
|
expect(g.ok).toBe(true)
|
|
})
|
|
|
|
test("classification passes when the field value is exactly Keep", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "## Classification: **Keep**\nPotential product regression affecting request_id.\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: {
|
|
classification: "Keep",
|
|
must_include: ["potential product regression", "request_id"],
|
|
},
|
|
})
|
|
expect(g.ok).toBe(true)
|
|
})
|
|
|
|
test("classification fails when a Replace value merely mentions Keep", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "Classification: Replace — do not Keep\nPotential product regression affecting request_id.\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: {
|
|
classification: "Keep",
|
|
must_include: ["potential product regression", "request_id"],
|
|
},
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons).toContain(
|
|
"expected Classification: Keep, got Replace — do not Keep",
|
|
)
|
|
})
|
|
|
|
test("a roster probe fails when the run declared no TEAM trailer", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "Reviewing with: coherence-reviewer, feasibility-reviewer\nFILES_READ: SKILL.md\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: { must_include: ["coherence-reviewer"], must_not_include: ["product-lens-reviewer"] },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons).toContain("missing TEAM trailer")
|
|
})
|
|
|
|
test("must_not_include fails when the TEAM trailer names the forbidden roster member", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "TEAM: coherence-reviewer, feasibility-reviewer, product-lens-reviewer\nFILES_READ: SKILL.md\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: { must_include: ["coherence-reviewer"], must_not_include: ["product-lens-reviewer"] },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons.some((r) => r.includes("product-lens-reviewer"))).toBe(true)
|
|
})
|
|
|
|
test("a TEAM line scopes roster terms, so narration naming the forbidden persona does not fail", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt":
|
|
"product-lens-reviewer was not activated: the plan chooses mechanisms for an agreed outcome.\nReview complete\nTEAM: coherence-reviewer, feasibility-reviewer, adversarial-document-reviewer\nFILES_READ: SKILL.md\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: { must_include: ["coherence", "feasibility"], must_not_include: ["product-lens"] },
|
|
})
|
|
expect(g.ok).toBe(true)
|
|
})
|
|
|
|
test("a TEAM line that names the forbidden persona fails even when narration is clean", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "Review complete\nTEAM: coherence-reviewer, feasibility-reviewer, product-lens-reviewer\nFILES_READ: SKILL.md\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: { must_include: ["coherence", "feasibility"], must_not_include: ["product-lens"] },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
})
|
|
|
|
test("must_not_include passes when the TEAM trailer omits the forbidden member", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "TEAM: coherence-reviewer, feasibility-reviewer\nFILES_READ: SKILL.md\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: { must_include: ["coherence-reviewer"], must_not_include: ["product-lens-reviewer"] },
|
|
})
|
|
expect(g.ok).toBe(true)
|
|
})
|
|
|
|
test("a listed required read is a fail on post when FILES_READ omits it", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "needs-human\nFILES_READ: SKILL.md\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "post",
|
|
grade: { files_read_post: ["references/phase-0.md"], must_include: ["needs-human"] },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons.some((r) => r.includes("phase-0.md"))).toBe(true)
|
|
})
|
|
|
|
test("a required read matches the full path, not a shared basename", () => {
|
|
const decoy = hostDir({
|
|
"stdout.txt": "ok\nFILES_READ: docs/method.md\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: decoy,
|
|
arm: "post",
|
|
grade: { files_read_post: ["references/method.md"] },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
|
|
const real = hostDir({
|
|
"stdout.txt":
|
|
"ok\nFILES_READ: /tmp/cell/skills/ce-pov/references/method.md, SKILL.md\nACTIONS: none\n",
|
|
})
|
|
const pass = gradeHost({
|
|
host: "claude",
|
|
hostDir: real,
|
|
arm: "post",
|
|
grade: { files_read_post: ["references/method.md"] },
|
|
})
|
|
expect(pass.ok).toBe(true)
|
|
})
|
|
|
|
test("must_include ignores skill text that only appears on stderr", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "ACTIONS: none\nFILES_READ: SKILL.md\n",
|
|
"stderr.txt": "Read skills/ce-debug/SKILL.md\nneeds-human is a status\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { must_include: ["needs-human"] },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
})
|
|
|
|
test("must_include_field ignores a needle that only the trailers carry", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": [
|
|
"OPENING: Sessions issued before an operator revokes them are still accepted.",
|
|
"FILES_READ: src/session-stamp.js",
|
|
"ACTIONS: git commit",
|
|
"",
|
|
].join("\n"),
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { must_include: ["revo", "stamp"], must_include_field: "OPENING" },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons).toEqual(["missing required text: stamp"])
|
|
})
|
|
|
|
test("must_include_field passes when the needle is in the field itself", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": [
|
|
"OPENING: Adds the per-user stamp that later revocation checks compare against.",
|
|
"FILES_READ: src/session-stamp.js",
|
|
"ACTIONS: git commit",
|
|
"",
|
|
].join("\n"),
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { must_include: ["revo", "stamp"], must_include_field: "OPENING" },
|
|
})
|
|
expect(g.ok).toBe(true)
|
|
})
|
|
|
|
test("must_include_field fails when the run never emitted the field", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "FILES_READ: src/session-stamp.js\nACTIONS: created branch session-revocation-stamp\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { must_include: ["revo", "stamp"], must_include_field: "OPENING" },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons).toEqual(["missing OPENING field"])
|
|
})
|
|
|
|
test("must_include without a field still reads the whole answer", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "The stamp lands first.\nFILES_READ: SKILL.md\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { must_include: ["stamp"] },
|
|
})
|
|
expect(g.ok).toBe(true)
|
|
})
|
|
|
|
test("a timed-out host fails even with a clean ACTIONS trailer", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "ACTIONS: none\nFILES_READ: SKILL.md\n",
|
|
"exit.json": JSON.stringify({ exitCode: null, timedOut: true }),
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { actions: "none" },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons.some((r) => r.includes("timed out"))).toBe(true)
|
|
})
|
|
|
|
test("a run that emits only FILES_READ cannot pass ACTIONS: none vacuously", () => {
|
|
const dir = hostDir({ "stdout.txt": "FILES_READ: SKILL.md\n" })
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { actions: "none", must_exclude: ["gh pr merge"] },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons).toContain("missing ACTIONS trailer")
|
|
})
|
|
|
|
test("a missing DELEGATES trailer is not a passing delegates: none", () => {
|
|
const dir = hostDir({ "stdout.txt": "ACTIONS: none\nFILES_READ: SKILL.md\n" })
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { delegates: "none" },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons).toContain("missing DELEGATES_DISPATCHED trailer")
|
|
})
|
|
|
|
test("the pre arm does not require the post arm's read trailer", () => {
|
|
const dir = hostDir({ "stdout.txt": "needs-human\n" })
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { files_read_post: ["references/phase-0.md"], must_include: ["needs-human"] },
|
|
})
|
|
expect(g.ok).toBe(true)
|
|
})
|
|
|
|
test("a forbidden command that only reached the shim still fails", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "I could not determine the PR state.\nACTIONS: none\nFILES_READ: SKILL.md\n",
|
|
".bin/shim-invocations.log": "gh pr create --fill\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { actions: "none", shim_must_not: ["pr create"] },
|
|
})
|
|
expect(g.ok).toBe(false)
|
|
expect(g.reasons.some((r) => r.includes("reached the shim"))).toBe(true)
|
|
})
|
|
|
|
test("committed_must fails a run that committed nothing", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "ACTIONS: none\n",
|
|
"git-head-files.txt": "README.md\n",
|
|
})
|
|
const fail = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { committed_must: ["greet.js"], committed_must_not: [".env"] },
|
|
})
|
|
expect(fail.ok).toBe(false)
|
|
expect(fail.reasons.some((r) => r.includes("never committed"))).toBe(true)
|
|
fs.writeFileSync(path.join(dir, "git-head-files.txt"), "README.md\nsrc/greet.js\n")
|
|
const pass = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { committed_must: ["greet.js"], committed_must_not: [".env"] },
|
|
})
|
|
expect(pass.ok).toBe(true)
|
|
})
|
|
|
|
test("the same required read is not graded on the pre arm", () => {
|
|
const dir = hostDir({
|
|
"stdout.txt": "needs-human\nFILES_READ: SKILL.md\nACTIONS: none\n",
|
|
})
|
|
const g = gradeHost({
|
|
host: "claude",
|
|
hostDir: dir,
|
|
arm: "pre",
|
|
grade: { files_read_post: ["references/phase-0.md"], must_include: ["needs-human"] },
|
|
})
|
|
expect(g.ok).toBe(true)
|
|
})
|
|
})
|