mirror of
https://github.com/merlinhu1/truthmark.git
synced 2026-08-25 07:53:25 +02:00
* feat: add workflow eval framework Add workflow evaluation scenarios, rubrics, schemas, and runner scripts for installed Truthmark workflows. Move research notes under docs/research and migrate tests from Vitest to node:test. * Potential fix for pull request finding 'CodeQL / Replacement of a substring with itself' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --------- Co-authored-by: MerlinH <merlinh221@gmail.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
254 lines
6.2 KiB
TypeScript
254 lines
6.2 KiB
TypeScript
import { afterEach, describe, it } from "node:test";
|
|
import { expect } from "expect";
|
|
|
|
import { validateEvidenceReferences } from "../../src/evidence/validate.js";
|
|
import { createTempRepo, type TempRepo } from "../helpers/temp-repo.js";
|
|
|
|
describe("validateEvidenceReferences", () => {
|
|
const repos: TempRepo[] = [];
|
|
|
|
afterEach(async () => {
|
|
await Promise.all(repos.splice(0).map((repo) => repo.cleanup()));
|
|
});
|
|
|
|
it("reports deleted referenced files", async () => {
|
|
const repo = await createTempRepo();
|
|
repos.push(repo);
|
|
await repo.writeFile(
|
|
"docs/truthmark/truth/sample.md",
|
|
"---\nstatus: active\nsource_of_truth:\n - ../../src/missing.ts\n---\n# Sample\n",
|
|
);
|
|
|
|
const diagnostics = await validateEvidenceReferences(repo.rootDir, [
|
|
"docs/truthmark/truth/sample.md",
|
|
]);
|
|
|
|
expect(diagnostics).toContainEqual(
|
|
expect.objectContaining({
|
|
category: "source-traceability",
|
|
severity: "error",
|
|
file: "docs/truthmark/truth/sample.md",
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("accepts source_of_truth glob references that match repository files", async () => {
|
|
const repo = await createTempRepo();
|
|
repos.push(repo);
|
|
|
|
await repo.writeFile("src/index.ts", "export const value = 1;\n");
|
|
await repo.writeFile(
|
|
"docs/truthmark/truth/sample.md",
|
|
"---\nstatus: active\nsource_of_truth:\n - ../../../src/**/*.ts\n---\n# Sample\n",
|
|
);
|
|
|
|
const diagnostics = await validateEvidenceReferences(repo.rootDir, [
|
|
"docs/truthmark/truth/sample.md",
|
|
]);
|
|
|
|
expect(diagnostics).toEqual([]);
|
|
});
|
|
|
|
it("resolves bare source_of_truth filenames relative to the truth doc", async () => {
|
|
const repo = await createTempRepo();
|
|
repos.push(repo);
|
|
|
|
await repo.writeFile("docs/truthmark/truth/overview.md", "# Overview\n");
|
|
await repo.writeFile(
|
|
"docs/truthmark/truth/sample.md",
|
|
"---\nstatus: active\nsource_of_truth:\n - overview.md\n---\n# Sample\n",
|
|
);
|
|
|
|
const diagnostics = await validateEvidenceReferences(repo.rootDir, [
|
|
"docs/truthmark/truth/sample.md",
|
|
]);
|
|
|
|
expect(diagnostics).toEqual([]);
|
|
});
|
|
|
|
it("validates final Source References bullets as traceability evidence", async () => {
|
|
const repo = await createTempRepo();
|
|
repos.push(repo);
|
|
|
|
await repo.writeFile("src/index.ts", "export const value = 1;\n");
|
|
await repo.writeFile(
|
|
"docs/truthmark/truth/valid.md",
|
|
`---
|
|
status: active
|
|
truth_kind: engineering-behavior
|
|
last_reviewed: 2026-06-14
|
|
---
|
|
|
|
# Valid
|
|
|
|
## Current Implementation Behavior
|
|
|
|
Uses the current source file.
|
|
|
|
## Source References
|
|
|
|
- ../../../src/index.ts
|
|
`,
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/truth/missing.md",
|
|
`---
|
|
status: active
|
|
truth_kind: engineering-behavior
|
|
last_reviewed: 2026-06-14
|
|
---
|
|
|
|
# Missing
|
|
|
|
## Current Implementation Behavior
|
|
|
|
References a missing file.
|
|
|
|
## Source References
|
|
|
|
- ../../../src/missing.ts
|
|
`,
|
|
);
|
|
|
|
const diagnostics = await validateEvidenceReferences(repo.rootDir, [
|
|
"docs/truthmark/truth/valid.md",
|
|
"docs/truthmark/truth/missing.md",
|
|
]);
|
|
|
|
expect(diagnostics).toContainEqual(
|
|
expect.objectContaining({
|
|
category: "source-traceability",
|
|
severity: "error",
|
|
file: "docs/truthmark/truth/missing.md",
|
|
}),
|
|
);
|
|
expect(diagnostics).not.toContainEqual(
|
|
expect.objectContaining({
|
|
file: "docs/truthmark/truth/valid.md",
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("reports evidence line spans outside the file even without a content hash", async () => {
|
|
const repo = await createTempRepo();
|
|
repos.push(repo);
|
|
|
|
await repo.writeFile("src/index.ts", "export const value = 1;\n");
|
|
await repo.writeFile(
|
|
"docs/truthmark/truth/sample.md",
|
|
`---
|
|
status: active
|
|
---
|
|
# Sample
|
|
|
|
\`\`\`yaml
|
|
evidence:
|
|
- path: ../../../src/index.ts
|
|
start_line: 10
|
|
end_line: 12
|
|
\`\`\`
|
|
`,
|
|
);
|
|
|
|
const diagnostics = await validateEvidenceReferences(repo.rootDir, [
|
|
"docs/truthmark/truth/sample.md",
|
|
]);
|
|
|
|
expect(diagnostics).toContainEqual(
|
|
expect.objectContaining({
|
|
category: "source-traceability",
|
|
severity: "error",
|
|
file: "docs/truthmark/truth/sample.md",
|
|
message: expect.stringContaining("outside the file"),
|
|
}),
|
|
);
|
|
});
|
|
|
|
it("treats evidence symbols as non-normative metadata", async () => {
|
|
const repo = await createTempRepo();
|
|
repos.push(repo);
|
|
|
|
await repo.writeFile("src/index.ts", "export const value = 1;\n");
|
|
await repo.writeFile(
|
|
"docs/truthmark/truth/symbol.md",
|
|
`---
|
|
status: active
|
|
---
|
|
# Symbol metadata
|
|
|
|
\`\`\`yaml
|
|
evidence:
|
|
- path: ../../../src/index.ts
|
|
symbol: missingSymbol
|
|
\`\`\`
|
|
`,
|
|
);
|
|
|
|
const diagnostics = await validateEvidenceReferences(repo.rootDir, [
|
|
"docs/truthmark/truth/symbol.md",
|
|
]);
|
|
|
|
expect(diagnostics).toEqual([]);
|
|
});
|
|
|
|
it("ignores malformed non-evidence YAML while reporting malformed evidence YAML", async () => {
|
|
const repo = await createTempRepo();
|
|
repos.push(repo);
|
|
|
|
await repo.writeFile("src/index.ts", "export const value = 1;\n");
|
|
await repo.writeFile(
|
|
"docs/truthmark/truth/non-evidence.md",
|
|
`---
|
|
status: active
|
|
source_of_truth:
|
|
- ../../../src/index.ts
|
|
---
|
|
# Non-evidence YAML
|
|
|
|
\`\`\`yaml
|
|
example:
|
|
- value: [
|
|
\`\`\`
|
|
`,
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/truth/evidence.md",
|
|
`---
|
|
status: active
|
|
source_of_truth:
|
|
- ../../../src/index.ts
|
|
---
|
|
# Evidence YAML
|
|
|
|
\`\`\`yaml
|
|
evidence:
|
|
- path: ../../../src/index.ts
|
|
start_line: [
|
|
\`\`\`
|
|
`,
|
|
);
|
|
|
|
const diagnostics = await validateEvidenceReferences(repo.rootDir, [
|
|
"docs/truthmark/truth/non-evidence.md",
|
|
"docs/truthmark/truth/evidence.md",
|
|
]);
|
|
|
|
expect(diagnostics).toContainEqual(
|
|
expect.objectContaining({
|
|
category: "source-traceability",
|
|
severity: "error",
|
|
file: "docs/truthmark/truth/evidence.md",
|
|
message: expect.stringContaining("Malformed evidence YAML block"),
|
|
}),
|
|
);
|
|
expect(diagnostics).not.toContainEqual(
|
|
expect.objectContaining({
|
|
category: "source-traceability",
|
|
severity: "error",
|
|
file: "docs/truthmark/truth/non-evidence.md",
|
|
message: expect.stringContaining("Malformed evidence YAML block"),
|
|
}),
|
|
);
|
|
});
|
|
});
|