docs: overhaul public product guides (#1749)

* docs: overhaul public product guides

* fix(docs): address review findings

* docs: clarify validation contracts

* docs: complete validator API contracts

* docs: clarify validator existence check
This commit is contained in:
José Almeida
2026-07-17 11:30:37 +01:00
committed by GitHub
parent 934b713ee9
commit c633b8faa1
66 changed files with 7322 additions and 3096 deletions
+806 -20
View File
@@ -1,3 +1,4 @@
import { createHash } from "node:crypto";
import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
@@ -6,6 +7,7 @@ const repoRoot = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"..",
);
const defaultDocsDir = path.join(repoRoot, "docs/public");
/**
* Validate that every published Markdown page has frontmatter and appears
@@ -14,9 +16,7 @@ const repoRoot = path.resolve(
* @param {string} [docsDir] Directory containing published docs and meta.json.
* @returns {Promise<{pageCount: number}>} Number of validated published pages.
*/
export async function validatePublicDocs(
docsDir = path.join(repoRoot, "docs/public"),
) {
export async function validatePublicDocs(docsDir = defaultDocsDir) {
const meta = await readMeta(docsDir);
const files = await collectMarkdownFiles(docsDir);
const pagesBySlug = new Map();
@@ -28,6 +28,7 @@ export async function validatePublicDocs(
if (path.posix.basename(file).toLowerCase() === "readme.md") continue;
assertFrontmatter(file, markdown);
assertDocumentStructure(file, markdown);
const slug = file.replace(/\.mdx?$/, "").replace(/\/index$/, "");
const existing = pagesBySlug.get(slug);
@@ -58,9 +59,685 @@ export async function validatePublicDocs(
}
}
const featureMediaDir = path.join(docsDir, "media/feature-guides");
if (await pathExists(featureMediaDir)) {
await validateFeatureMedia({ docsDir });
}
if (path.resolve(docsDir) === defaultDocsDir) {
await validateCoverageInventory({ repoRoot, docsDir });
}
return { pageCount: pagesBySlug.size };
}
/**
* Validate reviewed, focused feature-guide media and its publication ownership.
*
* The checked-in manifest is the durable boundary between disposable capture
* tooling and published documentation. Every clip must retain accepted QA,
* exact file hashes, a real page/section owner, and a complete DocsVideo embed.
*
* @param {{docsDir: string}} paths Published docs root.
* @returns {Promise<{clipCount: number}>} Number of validated clips.
*/
export async function validateFeatureMedia({ docsDir }) {
const mediaDir = path.join(docsDir, "media/feature-guides");
const manifestPath = path.join(mediaDir, "manifest.json");
const notesPath = path.join(mediaDir, "NOTES.txt");
const manifest = JSON.parse(await fs.readFile(manifestPath, "utf8"));
if (manifest?.schema_version !== 1 || !Array.isArray(manifest.clips)) {
throw new Error(
"feature media manifest must use schema version 1 and contain clips",
);
}
if (manifest.qa_status !== "accepted") {
throw new Error("feature media manifest must have accepted QA status");
}
if (
typeof manifest.generated_at !== "string" ||
!Number.isFinite(Date.parse(manifest.generated_at))
) {
throw new Error(
"feature media manifest must record a valid generation time",
);
}
if (manifest.clips.length < 1 || manifest.clips.length > 10) {
throw new Error(
"feature media manifest must contain between 1 and 10 clips",
);
}
assertFeatureMediaContract(manifest.delivery_contract);
const notes = await fs.readFile(notesPath, "utf8");
if (!notes.trim()) {
throw new Error(
"feature media NOTES.txt must describe capture provenance and QA",
);
}
const expectedFiles = new Set(["manifest.json", "NOTES.txt"]);
const slugs = new Set();
for (const clip of manifest.clips) {
assertFeatureClipShape(clip);
if (slugs.has(clip.slug)) {
throw new Error(`feature media manifest repeats clip slug: ${clip.slug}`);
}
slugs.add(clip.slug);
const pagePath = resolveInside(
docsDir,
clip.intended_docs.page,
`${clip.slug} documentation page`,
);
if (!/\.mdx?$/i.test(pagePath)) {
throw new Error(
`${clip.slug} documentation owner must be a Markdown page`,
);
}
const page = await fs.readFile(pagePath, "utf8");
if (!collectHeadingTitles(page).has(clip.intended_docs.section)) {
throw new Error(
`${clip.slug} targets missing section in ${clip.intended_docs.page}: ${clip.intended_docs.section}`,
);
}
if (!hasCompleteFeatureMediaEmbed(page, clip.filenames)) {
throw new Error(
`${clip.slug} is not embedded with its complete media triplet in ${clip.intended_docs.page}`,
);
}
const expectedCodecs = { webm: "vp9", mp4: "h264", poster: "webp" };
for (const [kind, extension] of Object.entries({
webm: "webm",
mp4: "mp4",
poster: "webp",
})) {
const filename = clip.filenames[kind];
if (filename !== `${clip.slug}.${extension}`) {
throw new Error(
`${clip.slug} has unexpected ${kind} filename: ${filename}`,
);
}
const record = clip.files[kind];
if (
!record ||
!Number.isInteger(record.bytes) ||
record.bytes <= 0 ||
record.codec !== expectedCodecs[kind] ||
typeof record.sha256 !== "string" ||
!/^[a-f0-9]{64}$/.test(record.sha256)
) {
throw new Error(`${clip.slug} has invalid ${kind} file metadata`);
}
const filePath = resolveInside(
mediaDir,
filename,
`${clip.slug} ${kind}`,
);
const contents = await fs.readFile(filePath);
if (contents.byteLength !== record.bytes) {
throw new Error(`${filename} byte count does not match manifest`);
}
const digest = createHash("sha256").update(contents).digest("hex");
if (digest !== record.sha256) {
throw new Error(`${filename} SHA-256 does not match manifest`);
}
expectedFiles.add(filename);
}
}
const entries = await fs.readdir(mediaDir, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isFile() || !expectedFiles.has(entry.name)) {
throw new Error(
`feature media directory contains untracked file: ${entry.name}`,
);
}
}
for (const filename of expectedFiles) {
if (!entries.some((entry) => entry.isFile() && entry.name === filename)) {
throw new Error(
`feature media directory is missing tracked file: ${filename}`,
);
}
}
return { clipCount: slugs.size };
}
/**
* Require the publication dimensions, cadence, codecs, and no-audio policy.
*
* @param {object} contract Media contract from the feature-guide manifest.
* @returns {void}
*/
function assertFeatureMediaContract(contract) {
if (
contract?.dimensions?.width !== 960 ||
contract?.dimensions?.height !== 600 ||
contract?.frame_rate !== 25 ||
contract?.audio !== false ||
JSON.stringify(contract?.video_formats) !==
JSON.stringify(["vp9-webm", "h264-mp4"]) ||
contract?.poster_format !== "webp"
) {
throw new Error(
"feature media manifest has an unsupported delivery contract",
);
}
}
/**
* Validate one clip's ownership, provenance, delivery metadata, and file maps.
*
* @param {object} clip Feature-guide manifest clip entry.
* @returns {void}
*/
function assertFeatureClipShape(clip) {
if (!clip || typeof clip !== "object" || Array.isArray(clip)) {
throw new Error("feature media manifest contains an invalid clip entry");
}
const fields = [
[
"slug",
typeof clip.slug === "string" &&
/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(clip.slug),
],
["title", typeof clip.title === "string" && clip.title.trim().length > 0],
[
"accessible_caption",
typeof clip.accessible_caption === "string" &&
clip.accessible_caption.trim().length > 0,
],
[
"source_scenario",
typeof clip.source_scenario === "string" &&
clip.source_scenario.trim().length >= 20,
],
[
"data_isolation",
typeof clip.data_isolation === "string" &&
clip.data_isolation.trim().length >= 20,
],
[
"duration_seconds",
typeof clip.duration_seconds === "number" &&
clip.duration_seconds >= 6 &&
clip.duration_seconds <= 15,
],
[
"dimensions",
clip.dimensions?.width === 960 && clip.dimensions?.height === 600,
],
[
"intended_docs",
typeof clip.intended_docs?.page === "string" &&
typeof clip.intended_docs?.section === "string" &&
clip.intended_docs.section.trim().length > 0,
],
[
"filenames",
Boolean(
clip.filenames &&
typeof clip.filenames === "object" &&
!Array.isArray(clip.filenames),
),
],
[
"files",
Boolean(
clip.files && typeof clip.files === "object" && !Array.isArray(clip.files),
),
],
];
const invalidField = fields.find(([, valid]) => !valid)?.[0];
if (invalidField) {
const owner =
typeof clip.slug === "string" && clip.slug.length > 0
? clip.slug
: "<unknown>";
throw new Error(`feature media clip ${owner} has invalid ${invalidField}`);
}
}
/**
* Match each manifest filename to its corresponding DocsVideo attribute.
*
* @param {string} markdown Published page source.
* @param {Record<string, string>} filenames Expected media filenames by format.
* @returns {boolean} Whether one DocsVideo embeds the complete media triplet.
*/
function hasCompleteFeatureMediaEmbed(markdown, filenames) {
return [
...stripMarkdownCode(markdown).matchAll(/<DocsVideo\b[\s\S]*?\/>/g),
].some((match) => {
const attributes = Object.fromEntries(
[
...match[0].matchAll(
/\b(webm|mp4|poster)\s*=\s*(?:"([^"]*)"|'([^']*)')/g,
),
].map((attribute) => [
attribute[1],
attribute[2] ?? attribute[3],
]),
);
return Object.entries(filenames).every(
([kind, filename]) =>
attributes[kind]?.replace(/^\.\//, "") ===
`media/feature-guides/${filename}`,
);
});
}
/**
* Collect visible heading labels for media section-ownership checks.
*
* @param {string} markdown Published page source.
* @returns {Set<string>} Normalized visible heading labels.
*/
function collectHeadingTitles(markdown) {
const titles = new Set();
for (const match of stripMarkdownCode(markdown, {
keepInlineCode: true,
}).matchAll(/^ {0,3}#{1,6}[ \t]+(.+?)\s*#*\s*$/gm)) {
titles.add(stripHeadingMarkup(match[1]));
}
return titles;
}
/**
* Remove supported inline heading markup and reject unterminated HTML tags.
*
* @param {string} value Raw Markdown heading label.
* @returns {string} Visible heading text.
*/
function stripHeadingMarkup(value) {
const linkedText = value
.replace(/!\[([^\]]*)\]\([^)]*\)/g, "$1")
.replace(/\[([^\]]+)\]\([^)]*\)/g, "$1");
let text = "";
let insideTag = false;
for (const character of linkedText) {
if (character === "<") {
insideTag = true;
} else if (character === ">" && insideTag) {
insideTag = false;
} else if (!insideTag) {
text += character;
}
}
if (insideTag) {
throw new Error("heading contains unterminated inline HTML");
}
return text.replace(/[`*_~]/g, "").trim();
}
/**
* Resolve a relative path while requiring it to remain below the supplied root.
*
* @param {string} root Allowed filesystem root.
* @param {string} relativePath Untrusted repository-relative path.
* @param {string} label Human-readable field name for validation errors.
* @returns {string} Absolute path inside the root.
*/
function resolveInside(root, relativePath, label) {
const target = path.resolve(root, relativePath);
const relative = path.relative(root, target);
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
throw new Error(`${label} must stay inside ${root}`);
}
return target;
}
/**
* Check whether a filesystem target exists.
*
* @param {string} target Absolute filesystem path.
* @returns {Promise<boolean>} Whether the target exists.
*/
async function pathExists(target) {
try {
await fs.access(target);
return true;
} catch {
return false;
}
}
/**
* Validate the source-backed feature coverage inventory.
*
* The inventory assigns every published product area to documentation pages
* and concrete implementation/test evidence. It also accounts for every
* statically registered Settings route and Kandev MCP tool, so newly shipped
* surfaces cannot silently bypass the public docs.
*
* @param {{repoRoot: string, docsDir: string}} paths Repository and docs roots.
* @returns {Promise<{areaCount: number, settingsRouteCount: number, mcpToolCount: number}>}
*/
export async function validateCoverageInventory({ repoRoot, docsDir }) {
const coveragePath = path.join(docsDir, "coverage.json");
const coverage = JSON.parse(await fs.readFile(coveragePath, "utf8"));
if (coverage?.version !== 1 || !Array.isArray(coverage.areas)) {
throw new Error(
"coverage.json must use version 1 and contain an areas array",
);
}
if (coverage.areas.length === 0) {
throw new Error("coverage.json must contain at least one coverage area");
}
const pageSlugs = new Set(
(await collectMarkdownFiles(docsDir))
.filter((file) => path.posix.basename(file).toLowerCase() !== "readme.md")
.map((file) => file.replace(/\.mdx?$/, "").replace(/\/index$/, "")),
);
const areaIds = new Set();
const coveredDocsPages = new Set();
const coveredSettingsRoutes = new Set();
const coveredMcpTools = new Set();
for (const area of coverage.areas) {
assertCoverageAreaShape(area);
if (areaIds.has(area.id)) {
throw new Error(`coverage.json repeats area id: ${area.id}`);
}
areaIds.add(area.id);
for (const slug of area.docs) {
if (!pageSlugs.has(slug)) {
throw new Error(`${area.id} cites unknown docs page: ${slug}`);
}
coveredDocsPages.add(slug);
}
for (const source of area.sources) {
await assertCoverageEvidence(repoRoot, area.id, "source", source);
}
for (const testFile of area.tests) {
await assertCoverageEvidence(repoRoot, area.id, "test", testFile);
}
addUniqueCoverageValues(
coveredSettingsRoutes,
area.settingsRoutes ?? [],
"settings route",
);
addUniqueCoverageValues(coveredMcpTools, area.mcpTools ?? [], "MCP tool");
}
for (const slug of pageSlugs) {
if (!coveredDocsPages.has(slug)) {
throw new Error(`coverage.json does not account for docs page: ${slug}`);
}
}
const exclusions = coverage.exclusions ?? {};
const excludedSettingsRoutes = validateCoverageExclusions(
exclusions.settingsRoutes ?? [],
"route",
"settings route",
);
const excludedMcpTools = validateCoverageExclusions(
exclusions.mcpTools ?? [],
"tool",
"MCP tool",
);
const shippedSettingsRoutes = await collectSettingsRoutes(repoRoot);
assertCompleteSurfaceCoverage(
shippedSettingsRoutes,
coveredSettingsRoutes,
excludedSettingsRoutes,
"settings route",
);
const registeredMcpTools = await collectMcpTools(repoRoot);
assertCompleteSurfaceCoverage(
registeredMcpTools,
coveredMcpTools,
excludedMcpTools,
"MCP tool",
);
return {
areaCount: areaIds.size,
settingsRouteCount: shippedSettingsRoutes.size,
mcpToolCount: registeredMcpTools.size,
};
}
/**
* Require one coverage area to declare audiences, docs, and concrete evidence.
*
* @param {object} area Coverage inventory area.
* @returns {void}
*/
function assertCoverageAreaShape(area) {
if (!area || typeof area !== "object" || Array.isArray(area)) {
throw new Error("coverage.json areas must contain objects");
}
if (
typeof area.id !== "string" ||
!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(area.id)
) {
throw new Error("coverage.json area ids must use lowercase kebab-case");
}
assertStringArray(area, "audiences", area.id);
assertStringArray(area, "docs", area.id);
assertStringArray(area, "sources", area.id);
assertStringArray(area, "tests", area.id);
if (!new Set(["stable", "beta", "experimental"]).has(area.stability)) {
throw new Error(`${area.id} has unsupported stability: ${area.stability}`);
}
for (const optionalField of ["settingsRoutes", "mcpTools"]) {
if (area[optionalField] !== undefined) {
assertStringArray(area, optionalField, area.id, { allowEmpty: true });
}
}
}
/**
* Validate a named inventory field as a string list.
*
* @param {object} object Inventory object containing the field.
* @param {string} field Field name to validate.
* @param {string} owner Area identifier used in validation errors.
* @param {{allowEmpty?: boolean}} options Empty-list policy.
* @returns {void}
*/
function assertStringArray(object, field, owner, { allowEmpty = false } = {}) {
const value = object[field];
if (
!Array.isArray(value) ||
(!allowEmpty && value.length === 0) ||
!value.every((entry) => typeof entry === "string" && entry.length > 0)
) {
throw new Error(
`${owner} ${field} must be ${allowEmpty ? "an" : "a non-empty"} array of strings`,
);
}
}
/**
* Require cited implementation or test evidence to be a repository file.
*
* @param {string} root Repository root.
* @param {string} areaId Coverage area identifier.
* @param {string} kind Evidence kind shown in validation errors.
* @param {string} relativePath Repository-relative evidence path.
* @returns {Promise<void>}
*/
async function assertCoverageEvidence(root, areaId, kind, relativePath) {
const target = path.resolve(root, relativePath);
const relative = path.relative(root, target);
if (relative.startsWith("..") || path.isAbsolute(relative)) {
throw new Error(
`${areaId} cites ${kind} outside the repository: ${relativePath}`,
);
}
let stats;
try {
stats = await fs.stat(target);
} catch {
throw new Error(`${areaId} cites missing ${kind}: ${relativePath}`);
}
if (!stats.isFile()) {
throw new Error(`${areaId} cites non-file ${kind}: ${relativePath}`);
}
}
/**
* Add coverage assignments while rejecting duplicate owners.
*
* @param {Set<string>} target Accumulated assignments.
* @param {string[]} values New settings routes or MCP tools.
* @param {string} label Surface name shown in validation errors.
* @returns {void}
*/
function addUniqueCoverageValues(target, values, label) {
for (const value of values) {
if (target.has(value)) {
throw new Error(
`coverage.json assigns ${label} more than once: ${value}`,
);
}
target.add(value);
}
}
/**
* Parse intentionally excluded surfaces and require a durable reason for each.
*
* @param {object[]} entries Coverage exclusion records.
* @param {string} key Property containing the excluded surface identifier.
* @param {string} label Surface name shown in validation errors.
* @returns {Set<string>} Excluded surface identifiers.
*/
function validateCoverageExclusions(entries, key, label) {
if (!Array.isArray(entries)) {
throw new Error(`coverage.json excluded ${label}s must be an array`);
}
const values = new Set();
for (const entry of entries) {
if (
!entry ||
typeof entry !== "object" ||
typeof entry[key] !== "string" ||
typeof entry.reason !== "string" ||
entry.reason.trim().length < 8
) {
throw new Error(
`coverage.json excluded ${label}s require ${key} and a reason`,
);
}
if (values.has(entry[key])) {
throw new Error(
`coverage.json excludes ${label} more than once: ${entry[key]}`,
);
}
values.add(entry[key]);
}
return values;
}
/**
* Extract the shipped Settings route registry from its typed frontend table.
*
* @param {string} root Repository root.
* @returns {Promise<Set<string>>} Registered Settings routes.
*/
async function collectSettingsRoutes(root) {
const source = await fs.readFile(
path.join(root, "apps/web/src/settings-routes.tsx"),
"utf8",
);
const routeTable = source.match(
/const SETTINGS_ROUTES[\s\S]*?\n};\s*\n\s*export function SettingsRoutes/,
)?.[0];
if (!routeTable) {
throw new Error("could not locate SETTINGS_ROUTES in settings-routes.tsx");
}
return new Set(
[...routeTable.matchAll(/^\s*"(\/settings(?:\/[^"]*)?)":/gm)].map(
(match) => match[1],
),
);
}
/**
* Extract every registered Kandev MCP tool name from backend server sources.
*
* @param {string} root Repository root.
* @returns {Promise<Set<string>>} Registered MCP tool names.
*/
async function collectMcpTools(root) {
const serverDir = path.join(root, "apps/backend/internal/mcp/server");
const files = await collectFilesWithExtension(serverDir, ".go");
const tools = new Set();
for (const file of files) {
const source = await fs.readFile(file, "utf8");
for (const match of source.matchAll(
/mcp\.NewTool(?:WithRawSchema)?\(\s*"([^"]+)"/g,
)) {
tools.add(match[1]);
}
}
return tools;
}
/**
* Recursively collect regular files with a requested extension.
*
* @param {string} dir Directory to traverse.
* @param {string} extension Filename extension including the leading dot.
* @returns {Promise<string[]>} Absolute matching file paths.
*/
async function collectFilesWithExtension(dir, extension) {
const entries = await fs.readdir(dir, { withFileTypes: true });
const files = await Promise.all(
entries.map(async (entry) => {
const target = path.join(dir, entry.name);
if (entry.isDirectory())
return collectFilesWithExtension(target, extension);
return entry.isFile() && entry.name.endsWith(extension) ? [target] : [];
}),
);
return files.flat();
}
/**
* Require shipped surfaces to form a disjoint covered-or-excluded partition.
*
* @param {Set<string>} shipped Surfaces registered by the application.
* @param {Set<string>} covered Surfaces assigned to documentation areas.
* @param {Set<string>} excluded Surfaces intentionally excluded with reasons.
* @param {string} label Surface name shown in validation errors.
* @returns {void}
*/
function assertCompleteSurfaceCoverage(shipped, covered, excluded, label) {
for (const value of covered) {
if (excluded.has(value)) {
throw new Error(`coverage.json both covers and excludes ${label}: ${value}`);
}
}
for (const value of shipped) {
if (!covered.has(value) && !excluded.has(value)) {
throw new Error(`coverage.json does not account for ${label}: ${value}`);
}
}
for (const value of [...covered, ...excluded]) {
if (!shipped.has(value)) {
throw new Error(`coverage.json references unknown ${label}: ${value}`);
}
}
}
/**
* Read and validate the shape of public navigation metadata.
*
@@ -128,6 +805,28 @@ function assertFrontmatter(file, markdown) {
}
}
/**
* Require one real page title immediately after frontmatter.
*
* @param {string} file Relative page path used in validation errors.
* @param {string} markdown Page source.
* @returns {void}
*/
function assertDocumentStructure(file, markdown) {
const frontmatter = markdown.match(
/^---\r?\n[\s\S]*?\r?\n---(?:\r?\n|$)/,
)?.[0];
const body = stripMarkdownCode(
markdown.slice(frontmatter?.length ?? 0),
).trimStart();
const headings = [...body.matchAll(/^# [^\n]+$/gm)];
if (!body.startsWith("# ") || headings.length !== 1) {
throw new Error(
`${file} must begin with exactly one level-one heading after frontmatter`,
);
}
}
/**
* Require every relative Markdown link or image to resolve on disk.
*
@@ -142,6 +841,7 @@ async function assertLocalLinks(docsDir, file, markdown) {
const referencePattern = /!?\[([^\]\n]+)\]\[([^\]\n]*)\]/g;
const shortcutReferencePattern = /(?<![!\\\[\]])\[([^\]\n]+)\](?![\[(:])/g;
const destinations = collectInlineLinkDestinations(source);
destinations.push(...collectDocsVideoDestinations(source));
const definitions = new Map();
for (const match of source.matchAll(definitionPattern)) {
@@ -176,7 +876,7 @@ async function assertLocalLinks(docsDir, file, markdown) {
for (const destination of destinations) {
const href = parseMarkdownDestination(destination);
if (!href || href.startsWith("#") || isExternalDestination(href)) {
if (!href || isExternalDestination(href)) {
continue;
}
if (href.startsWith("/")) {
@@ -185,28 +885,107 @@ async function assertLocalLinks(docsDir, file, markdown) {
);
}
const pathOnly = href.split(/[?#]/, 1)[0];
if (!pathOnly) continue;
const hashIndex = href.indexOf("#");
const pathAndQuery = hashIndex === -1 ? href : href.slice(0, hashIndex);
const rawFragment = hashIndex === -1 ? "" : href.slice(hashIndex + 1);
const pathOnly = pathAndQuery.split("?", 1)[0];
let decoded;
try {
decoded = decodeURIComponent(pathOnly);
} catch {
throw new Error(`${file} contains an invalid encoded local link: ${href}`);
throw new Error(
`${file} contains an invalid encoded local link: ${href}`,
);
}
const target = path.resolve(
path.dirname(path.join(docsDir, file)),
decoded.replace(/\\([\\() ])/g, "$1"),
);
const target = pathOnly
? path.resolve(
path.dirname(path.join(docsDir, file)),
decoded.replace(/\\([\\() ])/g, "$1"),
)
: path.join(docsDir, file);
try {
await fs.access(target);
} catch {
throw new Error(`${file} links to missing local target: ${href}`);
}
if (rawFragment && /\.mdx?$/i.test(target)) {
await assertHeadingFragment(file, href, target, rawFragment);
}
}
}
/**
* Require a local Markdown fragment to match the published heading identifier.
*
* @param {string} file Relative source path used in validation errors.
* @param {string} href Original link destination.
* @param {string} target Absolute target Markdown path.
* @param {string} rawFragment URL-encoded fragment without the hash marker.
* @returns {Promise<void>}
*/
async function assertHeadingFragment(file, href, target, rawFragment) {
let fragment;
try {
fragment = decodeURIComponent(rawFragment);
} catch {
throw new Error(`${file} contains an invalid encoded local link: ${href}`);
}
const markdown = await fs.readFile(target, "utf8");
if (!collectHeadingAnchors(markdown).has(fragment)) {
throw new Error(`${file} links to missing heading: ${href}`);
}
}
/**
* Collect the GitHub-style identifiers emitted for Markdown headings.
*
* Duplicate headings receive the same numeric suffix used by rehype-slug.
*
* @param {string} markdown Markdown page source.
* @returns {Set<string>} Published heading identifiers.
*/
function collectHeadingAnchors(markdown) {
const source = stripMarkdownCode(markdown, { keepInlineCode: true });
const anchors = new Set();
const counts = new Map();
for (const match of source.matchAll(/^ {0,3}#{1,6}[ \t]+(.+?)\s*#*\s*$/gm)) {
const base = stripHeadingMarkup(match[1])
.toLowerCase()
.replace(/[^\p{L}\p{N}\s_-]/gu, "")
.replace(/\s+/g, "-");
if (!base) continue;
const duplicateIndex = counts.get(base) ?? 0;
counts.set(base, duplicateIndex + 1);
anchors.add(duplicateIndex === 0 ? base : `${base}-${duplicateIndex}`);
}
return anchors;
}
/**
* Collect source and poster paths from the supported DocsVideo MDX component.
*
* @param {string} markdown Markdown with code regions removed.
* @returns {string[]} Local or external media destinations.
*/
function collectDocsVideoDestinations(markdown) {
const destinations = [];
for (const tag of markdown.matchAll(/<DocsVideo\b[\s\S]*?\/>/g)) {
for (const attribute of tag[0].matchAll(
/\b(?:webm|mp4|poster)=(?:"([^"]+)"|'([^']+)')/g,
)) {
destinations.push(attribute[1] ?? attribute[2]);
}
}
return destinations;
}
/**
* Collect inline Markdown destinations while preserving balanced parentheses.
*
@@ -269,7 +1048,11 @@ function collectInlineLinkDestinations(markdown) {
*/
function isEscaped(value, index) {
let backslashes = 0;
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
for (
let cursor = index - 1;
cursor >= 0 && value[cursor] === "\\";
cursor -= 1
) {
backslashes += 1;
}
return backslashes % 2 === 1;
@@ -280,9 +1063,10 @@ function isEscaped(value, index) {
* live links.
*
* @param {string} markdown Page source.
* @param {{keepInlineCode?: boolean}} [options] Inline-code handling.
* @returns {string} Markdown with code regions removed.
*/
function stripMarkdownCode(markdown) {
function stripMarkdownCode(markdown, { keepInlineCode = false } = {}) {
let fence = null;
let indentedCodeIndent = null;
let canStartIndentedCode = true;
@@ -329,20 +1113,22 @@ function stripMarkdownCode(markdown) {
return "";
}
const listMarker = line.match(
/^([ \t]*)(?:[-+*]|\d{1,9}[.)])([ \t]+)/,
);
const listMarker = line.match(/^([ \t]*)(?:[-+*]|\d{1,9}[.)])([ \t]+)/);
if (listMarker) {
listContentIndents.push(columnWidth(listMarker[0]));
}
canStartIndentedCode = /^(?: {0,3}#{1,6}(?:[ \t]+|$)| {0,3}(?:=+|-+)[ \t]*$| {0,3}\[[^\]\n]+\]:)/.test(
line,
);
canStartIndentedCode =
/^(?: {0,3}#{1,6}(?:[ \t]+|$)| {0,3}(?:=+|-+)[ \t]*$| {0,3}\[[^\]\n]+\]:)/.test(
line,
);
return line;
});
return lines.join("\n").replace(/`+[^`\n]*`+/g, "");
const withoutBlocks = lines.join("\n");
return keepInlineCode
? withoutBlocks
: withoutBlocks.replace(/`+[^`\n]*`+/g, "");
}
/**
+525 -3
View File
@@ -1,9 +1,14 @@
import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import test, { after } from "node:test";
import { validatePublicDocs } from "./validate-public-docs.mjs";
import {
validateCoverageInventory,
validateFeatureMedia,
validatePublicDocs,
} from "./validate-public-docs.mjs";
const tempDirs = [];
@@ -28,6 +33,158 @@ async function createDocs(files, meta) {
return dir;
}
/**
* Create a minimal repository fixture for source-backed coverage validation.
*
* @param {object} options Fixture overrides.
* @returns {Promise<{repoRoot: string, docsDir: string}>} Fixture paths.
*/
async function createCoverageRepo({
coverage,
settingsRoutes = ["/settings", "/settings/general"],
mcpTools = ["list_workspaces_kandev"],
omitFiles = [],
} = {}) {
const repoRoot = await fs.mkdtemp(
path.join(os.tmpdir(), "kandev-doc-coverage-"),
);
tempDirs.push(repoRoot);
const docsDir = path.join(repoRoot, "docs/public");
const files = {
"docs/public/index.md": validPage,
"apps/web/src/settings-routes.tsx": `const SETTINGS_ROUTES = {\n${settingsRoutes
.map((route) => ` "${route}": () => null,`)
.join("\n")}\n};\n\nexport function SettingsRoutes() {}`,
"apps/web/src/settings-routes.test.ts": "// settings route coverage",
"apps/backend/internal/mcp/server/server.go": mcpTools
.map((tool) => `mcp.NewTool("${tool}")`)
.join("\n"),
"apps/backend/internal/mcp/server/server_test.go": "// MCP coverage",
};
for (const [file, content] of Object.entries(files)) {
if (omitFiles.includes(file)) continue;
const target = path.join(repoRoot, file);
await fs.mkdir(path.dirname(target), { recursive: true });
await fs.writeFile(target, content);
}
const inventory = coverage ?? {
version: 1,
areas: [
{
id: "workspace-control",
audiences: ["user"],
stability: "stable",
docs: ["index"],
sources: [
"apps/web/src/settings-routes.tsx",
"apps/backend/internal/mcp/server/server.go",
],
tests: [
"apps/web/src/settings-routes.test.ts",
"apps/backend/internal/mcp/server/server_test.go",
],
settingsRoutes: ["/settings/general"],
mcpTools: ["list_workspaces_kandev"],
},
],
exclusions: {
settingsRoutes: [
{ route: "/settings", reason: "Alias for General settings." },
],
mcpTools: [],
},
};
await fs.writeFile(
path.join(docsDir, "coverage.json"),
JSON.stringify(inventory),
);
return { repoRoot, docsDir };
}
/**
* Create a complete focused-media fixture with one embedded clip.
*
* @param {object} options Fixture overrides.
* @returns {Promise<{docsDir: string, manifest: object, mediaDir: string}>}
*/
async function createFeatureMedia({ manifestPatch, extraFiles = {} } = {}) {
const docsDir = await fs.mkdtemp(path.join(os.tmpdir(), "kandev-doc-media-"));
tempDirs.push(docsDir);
const mediaDir = path.join(docsDir, "media/feature-guides");
await fs.mkdir(mediaDir, { recursive: true });
const files = {
"review.webm": "vp9-video",
"review.mp4": "h264-video",
"review.webp": "poster-image",
...extraFiles,
};
await Promise.all(
Object.entries(files).map(([file, content]) =>
fs.writeFile(path.join(mediaDir, file), content),
),
);
await fs.writeFile(
path.join(mediaDir, "NOTES.txt"),
"Isolated capture and QA notes.\n",
);
await fs.writeFile(
path.join(docsDir, "review.md"),
`${validPage.replace("# Kandev", "# Review")}\n## Review a diff\n\n<DocsVideo\n webm="./media/feature-guides/review.webm"\n mp4="./media/feature-guides/review.mp4"\n poster="./media/feature-guides/review.webp"\n title="Review a focused diff"\n/>\n`,
);
const fileRecord = (file, codec) => ({
bytes: Buffer.byteLength(files[file]),
codec,
sha256: createHash("sha256").update(files[file]).digest("hex"),
});
const manifest = {
schema_version: 1,
generated_at: "2026-07-16T00:00:00.000Z",
qa_status: "accepted",
delivery_contract: {
dimensions: { width: 960, height: 600 },
frame_rate: 25,
audio: false,
video_formats: ["vp9-webm", "h264-mp4"],
poster_format: "webp",
},
clips: [
{
slug: "review",
title: "Review a focused diff",
intended_docs: { page: "review.md", section: "Review a diff" },
accessible_caption: "Select a changed line and send focused feedback.",
duration_seconds: 8.4,
dimensions: { width: 960, height: 600 },
source_scenario:
"Review an isolated fixture diff and leave line-level feedback.",
data_isolation:
"Disposable E2E workspace with mock-only agent data and no credentials.",
filenames: {
webm: "review.webm",
mp4: "review.mp4",
poster: "review.webp",
},
files: {
webm: fileRecord("review.webm", "vp9"),
mp4: fileRecord("review.mp4", "h264"),
poster: fileRecord("review.webp", "webp"),
},
},
],
...manifestPatch,
};
await fs.writeFile(
path.join(mediaDir, "manifest.json"),
`${JSON.stringify(manifest, null, 2)}\n`,
);
return { docsDir, manifest, mediaDir };
}
after(async () => {
await Promise.all(
tempDirs.map((dir) => fs.rm(dir, { recursive: true, force: true })),
@@ -146,6 +303,52 @@ test("rejects published pages without title and description frontmatter", async
);
});
test("rejects a published page without a level-one content heading", async () => {
const dir = await createDocs(
{
"index.md": `---
title: "Overview"
description: "Start using Kandev."
---
Start here.
`,
},
{ pages: ["index"] },
);
await assert.rejects(
validatePublicDocs(dir),
/index.md must begin with exactly one level-one heading after frontmatter/,
);
});
test("rejects a second level-one content heading", async () => {
const dir = await createDocs(
{ "index.md": `${validPage}\n# Another page title\n` },
{ pages: ["index"] },
);
await assert.rejects(
validatePublicDocs(dir),
/index.md must begin with exactly one level-one heading after frontmatter/,
);
});
test("ignores level-one headings shown inside code examples", async () => {
const dir = await createDocs(
{
"index.md": validPage.replace(
"Page body.",
"```markdown\n# Example document\n```",
),
},
{ pages: ["index"] },
);
await assert.doesNotReject(validatePublicDocs(dir));
});
test("accepts existing relative page and asset links", async () => {
const dir = await createDocs(
{
@@ -193,6 +396,50 @@ test("rejects a broken local image", async () => {
);
});
test("accepts existing DocsVideo sources and poster assets", async () => {
const dir = await createDocs(
{
"index.md": validPage.replace(
"Page body.",
`<DocsVideo
webm="./media/review.webm"
mp4="./media/review.mp4"
poster="./media/review.webp"
title="Review changes"
/>`,
),
"media/review.webm": "webm",
"media/review.mp4": "mp4",
"media/review.webp": "webp",
},
{ pages: ["index"] },
);
await assert.doesNotReject(validatePublicDocs(dir));
});
test("rejects a DocsVideo attribute that points to missing media", async () => {
const dir = await createDocs(
{
"index.md": validPage.replace(
"Page body.",
`<DocsVideo
mp4="./media/missing.mp4"
poster="./media/review.webp"
title="Review changes"
/>`,
),
"media/review.webp": "webp",
},
{ pages: ["index"] },
);
await assert.rejects(
validatePublicDocs(dir),
/index.md links to missing local target: \.\/media\/missing\.mp4/,
);
});
test("rejects a broken local image nested inside a link", async () => {
const dir = await createDocs(
{
@@ -211,15 +458,65 @@ test("rejects a broken local image nested inside a link", async () => {
);
});
test("ignores external, anchor-only, and fenced-code links", async () => {
test("accepts external, existing heading, and fenced-code links", async () => {
const dir = await createDocs(
{
"index.md": validPage.replace(
"Page body.",
`[External](https://example.com/docs)\n\n[Section](#section)\n\n\`\`\`md
`[External](https://example.com/docs)\n\n## Local section\n\n[Section](#local-section)\n\n[Other section](guide.md#nested-options)\n\n\`\`\`md
[Example only](does-not-exist.md)
\`\`\``,
),
"guide.md": validPage.replace("Page body.", "## Nested `options`\n"),
},
{ pages: ["index", "guide"] },
);
await assert.doesNotReject(validatePublicDocs(dir));
});
test("rejects a missing same-page heading fragment", async () => {
const dir = await createDocs(
{
"index.md": validPage.replace(
"Page body.",
"[Missing section](#missing-section)",
),
},
{ pages: ["index"] },
);
await assert.rejects(
validatePublicDocs(dir),
/index.md links to missing heading: #missing-section/,
);
});
test("rejects a missing heading fragment in another page", async () => {
const dir = await createDocs(
{
"index.md": validPage.replace(
"Page body.",
"[Missing section](guide.md#missing-section)",
),
"guide.md": validPage,
},
{ pages: ["index", "guide"] },
);
await assert.rejects(
validatePublicDocs(dir),
/index.md links to missing heading: guide.md#missing-section/,
);
});
test("accepts heading fragments whose labels contain complete inline HTML", async () => {
const dir = await createDocs(
{
"index.md": validPage.replace(
"Page body.",
"## Configure <span>profiles</span>\n\n[Profiles](#configure-profiles)",
),
},
{ pages: ["index"] },
);
@@ -227,6 +524,23 @@ test("ignores external, anchor-only, and fenced-code links", async () => {
await assert.doesNotReject(validatePublicDocs(dir));
});
test("rejects unterminated inline HTML in a linked heading", async () => {
const dir = await createDocs(
{
"index.md": validPage.replace(
"Page body.",
"## Unsafe <script\n\n[Unsafe](#unsafe-script)",
),
},
{ pages: ["index"] },
);
await assert.rejects(
validatePublicDocs(dir),
/heading contains unterminated inline HTML/,
);
});
test("ignores links inside inline code and nested shorter fences", async () => {
const dir = await createDocs(
{
@@ -441,3 +755,211 @@ test("rejects site-root links because public docs use relative sources", async (
/index.md uses a site-root link instead of a relative source link: \/docs\/guide/,
);
});
test("accepts source-backed coverage for every settings route and MCP tool", async () => {
const fixture = await createCoverageRepo();
await assert.doesNotReject(validateCoverageInventory(fixture));
});
test("rejects a shipped settings route with no documentation owner", async () => {
const fixture = await createCoverageRepo({
settingsRoutes: [
"/settings",
"/settings/general",
"/settings/system/status",
],
});
await assert.rejects(
validateCoverageInventory(fixture),
/coverage.json does not account for settings route: \/settings\/system\/status/,
);
});
test("rejects a registered MCP tool with no documentation owner", async () => {
const fixture = await createCoverageRepo({
mcpTools: ["list_workspaces_kandev", "create_task_kandev"],
});
await assert.rejects(
validateCoverageInventory(fixture),
/coverage.json does not account for MCP tool: create_task_kandev/,
);
});
test("rejects coverage entries that cite missing evidence", async () => {
const fixture = await createCoverageRepo({
omitFiles: ["apps/web/src/settings-routes.test.ts"],
});
await assert.rejects(
validateCoverageInventory(fixture),
/workspace-control cites missing test: apps\/web\/src\/settings-routes\.test\.ts/,
);
});
test("rejects coverage evidence that points to a directory", async () => {
const fixture = await createCoverageRepo();
const coveragePath = path.join(fixture.docsDir, "coverage.json");
const coverage = JSON.parse(await fs.readFile(coveragePath, "utf8"));
coverage.areas[0].tests[0] = "apps/web/src";
await fs.writeFile(coveragePath, JSON.stringify(coverage));
await assert.rejects(
validateCoverageInventory(fixture),
/workspace-control cites non-file test: apps\/web\/src/,
);
});
test("rejects shipped surfaces listed as both covered and excluded", async () => {
const fixture = await createCoverageRepo();
const coveragePath = path.join(fixture.docsDir, "coverage.json");
const coverage = JSON.parse(await fs.readFile(coveragePath, "utf8"));
coverage.exclusions.settingsRoutes.push({
route: "/settings/general",
reason: "This deliberately overlaps the covered route.",
});
await fs.writeFile(coveragePath, JSON.stringify(coverage));
await assert.rejects(
validateCoverageInventory(fixture),
/coverage.json both covers and excludes settings route: \/settings\/general/,
);
});
test("rejects duplicate coverage area identifiers", async () => {
const sharedArea = {
id: "workspace-control",
audiences: ["user"],
stability: "stable",
docs: ["index"],
sources: ["apps/web/src/settings-routes.tsx"],
tests: ["apps/web/src/settings-routes.test.ts"],
settingsRoutes: ["/settings/general"],
mcpTools: ["list_workspaces_kandev"],
};
const fixture = await createCoverageRepo({
coverage: {
version: 1,
areas: [sharedArea, { ...sharedArea }],
exclusions: {
settingsRoutes: [
{ route: "/settings", reason: "Alias for General settings." },
],
mcpTools: [],
},
},
});
await assert.rejects(
validateCoverageInventory(fixture),
/coverage.json repeats area id: workspace-control/,
);
});
test("rejects a published page with no feature coverage owner", async () => {
const { repoRoot, docsDir } = await createCoverageRepo();
await fs.writeFile(path.join(docsDir, "security.md"), validPage);
await assert.rejects(
validateCoverageInventory({ repoRoot, docsDir }),
/coverage.json does not account for docs page: security/,
);
});
test("accepts reviewed focused media with matching files and documentation owner", async () => {
const { docsDir } = await createFeatureMedia();
await assert.doesNotReject(validateFeatureMedia({ docsDir }));
});
test("rejects focused media whose QA status is not accepted", async () => {
const { docsDir } = await createFeatureMedia({
manifestPatch: { qa_status: "rejected" },
});
await assert.rejects(
validateFeatureMedia({ docsDir }),
/feature media manifest must have accepted QA status/,
);
});
test("rejects focused media without durable capture provenance", async () => {
const { docsDir, manifest, mediaDir } = await createFeatureMedia();
delete manifest.clips[0].data_isolation;
await fs.writeFile(
path.join(mediaDir, "manifest.json"),
`${JSON.stringify(manifest, null, 2)}\n`,
);
await assert.rejects(
validateFeatureMedia({ docsDir }),
/feature media clip review has invalid data_isolation/,
);
});
test("rejects focused media whose content no longer matches its hash", async () => {
const { docsDir, mediaDir } = await createFeatureMedia();
await fs.writeFile(path.join(mediaDir, "review.mp4"), "h264-videX");
await assert.rejects(
validateFeatureMedia({ docsDir }),
/review\.mp4 SHA-256 does not match manifest/,
);
});
test("rejects a focused-media target section that is absent from the page", async () => {
const { docsDir, manifest, mediaDir } = await createFeatureMedia();
manifest.clips[0].intended_docs.section = "Missing workflow";
await fs.writeFile(
path.join(mediaDir, "manifest.json"),
`${JSON.stringify(manifest, null, 2)}\n`,
);
await assert.rejects(
validateFeatureMedia({ docsDir }),
/review targets missing section in review\.md: Missing workflow/,
);
});
test("rejects focused media that is not embedded on its intended page", async () => {
const { docsDir } = await createFeatureMedia();
await fs.writeFile(
path.join(docsDir, "review.md"),
`${validPage}\n## Review a diff\n\nNo video is embedded here.\n`,
);
await assert.rejects(
validateFeatureMedia({ docsDir }),
/review is not embedded with its complete media triplet in review\.md/,
);
});
test("requires each focused-media file in its matching DocsVideo attribute", async () => {
const { docsDir } = await createFeatureMedia();
await fs.writeFile(
path.join(docsDir, "review.md"),
`${validPage}\n## Review a diff\n\n<DocsVideo
webm="./media/feature-guides/review.webm"
poster="./media/feature-guides/review.webp"
title="media/feature-guides/review.mp4"
/>\n`,
);
await assert.rejects(
validateFeatureMedia({ docsDir }),
/review is not embedded with its complete media triplet in review\.md/,
);
});
test("rejects orphaned focused-media deliverables", async () => {
const { docsDir } = await createFeatureMedia({
extraFiles: { "orphan.webp": "unused-poster" },
});
await assert.rejects(
validateFeatureMedia({ docsDir }),
/feature media directory contains untracked file: orphan\.webp/,
);
});