mirror of
https://github.com/merlinhu1/truthmark.git
synced 2026-08-25 07:53:25 +02:00
* feat: add interactive platform selection to init * chore: remove completed OpenSpec artifacts * chore: remove implemented design note * fix: protect init lifecycle from unsafe config paths * fix: support clearing init platforms from CLI * docs: retire config command from repository rules * docs: align init lifecycle and clear-platform contracts * docs: keep repository guidance current-state focused * docs: limit cleanup to repository-native documents * docs: preserve historical version notes --------- Co-authored-by: MerlinH <merlinh221@gmail.com>
2363 lines
61 KiB
TypeScript
2363 lines
61 KiB
TypeScript
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
|
|
import { describe, it } from "node:test";
|
|
import { expect } from "expect";
|
|
|
|
import { runInit } from "../../src/init/init.js";
|
|
import { runCheck } from "../../src/checks/check.js";
|
|
import type { TruthHealthScorecard } from "../../src/checks/scorecard.js";
|
|
import { writeTruthmarkConfig } from "../helpers/truthmark-config.js";
|
|
import { createTempRepo } from "../helpers/temp-repo.js";
|
|
|
|
const initializeRepo = async (rootDir: string): Promise<void> => {
|
|
await writeTruthmarkConfig(rootDir);
|
|
const configPath = path.join(rootDir, ".truthmark/config.yml");
|
|
const configFile = await fs.readFile(configPath, "utf8");
|
|
await fs.writeFile(
|
|
configPath,
|
|
configFile.replace(
|
|
"version: 2\n",
|
|
[
|
|
"version: 2",
|
|
"platforms:",
|
|
" - codex",
|
|
" - opencode",
|
|
" - claude-code",
|
|
" - github-copilot",
|
|
" - antigravity",
|
|
" - cursor",
|
|
"",
|
|
].join("\n"),
|
|
),
|
|
);
|
|
await runInit(rootDir);
|
|
};
|
|
|
|
const scorecardFrom = (
|
|
result: Awaited<ReturnType<typeof runCheck>>,
|
|
): TruthHealthScorecard => {
|
|
const scorecard = result.data?.scorecard;
|
|
expect(scorecard).toBeDefined();
|
|
return scorecard as TruthHealthScorecard;
|
|
};
|
|
|
|
const scorecardDimension = (
|
|
scorecard: TruthHealthScorecard,
|
|
id: TruthHealthScorecard["dimensions"][number]["id"],
|
|
) => {
|
|
const dimension = scorecard.dimensions.find(
|
|
(candidate) => candidate.id === id,
|
|
);
|
|
expect(dimension).toBeDefined();
|
|
return dimension!;
|
|
};
|
|
|
|
describe("runCheck", () => {
|
|
it("returns no error diagnostics for a healthy initialized repository", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile("src/index.ts", "export const value = true;\n");
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(result.command).toBe("check");
|
|
expect(
|
|
result.diagnostics.filter(
|
|
(diagnostic) => diagnostic.severity === "error",
|
|
),
|
|
).toEqual([]);
|
|
|
|
const scorecard = scorecardFrom(result);
|
|
expect(scorecard.schemaVersion).toBe("truthmark-scorecard/v0");
|
|
expect(scorecard.dimensions).toHaveLength(7);
|
|
expect(scorecardDimension(scorecard, "routing-coverage").status).toBe(
|
|
"pass",
|
|
);
|
|
expect(scorecardDimension(scorecard, "branch-freshness").status).toBe(
|
|
"not-run",
|
|
);
|
|
expect(result.data).toHaveProperty("truthVisibility");
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("resolves the repository root when check runs from a subdirectory", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await writeTruthmarkConfig(repo.rootDir);
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"src/auth/session.ts",
|
|
"export const session = true;\n",
|
|
);
|
|
|
|
const result = await runCheck(path.join(repo.rootDir, "src"));
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) => diagnostic.category === "config",
|
|
),
|
|
).toBe(false);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports missing host skill package support files", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await fs.rm(
|
|
`${repo.rootDir}/.agents/skills/truthmark-sync/support/procedure.md`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "generated-surface" &&
|
|
diagnostic.file ===
|
|
".agents/skills/truthmark-sync/support/procedure.md" &&
|
|
diagnostic.message.includes("is missing"),
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports stale host skill package entrypoints", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
".agents/skills/truthmark-sync/SKILL.md",
|
|
`${await repo.readFile(".agents/skills/truthmark-sync/SKILL.md")}
|
|
Local stale edit.
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "generated-surface" &&
|
|
diagnostic.file === ".agents/skills/truthmark-sync/SKILL.md" &&
|
|
diagnostic.message.includes("is stale"),
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports stale host skill package support files", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
".claude/skills/truthmark-sync/support/procedure.md",
|
|
`${await repo.readFile(
|
|
".claude/skills/truthmark-sync/support/procedure.md",
|
|
)}
|
|
Local stale edit.
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "generated-surface" &&
|
|
diagnostic.file ===
|
|
".claude/skills/truthmark-sync/support/procedure.md" &&
|
|
diagnostic.message.includes("is stale"),
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports obsolete generated workflow surfaces from retired renderer packages", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
".agents/skills/truthmark-preview/SKILL.md",
|
|
"# Legacy preview entrypoint\n",
|
|
);
|
|
await repo.writeFile("GEMINI.md", "# Legacy Gemini instructions\n");
|
|
await repo.writeFile(
|
|
".gemini/skills/truthmark-sync/SKILL.md",
|
|
"# Legacy Gemini sync skill\n",
|
|
);
|
|
await repo.writeFile(
|
|
".gemini/agents/truth-doc-writer.md",
|
|
"# Legacy Gemini doc writer\n",
|
|
);
|
|
await repo.writeFile(
|
|
".gemini/commands/truthmark/sync.toml",
|
|
'description = "Legacy Gemini sync command"\n',
|
|
);
|
|
await repo.writeFile(
|
|
".agents/skills/truthmark-sync/helper-manifest.yml",
|
|
"id: truthmark-sync\n",
|
|
);
|
|
await repo.writeFile(
|
|
".opencode/skills/truthmark-check/support/helper-policy.md",
|
|
"Legacy helper policy.\n",
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "generated-surface" &&
|
|
diagnostic.file === ".agents/skills/truthmark-preview/SKILL.md" &&
|
|
diagnostic.message.includes("obsolete"),
|
|
),
|
|
).toHaveLength(1);
|
|
for (const retiredPath of [
|
|
"GEMINI.md",
|
|
".gemini/skills/truthmark-sync/SKILL.md",
|
|
".gemini/agents/truth-doc-writer.md",
|
|
".gemini/commands/truthmark/sync.toml",
|
|
]) {
|
|
const obsoleteDiagnostics = result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "generated-surface" &&
|
|
diagnostic.file === retiredPath &&
|
|
diagnostic.message.includes("obsolete"),
|
|
);
|
|
expect(obsoleteDiagnostics).toHaveLength(1);
|
|
}
|
|
expect(
|
|
result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "generated-surface" &&
|
|
diagnostic.file ===
|
|
".agents/skills/truthmark-sync/helper-manifest.yml" &&
|
|
diagnostic.message.includes("obsolete"),
|
|
),
|
|
).toHaveLength(1);
|
|
expect(
|
|
result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "generated-surface" &&
|
|
diagnostic.file ===
|
|
".opencode/skills/truthmark-check/support/helper-policy.md" &&
|
|
diagnostic.message.includes("obsolete"),
|
|
),
|
|
).toHaveLength(1);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns links diagnostics for broken internal markdown links", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await writeTruthmarkConfig(repo.rootDir);
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/repository/bootstrap-routing.md",
|
|
`${await repo.readFile("docs/truthmark/engineering/repository/bootstrap-routing.md")}\nSee [Missing](docs/missing.md).\n`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) => diagnostic.category === "links",
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
scorecardDimension(scorecardFrom(result), "truth-doc-structure").status,
|
|
).toBe("fail");
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns links diagnostics instead of accepting links that escape the repo", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await writeTruthmarkConfig(repo.rootDir);
|
|
await initializeRepo(repo.rootDir);
|
|
await fs.writeFile(
|
|
path.resolve(repo.rootDir, "..", "truthmark-outside-link.md"),
|
|
"# Outside Link\n",
|
|
"utf8",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/repository/bootstrap-routing.md",
|
|
`${await repo.readFile("docs/truthmark/engineering/repository/bootstrap-routing.md")}\nSee [Outside](../truthmark-outside-link.md).\n`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "links" &&
|
|
diagnostic.file ===
|
|
"docs/truthmark/engineering/repository/bootstrap-routing.md",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await fs.rm(
|
|
path.resolve(repo.rootDir, "..", "truthmark-outside-link.md"),
|
|
{
|
|
force: true,
|
|
},
|
|
);
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns links diagnostics for symlink targets that resolve outside the repo", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await writeTruthmarkConfig(repo.rootDir);
|
|
await initializeRepo(repo.rootDir);
|
|
await fs.writeFile(
|
|
path.resolve(repo.rootDir, "..", "truthmark-symlink-link-target.md"),
|
|
"# Outside Link\n",
|
|
"utf8",
|
|
);
|
|
await fs.mkdir(path.resolve(repo.rootDir, "docs"), { recursive: true });
|
|
await fs.symlink(
|
|
path.resolve(repo.rootDir, "..", "truthmark-symlink-link-target.md"),
|
|
path.resolve(repo.rootDir, "docs", "linked-outside.md"),
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/repository/bootstrap-routing.md",
|
|
`${await repo.readFile("docs/truthmark/engineering/repository/bootstrap-routing.md")}\nSee [Outside](docs/linked-outside.md).\n`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "links" &&
|
|
diagnostic.file ===
|
|
"docs/truthmark/engineering/repository/bootstrap-routing.md",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await fs.rm(
|
|
path.resolve(repo.rootDir, "..", "truthmark-symlink-link-target.md"),
|
|
{
|
|
force: true,
|
|
},
|
|
);
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns authority errors for missing literal authority files", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await writeTruthmarkConfig(repo.rootDir);
|
|
await initializeRepo(repo.rootDir);
|
|
await fs.rm(`${repo.rootDir}/docs/truthmark/routes/areas.md`);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "authority" &&
|
|
diagnostic.severity === "error",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns config diagnostics instead of loading legacy authority entries that escape the repo", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await fs.writeFile(
|
|
path.resolve(repo.rootDir, "..", "truthmark-outside-authority.md"),
|
|
"# Outside Authority\n",
|
|
"utf8",
|
|
);
|
|
await repo.writeFile(
|
|
".truthmark/config.yml",
|
|
`version: 1
|
|
authority:
|
|
- ../truthmark-outside-authority.md
|
|
- ../truthmark-outside-*.md
|
|
instruction_targets:
|
|
- AGENTS.md
|
|
frontmatter:
|
|
required: []
|
|
recommended:
|
|
- status
|
|
ignore: []
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "config" &&
|
|
diagnostic.severity === "error" &&
|
|
diagnostic.message.includes("Unsupported Truthmark config shape"),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) => diagnostic.category === "authority",
|
|
),
|
|
).toBe(false);
|
|
|
|
const scorecard = scorecardFrom(result);
|
|
expect(scorecardDimension(scorecard, "routing-coverage").status).toBe(
|
|
"fail",
|
|
);
|
|
expect(scorecardDimension(scorecard, "branch-freshness").status).toBe(
|
|
"not-run",
|
|
);
|
|
} finally {
|
|
await fs.rm(
|
|
path.resolve(repo.rootDir, "..", "truthmark-outside-authority.md"),
|
|
{
|
|
force: true,
|
|
},
|
|
);
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns config diagnostics for legacy symlinked authority docs", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await fs.writeFile(
|
|
path.resolve(
|
|
repo.rootDir,
|
|
"..",
|
|
"truthmark-symlink-authority-target.md",
|
|
),
|
|
"# Outside Authority\n",
|
|
"utf8",
|
|
);
|
|
await fs.mkdir(path.resolve(repo.rootDir, "docs", "custom"), {
|
|
recursive: true,
|
|
});
|
|
await fs.symlink(
|
|
path.resolve(
|
|
repo.rootDir,
|
|
"..",
|
|
"truthmark-symlink-authority-target.md",
|
|
),
|
|
path.resolve(repo.rootDir, "docs", "custom", "outside-authority.md"),
|
|
);
|
|
await repo.writeFile(
|
|
".truthmark/config.yml",
|
|
`version: 1
|
|
authority:
|
|
- docs/custom/outside-authority.md
|
|
instruction_targets:
|
|
- AGENTS.md
|
|
frontmatter:
|
|
required: []
|
|
recommended:
|
|
- status
|
|
ignore: []
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "config" &&
|
|
diagnostic.severity === "error" &&
|
|
diagnostic.message.includes("Unsupported Truthmark config shape"),
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await fs.rm(
|
|
path.resolve(
|
|
repo.rootDir,
|
|
"..",
|
|
"truthmark-symlink-authority-target.md",
|
|
),
|
|
{
|
|
force: true,
|
|
},
|
|
);
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("rejects legacy optional authority globs instead of checking them", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
".truthmark/config.yml",
|
|
`version: 1
|
|
authority:
|
|
- docs/truthmark/routes/areas.md
|
|
- docs/truthmark/engineering/**/*.md
|
|
- docs/optional/**/*.md
|
|
instruction_targets:
|
|
- AGENTS.md
|
|
frontmatter:
|
|
required: []
|
|
recommended: []
|
|
ignore: []
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "config" &&
|
|
diagnostic.severity === "error" &&
|
|
diagnostic.message.includes("Unsupported Truthmark config shape"),
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) => diagnostic.category === "authority",
|
|
),
|
|
).toBe(false);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns area-index diagnostics for malformed areas and coverage diagnostics for unmapped code", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"src/auth/session.ts",
|
|
"export const session = true;\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/authentication.md",
|
|
"---\nstatus: active\n---\n\n# Authentication\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Authentication
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/authentication.md
|
|
`,
|
|
);
|
|
|
|
const malformedResult = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
malformedResult.diagnostics.some(
|
|
(diagnostic) => diagnostic.category === "area-index",
|
|
),
|
|
).toBe(true);
|
|
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Authentication
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/authentication.md
|
|
|
|
Code surface:
|
|
- src/billing/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const weakResult = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
weakResult.diagnostics.some(
|
|
(diagnostic) => diagnostic.category === "coverage",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports coverage diagnostics for unmapped Go, Python, C#, and Java code", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/platform.md",
|
|
"---\nstatus: active\n---\n\n# Platform\n",
|
|
);
|
|
await repo.writeFile(
|
|
"cmd/server/main.go",
|
|
"package main\n\nfunc main() {}\n",
|
|
);
|
|
await repo.writeFile("scripts/task.py", "print('task')\n");
|
|
await repo.writeFile(
|
|
"src/App/Program.cs",
|
|
"namespace App;\n\npublic class Program {}\n",
|
|
);
|
|
await repo.writeFile(
|
|
"src/main/java/com/example/App.java",
|
|
"package com.example;\n\npublic class App {}\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Platform
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/platform.md
|
|
|
|
Code surface:
|
|
- web/**
|
|
|
|
Update truth when:
|
|
- platform behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
const coverageFiles = result.diagnostics
|
|
.filter((diagnostic) => diagnostic.category === "coverage")
|
|
.map((diagnostic) => diagnostic.file);
|
|
|
|
expect(coverageFiles).toEqual(
|
|
expect.arrayContaining([
|
|
"cmd/server/main.go",
|
|
"scripts/task.py",
|
|
"src/App/Program.cs",
|
|
"src/main/java/com/example/App.java",
|
|
]),
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports coverage diagnostics for unmapped IaC, API schema, frontend, workflow, and monorepo code", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/platform.md",
|
|
"---\nstatus: active\n---\n\n# Platform\n",
|
|
);
|
|
await repo.writeFile(
|
|
"infra/main.tf",
|
|
'resource "null_resource" "example" {}\n',
|
|
);
|
|
await repo.writeFile(
|
|
"k8s/deployment.yaml",
|
|
"apiVersion: apps/v1\nkind: Deployment\n",
|
|
);
|
|
await repo.writeFile(
|
|
"api/openapi.yaml",
|
|
"openapi: 3.1.0\ninfo:\n title: API\n",
|
|
);
|
|
await repo.writeFile("schema/user.graphql", "type User { id: ID! }\n");
|
|
await repo.writeFile(
|
|
"proto/user.proto",
|
|
'syntax = "proto3";\nmessage User {}\n',
|
|
);
|
|
await repo.writeFile(
|
|
"frontend/components/Login.tsx",
|
|
"export const Login = () => null;\n",
|
|
);
|
|
await repo.writeFile(
|
|
".github/workflows/ci.yml",
|
|
"name: CI\non: [push]\n",
|
|
);
|
|
await repo.writeFile(
|
|
"apps/web/src/App.tsx",
|
|
"export const App = () => null;\n",
|
|
);
|
|
await repo.writeFile(
|
|
"packages/auth/src/session.ts",
|
|
"export const session = true;\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Platform
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/platform.md
|
|
|
|
Code surface:
|
|
- src/**
|
|
|
|
Update truth when:
|
|
- platform behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
const coverageFiles = result.diagnostics
|
|
.filter((diagnostic) => diagnostic.category === "coverage")
|
|
.map((diagnostic) => diagnostic.file);
|
|
|
|
expect(coverageFiles).toEqual(
|
|
expect.arrayContaining([
|
|
"infra/main.tf",
|
|
"k8s/deployment.yaml",
|
|
"api/openapi.yaml",
|
|
"schema/user.graphql",
|
|
"proto/user.proto",
|
|
"frontend/components/Login.tsx",
|
|
".github/workflows/ci.yml",
|
|
"apps/web/src/App.tsx",
|
|
"packages/auth/src/session.ts",
|
|
]),
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("uses delegated route files when checking coverage", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await repo.writeFile(
|
|
".truthmark/config.yml",
|
|
`version: 2
|
|
truthmark:
|
|
workspace: docs/truthmark
|
|
generated:
|
|
portal:
|
|
enabled: false
|
|
frontmatter:
|
|
required: []
|
|
recommended: []
|
|
ignore: []
|
|
`,
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Payments
|
|
|
|
Area files:
|
|
- docs/truthmark/routes/areas/payments.md
|
|
|
|
Code surface:
|
|
- services/payments/**
|
|
|
|
Update truth when:
|
|
- payment behavior changes
|
|
`,
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas/payments.md",
|
|
`# Payments Areas
|
|
|
|
## Checkout
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/payments/checkout.md
|
|
|
|
Code surface:
|
|
- services/payments/checkout/**
|
|
|
|
Update truth when:
|
|
- checkout behavior changes
|
|
`,
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/payments/checkout.md",
|
|
"# Checkout\n",
|
|
);
|
|
await repo.writeFile(
|
|
"services/payments/checkout/handler.ts",
|
|
"export const handler = () => 'ok';\n",
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "config" && diagnostic.severity === "error",
|
|
),
|
|
).toBe(false);
|
|
expect(result.diagnostics).not.toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
category: "coverage",
|
|
file: "services/payments/checkout/handler.ts",
|
|
}),
|
|
]),
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports stale generated workflow surfaces by comparing rendered content", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
".agents/skills/truthmark-sync/SKILL.md",
|
|
`${(
|
|
await repo.readFile(".agents/skills/truthmark-sync/SKILL.md")
|
|
).replace(
|
|
"Truthmark-managed generated file.",
|
|
"Locally edited generated file.",
|
|
)}\n`,
|
|
);
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(result.diagnostics).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
category: "generated-surface",
|
|
severity: "review",
|
|
file: ".agents/skills/truthmark-sync/SKILL.md",
|
|
message: expect.stringContaining("stale"),
|
|
}),
|
|
]),
|
|
);
|
|
expect(result.diagnostics).not.toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
category: "generated-surface",
|
|
file: ".agents/skills/truthmark-sync/SKILL.md",
|
|
message: expect.stringContaining("version"),
|
|
}),
|
|
]),
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports stale Claude Code generated skill surfaces", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
".claude/skills/truthmark-sync/SKILL.md",
|
|
`${await repo.readFile(".claude/skills/truthmark-sync/SKILL.md")}\nmanual drift\n`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(result.diagnostics).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
category: "generated-surface",
|
|
severity: "review",
|
|
file: ".claude/skills/truthmark-sync/SKILL.md",
|
|
message: expect.stringContaining("stale"),
|
|
}),
|
|
]),
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports stale GitHub Copilot generated prompt surfaces", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
".github/prompts/truthmark-sync.prompt.md",
|
|
`${await repo.readFile(".github/prompts/truthmark-sync.prompt.md")}\nmanual drift\n`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(result.diagnostics).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
category: "generated-surface",
|
|
severity: "review",
|
|
file: ".github/prompts/truthmark-sync.prompt.md",
|
|
message: expect.stringContaining("stale"),
|
|
}),
|
|
]),
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("ignores manual version notes outside managed instruction blocks", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"AGENTS.md",
|
|
`${await repo.readFile("AGENTS.md")}\n\nManual notes:\n- Keep legacy host bridge pinned at version: "0.9.0"\n`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "generated-surface" &&
|
|
diagnostic.file === "AGENTS.md",
|
|
),
|
|
).toEqual([]);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports stale generated Cursor skill surfaces when configured", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await repo.writeFile(
|
|
".truthmark/config.yml",
|
|
`version: 2
|
|
platforms:
|
|
- cursor
|
|
truthmark:
|
|
workspace: docs/truthmark
|
|
generated:
|
|
portal:
|
|
enabled: false
|
|
instruction_targets:
|
|
- AGENTS.md
|
|
frontmatter:
|
|
required: []
|
|
recommended: []
|
|
ignore: []
|
|
`,
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
"# Truthmark Areas\n",
|
|
);
|
|
await runInit(repo.rootDir);
|
|
await repo.writeFile(
|
|
".cursor/skills/truthmark-sync/SKILL.md",
|
|
`${await repo.readFile(".cursor/skills/truthmark-sync/SKILL.md")}\n# stale\n`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(result.diagnostics).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
category: "generated-surface",
|
|
severity: "review",
|
|
file: ".cursor/skills/truthmark-sync/SKILL.md",
|
|
message: expect.stringContaining("stale"),
|
|
}),
|
|
]),
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns truth visibility quality metrics in JSON data", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"apps/web/src/unmapped.ts",
|
|
"export const unmapped = true;\n",
|
|
);
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(result.data?.truthVisibility).toEqual(
|
|
expect.objectContaining({
|
|
routePrecision: expect.objectContaining({
|
|
leafAreaCount: expect.any(Number),
|
|
broadAreaCount: expect.any(Number),
|
|
}),
|
|
unmappedSurfaceCount: expect.any(Number),
|
|
staleGeneratedSurfaceCount: expect.any(Number),
|
|
syncCompletenessIssueCount: expect.any(Number),
|
|
topologyPressureCount: expect.any(Number),
|
|
}),
|
|
);
|
|
expect(
|
|
(
|
|
result.data?.truthVisibility as {
|
|
unmappedSurfaceCount?: number;
|
|
}
|
|
).unmappedSurfaceCount,
|
|
).toBeGreaterThan(0);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns area-index diagnostics for missing truth documents referenced by areas", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Authentication
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/missing-authentication.md
|
|
|
|
Code surface:
|
|
- src/auth/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "area-index" &&
|
|
diagnostic.message.includes("missing-authentication.md"),
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns area-index diagnostics for unmatched code surface globs", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Authentication
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/authentication.md
|
|
|
|
Code surface:
|
|
- src/typo/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "area-index" &&
|
|
diagnostic.file === "src/typo/**",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("keeps valid code-surface entries active when a sibling code-surface glob is stale", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"src/auth/session.ts",
|
|
"export const session = true;\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/authentication.md",
|
|
"---\nstatus: active\n---\n\n# Authentication\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Authentication
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/authentication.md
|
|
|
|
Code surface:
|
|
- src/auth/**
|
|
- src/stale/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "area-index" &&
|
|
diagnostic.file === "src/stale/**",
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "coverage" &&
|
|
diagnostic.file === "src/auth/session.ts",
|
|
),
|
|
).toBe(false);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports missing recommended frontmatter as review and missing required frontmatter as error", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/authentication.md",
|
|
"# Authentication\n",
|
|
);
|
|
|
|
const recommendedResult = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
recommendedResult.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "frontmatter" &&
|
|
diagnostic.severity === "review",
|
|
),
|
|
).toBe(true);
|
|
|
|
await repo.writeFile(
|
|
".truthmark/config.yml",
|
|
`version: 2
|
|
truthmark:
|
|
workspace: docs/truthmark
|
|
generated:
|
|
portal:
|
|
enabled: false
|
|
instruction_targets:
|
|
- AGENTS.md
|
|
frontmatter:
|
|
required:
|
|
- status
|
|
recommended: []
|
|
ignore: []
|
|
`,
|
|
);
|
|
|
|
const requiredResult = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
requiredResult.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "frontmatter" &&
|
|
diagnostic.severity === "error",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("runs frontmatter and link checks across routed truth docs that are outside authority globs", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/custom/auth-guidance.md",
|
|
"# Auth Guidance\n\nSee [Missing](missing.md).\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Authentication
|
|
|
|
Truth documents:
|
|
- docs/custom/auth-guidance.md
|
|
|
|
Code surface:
|
|
- src/auth/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "frontmatter" &&
|
|
diagnostic.file === "docs/custom/auth-guidance.md",
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "links" &&
|
|
diagnostic.file === "docs/custom/auth-guidance.md",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns diagnostics instead of throwing when a routed markdown doc has invalid frontmatter", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/custom/broken-frontmatter.md",
|
|
"---\nstatus: [broken\n---\n# Broken\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Custom
|
|
|
|
Truth documents:
|
|
- docs/custom/broken-frontmatter.md
|
|
|
|
Code surface:
|
|
- src/custom/**
|
|
|
|
Update truth when:
|
|
- custom behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "frontmatter" &&
|
|
diagnostic.severity === "error" &&
|
|
diagnostic.file === "docs/custom/broken-frontmatter.md",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("still checks valid routed docs when another area is malformed", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/custom/auth-guidance.md",
|
|
"# Auth Guidance\n\nSee [Missing](missing.md).\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Broken Area
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/authentication.md
|
|
|
|
## Valid Area
|
|
|
|
Truth documents:
|
|
- docs/custom/auth-guidance.md
|
|
|
|
Code surface:
|
|
- src/auth/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) => diagnostic.category === "area-index",
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "links" &&
|
|
diagnostic.file === "docs/custom/auth-guidance.md",
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "frontmatter" &&
|
|
diagnostic.file === "docs/custom/auth-guidance.md",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns diagnostics instead of throwing when an area truth document path escapes the repo", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Unsafe Area
|
|
|
|
Truth documents:
|
|
- ../outside.md
|
|
|
|
Code surface:
|
|
- src/auth/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "area-index" &&
|
|
diagnostic.file === "../outside.md",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns area-index diagnostics for symlinked truth docs that resolve outside the repo", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await fs.writeFile(
|
|
path.resolve(repo.rootDir, "..", "truthmark-symlink-area-target.md"),
|
|
"---\nstatus: active\n---\n\n# Outside Area Doc\n",
|
|
"utf8",
|
|
);
|
|
await fs.mkdir(path.resolve(repo.rootDir, "docs", "custom"), {
|
|
recursive: true,
|
|
});
|
|
await fs.symlink(
|
|
path.resolve(repo.rootDir, "..", "truthmark-symlink-area-target.md"),
|
|
path.resolve(repo.rootDir, "docs", "custom", "outside-area-doc.md"),
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Unsafe Area
|
|
|
|
Truth documents:
|
|
- docs/custom/outside-area-doc.md
|
|
|
|
Code surface:
|
|
- src/auth/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "area-index" &&
|
|
diagnostic.file === "docs/custom/outside-area-doc.md",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await fs.rm(
|
|
path.resolve(repo.rootDir, "..", "truthmark-symlink-area-target.md"),
|
|
{
|
|
force: true,
|
|
},
|
|
);
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("does not report missing product links for engineering-only route areas", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/contracts/internal-cache.md",
|
|
"# Internal Cache\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Internal Cache
|
|
|
|
Truth documents:
|
|
\`\`\`yaml
|
|
truth_documents:
|
|
- path: docs/truthmark/engineering/contracts/internal-cache.md
|
|
kind: engineering-contract
|
|
\`\`\`
|
|
|
|
Code surface:
|
|
- src/cache/**
|
|
|
|
Update truth when:
|
|
- internal cache contracts change
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "traceability" &&
|
|
diagnostic.severity === "review" &&
|
|
diagnostic.file ===
|
|
"docs/truthmark/engineering/contracts/internal-cache.md" &&
|
|
diagnostic.message.includes(
|
|
"User-visible engineering truth document",
|
|
),
|
|
),
|
|
).toEqual([]);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports missing product links when an engineering doc shares an area with product truth", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/product/payments/checkout.md",
|
|
"# Checkout Capability\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/behaviors/checkout.md",
|
|
"# Checkout Behavior\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Checkout
|
|
|
|
Truth documents:
|
|
\`\`\`yaml
|
|
truth_documents:
|
|
- path: docs/truthmark/product/payments/checkout.md
|
|
kind: product-capability
|
|
- path: docs/truthmark/engineering/behaviors/checkout.md
|
|
kind: engineering-behavior
|
|
\`\`\`
|
|
|
|
Code surface:
|
|
- src/checkout/**
|
|
|
|
Update truth when:
|
|
- checkout behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(result.diagnostics).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
category: "traceability",
|
|
severity: "review",
|
|
file: "docs/truthmark/engineering/behaviors/checkout.md",
|
|
message: expect.stringContaining(
|
|
"User-visible engineering truth document",
|
|
),
|
|
}),
|
|
]),
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("allows product realized_by links without reciprocal engineering realizes links", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/product/payments/checkout.md",
|
|
"# Checkout Capability\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/behaviors/checkout.md",
|
|
"# Checkout Behavior\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Checkout
|
|
|
|
Truth documents:
|
|
\`\`\`yaml
|
|
truth_documents:
|
|
- path: docs/truthmark/product/payments/checkout.md
|
|
kind: product-capability
|
|
realized_by:
|
|
- docs/truthmark/engineering/behaviors/checkout.md
|
|
- path: docs/truthmark/engineering/behaviors/checkout.md
|
|
kind: engineering-behavior
|
|
\`\`\`
|
|
|
|
Code surface:
|
|
- src/checkout/**
|
|
|
|
Update truth when:
|
|
- checkout behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
const traceabilityErrors = result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "traceability" &&
|
|
diagnostic.severity === "error" &&
|
|
diagnostic.file === "docs/truthmark/product/payments/checkout.md",
|
|
);
|
|
|
|
expect(traceabilityErrors).toEqual([]);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("allows engineering realizes links without reciprocal product realized_by links", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/product/payments/checkout.md",
|
|
"# Checkout Capability\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/behaviors/checkout.md",
|
|
"# Checkout Behavior\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Checkout
|
|
|
|
Truth documents:
|
|
\`\`\`yaml
|
|
truth_documents:
|
|
- path: docs/truthmark/product/payments/checkout.md
|
|
kind: product-capability
|
|
- path: docs/truthmark/engineering/behaviors/checkout.md
|
|
kind: engineering-behavior
|
|
realizes:
|
|
- docs/truthmark/product/payments/checkout.md
|
|
\`\`\`
|
|
|
|
Code surface:
|
|
- src/checkout/**
|
|
|
|
Update truth when:
|
|
- checkout behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
const traceabilityErrors = result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "traceability" &&
|
|
diagnostic.severity === "error" &&
|
|
diagnostic.file ===
|
|
"docs/truthmark/engineering/behaviors/checkout.md",
|
|
);
|
|
|
|
expect(traceabilityErrors).toEqual([]);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("merges duplicate route entries with divergent relationship metadata", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/product/payments/checkout.md",
|
|
"# Checkout Capability\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/behaviors/checkout.md",
|
|
"# Checkout Behavior\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Checkout
|
|
|
|
Truth documents:
|
|
\`\`\`yaml
|
|
truth_documents:
|
|
- path: docs/truthmark/product/payments/checkout.md
|
|
kind: product-capability
|
|
realized_by:
|
|
- docs/truthmark/engineering/behaviors/checkout.md
|
|
- path: docs/truthmark/engineering/behaviors/checkout.md
|
|
kind: engineering-behavior
|
|
realizes:
|
|
- docs/truthmark/product/payments/checkout.md
|
|
- path: docs/truthmark/engineering/behaviors/checkout.md
|
|
kind: engineering-behavior
|
|
\`\`\`
|
|
|
|
Code surface:
|
|
- src/checkout/**
|
|
|
|
Update truth when:
|
|
- checkout behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
const duplicateDiagnostics = result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "area-index" &&
|
|
diagnostic.severity === "error" &&
|
|
diagnostic.file ===
|
|
"docs/truthmark/engineering/behaviors/checkout.md" &&
|
|
diagnostic.message.includes("conflicting relationship metadata"),
|
|
);
|
|
const traceabilityErrors = result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "traceability" &&
|
|
diagnostic.severity === "error" &&
|
|
diagnostic.file === "docs/truthmark/product/payments/checkout.md",
|
|
);
|
|
|
|
expect(duplicateDiagnostics).toEqual([]);
|
|
expect(traceabilityErrors).toEqual([]);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("merges duplicate route relationship metadata before validating targets", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/product/payments/checkout.md",
|
|
"# Checkout Capability\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/product/payments/refunds.md",
|
|
"# Refunds Capability\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/behaviors/checkout.md",
|
|
"# Checkout Behavior\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Checkout
|
|
|
|
Truth documents:
|
|
\`\`\`yaml
|
|
truth_documents:
|
|
- path: docs/truthmark/product/payments/checkout.md
|
|
kind: product-capability
|
|
realized_by:
|
|
- docs/truthmark/engineering/behaviors/checkout.md
|
|
- path: docs/truthmark/product/payments/refunds.md
|
|
kind: product-capability
|
|
realized_by:
|
|
- docs/truthmark/engineering/behaviors/checkout.md
|
|
- path: docs/truthmark/engineering/behaviors/checkout.md
|
|
kind: engineering-behavior
|
|
realizes:
|
|
- docs/truthmark/product/payments/checkout.md
|
|
- path: docs/truthmark/engineering/behaviors/checkout.md
|
|
kind: engineering-behavior
|
|
realizes:
|
|
- docs/truthmark/product/payments/refunds.md
|
|
\`\`\`
|
|
|
|
Code surface:
|
|
- src/checkout/**
|
|
|
|
Update truth when:
|
|
- checkout behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "area-index" &&
|
|
diagnostic.file ===
|
|
"docs/truthmark/engineering/behaviors/checkout.md" &&
|
|
diagnostic.message.includes("conflicting relationship metadata"),
|
|
),
|
|
).toEqual([]);
|
|
expect(
|
|
result.diagnostics.filter(
|
|
(diagnostic) =>
|
|
diagnostic.category === "traceability" &&
|
|
diagnostic.severity === "error" &&
|
|
diagnostic.file === "docs/truthmark/product/payments/refunds.md",
|
|
),
|
|
).toEqual([]);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("propagates explicit truth kind metadata from glob routes to matched docs", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile("src/api.ts", "export const api = true;\n");
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/api.md",
|
|
`---
|
|
status: active
|
|
doc_type: behavior
|
|
truth_kind: engineering-behavior
|
|
last_reviewed: 2026-05-14
|
|
source_of_truth:
|
|
- docs/truthmark/routes/areas.md
|
|
---
|
|
|
|
# API
|
|
|
|
## Scope
|
|
|
|
API truth.
|
|
|
|
## Current Implementation Behavior
|
|
|
|
API behavior.
|
|
|
|
## Engineering Decisions
|
|
|
|
- Decision (2026-05-14): Test glob kind propagation.
|
|
|
|
## Rationale
|
|
|
|
This doc intentionally disagrees with the routed glob kind.
|
|
`,
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## API
|
|
|
|
Truth documents:
|
|
\`\`\`yaml
|
|
truth_documents:
|
|
- path: docs/truthmark/engineering/**/*.md
|
|
kind: engineering-contract
|
|
\`\`\`
|
|
|
|
Code surface:
|
|
- src/**
|
|
|
|
Update truth when:
|
|
- API behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(result.diagnostics).toEqual(
|
|
expect.arrayContaining([
|
|
expect.objectContaining({
|
|
category: "frontmatter",
|
|
severity: "error",
|
|
file: "docs/truthmark/engineering/api.md",
|
|
message: expect.stringContaining(
|
|
"routed truth kind engineering-contract",
|
|
),
|
|
}),
|
|
]),
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("returns diagnostics instead of throwing when an area truth document glob escapes the repo", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await fs.writeFile(
|
|
path.resolve(repo.rootDir, "..", "truthmark-outside-shared.md"),
|
|
"---\ntitle: Shared\nstatus: active\n---\n\n# Shared\n",
|
|
"utf8",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Unsafe Area
|
|
|
|
Truth documents:
|
|
- ../truthmark-outside-*.md
|
|
|
|
Code surface:
|
|
- src/auth/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "area-index" &&
|
|
diagnostic.file === "../truthmark-outside-shared.md",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await fs.rm(
|
|
path.resolve(repo.rootDir, "..", "truthmark-outside-shared.md"),
|
|
{
|
|
force: true,
|
|
},
|
|
);
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("still validates truth docs referenced by a malformed area", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/custom/malformed-area-doc.md",
|
|
"# Custom Guidance\n\nSee [Missing](missing.md).\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Broken Area
|
|
|
|
Truth documents:
|
|
- docs/custom/malformed-area-doc.md
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) => diagnostic.category === "area-index",
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "frontmatter" &&
|
|
diagnostic.file === "docs/custom/malformed-area-doc.md",
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "links" &&
|
|
diagnostic.file === "docs/custom/malformed-area-doc.md",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("does not count an area with broken truth documents toward code coverage", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"src/auth/session.ts",
|
|
"export const session = true;\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Broken Area
|
|
|
|
Truth documents:
|
|
- docs/truthmark/missing.md
|
|
|
|
Code surface:
|
|
- src/auth/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "coverage" &&
|
|
diagnostic.file === "src/auth/session.ts",
|
|
),
|
|
).toBe(true);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("keeps colliding area slugs from corrupting coverage state", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"src/auth/session.ts",
|
|
"export const session = true;\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/authentication.md",
|
|
"---\nstatus: active\n---\n\n# Authentication\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Auth API
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/authentication.md
|
|
|
|
Code surface:
|
|
- src/auth/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
|
|
## Auth/API
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/missing-authentication.md
|
|
|
|
Code surface:
|
|
- src/billing/**
|
|
|
|
Update truth when:
|
|
- billing behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "coverage" &&
|
|
diagnostic.file === "src/auth/session.ts",
|
|
),
|
|
).toBe(false);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("does not report coverage for files matched by ignore globs", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/authentication.md",
|
|
"---\nstatus: active\n---\n\n# Authentication\n",
|
|
);
|
|
await repo.writeFile(
|
|
"src/auth/session.ts",
|
|
"export const session = true;\n",
|
|
);
|
|
await repo.writeFile(
|
|
"src/generated/out.ts",
|
|
"export const generated = true;\n",
|
|
);
|
|
await repo.writeFile(
|
|
"src/unmapped/manual.ts",
|
|
"export const manual = true;\n",
|
|
);
|
|
await repo.writeFile(
|
|
".truthmark/config.yml",
|
|
`version: 2
|
|
truthmark:
|
|
workspace: docs/truthmark
|
|
generated:
|
|
portal:
|
|
enabled: false
|
|
instruction_targets:
|
|
- AGENTS.md
|
|
frontmatter:
|
|
required: []
|
|
recommended:
|
|
- status
|
|
ignore:
|
|
- src/generated/**
|
|
`,
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Authentication
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/authentication.md
|
|
|
|
Code surface:
|
|
- src/auth/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
const coverageFiles = result.diagnostics
|
|
.filter((diagnostic) => diagnostic.category === "coverage")
|
|
.map((diagnostic) => diagnostic.file);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "config" && diagnostic.severity === "error",
|
|
),
|
|
).toBe(false);
|
|
expect(coverageFiles).toContain("src/unmapped/manual.ts");
|
|
expect(coverageFiles).not.toContain("src/generated/out.ts");
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("reports unmapped functional code under an unknown root in coverage and scorecard output", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"backend/auth/session.ts",
|
|
"export const session = true;\n",
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
const coverageDiagnostics = result.diagnostics.filter(
|
|
(diagnostic) => diagnostic.category === "coverage",
|
|
);
|
|
const scorecard = scorecardFrom(result);
|
|
|
|
expect(coverageDiagnostics).toEqual([
|
|
expect.objectContaining({
|
|
category: "coverage",
|
|
severity: "review",
|
|
message:
|
|
"Code file backend/auth/session.ts is not covered by any Truthmark area mapping.",
|
|
file: "backend/auth/session.ts",
|
|
}),
|
|
]);
|
|
expect(
|
|
(result.data?.truthVisibility as { unmappedSurfaceCount: number })
|
|
.unmappedSurfaceCount,
|
|
).toBe(1);
|
|
expect(scorecardDimension(scorecard, "routing-coverage").status).toBe(
|
|
"warn",
|
|
);
|
|
expect(scorecardDimension(scorecard, "ownership-clarity").status).toBe(
|
|
"warn",
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("recognizes a mapped functional source file under an unknown root", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile("engine/runtime/main.rs", "fn main() {}\n");
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/runtime.md",
|
|
"---\nstatus: active\n---\n\n# Runtime\n",
|
|
);
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Runtime
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/runtime.md
|
|
|
|
Code surface:
|
|
- engine/runtime/**
|
|
|
|
Update truth when:
|
|
- runtime behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(result.diagnostics).not.toContainEqual(
|
|
expect.objectContaining({
|
|
category: "coverage",
|
|
file: "engine/runtime/main.rs",
|
|
}),
|
|
);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("limits coverage diagnostics to ordinary non-test functional code", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"backend/service.ts",
|
|
"export const service = true;\n",
|
|
);
|
|
await repo.writeFile("README.md", "# Read me\n");
|
|
await repo.writeFile("assets/logo.png", "not a source file\n");
|
|
await repo.writeFile("tests/service.test.ts", "void 0;\n");
|
|
await repo.writeFile("backend/service.test.ts", "void 0;\n");
|
|
await repo.writeFile("backend/service.spec.ts", "void 0;\n");
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
const coverageFiles = result.diagnostics
|
|
.filter((diagnostic) => diagnostic.category === "coverage")
|
|
.map((diagnostic) => diagnostic.file);
|
|
|
|
expect(coverageFiles).toEqual(["backend/service.ts"]);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("limits coverage diagnostics for mixed-surface repositories to ordinary functional source only", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
await writeTruthmarkConfig(repo.rootDir);
|
|
const configPath = path.join(repo.rootDir, ".truthmark/config.yml");
|
|
const configFile = await fs.readFile(configPath, "utf8");
|
|
await fs.writeFile(
|
|
configPath,
|
|
configFile.replace(
|
|
"version: 2\n",
|
|
[
|
|
"version: 2",
|
|
"platforms:",
|
|
" - codex",
|
|
"",
|
|
].join("\n"),
|
|
),
|
|
);
|
|
await runInit(repo.rootDir);
|
|
|
|
await repo.writeFile("backend/service.ts", "export const service = true;\n");
|
|
await repo.writeFile("README.md", "# Read me\n");
|
|
await repo.writeFile("assets/logo.png", "pretend-png\n");
|
|
await repo.writeFile("tests/service.test.ts", "void 0;\n");
|
|
await repo.writeFile("backend/service.spec.ts", "void 0;\n");
|
|
await repo.writeFile("backend/service.test.ts", "void 0;\n");
|
|
await repo.writeFile("docs/truthmark/engineering/overview.md", "# Overview\n");
|
|
await repo.writeFile(
|
|
"tests/nested/nested.unit.spec.ts",
|
|
"void 0;\n",
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
const coverageFiles = result.diagnostics
|
|
.filter((diagnostic) => diagnostic.category === "coverage")
|
|
.map((diagnostic) => diagnostic.file);
|
|
|
|
expect(coverageFiles).toEqual(["backend/service.ts"]);
|
|
} finally {
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
|
|
it("does not treat symlinked source directories outside the repo as live code coverage", async () => {
|
|
const repo = await createTempRepo();
|
|
|
|
try {
|
|
const outsideDir = path.resolve(
|
|
repo.rootDir,
|
|
"..",
|
|
"truthmark-coverage-outside-dir",
|
|
);
|
|
|
|
await initializeRepo(repo.rootDir);
|
|
await repo.writeFile(
|
|
"docs/truthmark/engineering/authentication.md",
|
|
"---\nstatus: active\n---\n\n# Authentication\n",
|
|
);
|
|
await fs.mkdir(outsideDir, { recursive: true });
|
|
await fs.writeFile(
|
|
path.join(outsideDir, "outside.ts"),
|
|
"export const outside = true;\n",
|
|
"utf8",
|
|
);
|
|
await fs.mkdir(path.join(repo.rootDir, "src"), { recursive: true });
|
|
await fs.symlink(outsideDir, path.join(repo.rootDir, "src", "external"));
|
|
await repo.writeFile(
|
|
"docs/truthmark/routes/areas.md",
|
|
`# Truthmark Areas
|
|
|
|
## Authentication
|
|
|
|
Truth documents:
|
|
- docs/truthmark/engineering/authentication.md
|
|
|
|
Code surface:
|
|
- src/external/**
|
|
|
|
Update truth when:
|
|
- authentication behavior changes
|
|
`,
|
|
);
|
|
|
|
const result = await runCheck(repo.rootDir);
|
|
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "area-index" &&
|
|
diagnostic.file === "src/external/**",
|
|
),
|
|
).toBe(true);
|
|
expect(
|
|
result.diagnostics.some(
|
|
(diagnostic) =>
|
|
diagnostic.category === "coverage" &&
|
|
diagnostic.file === "src/external/outside.ts",
|
|
),
|
|
).toBe(false);
|
|
} finally {
|
|
await fs.rm(
|
|
path.resolve(repo.rootDir, "..", "truthmark-coverage-outside-dir"),
|
|
{
|
|
force: true,
|
|
recursive: true,
|
|
},
|
|
);
|
|
await repo.cleanup();
|
|
}
|
|
});
|
|
});
|