Files
stack/packages/mosaic/src/fleet/fleet-documentation.spec.ts
jason.woltje 627cf2bb38
Some checks failed
ci/woodpecker/push/ci Pipeline failed
ci/woodpecker/push/publish Pipeline was successful
docs(fleet): add operator configuration guide (#789)
2026-07-20 05:22:25 +00:00

940 lines
34 KiB
TypeScript

import { readFile, readdir } from 'node:fs/promises';
import { dirname, extname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import { parseRosterV2, validateRosterV2Semantics } from './roster-v2.js';
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
const repositoryRoot = resolve(packageRoot, '..', '..');
const fleetDocs = join(repositoryRoot, 'docs', 'fleet');
const frameworkFleet = join(packageRoot, 'framework', 'fleet');
const REQUIRED_FLEET_PAGES = [
'README.md',
'concepts/desired-vs-observed-state.md',
'concepts/identity-class-runtime.md',
'concepts/role-authority-and-leases.md',
'concepts/generated-env-launch-chain.md',
'reference/roster-v2.schema.json',
'reference/roster-v2-fields.md',
'reference/cli.md',
'reference/role-classes.md',
'reference/lifecycle-transitions.md',
'reference/status-and-drift.md',
'how-to/create-update-delete-agent.md',
'how-to/start-stop-restart.md',
'how-to/configure-tess-interaction.md',
'how-to/configure-ultron-validator.md',
'how-to/customize-roles.md',
'operations/reconcile-and-recover.md',
'operations/env-quarantine.md',
'operations/systemd-tmux-troubleshooting.md',
'operations/backup-restore.md',
'operations/upgrade-assets.md',
'migration/v1-to-v2.md',
'migration/example-profile-disposition.md',
'migration/legacy-class-aliases.md',
] as const;
async function markdownFiles(root: string): Promise<string[]> {
const entries = await readdir(root, { withFileTypes: true });
const paths = await Promise.all(
entries.map(async (entry): Promise<string[]> => {
const path = join(root, entry.name);
if (entry.isDirectory()) return markdownFiles(path);
return extname(entry.name) === '.md' ? [path] : [];
}),
);
return paths.flat().sort();
}
function localMarkdownTargets(source: string): string[] {
const link =
/\[[^\]]*\]\(\s*(?:<([^>]+)>|((?:\\.|[^()\s]|\([^()]*\))+))(?:\s+(?:"[^"]*"|'[^']*'|\([^)]*\)))?\s*\)/g;
return [...source.matchAll(link)]
.map((match): string => match[1] ?? match[2] ?? '')
.filter(
(target): boolean =>
target !== '' &&
!target.startsWith('http://') &&
!target.startsWith('https://') &&
!target.startsWith('mailto:'),
);
}
function markdownHeadingAnchors(source: string): Set<string> {
const anchors = new Set<string>();
let fence: { readonly marker: string; readonly length: number } | undefined;
for (const line of source.split('\n')) {
const fenceMatch = line.match(/^\s{0,3}(`{3,}|~{3,})(.*)$/);
if (fence === undefined && fenceMatch !== null) {
const run = fenceMatch[1] ?? '';
fence = { marker: run[0] ?? '', length: run.length };
continue;
}
if (fence !== undefined) {
const closingRun = line.match(/^\s{0,3}(`{3,}|~{3,})\s*$/)?.[1];
if (
closingRun !== undefined &&
closingRun[0] === fence.marker &&
closingRun.length >= fence.length
) {
fence = undefined;
}
continue;
}
const heading = line.match(/^\s{0,3}#{1,6}\s+(.+?)\s*#*\s*$/)?.[1];
if (heading === undefined) continue;
const base = heading
.replace(/!?\[([^\]]*)\]\([^)]*\)/g, '$1')
.replace(/<[^>]*>/g, '')
.replace(/[`*_~]/g, '')
.toLowerCase()
.trim()
.replace(/[^\p{L}\p{N}\s-]/gu, '')
.replace(/\s+/g, '-');
let anchor = base;
let duplicate = 0;
while (anchors.has(anchor)) {
duplicate += 1;
anchor = `${base}-${duplicate}`;
}
anchors.add(anchor);
}
return anchors;
}
function markdownLinkViolations(
sourcePath: string,
source: string,
documents: Readonly<Record<string, string>>,
): string[] {
const violations: string[] = [];
for (const target of localMarkdownTargets(source)) {
const [encodedPath = '', encodedFragment] = target.split('#', 2);
const targetPath = decodeURIComponent(encodedPath);
const normalizedTarget = resolve('/', dirname(sourcePath), targetPath).slice(1);
const targetSource = documents[normalizedTarget];
if (targetSource === undefined) {
violations.push(`${sourcePath} -> ${target}: missing file`);
continue;
}
if (encodedFragment !== undefined) {
const fragment = decodeURIComponent(encodedFragment);
if (fragment === '' || !markdownHeadingAnchors(targetSource).has(fragment)) {
violations.push(`${sourcePath} -> ${target}: missing heading`);
}
}
}
return violations;
}
type CodeSurfaceCategory = 'ConcreteCommand' | 'Synopsis' | 'DataProfile' | 'InlineLiteral';
interface CodeSurface {
readonly category: CodeSurfaceCategory;
readonly path: string;
readonly line: number;
readonly block?: number;
readonly info?: string;
readonly source: string;
}
interface SurfaceDiagnostic {
readonly path: string;
readonly line: number;
readonly block?: number;
readonly category?: CodeSurfaceCategory;
readonly code: string;
}
interface FenceProfile {
readonly path: string;
readonly block: number;
readonly info: string;
readonly category: Exclude<CodeSurfaceCategory, 'InlineLiteral'>;
readonly recordSchemas?: readonly string[];
}
const FENCE_PROFILES = [
{
path: 'FLEET-LAUNCH.md',
block: 1,
info: 'dotenv',
category: 'DataProfile',
recordSchemas: ['DATA.DOTENV.FLEET_LAUNCH'],
},
{
path: 'TASKS.md',
block: 1,
info: 'text-table',
category: 'DataProfile',
recordSchemas: ['DATA.TEXT_TABLE.FLEET_TASKS'],
},
{
path: 'backlog-conventions.md',
block: 1,
info: 'text-diagram',
category: 'DataProfile',
recordSchemas: ['DATA.TEXT_DIAGRAM.BACKLOG_FLOW'],
},
{
path: 'backlog-conventions.md',
block: 2,
info: 'fleet-command',
category: 'ConcreteCommand',
recordSchemas: [
'CMD.BACKLOG.CREATE.1',
'CMD.BACKLOG.CREATE.2',
'CMD.BACKLOG.CLAIM',
'CMD.BACKLOG.COMPLETE',
'CMD.BACKLOG.LIST_READY',
'CMD.BACKLOG.RECLAIM',
],
},
{
path: 'f4-matrix-connector.md',
block: 1,
info: 'typescript',
category: 'DataProfile',
recordSchemas: ['DATA.TYPESCRIPT.MATRIX_CONNECTOR_TYPE'],
},
{
path: 'f4-matrix-connector.md',
block: 2,
info: 'yaml',
category: 'DataProfile',
recordSchemas: ['DATA.YAML.MATRIX_CONNECTOR_CONFIG'],
},
{
path: 'how-to/configure-tess-interaction.md',
block: 1,
info: 'yaml',
category: 'DataProfile',
recordSchemas: ['DATA.YAML.INTERACTION_AGENT'],
},
{
path: 'how-to/configure-ultron-validator.md',
block: 1,
info: 'yaml',
category: 'DataProfile',
recordSchemas: ['DATA.YAML.VALIDATOR_AGENT'],
},
{
path: 'how-to/create-update-delete-agent.md',
block: 1,
info: 'fleet-synopsis',
category: 'Synopsis',
recordSchemas: ['SYN.AGENT.GET', 'SYN.PLAN.CREATE', 'SYN.PLAN.UPDATE', 'SYN.PLAN.DELETE'],
},
{
path: 'how-to/create-update-delete-agent.md',
block: 2,
info: 'fleet-command',
category: 'ConcreteCommand',
recordSchemas: ['CMD.AGENT.CREATE_JSON'],
},
{
path: 'how-to/create-update-delete-agent.md',
block: 3,
info: 'fleet-synopsis',
category: 'Synopsis',
recordSchemas: ['SYN.AGENT.UPDATE_COMPLETE', 'SYN.AGENT.DELETE'],
},
{
path: 'how-to/create-update-delete-agent.md',
block: 4,
info: 'json',
category: 'DataProfile',
recordSchemas: ['DATA.JSON.PARTIAL_FAILURE'],
},
{
path: 'how-to/customize-roles.md',
block: 1,
info: 'markdown',
category: 'DataProfile',
recordSchemas: ['DATA.MARKDOWN.ROLE_TEMPLATE'],
},
{
path: 'how-to/customize-roles.md',
block: 2,
info: 'markdown',
category: 'DataProfile',
recordSchemas: ['DATA.MARKDOWN.ROLE_EXAMPLE'],
},
{
path: 'how-to/start-stop-restart.md',
block: 1,
info: 'fleet-synopsis',
category: 'Synopsis',
recordSchemas: [
'SYN.APPLY.DRY',
'SYN.APPLY',
'SYN.RECONCILE',
'SYN.START.REQUIRED',
'SYN.STOP.REQUIRED',
'SYN.RESTART.REQUIRED',
'SYN.STATUS.OPTIONAL',
'SYN.VERIFY',
'SYN.DOCTOR',
],
},
{
path: 'migration/example-profile-disposition.md',
block: 1,
info: 'fleet-command',
category: 'ConcreteCommand',
recordSchemas: ['CMD.PNPM.MIGRATION_TEST'],
},
{
path: 'migration/v1-to-v2.md',
block: 1,
info: 'fleet-command',
category: 'ConcreteCommand',
recordSchemas: ['CMD.MIGRATE.PREVIEW'],
},
{
path: 'migration/v1-to-v2.md',
block: 2,
info: 'json',
category: 'DataProfile',
recordSchemas: ['DATA.JSON.LIFECYCLE_OBSERVATIONS'],
},
{
path: 'operations/reconcile-and-recover.md',
block: 1,
info: 'json',
category: 'DataProfile',
recordSchemas: ['DATA.JSON.RECOVERY_RESULT'],
},
{
path: 'reference/agent-mutations.md',
block: 1,
info: 'fleet-synopsis',
category: 'Synopsis',
recordSchemas: [
'SYN.AGENT.GET',
'SYN.PLAN.GENERIC',
'SYN.AGENT.CREATE',
'SYN.AGENT.UPDATE',
'SYN.AGENT.DELETE_DRY',
],
},
{
path: 'reference/agent-mutations.md',
block: 2,
info: 'json',
category: 'DataProfile',
recordSchemas: ['DATA.JSON.MUTATION_RESULT'],
},
{
path: 'reference/cli.md',
block: 1,
info: 'fleet-synopsis',
category: 'Synopsis',
recordSchemas: [
'SYN.APPLY',
'SYN.RECONCILE',
'SYN.START.OPTIONAL',
'SYN.STOP.OPTIONAL',
'SYN.RESTART.OPTIONAL',
'SYN.STATUS.OPTIONAL',
'SYN.VERIFY',
'SYN.DOCTOR',
'SYN.MIGRATE.PREVIEW',
],
},
{
path: 'reference/generated-env-boundary.md',
block: 1,
info: 'dotenv',
category: 'DataProfile',
recordSchemas: ['DATA.DOTENV.GENERATED_ENV'],
},
{
path: 'reference/roster-v2-fields.md',
block: 1,
info: 'yaml',
category: 'DataProfile',
recordSchemas: ['DATA.YAML.ROSTER_FIELDS'],
},
] as const satisfies readonly FenceProfile[];
const COMMAND_RECORDS: Readonly<Record<string, RegExp>> = {
'CMD.BACKLOG.CREATE.1': /^mosaic fleet backlog create --id A1 --title "schema" --priority 5$/,
'CMD.BACKLOG.CREATE.2':
/^mosaic fleet backlog create --id A2 --title "service" --depends-on A1 --priority 9$/,
'CMD.BACKLOG.CLAIM': /^mosaic fleet backlog claim --owner worker-1 --ttl 600 --json$/,
'CMD.BACKLOG.COMPLETE': /^mosaic fleet backlog complete --id A1$/,
'CMD.BACKLOG.LIST_READY': /^mosaic fleet backlog list --ready-only --json$/,
'CMD.BACKLOG.RECLAIM': /^mosaic fleet backlog reclaim --json$/,
'CMD.AGENT.CREATE_JSON':
/^mosaic fleet create --expected-generation [1-9][0-9]* --agent '\{\n(?:[ -~]*\n)*\}'$/,
'CMD.MIGRATE.PREVIEW':
/^mosaic fleet migrate-v1 preview \\\n --source [A-Za-z0-9_./@:+,=-]+ \\\n --decisions [A-Za-z0-9_./@:+,=-]+ \\\n --observations [A-Za-z0-9_./@:+,=-]+$/,
'CMD.PNPM.MIGRATION_TEST':
/^pnpm --filter @mosaicstack\/mosaic test -- v1-v2-migration\.spec\.ts \\\n -t "[A-Za-z0-9 _./@:+,=-]+"$/,
};
const DATA_PROFILE_BODIES: Readonly<Record<string, string>> = {
'DATA.DOTENV.FLEET_LAUNCH':
'MOSAIC_AGENT_NAME=<roster name>\nMOSAIC_AGENT_CLASS=<roster class>\nMOSAIC_AGENT_RUNTIME=<roster runtime>\nMOSAIC_AGENT_MODEL=<roster model hint>\nMOSAIC_AGENT_REASONING=<roster reasoning>\nMOSAIC_AGENT_TOOL_POLICY=<roster tool policy>\nMOSAIC_AGENT_WORKDIR=<absolute roster work directory>\nMOSAIC_TMUX_SOCKET=<roster socket or empty>',
'DATA.TEXT_TABLE.FLEET_TASKS':
'| W-FLEET | in-progress | Fleet (agent-session execution layer) | Phase 2/5 | docs/fleet/TASKS.md | observability dogfooded on live stub fleet; control plane rides federation (W1) |',
'DATA.TEXT_DIAGRAM.BACKLOG_FLOW':
' create\n \u2502\n \u25bc\n \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u25ba ready \u2500\u2500\u2500\u2500\u2500 claim \u2500\u2500\u2500\u2500\u2500\u25ba claimed \u2500\u2500\u2500\u2500\u2500 complete \u2500\u2500\u2500\u2500\u2500\u25ba done\n \u2502 \u2502 \u2502\n \u2502 block reclaim (TTL expiry or --id)\n \u2502 \u25bc \u2502\n \u2502 blocked \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 (back to ready)\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 (reclaim / re-create can return a card to ready)',
'DATA.TYPESCRIPT.MATRIX_CONNECTOR_TYPE':
"interface OrchestratorConnector {\n readonly kind: 'tmux' | 'discord' | 'matrix';\n send(message: OutboundMessage): Promise<SendResult>; // orchestrator \u2192 human\n subscribe(handler: (m: InboundMessage) => void): Unsubscribe; // human \u2192 orchestrator\n health(): Promise<ConnectorHealth>; // reachable + authenticated\n}",
'DATA.YAML.MATRIX_CONNECTOR_CONFIG':
"connector:\n kind: matrix\n matrix:\n homeserver_url: https://matrix.example.internal\n user_id: '@mos:example.internal'\n room_id: '!abc:example.internal'",
'DATA.YAML.INTERACTION_AGENT':
'name: interaction-example\nalias: Interaction Example\nclass: interaction\ntool_policy: interaction\nlifecycle:\n enabled: true\n desired_state: stopped',
'DATA.YAML.VALIDATOR_AGENT':
'name: validator-example\nalias: Validator Example\nclass: validator\ntool_policy: validator\nlifecycle:\n enabled: true\n desired_state: stopped',
'DATA.JSON.PARTIAL_FAILURE':
'{\n "applied": false,\n "authoritativeRoster": "committed",\n "projections": "incomplete",\n "recovery": {\n "code": "projection-apply-failed",\n "action": "regenerate-projections-from-roster"\n }\n}',
'DATA.MARKDOWN.ROLE_TEMPLATE':
"# Code \u2014 local role definition\n\nThe local code role (`class: code`) follows the operator's repository conventions.",
'DATA.MARKDOWN.ROLE_EXAMPLE':
'# Release notes \u2014 local role definition\n\nThe release-notes role (`class: release-notes`) prepares operator-reviewed release copy.',
'DATA.JSON.LIFECYCLE_OBSERVATIONS':
'{\n "coder0": { "systemd": "inactive", "tmux": "missing" }\n}',
'DATA.JSON.RECOVERY_RESULT':
'{\n "applied": false,\n "authoritativeRoster": "unchanged",\n "projections": "incomplete",\n "lifecycle": "not-applied",\n "recovery": { "code": "projection-apply-failed", "action": "regenerate-projections-from-roster" }\n}',
'DATA.JSON.MUTATION_RESULT':
'{\n "applied": false,\n "authoritativeRoster": "committed",\n "projections": "incomplete",\n "recovery": {\n "code": "projection-apply-failed",\n "action": "regenerate-projections-from-roster"\n }\n}',
'DATA.DOTENV.GENERATED_ENV':
'MOSAIC_AGENT_NAME=<roster name>\nMOSAIC_AGENT_CLASS=<roster class>\nMOSAIC_AGENT_RUNTIME=<roster runtime>\nMOSAIC_AGENT_MODEL=<roster model hint>\nMOSAIC_AGENT_REASONING=<roster reasoning>\nMOSAIC_AGENT_TOOL_POLICY=<roster tool policy>\nMOSAIC_AGENT_WORKDIR=<absolute roster work directory>\nMOSAIC_TMUX_SOCKET=<roster socket or empty>',
'DATA.YAML.ROSTER_FIELDS':
'version: 2\ngeneration: 1\ntransport: tmux\ntmux:\n socket_name: mosaic-fleet\n holder_session: _holder\ndefaults:\n working_directory: ~/src\n runtime: pi\nruntimes:\n pi:\n reset_command: /new\nagents:\n - name: coder0\n alias: Coder 0\n class: code\n runtime: pi\n provider: openai\n model: gpt-5.6-sol\n reasoning: high\n tool_policy: code\n working_directory: ~/src\n persistent_persona: false\n reset_between_tasks: true\n lifecycle:\n enabled: true\n desired_state: stopped\n launch:\n yolo: true',
};
const SYNOPSIS_RECORDS: Readonly<Record<string, string>> = {
'SYN.AGENT.GET': 'mosaic fleet get <name>',
'SYN.PLAN.CREATE': "mosaic fleet plan create --expected-generation <n> --agent '<json>'",
'SYN.PLAN.UPDATE': "mosaic fleet plan update <name> --expected-generation <n> --agent '<json>'",
'SYN.PLAN.DELETE': 'mosaic fleet plan delete <name> --expected-generation <n>',
'SYN.AGENT.UPDATE_COMPLETE':
"mosaic fleet update <name> --expected-generation <n> --agent '<complete JSON agent payload>'",
'SYN.AGENT.DELETE': 'mosaic fleet delete <name> --expected-generation <n>',
'SYN.PLAN.GENERIC':
"mosaic fleet plan <create|update|delete> [<name>] --expected-generation <n> [--agent '<json>'] [--persisted-start]",
'SYN.AGENT.CREATE':
"mosaic fleet create --expected-generation <n> --agent '<json>' [--dry-run] [--persisted-start]",
'SYN.AGENT.UPDATE':
"mosaic fleet update <name> --expected-generation <n> --agent '<json>' [--dry-run]",
'SYN.AGENT.DELETE_DRY': 'mosaic fleet delete <name> --expected-generation <n> [--dry-run]',
'SYN.APPLY.DRY': 'mosaic fleet apply --expected-generation <n> --dry-run',
'SYN.APPLY': 'mosaic fleet apply --expected-generation <n>',
'SYN.RECONCILE': 'mosaic fleet reconcile --expected-generation <n>',
'SYN.START.REQUIRED': 'mosaic fleet start <name> --expected-generation <n>',
'SYN.STOP.REQUIRED': 'mosaic fleet stop <name> --expected-generation <n>',
'SYN.RESTART.REQUIRED': 'mosaic fleet restart <name> --expected-generation <n>',
'SYN.START.OPTIONAL': 'mosaic fleet start [<name>] --expected-generation <n> [--dry-run]',
'SYN.STOP.OPTIONAL': 'mosaic fleet stop [<name>] --expected-generation <n> [--dry-run]',
'SYN.RESTART.OPTIONAL': 'mosaic fleet restart [<name>] --expected-generation <n> [--dry-run]',
'SYN.STATUS.OPTIONAL': 'mosaic fleet status [<name>]',
'SYN.VERIFY': 'mosaic fleet verify',
'SYN.DOCTOR': 'mosaic fleet doctor',
'SYN.MIGRATE.PREVIEW':
'mosaic fleet migrate-v1 preview --source <path> --decisions <path> --observations <path>',
};
function profileFor(path: string, block: number): FenceProfile | undefined {
return FENCE_PROFILES.find(
(profile): boolean => profile.path === path && profile.block === block,
);
}
function publicDiagnostic(
surface: Pick<CodeSurface, 'path' | 'line' | 'block' | 'category'>,
code: string,
): SurfaceDiagnostic {
return {
path: surface.path,
line: surface.line,
...(surface.block === undefined ? {} : { block: surface.block }),
...(surface.category === undefined ? {} : { category: surface.category }),
code,
};
}
function codeSurfaceDiagnostics(path: string, source: string): SurfaceDiagnostic[] {
const diagnostics: SurfaceDiagnostic[] = [];
let inFence = false;
let block = 0;
for (const [index, line] of source.split('\n').entries()) {
const lineNumber = index + 1;
if (inFence) {
if (line === '```') inFence = false;
else if (/^(?:`{3,}|~{3,})/.test(line)) {
diagnostics.push({ path, line: lineNumber, block, code: 'fence-conflict' });
}
continue;
}
if (/^(?: {0,3}(?:(?:> ?)|(?:(?:[-+*]|[0-9]{1,9}[.)]) +)))+(`{3,}|~{3,})/.test(line)) {
diagnostics.push({ path, line: lineNumber, code: 'fence-context' });
continue;
}
if (/^(?: {4,}|\t).*\S/.test(line)) {
diagnostics.push({ path, line: lineNumber, code: 'indented-code' });
continue;
}
const marker = line.match(/^(`{3,}|~{3,})(.*)$/);
if (marker !== null) {
block += 1;
const info = marker[2] ?? '';
if (marker[1] !== '```' || /[`~]/.test(info)) {
diagnostics.push({ path, line: lineNumber, block, code: 'fence-marker' });
continue;
}
if (info === '' || !FENCE_PROFILES.some((profile): boolean => profile.info === info)) {
diagnostics.push({ path, line: lineNumber, block, code: 'fence-info' });
continue;
}
const profile = profileFor(path, block);
if (profile === undefined || profile.info !== info) {
diagnostics.push({ path, line: lineNumber, block, code: 'profile-unknown' });
continue;
}
inFence = true;
continue;
}
if (/`{2,}/.test(line)) {
diagnostics.push({ path, line: lineNumber, code: 'inline-delimiter' });
continue;
}
const withoutClosedInlineSpans = line.replace(/`[^`\n]+`/g, '');
if (withoutClosedInlineSpans.includes('`')) {
diagnostics.push({ path, line: lineNumber, code: 'inline-delimiter' });
continue;
}
if (/<\/?(?:pre|code|script|style|xmp|listing)(?=$|\s|[>/])/i.test(line)) {
diagnostics.push({ path, line: lineNumber, code: 'raw-code-container' });
}
for (const match of line.matchAll(/(?<!`)`([^`\n]+)`(?!`)/g)) {
if (!/^[A-Za-z0-9_./@:+,=-]{1,256}$/.test(match[1] ?? '')) {
diagnostics.push({
path,
line: lineNumber,
category: 'InlineLiteral',
code: 'inline-literal',
});
}
}
}
if (inFence)
diagnostics.push({ path, line: source.split('\n').length, block, code: 'fence-unclosed' });
return diagnostics;
}
function codeSurfaces(path: string, source: string): CodeSurface[] {
const diagnostics = codeSurfaceDiagnostics(path, source);
if (diagnostics.length > 0) return [];
const surfaces: CodeSurface[] = [];
const lines = source.split('\n');
let fence:
| {
readonly block: number;
readonly line: number;
readonly info: string;
readonly body: string[];
}
| undefined;
let block = 0;
for (const [index, line] of lines.entries()) {
const lineNumber = index + 1;
if (fence !== undefined) {
if (line === '```') {
const profile = profileFor(path, fence.block);
if (profile !== undefined && profile.info === fence.info) {
surfaces.push({
category: profile.category,
path,
line: fence.line,
block: fence.block,
info: fence.info,
source: fence.body.join('\n'),
});
}
fence = undefined;
} else fence.body.push(line);
continue;
}
const opener = line.match(/^```([a-z-]+)$/);
if (opener !== null) {
block += 1;
fence = { block, line: lineNumber, info: opener[1] ?? '', body: [] };
continue;
}
for (const match of line.matchAll(/(?<!`)`([^`\n]+)`(?!`)/g)) {
surfaces.push({
category: 'InlineLiteral',
path,
line: lineNumber,
source: match[1] ?? '',
});
}
}
return surfaces;
}
function closedGrammarViolationKinds(surface: CodeSurface): string[] {
const kinds = new Set<string>();
const credentialFormat =
/(?:\bAKIA[0-9A-Z]{16}\b|\bAIza[0-9A-Za-z_-]{35}\b|\bgh[pousr]_[A-Za-z0-9]{20,}\b|\bgithub_pat_[A-Za-z0-9_]{20,}\b|\bglpat-[A-Za-z0-9_-]{20,}\b|\bnpm_[A-Za-z0-9]{20,}\b|\bsk-ant-(?:api\d{2}-)?[A-Za-z0-9_-]{20,}\b|\bsk-proj-[A-Za-z0-9_-]{20,}\b|\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{16,}\b|\bxox[baprs]-[A-Za-z0-9-]{10,}\b|\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b|\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b|-----BEGIN [A-Z ]*PRIVATE KEY-----|\b[A-Za-z][A-Za-z0-9+.-]*:\/\/[^\s/:]+:[^\s/@]+@)/;
if (credentialFormat.test(surface.source)) kinds.add('credential-format');
if (/\b(?:Tess|Ultron)\b/.test(surface.source)) kinds.add('identity');
if (surface.category === 'InlineLiteral') {
if (!/^[A-Za-z0-9_./@:+,=-]{1,256}$/.test(surface.source)) kinds.add('inline-literal');
return [...kinds].sort();
}
const profile = profileFor(surface.path, surface.block ?? 0);
if (
profile === undefined ||
profile.info !== surface.info ||
profile.category !== surface.category
) {
kinds.add('profile-unknown');
return [...kinds].sort();
}
if (surface.category === 'DataProfile') {
const schema = profile.recordSchemas?.[0] ?? '';
if (profile.recordSchemas?.length !== 1 || surface.source !== DATA_PROFILE_BODIES[schema]) {
kinds.add('data-profile');
}
return [...kinds].sort();
}
if (/^(?:# |\$ |> )/m.test(surface.source)) kinds.add('comment-or-prompt');
if (/(?:^|\s)[A-Za-z_][A-Za-z0-9_]*\+?=[^\s]*/.test(surface.source)) kinds.add('assignment');
const schemas = profile.recordSchemas ?? [];
if (surface.category === 'Synopsis') {
const records = surface.source.split('\n').filter((record): boolean => record !== '');
if (
records.length !== schemas.length ||
records.some((record, index): boolean => record !== SYNOPSIS_RECORDS[schemas[index] ?? ''])
) {
kinds.add('synopsis-schema');
}
} else if (schemas.length === 1) {
if (!COMMAND_RECORDS[schemas[0] ?? '']?.test(surface.source)) kinds.add('command-schema');
} else {
const records = surface.source.split('\n').filter((record): boolean => record !== '');
if (
records.length !== schemas.length ||
records.some((record, index): boolean => !COMMAND_RECORDS[schemas[index] ?? '']?.test(record))
) {
kinds.add('command-schema');
}
}
return [...kinds].sort();
}
function surfaceDiagnostics(surfaces: readonly CodeSurface[]): SurfaceDiagnostic[] {
return surfaces.flatMap((surface): SurfaceDiagnostic[] =>
closedGrammarViolationKinds(surface).map(
(kind): SurfaceDiagnostic => publicDiagnostic(surface, kind),
),
);
}
const CLOSED_GRAMMAR_REJECTION_FIXTURES = [
'sudo systemctl restart example',
'env -S apt-get install example',
"sh -c 'apt-get --version'",
'su root',
'command -- apt-get install example',
'mosaic fleet verify; reboot',
'# mosaic fleet verify',
'$ mosaic fleet verify',
'FOO=value mosaic fleet verify',
] as const;
describe('closed documentation publication grammar', (): void => {
it('classifies only the four approved code-surface categories', (): void => {
const categories: readonly CodeSurfaceCategory[] = [
'ConcreteCommand',
'Synopsis',
'DataProfile',
'InlineLiteral',
];
expect(new Set(categories)).toEqual(
new Set(['ConcreteCommand', 'Synopsis', 'DataProfile', 'InlineLiteral']),
);
});
it.each(CLOSED_GRAMMAR_REJECTION_FIXTURES)(
'rejects shell-shaped input without parsing shell grammar',
(source): void => {
const surface: CodeSurface = {
category: 'ConcreteCommand',
path: 'migration/v1-to-v2.md',
line: 1,
block: 1,
info: 'fleet-command',
source,
};
expect(closedGrammarViolationKinds(surface)).toContain('command-schema');
},
);
it('rejects DSL comments, prompt prefixes, assignments, and root-prompt ambiguity', (): void => {
for (const source of [
'# mosaic fleet verify',
'$ mosaic fleet verify',
'> mosaic fleet verify',
'ROOT=1 mosaic fleet verify',
]) {
const surface: CodeSurface = {
category: 'Synopsis',
path: 'reference/cli.md',
line: 1,
block: 1,
info: 'fleet-synopsis',
source,
};
expect(closedGrammarViolationKinds(surface)).not.toEqual([]);
}
});
it('rejects unmatched single-backtick delimiters on either side', (): void => {
for (const source of ['`literal', 'literal`', 'text `literal', 'literal` text']) {
expect(codeSurfaceDiagnostics('fixture.md', source)).toContainEqual({
path: 'fixture.md',
line: 1,
code: 'inline-delimiter',
});
}
});
it('counts every invalid column-one fence candidate before later profile selection', (): void => {
for (const firstCandidate of [
'````fleet-synopsis',
'```fleet-synopsis```',
'~~~fleet-synopsis~~~',
]) {
expect(
codeSurfaceDiagnostics(
'reference/cli.md',
`${firstCandidate}\n\`\`\`unknown\n\`\`\`fleet-synopsis\nmosaic fleet verify\n\`\`\``,
),
).toEqual([
{ path: 'reference/cli.md', line: 1, block: 1, code: 'fence-marker' },
{ path: 'reference/cli.md', line: 2, block: 2, code: 'fence-info' },
{ path: 'reference/cli.md', line: 3, block: 3, code: 'profile-unknown' },
{ path: 'reference/cli.md', line: 5, block: 4, code: 'fence-info' },
]);
}
});
it('rejects inline delimiter runs instead of silently omitting them', (): void => {
for (const source of ['``literal``', 'text ```literal```', 'text ``literal`` text']) {
expect(codeSurfaceDiagnostics('fixture.md', source)).toContainEqual({
path: 'fixture.md',
line: 1,
code: 'inline-delimiter',
});
}
});
it('rejects every nonblank line with four leading spaces or a leading tab', (): void => {
for (const source of [
' mosaic fleet verify',
' mosaic fleet verify',
' \tmosaic fleet verify',
'\t mosaic fleet verify',
]) {
expect(codeSurfaceDiagnostics('fixture.md', source)).toEqual([
{ path: 'fixture.md', line: 1, code: 'indented-code' },
]);
}
});
it('rejects raw HTML code-container tag prefixes at every boundary', (): void => {
for (const source of [
'<pre',
'<pre ',
'<pre>',
'<pre/',
'<code',
'<code ',
'<code>',
'<code/',
]) {
expect(codeSurfaceDiagnostics('fixture.md', source)).toEqual([
{ path: 'fixture.md', line: 1, code: 'raw-code-container' },
]);
}
expect(codeSurfaceDiagnostics('fixture.md', '<prelude>prose</prelude>')).toEqual([]);
});
it('rejects nested blockquote and list fence contexts', (): void => {
for (const source of [
'>> ```fleet-command',
'> > ```fleet-command',
'> - ```fleet-command',
'- > ```fleet-command',
]) {
expect(codeSurfaceDiagnostics('fixture.md', source)).toEqual([
{ path: 'fixture.md', line: 1, code: 'fence-context' },
]);
}
});
it('requires optional metavariables to use bracketed angle notation', (): void => {
const accepted: CodeSurface = {
category: 'Synopsis',
path: 'reference/cli.md',
line: 1,
block: 1,
info: 'fleet-synopsis',
source: Object.values(SYNOPSIS_RECORDS)
.filter((record): boolean =>
[
'SYN.APPLY',
'SYN.RECONCILE',
'SYN.START.OPTIONAL',
'SYN.STOP.OPTIONAL',
'SYN.RESTART.OPTIONAL',
'SYN.STATUS.OPTIONAL',
'SYN.VERIFY',
'SYN.DOCTOR',
'SYN.MIGRATE.PREVIEW',
].includes(
Object.entries(SYNOPSIS_RECORDS).find(([, value]): boolean => value === record)?.[0] ??
'',
),
)
.join('\n'),
};
expect(closedGrammarViolationKinds(accepted)).toEqual([]);
expect(
closedGrammarViolationKinds({
...accepted,
source: accepted.source.replace('[<name>]', '[name]'),
}),
).toContain('synopsis-schema');
});
it('emits only location, category, and closed diagnostic codes', (): void => {
const sensitiveFixture = ['sk-ant-api03-', 'a'.repeat(80)].join('');
const diagnostic = surfaceDiagnostics([
{
category: 'InlineLiteral',
path: 'fixture.md',
line: 7,
source: sensitiveFixture,
},
]);
expect(diagnostic).toEqual([
{
path: 'fixture.md',
line: 7,
category: 'InlineLiteral',
code: 'credential-format',
},
]);
expect(JSON.stringify(diagnostic)).not.toContain(sensitiveFixture);
});
});
describe('fleet operator documentation', (): void => {
it('ships every accepted information-architecture page', async (): Promise<void> => {
await expect(
Promise.all(REQUIRED_FLEET_PAGES.map((path) => readFile(join(fleetDocs, path), 'utf8'))),
).resolves.toHaveLength(REQUIRED_FLEET_PAGES.length);
});
it('resolves every local Markdown link and heading fragment in the fleet book and sitemap', async (): Promise<void> => {
const files = [...(await markdownFiles(fleetDocs)), join(repositoryRoot, 'docs', 'SITEMAP.md')];
const documents: Record<string, string> = {};
for (const file of files) {
const relative = file.slice(repositoryRoot.length + 1);
documents[relative] = await readFile(file, 'utf8');
}
const violations: string[] = [];
for (const [sourcePath, source] of Object.entries(documents)) {
for (const target of localMarkdownTargets(source)) {
const encodedPath = target.split('#', 1)[0] ?? '';
const targetPath = resolve(
dirname(join(repositoryRoot, sourcePath)),
decodeURIComponent(encodedPath),
);
const relativeTarget = targetPath.slice(repositoryRoot.length + 1);
if (documents[relativeTarget] === undefined) {
try {
documents[relativeTarget] = await readFile(targetPath, 'utf8');
} catch {
// The deterministic validator below records the missing target without exposing content.
}
}
}
violations.push(...markdownLinkViolations(sourcePath, source, documents));
}
expect(violations).toEqual([]);
});
it('validates the canonical documentation example through the production compiler and resolver', async (): Promise<void> => {
const source = await readFile(join(fleetDocs, 'examples', 'roster-v2.yaml'), 'utf8');
const roster = parseRosterV2(source, 'yaml');
const validated = await validateRosterV2Semantics(roster, {
rolesDir: join(frameworkFleet, 'roles'),
overrideDir: join(fleetDocs, 'examples', 'roles.local'),
});
expect(validated.generation).toBe(1);
expect(validated.agents.map((agent) => agent.canonicalClass)).toEqual([
'code',
'interaction',
'validator',
]);
});
it('keeps every rendered fleet code surface in one closed category without exposing sensitive values', async (): Promise<void> => {
const diagnostics: SurfaceDiagnostic[] = [];
const surfaces: CodeSurface[] = [];
for (const file of await markdownFiles(fleetDocs)) {
const source = await readFile(file, 'utf8');
const relative = file.slice(fleetDocs.length + 1);
diagnostics.push(...codeSurfaceDiagnostics(relative, source));
surfaces.push(...codeSurfaces(relative, source));
}
diagnostics.push(...surfaceDiagnostics(surfaces));
expect(diagnostics).toEqual([]);
expect(
surfaces.filter((surface): boolean => surface.category === 'ConcreteCommand'),
).toHaveLength(4);
expect(surfaces.filter((surface): boolean => surface.category === 'Synopsis')).toHaveLength(5);
expect(surfaces.filter((surface): boolean => surface.category === 'DataProfile')).toHaveLength(
15,
);
expect(
surfaces.filter((surface): boolean => surface.category === 'InlineLiteral'),
).toHaveLength(858);
expect(surfaces).toHaveLength(882);
const rosterSource = await readFile(join(fleetDocs, 'examples', 'roster-v2.yaml'), 'utf8');
const auxiliary: CodeSurface = {
category: 'DataProfile',
path: 'examples/roster-v2.yaml',
line: 1,
source: rosterSource,
};
expect(
closedGrammarViolationKinds(auxiliary).filter((kind): boolean => kind !== 'profile-unknown'),
).toEqual([]);
});
});