domain tier

domain-ai-report

LLM-prompt-driven market-research report generation (executive brief, competitive landscape, competitor profile) over infrastructure-ai::AiProvider — industry-agnostic.

LLM-prompt-driven market-research report generation (executive brief, competitive landscape, competitor profile) over infrastructure-ai::AiProvider — industry-agnostic.

Tierdomain
Roleunclassified (baselined)
Pathcrates/domain/ai-report
Edition2021
Targetsdomain_ai_report
Public items37 across 9 modules
Tests25

What it is for

LLM-prompt-driven market-research report generation.

Orchestrates a infrastructure_ai::AiProvider to generate three report types — an executive brief, a competitive-landscape report, and a competitor profile — from prompt-template structs with generic numeric/ string fields (competitor counts, ratings, keyword stats, etc.).

Ported from plumber/src/ai/** (Sprint 3.46 crate 21). The source hardcoded plumbing/Phoenix content into its system prompt, its assembled- report headers/footer, and one prompt struct's field name; this crate parameterizes all of that via ReportContext (business vertical + geography + product branding) so the report-assembly engine is industry-agnostic. See CHANGELOG.md for the full list of AC-generic changes and their rationale.

# Example

use infrastructure_ai::StubAiProvider;
use domain_ai_report::{CostRates, ExecutiveBriefData, ReportContext, ReportWriter};
use std::sync::Arc;

# async fn example() -> domain_ai_report::Result<()> {
let context = ReportContext::new("plumbing", "Phoenix, Arizona", "MarketScope");
let mut writer = ReportWriter::new(
Arc::new(StubAiProvider::new(true)),
context,
CostRates::default(),
);

let report = writer
.generate_executive_brief(ExecutiveBriefData {
competitor_count: 10,
avg_rating: 4.4,
avg_reviews: 60.0,
top_3_names: vec"A".into(), "B".into(), "C".into(),
total_pages: 500,
unique_keywords: 100,
keyword_gaps: 12,
performance_issues_pct: 20.0,
top_opportunities: vec"Opp".into(),
top_threats: vec"Threat".into(),
})
.await?;
assert!(report.contains("Phoenix, Arizona plumbing Market"));
# Ok(())
# }

Capabilities

ReportContext

Caller-supplied report context: the business vertical, geography, and

Item
pub struct ReportContext
ReportContext :: fn new(business_type : impl Into <String>, geography : impl Into <String>, product_name : impl Into <String>,) -> Self
ReportContext :: fn system_prompt(& self) -> String

CostRates

Token-cost estimation rates.

Item
pub struct CostRates
CostRates :: fn new(input_per_million : f64, output_per_million : f64) -> Self
CostRates :: fn estimate(& self, input_tokens : u32, output_tokens : u32) -> f64
CostRates :: fn default() -> Self

ReportError

Error type for report generation.

Item
pub enum ReportError

Result

Error type for report generation.

Item
pub type Result<T>: std::result::Result <T, ReportError>

CompetitorAnalysisPrompt

Competitor Analysis prompt template.

Item
pub struct CompetitorAnalysisPrompt
CompetitorAnalysisPrompt :: fn render(& self) -> String

ExecutiveSummaryPrompt

Executive Summary prompt template.

Item
pub struct ExecutiveSummaryPrompt
ExecutiveSummaryPrompt :: fn render(& self) -> String

KeywordStats

Market Landscape prompt template.

Item
pub struct KeywordStats

LeaderInfo

Market Landscape prompt template.

Item
pub struct LeaderInfo

MarketLandscapePrompt

Market Landscape prompt template.

Item
pub struct MarketLandscapePrompt
MarketLandscapePrompt :: fn render(& self) -> String

TechAdoption

Market Landscape prompt template.

Item
pub struct TechAdoption

TierBreakdown

Market Landscape prompt template.

Item
pub struct TierBreakdown

CompetitorWeakness

Opportunity Finder prompt template.

Item
pub struct CompetitorWeakness

ContentGap

Opportunity Finder prompt template.

Item
pub struct ContentGap

KeywordGap

Opportunity Finder prompt template.

Item
pub struct KeywordGap

OpportunityFinderPrompt

Opportunity Finder prompt template.

Item
pub struct OpportunityFinderPrompt
OpportunityFinderPrompt :: fn render(& self) -> String

TechGap

Opportunity Finder prompt template.

Item
pub struct TechGap

CompetitorProfileData

Report writer that orchestrates AI analysis and generates reports.

Item
pub struct CompetitorProfileData

ExecutiveBriefData

Report writer that orchestrates AI analysis and generates reports.

Item
pub struct ExecutiveBriefData

LandscapeReportData

Report writer that orchestrates AI analysis and generates reports.

Item
pub struct LandscapeReportData

ReportWriter

Report writer that orchestrates AI analysis and generates reports.

Item
pub struct ReportWriter
ReportWriter :: fn new(provider : Arc <dyn AiProvider>, context : ReportContext, cost_rates : CostRates,) -> Self
ReportWriter :: fn tokens_used(& self) ->(u32, u32)
ReportWriter :: fn estimated_cost(& self) -> f64
ReportWriter :: fn provider_name(& self) -> & 'static str
ReportWriter :: fn is_available(& self) -> bool
ReportWriter :: async fn generate_executive_brief(& mut self, data : ExecutiveBriefData) -> Result <String>
ReportWriter :: async fn generate_landscape_report(& mut self, data : LandscapeReportData) -> Result <String>
ReportWriter :: async fn generate_competitor_profile(& mut self, data : CompetitorProfileData,) -> Result <String>

How to use it

From this crate's own rustdoc:

use infrastructure_ai::StubAiProvider;
use domain_ai_report::{CostRates, ExecutiveBriefData, ReportContext, ReportWriter};
use std::sync::Arc;

# async fn example() -> domain_ai_report::Result<()> {
let context = ReportContext::new("plumbing", "Phoenix, Arizona", "MarketScope");
let mut writer = ReportWriter::new(
    Arc::new(StubAiProvider::new(true)),
    context,
    CostRates::default(),
);

let report = writer
    .generate_executive_brief(ExecutiveBriefData {
        competitor_count: 10,
        avg_rating: 4.4,
        avg_reviews: 60.0,
        top_3_names: vec!["A".into(), "B".into(), "C".into()],
        total_pages: 500,
        unique_keywords: 100,
        keyword_gaps: 12,
        performance_issues_pct: 20.0,
        top_opportunities: vec!["Opp".into()],
        top_threats: vec!["Threat".into()],
    })
    .await?;
assert!(report.contains("Phoenix, Arizona plumbing Market"));
# Ok(())
# }

Module structure

domain_ai_report

flowchart TD
  n_domain_ai_report["domain_ai_report"]
  n_domain_ai_report --> n_context["context"]
  n_domain_ai_report --> n_cost["cost"]
  n_domain_ai_report --> n_error["error"]
  n_domain_ai_report --> n_prompts["prompts"]
  n_prompts --> n_prompts__competitor_analysis["competitor_analysis"]
  n_prompts --> n_prompts__executive_summary["executive_summary"]
  n_prompts --> n_prompts__market_landscape["market_landscape"]
  n_prompts --> n_prompts__opportunity_finder["opportunity_finder"]
  n_domain_ai_report --> n_report_writer["report_writer"]

Public surface

`context`

ItemWhat it is
pub struct ReportContextThe business vertical, geography, and product branding a report is generated for
ReportContext :: fn new(business_type : impl Into <String>, geography : impl Into <String>, product_name : impl Into <String>,) -> SelfConstruct a new report context.
ReportContext :: fn system_prompt(& self) -> StringBuild the system prompt for all market-research completions from this context

`cost`

ItemWhat it is
pub struct CostRatesPer-million-token pricing used to estimate the dollar cost of a report generation session from token usage
CostRates :: fn new(input_per_million : f64, output_per_million : f64) -> SelfConstruct explicit rates.
CostRates :: fn estimate(& self, input_tokens : u32, output_tokens : u32) -> f64Estimate the dollar cost of the given token usage at these rates.
CostRates :: fn default() -> SelfExample/default rates only (Claude Sonnet 4 pricing as ported from plumber/src/ai/report_writer.rs's INPUT_COST_PER_MILLION / OUTPUT_COST_PER_MILLION constants) — not authoritative or necessarily current

`error`

ItemWhat it is
pub enum ReportErrorError type for ReportWriter operations
pub type Result<T>: std::result::Result <T, ReportError>Result type for ReportWriter operations.

`prompts::competitor_analysis`

ItemWhat it is
pub struct CompetitorAnalysisPromptPrompt data for a single-competitor deep-dive analysis
CompetitorAnalysisPrompt :: fn render(& self) -> StringRender the LLM-facing prompt text for this competitor analysis.

`prompts::executive_summary`

ItemWhat it is
pub struct ExecutiveSummaryPromptPrompt data for a market-research executive summary
ExecutiveSummaryPrompt :: fn render(& self) -> StringRender the LLM-facing prompt text for this executive summary.

`prompts::market_landscape`

ItemWhat it is
pub struct MarketLandscapePromptPrompt data for the competitive-landscape section of a market-research report
pub struct LeaderInfo
pub struct TierBreakdown
pub struct TechAdoption
pub struct KeywordStats
MarketLandscapePrompt :: fn render(& self) -> StringRender the LLM-facing prompt text for the market-landscape section.

`prompts::opportunity_finder`

ItemWhat it is
pub struct OpportunityFinderPromptPrompt data for a market-opportunity-ranking section
pub struct KeywordGap
pub struct TechGap
pub struct ContentGap
pub struct CompetitorWeakness
OpportunityFinderPrompt :: fn render(& self) -> StringRender the LLM-facing prompt text for opportunity ranking.

`report_writer`

ItemWhat it is
pub struct ReportWriterReport writer that generates AI-powered market-research reports
pub struct ExecutiveBriefDataData for generating an executive brief.
pub struct LandscapeReportDataData for generating a landscape report
pub struct CompetitorProfileDataData for generating a competitor profile
ReportWriter :: fn new(provider : Arc <dyn AiProvider>, context : ReportContext, cost_rates : CostRates,) -> SelfCreate a new report writer
ReportWriter :: fn tokens_used(& self) ->(u32, u32)Get total tokens used in this session.
ReportWriter :: fn estimated_cost(& self) -> f64Estimate total cost for this session at this writer's CostRates.
ReportWriter :: fn provider_name(& self) -> & 'static strGet the provider name.
ReportWriter :: fn is_available(& self) -> boolCheck if the provider is available.
ReportWriter :: async fn generate_executive_brief(& mut self, data : ExecutiveBriefData) -> Result <String>Generate an Executive Intelligence Brief.
ReportWriter :: async fn generate_landscape_report(& mut self, data : LandscapeReportData) -> Result <String>Generate a Competitive Landscape Report.
ReportWriter :: async fn generate_competitor_profile(& mut self, data : CompetitorProfileData,) -> Result <String>Generate a Competitor Profile.

Re-exports. Exported here, defined elsewhere.

ExportDefined in
CompetitorAnalysisPromptcompetitor_analysis::CompetitorAnalysisPrompt
CostRatescost::CostRates
ExecutiveSummaryPromptexecutive_summary::ExecutiveSummaryPrompt
ReportContextcontext::ReportContext
{CompetitorAnalysisPrompt,CompetitorWeakness,ContentGap,ExecutiveSummaryPrompt,KeywordGap,KeywordStats,LeaderInfo,MarketLandscapePrompt,OpportunityFinderPrompt,TechAdoption,TechGap,TierBreakdown,}prompts::{CompetitorAnalysisPrompt,CompetitorWeakness,ContentGap,ExecutiveSummaryPrompt,KeywordGap,KeywordStats,LeaderInfo,MarketLandscapePrompt,OpportunityFinderPrompt,TechAdoption,TechGap,TierBreakdown,}
{CompetitorProfileData,ExecutiveBriefData,LandscapeReportData,ReportWriter,}report_writer::{CompetitorProfileData,ExecutiveBriefData,LandscapeReportData,ReportWriter,}
{CompetitorWeakness,ContentGap,KeywordGap,OpportunityFinderPrompt,TechGap,}opportunity_finder::{CompetitorWeakness,ContentGap,KeywordGap,OpportunityFinderPrompt,TechGap,}
{KeywordStats,LeaderInfo,MarketLandscapePrompt,TechAdoption,TierBreakdown,}market_landscape::{KeywordStats,LeaderInfo,MarketLandscapePrompt,TechAdoption,TierBreakdown,}
{ReportError,Result}error::{ReportError,Result}

Boundary

Reaches into infrastructure.

Shares tier domain with 41 other crates: domain-agreements, domain-billing, domain-catalog, domain-classify, domain-comments, domain-competitive-intel, domain-contact, domain-conversation-engine, … (41 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)domain
Architectural role (taxonomy)unclassified (baselined)
Locationcrates/domain/ai-report
Vocabulary in force (lexicon)current

Tier flow. Which tiers this crate's own edges cross.

flowchart LR
  n_domain["domain"] --> n_infrastructure["infrastructure"]

Dependencies

Runtime, in this workspace.

CrateTierOptionalOnly on
`infrastructure-ai`infrastructurenoalways

Runtime, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
chrono^0.4serdenoalways
serde^1derivenoalways
thiserror^2noalways

Development, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
tokio^1full, macros, rt-multi-threadnoalways

Build. None.

Depended on by. Nothing in this workspace.

Signal flow — what reaches this crate, and what it reaches.

flowchart LR
  SELF["domain-ai-report"]
  SELF -->|runtime| n_infrastructure_ai["infrastructure-ai"]
  classDef self fill:#1f883d,stroke:#1f883d,color:#fff;
  class SELF self;

Feature flags

No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.

Targets

KindNameSource
libdomain_ai_report`src/lib.rs`

Error model

Error typeNamed by
ReportErrorResult

Operational characteristics

PropertyEvidence
async public surfaceyes
async runtimenone detected
database accessnone detected
network I/Onone detected
unsafe codenone detected
environment variablesnone detected

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.

No workspace crate depends on this one.

Verification

KindCount
Unit tests25
Integration tests0
Examples0
Doctests1

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
context100
cost100
error200
prompts::competitor_analysis100
prompts::executive_summary100
prompts::market_landscape500
prompts::opportunity_finder500
report_writer400

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc2937
Public modules with a //! block99
pie showData
    title Public items with rustdoc
    "Documented" : 29
    "No rustdoc detected" : 8

Metrics

MetricValue
Rust source files10
Source lines1507
Code lines1104
Public API items37
Public modules9
Tests25
Examples0
Cargo features0
Direct runtime dependencies4
Workspace reverse dependencies0
pie showData
    title Public API by kind
    "enum" : 1
    "method" : 17
    "struct" : 18
    "type alias" : 1
pie showData
    title Rust source composition
    "Code" : 1104
    "Blank or comment" : 403

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

All domain · Manual