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 { const entries = await readdir(root, { withFileTypes: true }); const paths = await Promise.all( entries.map(async (entry): Promise => { 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 { const anchors = new Set(); 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>, ): 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; 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> = { '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> = { 'DATA.DOTENV.FLEET_LAUNCH': 'MOSAIC_AGENT_NAME=\nMOSAIC_AGENT_CLASS=\nMOSAIC_AGENT_RUNTIME=\nMOSAIC_AGENT_MODEL=\nMOSAIC_AGENT_REASONING=\nMOSAIC_AGENT_TOOL_POLICY=\nMOSAIC_AGENT_WORKDIR=\nMOSAIC_TMUX_SOCKET=', '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; // orchestrator \u2192 human\n subscribe(handler: (m: InboundMessage) => void): Unsubscribe; // human \u2192 orchestrator\n health(): Promise; // 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=\nMOSAIC_AGENT_CLASS=\nMOSAIC_AGENT_RUNTIME=\nMOSAIC_AGENT_MODEL=\nMOSAIC_AGENT_REASONING=\nMOSAIC_AGENT_TOOL_POLICY=\nMOSAIC_AGENT_WORKDIR=\nMOSAIC_TMUX_SOCKET=', '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> = { 'SYN.AGENT.GET': 'mosaic fleet get ', 'SYN.PLAN.CREATE': "mosaic fleet plan create --expected-generation --agent ''", 'SYN.PLAN.UPDATE': "mosaic fleet plan update --expected-generation --agent ''", 'SYN.PLAN.DELETE': 'mosaic fleet plan delete --expected-generation ', 'SYN.AGENT.UPDATE_COMPLETE': "mosaic fleet update --expected-generation --agent ''", 'SYN.AGENT.DELETE': 'mosaic fleet delete --expected-generation ', 'SYN.PLAN.GENERIC': "mosaic fleet plan [] --expected-generation [--agent ''] [--persisted-start]", 'SYN.AGENT.CREATE': "mosaic fleet create --expected-generation --agent '' [--dry-run] [--persisted-start]", 'SYN.AGENT.UPDATE': "mosaic fleet update --expected-generation --agent '' [--dry-run]", 'SYN.AGENT.DELETE_DRY': 'mosaic fleet delete --expected-generation [--dry-run]', 'SYN.APPLY.DRY': 'mosaic fleet apply --expected-generation --dry-run', 'SYN.APPLY': 'mosaic fleet apply --expected-generation ', 'SYN.RECONCILE': 'mosaic fleet reconcile --expected-generation ', 'SYN.START.REQUIRED': 'mosaic fleet start --expected-generation ', 'SYN.STOP.REQUIRED': 'mosaic fleet stop --expected-generation ', 'SYN.RESTART.REQUIRED': 'mosaic fleet restart --expected-generation ', 'SYN.START.OPTIONAL': 'mosaic fleet start [] --expected-generation [--dry-run]', 'SYN.STOP.OPTIONAL': 'mosaic fleet stop [] --expected-generation [--dry-run]', 'SYN.RESTART.OPTIONAL': 'mosaic fleet restart [] --expected-generation [--dry-run]', 'SYN.STATUS.OPTIONAL': 'mosaic fleet status []', 'SYN.VERIFY': 'mosaic fleet verify', 'SYN.DOCTOR': 'mosaic fleet doctor', 'SYN.MIGRATE.PREVIEW': 'mosaic fleet migrate-v1 preview --source --decisions --observations ', }; function profileFor(path: string, block: number): FenceProfile | undefined { return FENCE_PROFILES.find( (profile): boolean => profile.path === path && profile.block === block, ); } function publicDiagnostic( surface: Pick, 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(/(? 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(/(?(); 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 [ '', '
',
      'prose')).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]'),
      }),
    ).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 => {
    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 => {
    const files = [...(await markdownFiles(fleetDocs)), join(repositoryRoot, 'docs', 'SITEMAP.md')];
    const documents: Record = {};
    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 => {
    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 => {
    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([]);
  });
});