fix(P03): honest execution — real rollback, honest orchestrator, git-native verification

---ci---
project: ci
phase: 3
milestone: v0.5
status: complete
decisions:
  - id: D-026
    decision: Phase 3 Honest Execution complete
    rationale: All HONEST requirements covered; no more fake success returns
    confidence: 0.95
    alternatives: []
requirements:
  covered: [HONEST-01, HONEST-02, HONEST-03]
---/ci---
This commit is contained in:
Jon Chery
2026-05-29 16:44:46 +00:00
parent 815c928a43
commit 5753e2dc96
4 changed files with 174 additions and 16 deletions
+25 -2
View File
@@ -49,10 +49,33 @@ describe("BehavioralVerification", () => {
expect(testFilesCheck?.status).toBe("pass");
});
it("passes with specification and requirements", async () => {
it("passes with REQUIREMENTS.md", async () => {
const ciDir = path.join(tempDir, ".ci");
fs.mkdirSync(ciDir, { recursive: true });
fs.writeFileSync(path.join(ciDir, "specification.md"), "# Test\n## Objective\nBuild it\n\n## Requirements\n- Must have auth\n- Shall support CRUD\n");
fs.writeFileSync(path.join(ciDir, "REQUIREMENTS.md"), "# Requirements\n\n| REQ-ID | Requirement | Priority | Phase | Status |\n|--------|-------------|----------|-------|--------|\n| REQ-01 | Must have auth | P0 | 1 | pending |\n");
const verifier = new BehavioralVerification();
const result = await verifier.verify(tempDir, 1);
const specCheck = result.checks.find((c) => c.name === "Specification requirements traceable");
expect(specCheck?.status).toBe("pass");
});
it("skips when no REQUIREMENTS.md or PROJECT.md", async () => {
const ciDir = path.join(tempDir, ".ci");
fs.mkdirSync(ciDir, { recursive: true });
const verifier = new BehavioralVerification();
const result = await verifier.verify(tempDir, 1);
const specCheck = result.checks.find((c) => c.name === "Specification requirements traceable");
expect(specCheck?.status).toBe("skipped");
});
it("passes with PROJECT.md when no REQUIREMENTS.md", async () => {
const ciDir = path.join(tempDir, ".ci");
fs.mkdirSync(ciDir, { recursive: true });
fs.writeFileSync(path.join(ciDir, "PROJECT.md"), "# Test\n\n## What This Is\nBuild it\n\n## Requirements\n\n### Active\n\n- [ ] Must have auth\n- [ ] Shall support CRUD\n");
const verifier = new BehavioralVerification();
const result = await verifier.verify(tempDir, 1);
+49 -4
View File
@@ -1,5 +1,6 @@
import * as fs from "node:fs";
import * as path from "node:path";
import { execSync } from "node:child_process";
import { VerificationLayer, VerificationResult, VerificationCheck } from "./types.js";
const TEST_FRAMEWORK_PATTERNS = [
@@ -106,15 +107,59 @@ export class BehavioralVerification extends VerificationLayer {
}
private checkSpecificationRequirements(projectPath: string): VerificationCheck {
const specPath = path.join(projectPath, ".ci", "specification.md");
const reqPath = path.join(projectPath, ".ci", "REQUIREMENTS.md");
const projectPath_md = path.join(projectPath, ".ci", "PROJECT.md");
const specPath = reqPath;
if (!fs.existsSync(specPath)) {
const altPath = projectPath_md;
if (!fs.existsSync(altPath)) {
return this.check(
"Specification requirements traceable",
"skipped",
"No REQUIREMENTS.md or PROJECT.md found"
);
}
return this.checkFromProjectMd(altPath);
}
const content = fs.readFileSync(specPath, "utf-8");
const requirements = content
.split("\n")
.filter((line) => /^\|.*\|.*\|.*\|/.test(line) && !line.includes("REQ-ID") && !line.includes("---"))
.map((line) => {
const cols = line.split("|").map((c) => c.trim()).filter(Boolean);
return cols.length >= 2 ? cols[1] : "";
})
.filter(Boolean);
if (requirements.length === 0) {
const listRequirements = content
.split("\n")
.filter((line) => line.trim().startsWith("- "))
.map((line) => line.trim().slice(2));
if (listRequirements.length === 0) {
return this.check(
"Specification requirements traceable",
"warning",
"No requirements found in REQUIREMENTS.md"
);
}
return this.check(
"Specification requirements traceable",
"skipped",
"No specification file found"
"pass",
`Found ${listRequirements.length} requirement(s)`
);
}
return this.check(
"Specification requirements traceable",
"pass",
`Found ${requirements.length} requirement(s) in REQUIREMENTS.md`
);
}
private checkFromProjectMd(specPath: string): VerificationCheck {
const content = fs.readFileSync(specPath, "utf-8");
const requirements = content
.split("\n")
@@ -129,7 +174,7 @@ export class BehavioralVerification extends VerificationLayer {
return this.check(
"Specification requirements traceable",
"warning",
"No requirements found in specification"
"No requirements found in PROJECT.md"
);
}