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_GIT_IDENTITY=<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_GIT_IDENTITY=<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(882);
    expect(surfaces).toHaveLength(906);

    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([]);
  });
});
