// retoor <retoor@molodetz.nl>
export const meta = {
  name: 'full-docs-refactor',
  description:
    'Documentation reality audit: verify every falsifiable claim in README.md, the root CLAUDE.md, every nested CLAUDE.md, and the entire /docs site (prose + docs_api) against the actual source, fix drift in place, and confirm role-gating. Every agent owns a disjoint set of files so there are never write conflicts.',
  phases: [
    { title: 'Ground truth', detail: 'extract authoritative facts (routes, CLI, env, deps, test count, package layout, docs registry) from source' },
    { title: 'Root docs', detail: 'audit README.md plus every CLAUDE.md (root and nested per-subsystem) in parallel - one file per agent' },
    { title: 'Docs site', detail: 'audit the docs_api package and every /docs prose section in parallel - disjoint template ownership' },
    { title: 'Gating + validate', detail: 'verify role-gating and run the full validation sweep (import, template compile, em-dash, broken links)' },
  ],
}

const REPORT_SCHEMA = {
  type: 'object',
  additionalProperties: false,
  required: ['target', 'changed', 'changes', 'verifiedAccurate'],
  properties: {
    target: { type: 'string' },
    changed: { type: 'boolean' },
    changes: {
      type: 'array',
      items: {
        type: 'object',
        additionalProperties: false,
        required: ['location', 'wrong', 'fixed'],
        properties: {
          location: { type: 'string' },
          wrong: { type: 'string' },
          fixed: { type: 'string' },
          source: { type: 'string' },
        },
      },
    },
    verifiedAccurate: { type: 'array', items: { type: 'string' } },
    gatingIssues: { type: 'array', items: { type: 'string' } },
    unverifiable: { type: 'array', items: { type: 'string' } },
  },
}

const VALIDATE_SCHEMA = {
  type: 'object',
  additionalProperties: false,
  required: ['appImports', 'docsApiValid', 'templatesCompile', 'emDashClean', 'brokenLinks', 'gatingClean'],
  properties: {
    appImports: { type: 'boolean' },
    docsApiValid: { type: 'boolean' },
    templatesCompile: { type: 'boolean' },
    emDashClean: { type: 'boolean' },
    brokenLinks: { type: 'array', items: { type: 'string' } },
    gatingClean: { type: 'boolean' },
    gatingFixes: { type: 'array', items: { type: 'string' } },
    notes: { type: 'string' },
  },
}

const SHARED_RULES =
  'RULES (all mandatory):\n' +
  '- The CODE is the source of truth. When docs disagree with code, fix the DOCS, never the code. Do not invent or aspirationally document features. If docs describe something removed/renamed, correct or remove it.\n' +
  '- Use Read/Grep/Glob/Bash to CONFIRM every claim before you edit it. Never edit on assumption.\n' +
  '- NEVER introduce an em-dash character or its HTML entity; use a hyphen. Replace any em-dash in a passage you rewrite.\n' +
  '- Be surgical: change only what is verifiably wrong or verifiably missing from a list/table meant to be complete. Preserve tone, structure, and formatting.\n' +
  '- Do not corrupt markdown tables, HTML, or Jinja.\n' +
  'DOCS PROSE STRUCTURE (for /docs/*.html templates): the body is <div class="docs-content" data-render> rendered to HTML SERVER-SIDE from markdown; example markup shown as code INSIDE that block stays HTML-entity-escaped (&lt;...&gt;). Real live-demo markup and its <script type="module"> live OUTSIDE that block - update a demo only if the API it shows changed.\n' +
  'ROLE GATING: pages flagged admin:true in routers/docs/pages.py 404 for non-admins and are nav-filtered. Every /docs/<slug>.html link must resolve to a real slug (or a real /docs route like download.html/download.md). If a page visible to guests/members links to an admin-only route or admin doc slug, wrap it in {% if is_admin(user) %}...{% endif %}.\n' +
  'REPORT: return structured output - target, changed, one entry per fix (location, wrong, fixed, source), the claim categories you verified as accurate, any gating issue, and anything you could not verify.'

function rootPrompt(file, gt) {
  const isNested = file !== 'README.md' && file !== 'CLAUDE.md'
  const nestedNote = isNested
    ? ` This is a NESTED CLAUDE.md (Claude Code auto-loads it only when a file under its own directory is read/edited) - its claims must be scoped to that subsystem; do not duplicate content that belongs in the root CLAUDE.md's cross-cutting rules or in a sibling nested file, and do not reintroduce a top-level AGENTS.md or any reference to one (it was deleted - all of its content now lives across the root CLAUDE.md and the nested CLAUDE.md files).`
    : ''
  return (
    `DOCUMENTATION REALITY AUDIT of a single file: ${file}. Verify EVERY falsifiable claim against the actual source and FIX inconsistencies in place. EDIT ONLY ${file}.${nestedNote}\n\n` +
    `Verify (where the file claims them): make targets + comments, devplace/devii CLI subcommands + flags, router prefixes/paths, env vars + defaults, config keys + defaults, function/class/helper/table/setting names, file/module paths (must exist), dependency names, version numbers, test counts, and internal links/anchors. For a routing table, env-var table, commands block, or CLI list that is meant to be COMPLETE, add rows that exist in code but are missing. If this file is the root CLAUDE.md, verify its "Subsystem map" table still lists every nested CLAUDE.md that actually exists in the repo and no stale entries for one that was removed.\n\n` +
    `AUTHORITATIVE GROUND TRUTH (freshly extracted from this repo - trust it, but re-confirm anything you edit):\n${gt}\n\n` +
    SHARED_RULES
  )
}

const DOCS_SECTIONS = [
  {
    key: 'docs_api',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX the /docs API reference, which is GENERATED from the `devplacepy/docs_api/` package (groups/ + services_group.py), NOT from templates. EDIT ONLY files under `devplacepy/docs_api/`. For EVERY documented endpoint verify against the real router + schema: method+path exists (grep @router in routers/, account for the main.py mount prefix), documented params/body match the real Form/query params (models.py, route signature), sample_response shape matches the real *Out schema (schemas/), and the stated auth matches the route guard (get_current_user/require_user/require_admin). The admin API groups (containers/gateway/services/admin) must be genuinely admin routes. Keep the group data valid Python (verify `python -c "from devplacepy.docs_api import API_GROUPS; print(len(API_GROUPS))"`). Remove documented endpoints that no longer exist; correct wrong params/paths/responses; note real endpoints the docs omit.',
  },
  {
    key: 'general-a',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX these /docs prose templates (EDIT ONLY these, under devplacepy/templates/docs/): index.html, getting-started.html, getting-started-vibing.html, feed.html, code-farm.html, block-and-mute.html, emoji-shortcodes.html, presence.html. Verify against: routers/{feed,game/,relations,news}.py, rendering.py (emoji shortcodes via build_emoji_shortcodes + `devplace emoji-sync`), services/presence.py + presence_relay.py, config.py presence defaults, main.py GET / home behavior. code-farm documents the /game Code Farm game; block-and-mute documents relations (/block,/block/unblock,/mute,/mute/unmute).',
  },
  {
    key: 'general-b',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX these /docs prose templates (EDIT ONLY these): devii.html, telegram.html, media-gallery.html, notification-settings.html, timezones.html, ai-correction.html, ai-modifier.html, dashboard.html (kind=live). Verify against: services/devii/ (member page), services/telegram/, services/correction.py, services/ai_modifier.py, routers/profile/{notifications,ai_correction,ai_modifier,telegram}.py, database notification prefs (NOTIFICATION_TYPES/NOTIFICATION_CHANNELS + defaults), templating.py local_dt/dt_ago + static/js/LocalTime.js, routers/media.py, routers/docs/views.py + docs_live.py (dashboard facts).',
  },
  {
    key: 'components',
    agentType: 'frontend-maintainer',
    prompt:
      'Audit and FIX the /docs Components pages (EDIT ONLY: components.html and component-*.html under templates/docs/). Source of truth: devplacepy/static/js/components/*.js and devii/*.js. For each page verify the customElements.define tag name, every documented attribute/property (attr/boolAttr/intAttr reads), methods/events, and the singleton access path (app.dialog/app.contextMenu/app.toast/app.lightbox/app.containerTerminals). Confirm the live-demo markup uses attributes that still exist; fix demos referencing removed attributes. component-emoji-picker documents the external emoji-picker-element (confirm it is still loaded in base.html).',
  },
  {
    key: 'styles-tools',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX (EDIT ONLY): styles.html, styles-colors.html, styles-layout.html, styles-responsiveness.html, styles-consistency.html, tools-seo.html, tools-deepsearch.html. Styles pages: every documented CSS --token name/value must match devplacepy/static/css/variables.css; breakpoints/structural rules must match base.css (and feed.css/projects.css for layout examples). Tools pages: verify routes and caps against routers/tools/{seo,deepsearch}.py, services/jobs/{seo,deepsearch}/, and models.py (SeoRunForm.max_pages 1-50; DeepSearch depth 1-4, max_pages 1-30).',
  },
  {
    key: 'devrant',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX the /docs devRant compatibility API pages (EDIT ONLY: devrant.html, devrant-auth.html, devrant-rants.html, devrant-comments.html, devrant-users.html, devrant-notifications.html, devrant-clients.html). Source: routers/devrant/ (mounted at /api) and services/devrant/. Also audit the backing devplacepy/docs_devrant.py if the widget data is wrong (it feeds _devrant_endpoints.html) - but only edit it if a claim is factually wrong. Verify each endpoint path (under /api), method, merged query+form+JSON params, the token triple auth, and the dr_ok/dr_error envelope. Reference client dir is examples/devrant/ (fix any stale devranta/ path).',
  },
  {
    key: 'claude',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX the /docs Claude Code pages (EDIT ONLY: claude.html, claude-manual.html, claude-agents.html, claude-commands.html, claude-workflows.html). Source of truth for project-specific claims: .claude/agents/*.md, .claude/commands/*.md, .claude/workflows/*.js. Fix any agent/command/workflow list that drifted from what exists, and any count of them. For general Claude Code product facts not verifiable from the repo, be CONSERVATIVE - leave them unless a .claude/ file contradicts.',
  },
  {
    key: 'admin-prose',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX the admin-gated /docs Administration prose pages (EDIT ONLY: devii-admin.html, telegram-admin.html, media-moderation.html, soft-delete.html, backups.html, gamification.html, audit-log.html). Sources: services/audit/ + events.md (event count/domains - match events.md self-reported figure), services/backups/ + routers/admin/backups.py (primary-admin-only download via utils.is_primary_admin), database soft-delete (SOFT_DELETE_TABLES) + /admin/trash, utils badges (ACHIEVEMENTS/BADGE_CATALOG/track_action - include the Code Farm badges), routers/media.py + /admin/media, Devii admin caps + config, services/telegram/ admin config. Verify routes, config-field names+defaults, function/class/table names, CLI commands.',
  },
  {
    key: 'devii-internals',
    agentType: 'devii-maintainer',
    prompt:
      'Audit and FIX the admin-gated /docs Devii internals pages (EDIT ONLY: devii-internals.html, devii-architecture.html, devii-tools.html, devii-data.html, devii-security.html, devii-config.html). Source: services/devii/ (session/ package, agentic/, actions/catalog/ package + dispatcher, hub, tasks/, behavior/, virtual_tools/, customization/, client/, rsearch/, email/, container/) and routers/devii.py. Verify: the documented tool/action names exist and their requires_auth/requires_admin/requires_primary_admin/CONFIRM_REQUIRED flags match the catalog; the total action+handler counts; session keying is (owner_kind, owner_id, channel); the persistence tables (devii_conversations/usage_ledger/turns/tasks/lessons/behavior/virtual_tools); the 4013/1013 close codes; financial-data-admin-only; run_js gated by devii_allow_eval; db_* tools primary-admin-only. NOTE session and actions/catalog are PACKAGES now.',
  },
  {
    key: 'bots',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX the admin-gated /docs Bots internals pages (EDIT ONLY: bots-internals.html, bots-architecture.html, bots-personas.html, bots-content.html, bots-engagement.html, bots-realism.html, bots-config.html). Source: services/bot/ (config.py for every documented default; llm.py/loop.py/posting.py/helpers.py/social.py/service.py for mechanics). Verify EVERY config default against services/bot/config.py, the service registration name/interval/default_enabled, the [bots] extra (playwright+faker), the referenced function names (generate_post_title, gist_quality_check, _engage_community, persona_article_score, pick_category, strip_label), and the design-narrative numbers (REACT_RATES, MAX_BOTS_PER_ARTICLE, etc.).',
  },
  {
    key: 'services',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX the admin-gated /docs Services pages (EDIT ONLY: services-overview.html, services-framework.html, services-data.html, services-gateway.html, services-devii.html, services-news.html, services-bots.html, services-zip.html, services-containers.html, services-dbapi.html, services-pubsub.html). Source: services/ subpackages and the main.py service registrations (the real count of registered services). Verify each service registration name/default_enabled/interval, config fields+defaults, tables, route surface, and source paths (NewsService now lives in services/news/service.py - news is a PACKAGE; runtime dirs default to data/ NOT var/; there is NO in-app container build / ContainerBuildService; /dbapi is READ-ONLY primary-admin-only).',
  },
  {
    key: 'architecture',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX the admin-gated /docs Architecture pages (EDIT ONLY: architecture.html, architecture-backend.html, architecture-frontend.html, architecture-styling.html, architecture-conventions.html, architecture-workflow.html, architecture-jobs.html). Source: main.py (request pipeline, middleware order, mounts), routers/ tree, static/js/ (ES6 modules on app, Application.js, dp-* components, shared utils Http/Poller/JobPoller/OptimisticAction/FloatingWindow), templating.py, rendering.py, services/jobs/ (JobService pattern). Fix any file/module path that no longer exists - database/utils/schemas/docs_api are PACKAGES now. Do NOT "fix" the deliberate synchronous-SQLite design to async.',
  },
  {
    key: 'testing-prod',
    agentType: 'docs-maintainer',
    prompt:
      'Audit and FIX the admin-gated /docs Testing + Production pages (EDIT ONLY: testing.html, testing-framework.html, testing-locust.html, testing-make.html, testing-cicd.html, production.html, production-deploy.html, production-nginx.html, production-concurrency.html, static-caching.html). Sources: Makefile, pyproject.toml ([tool.pytest.ini_options]), tests/ layout + conftest.py fixtures, locustfile.py, .gitea/workflows/, Dockerfile, docker-compose*.yml, nginx config, config.py (STATIC_VERSION). Verify every make target + behavior, the live test count (run `python -m pytest tests/ --collect-only -q | tail -1`), the tier layout, fixtures, ports, CI steps, the worker model (make prod = nproc; the Docker image pins 2 - keep that distinction), nginx WS-upgrade locations, and /static/v<version>/ caching.',
  },
]

function sectionPrompt(section, gt) {
  return (
    section.prompt +
    `\n\nAUTHORITATIVE GROUND TRUTH (freshly extracted from this repo - trust it, re-confirm what you edit):\n${gt}\n\n` +
    SHARED_RULES
  )
}

function selected(list) {
  const only = args && args.only
  if (!only) return list
  const keys = Array.isArray(only) ? only : String(only).split(',').map((s) => s.trim()).filter(Boolean)
  return list.filter((item) => keys.includes(item.key))
}

const GT_PROMPT =
  'Operate READ-ONLY (do not edit any file). Extract the AUTHORITATIVE, current ground-truth facts of this repository so a documentation audit can cross-check against them. Use Bash/Read/Grep. Produce a compact but complete plain-text reference covering:\n' +
  '1. Makefile: every target name and what it actually runs (esp. `prod` worker count, `install` steps, `test`).\n' +
  '2. pyproject.toml: version, requires-python, [project.scripts], the full dependency list (note pins), optional-dependency extras.\n' +
  '3. CLI: every top-level `devplace` subcommand and its sub-subcommands (from devplacepy/cli/*.py).\n' +
  '4. Routers: every prefix mounted in devplacepy/main.py (include_router lines), including no-prefix routers.\n' +
  '5. Env vars: every var read in devplacepy/config.py with its default.\n' +
  '6. Live test count: `python -m pytest tests/ --collect-only -q | tail -1`.\n' +
  '7. Package-vs-file: for database, utils, schemas, models, docs_api, seo, config, constants, rendering, templating - state whether each is a devplacepy/<name>.py FILE or a devplacepy/<name>/ PACKAGE.\n' +
  '8. Docs registry: total DOCS_PAGES count, section names, count of admin-gated pages, and the list of docs_api API_GROUPS slugs.\n' +
  'Return this as your final text - it will be injected verbatim into every downstream audit agent, so make it accurate and self-contained.'

log('Phase 1: extracting ground truth from source')
phase('Ground truth')
const groundTruth =
  (await agent(GT_PROMPT, { agentType: 'docs-maintainer', label: 'ground-truth', phase: 'Ground truth' })) ||
  'Ground-truth extraction failed; verify every claim directly against source before editing.'

log('Phase 2: auditing README.md and every CLAUDE.md (root + nested) in parallel')
phase('Root docs')
const ROOT_FILES = [
  { key: 'readme', file: 'README.md' },
  { key: 'claude-root', file: 'CLAUDE.md' },
  { key: 'nested-routers', file: 'devplacepy/routers/CLAUDE.md' },
  { key: 'nested-routers-projects', file: 'devplacepy/routers/projects/CLAUDE.md' },
  { key: 'nested-routers-docs', file: 'devplacepy/routers/docs/CLAUDE.md' },
  { key: 'nested-routers-devrant', file: 'devplacepy/routers/devrant/CLAUDE.md' },
  { key: 'nested-services', file: 'devplacepy/services/CLAUDE.md' },
  { key: 'nested-services-audit', file: 'devplacepy/services/audit/CLAUDE.md' },
  { key: 'nested-services-backup', file: 'devplacepy/services/backup/CLAUDE.md' },
  { key: 'nested-services-bot', file: 'devplacepy/services/bot/CLAUDE.md' },
  { key: 'nested-services-containers', file: 'devplacepy/services/containers/CLAUDE.md' },
  { key: 'nested-services-dbapi', file: 'devplacepy/services/dbapi/CLAUDE.md' },
  { key: 'nested-services-devii', file: 'devplacepy/services/devii/CLAUDE.md' },
  { key: 'nested-services-email', file: 'devplacepy/services/email/CLAUDE.md' },
  { key: 'nested-services-game', file: 'devplacepy/services/game/CLAUDE.md' },
  { key: 'nested-services-gitea', file: 'devplacepy/services/gitea/CLAUDE.md' },
  { key: 'nested-services-jobs', file: 'devplacepy/services/jobs/CLAUDE.md' },
  { key: 'nested-services-messaging', file: 'devplacepy/services/messaging/CLAUDE.md' },
  { key: 'nested-services-news', file: 'devplacepy/services/news/CLAUDE.md' },
  { key: 'nested-services-openai-gateway', file: 'devplacepy/services/openai_gateway/CLAUDE.md' },
  { key: 'nested-services-pubsub', file: 'devplacepy/services/pubsub/CLAUDE.md' },
  { key: 'nested-services-telegram', file: 'devplacepy/services/telegram/CLAUDE.md' },
  { key: 'nested-services-xmlrpc', file: 'devplacepy/services/xmlrpc/CLAUDE.md' },
  { key: 'nested-database', file: 'devplacepy/database/CLAUDE.md' },
  { key: 'nested-utils', file: 'devplacepy/utils/CLAUDE.md' },
  { key: 'nested-static-js', file: 'devplacepy/static/js/CLAUDE.md' },
  { key: 'nested-templates', file: 'devplacepy/templates/CLAUDE.md' },
  { key: 'nested-tests', file: 'tests/CLAUDE.md' },
]
const rootReports = await parallel(
  selected(ROOT_FILES).map((root) => () =>
    agent(rootPrompt(root.file, groundTruth), {
      agentType: 'docs-maintainer',
      label: `root:${root.key}`,
      phase: 'Root docs',
      schema: REPORT_SCHEMA,
    })
  )
)

log('Phase 3: auditing the docs_api package and every /docs prose section in parallel')
phase('Docs site')
const sectionReports = await parallel(
  selected(DOCS_SECTIONS).map((section) => () =>
    agent(sectionPrompt(section, groundTruth), {
      agentType: section.agentType,
      label: `docs:${section.key}`,
      phase: 'Docs site',
      schema: REPORT_SCHEMA,
    })
  )
)

log('Phase 4: verifying role-gating and running the validation sweep')
phase('Gating + validate')
const rootFileList = ROOT_FILES.map((f) => f.file).join(', ')
const validatePrompt =
  'The documentation audit edits are complete. Run the final VERIFICATION over the repo and FIX any residual gating issue you find (edit only routers/docs/pages.py flags or add {% if is_admin(user) %} guards in the specific template that leaks an admin link). Do the following with Bash and report structured results:\n' +
  '1. `python -c "from devplacepy.main import app"` imports clean (appImports).\n' +
  '2. `python -c "from devplacepy.docs_api import API_GROUPS; print(len(API_GROUPS))"` works (docsApiValid).\n' +
  '3. Every template under devplacepy/templates/docs/ compiles via the shared Jinja env (templatesCompile). Report any that fail.\n' +
  `4. No em-dash character or entity in any of: ${rootFileList}, or any devplacepy/templates/docs/*.html (emDashClean).\n` +
  '5. Broken internal links: every /docs/<slug>.html href in the doc templates must resolve to a real DOCS_PAGES slug OR a real /docs route (download.html/download.md); list any that do not (brokenLinks).\n' +
  '6. Role-gating: no page whose content is admin-only is left ungated (admin:true in pages.py), and no public (non-admin) page links to an admin-gated slug outside an {% if is_admin(user) %} block. Fix violations; report gatingClean + gatingFixes.\n' +
  '7. Confirm AGENTS.md does not exist at the repo root (`test -f AGENTS.md && echo EXISTS || echo ABSENT` must print ABSENT) and grep the repo for stray `AGENTS.md` references outside third-party/vendor/backup paths (.venv, *.bak, .git); report any as gatingIssues so a human can decide whether to fix them (this workflow does not own arbitrary non-doc files, e.g. .claude/ agent/command/workflow definitions).\n' +
  'Confirm each item against actual command output; do not guess.'
const validation = await agent(validatePrompt, {
  agentType: 'docs-maintainer',
  label: 'gating+validate',
  phase: 'Gating + validate',
  schema: VALIDATE_SCHEMA,
})

const roots = rootReports.filter(Boolean)
const sections = sectionReports.filter(Boolean)
const totalFixes =
  roots.reduce((n, r) => n + ((r && r.changes && r.changes.length) || 0), 0) +
  sections.reduce((n, r) => n + ((r && r.changes && r.changes.length) || 0), 0)

log(`Done. ${totalFixes} documentation fix(es) applied across ${roots.length} root file(s) and ${sections.length} /docs section(s).`)

return {
  workflow: 'full-docs-refactor',
  totalFixes,
  rootDocs: roots,
  docsSections: sections,
  validation,
}
