///|
fn research_question_seed_text(entry : BookCatalogEntry) -> String {
  let topic = research_topic_id(entry)
  let display = display_topic_name(topic)
  [
    "# Research Question",
    "",
    "## Core Question",
    "",
    research_question_text(topic, display),
    "",
    "## Scope",
    "",
    "This seed file frames a web-first research pass for \{display}. It is intentionally provisional; the worker should revise it when source screening finds better boundaries.",
    "",
    "## Inclusion Criteria",
    "",
    "- directly relevant to \{display}",
    "- attributable to a reputable publisher, official body, company, operator, or named expert",
    "- specific enough to support falsifiable claims",
    "- current enough for the research question, or clearly foundational if older",
    "",
    "## Exclusion Criteria",
    "",
    "- search snippets treated as verified evidence",
    "- generic or motivational content without inspectable claims",
    "- local repository interpretation unless screened sources prove that meaning",
    "- final claims written before source inspection",
    "",
    "## Query Seeds",
    "",
    ..research_web_queries(topic).map(fn(query) { "- `\{query}`" }),
    "",
    "## Local Source Position",
    "",
    if is_external_domain_research_topic(topic) {
      "`SOURCE_HINTS.md` says no local repository is implied for this lane. Keep local evidence empty unless screened web evidence points to a concrete local artifact."
    } else {
      "Inspect local files only after web discovery has been recorded."
    },
  ].join("\n")
}

///|
fn research_search_log_seed_text(entry : BookCatalogEntry) -> String {
  let topic = research_topic_id(entry)
  let display = display_topic_name(topic)
  [
    "# Search Log",
    "",
    "## Seed Status",
    "",
    "MoonTown created this starter log before MoonClaw source screening so the research trail is durable. It contains planned queries only; source screening must revise it with actual attempts, selected URLs, rejected URLs, blockers, and decisions.",
    "",
    "## Planned Queries",
    "",
    "| Query ID | Query | Purpose | Status |",
    "| --- | --- | --- | --- |",
    ..research_query_seed_rows(topic, display),
    "",
    "## Source Screening Rules",
    "",
    "- Use native web tools when available; otherwise use bounded command-line discovery such as `curl -L --max-time 12`.",
    "- Retry `{bad request}` once with a simpler query or URL before recording a blocker.",
    "- Use search pages only for discovery; do not cite them as evidence.",
    "- Prefer inspected source content, clear provenance, and claim-level extraction.",
    "- Keep blocked or weak sources visible in `\{@research_policy.source_screen_path()}` or `\{@research_policy.tool_blockers_path()}`.",
  ].join("\n")
}

///|
fn research_query_seed_rows(topic : String, display : String) -> Array[String] {
  let rows : Array[String] = []
  let queries = research_web_queries(topic)
  for index, query in queries {
    rows.push(
      "| Q\{index + 1} | `\{query}` | source discovery for \{display} | planned |",
    )
  }
  rows
}

///|
fn research_source_hints_text(entry : BookCatalogEntry) -> String {
  let topic = research_topic_id(entry)
  let display = display_topic_name(topic)
  let web_queries = research_web_queries(topic)
  let local_paths = research_local_paths(topic)
  let reference_urls = research_reference_urls(topic)
  let lines : Array[String] = [
    "# Source Hints",
    "",
    "These are MoonTown-generated hints for the \{display} research lane.",
    "",
  ]
  if is_external_domain_research_topic(topic) {
    lines.push("## Interpretation Guard")
    lines.push("")
    lines.push(
      "- Treat \{display} as an external domain research topic, not as a Vectie repository, MoonBit package, or local codebase unless source evidence proves otherwise.",
    )
    lines.push(
      "- Let the LLM choose the best current sources, but require screened web evidence before synthesis.",
    )
    lines.push(
      "- Prefer recent, reputable, source-backed material over search snippets, generic explainers, or run-log prose.",
    )
    lines.push("")
  }
  lines.push("## Web Search First")
  lines.push("")
  for query in web_queries {
    lines.push("- \{query}")
  }
  lines.push("")
  lines.push("## Optional Reference Style Inputs")
  lines.push("")
  lines.push(
    "- `raw/bootstrap/REFERENCE_STYLE.md`: if present, explains how to use user-supplied reference material as a style and quality target.",
  )
  lines.push(
    "- `raw/bootstrap/REFERENCE_OUTPUT.md`: if present, match its length class, section discipline, evidence density, tables, visualization style, and language when appropriate.",
  )
  lines.push(
    "- `raw/bootstrap/REFERENCE_SOURCE_HINTS.md`: if present, use it as a candidate lead sheet only. Every lead still needs source screening before it can support claims.",
  )
  lines.push(
    "- Reference files are not evidence for \{display}; use them to improve report craft, not to import facts.",
  )
  lines.push(
    "- If the reference report names candidate routes, comparison axes, or visual dimensions that fit the user's objective, use them as search hypotheses and independently screen sources for each adopted route.",
  )
  if !reference_urls.is_empty() {
    lines.push("")
    lines.push("## High-Signal URLs")
    lines.push("")
    for url in reference_urls {
      lines.push("- \{url}")
    }
  }
  if !local_paths.is_empty() {
    lines.push("")
    lines.push("## Local Repository Follow-Up")
    lines.push("")
    for path in local_paths {
      lines.push("- \{path}")
    }
  } else if is_external_domain_research_topic(topic) {
    lines.push("")
    lines.push("## Local Follow-Up")
    lines.push("")
    lines.push(
      "- No local repository is implied for this lane. Record `\{@research_policy.local_sources_path()}` as intentionally empty unless web evidence points to a concrete local artifact.",
    )
  }
  lines.push("")
  lines.push("## Materialization Target")
  lines.push("")
  lines.push(
    "- Turn screened evidence into topic-specific source, entity, concept, and synthesis pages.",
  )
  lines.push(
    "- Generic statements like `LLM Wiki is a maintained workspace` are not acceptable final coverage for this lane.",
  )
  lines.push(
    "- Candidate source lists are not enough. MoonBook now treats durable coverage as verified only after source pages digest inspected material with provenance.",
  )
  lines.join("\n")
}