use super::*;
use a3s::research::{EvidenceRef, InquiryEvent, InquiryLimits, Question, ResearchMethod};
fn observed_workflow_output(sources: &[&str]) -> String {
let sources = sources
.iter()
.enumerate()
.map(|(index, url)| {
serde_json::json!({
"title": format!("Observed source {index}"),
"url_or_path": url,
"quote_or_fact": "Observed evidence for the report.",
"reliability": "Traceable source"
})
})
.collect::<Vec<_>>();
serde_json::json!({
"mode": "direct_web",
"checker": { "decision": "finalize" },
"research": {
"status": "success",
"results": [{
"success": true,
"structured": {
"summary": "Observed evidence",
"sources": sources,
"key_evidence": ["Observed evidence for the report."],
"contradictions": [],
"confidence": "high",
"gaps": []
}
}]
}
})
.to_string()
}
#[test]
fn completed_artifact_validation_rejects_an_outlining_inquiry() {
let events = vec![
InquiryEvent::StrategySelected {
method: ResearchMethod::Focused,
},
InquiryEvent::QuestionsQueued {
questions: vec![Question::queued(
"question:one",
None,
"What does the evidence establish?",
)],
},
InquiryEvent::EvidenceAccepted {
evidence: EvidenceRef::new(
"evidence:one",
vec!["claim:one".to_string()],
vec!["source:one".to_string()],
),
},
InquiryEvent::QuestionAnswered {
question_id: "question:one".to_string(),
answer: "The evidence establishes the finding.".to_string(),
evidence_ids: vec!["evidence:one".to_string()],
},
];
let state = a3s::research::replay(&events, &InquiryLimits::default()).unwrap();
let workflow = serde_json::json!({
"inquiry": {"events": events, "state": state}
})
.to_string();
let error = validate_deep_research_completed_report_content(
"# Report\n\nA sufficiently long report body that would otherwise continue through the remaining validation gates.",
"<!doctype html><html><body>report</body></html>",
"query",
&workflow,
None,
)
.expect_err("Outlining evidence readiness must not publish a completed artifact");
assert!(error.contains("current phase is Outlining"), "{error}");
}
#[test]
fn source_display_domains_do_not_become_unobserved_local_citations() {
let query = "Compare runtime maintenance";
let crates = "https://crates.io/crates/runtime";
let docs = "https://docs.rs/runtime";
let workflow_output = observed_workflow_output(&[crates, docs]);
let markdown = format!(
"# Runtime report\n\n\
## Findings\n\nThe runtime remains maintained, with explicit limitations in the available evidence.\n\n\
## Sources\n\n\
- Runtime on crates.io — {crates}\n\
- Runtime documentation on docs.rs — {docs}\n\n\
## Limitations\n\nConfidence is bounded by the cited evidence.\n"
);
let html = deep_research_completed_report_html(query, &markdown);
assert!(
deep_research_report_content_sources_trace_workflow(
&markdown,
&html,
query,
&workflow_output,
None,
),
"display-only domain names must not be treated as local source paths"
);
}
#[test]
fn legitimate_unavailable_finding_is_not_placeholder_content() {
let markdown = "# Runtime report\n\n## Findings\n\nIndependent adoption data is not yet available, so the report does not claim a precise market share. The available release history still supports a bounded maintenance comparison.\n\n## Sources\n\n- https://example.com/releases\n\n## Limitations\n\nConfidence is limited by the unavailable adoption data.\n";
let html = deep_research_completed_report_html("Runtime report", markdown);
assert!(
has_research_report_substance(markdown, &html),
"a disclosed evidence gap is a legitimate finding, not placeholder text"
);
}
#[test]
fn source_trace_diagnostic_names_every_unobserved_citation() {
let observed = "https://example.com/observed";
let unobserved = "https://example.com/unobserved";
let workflow_output = observed_workflow_output(&[observed]);
let markdown = format!(
"# Runtime report\n\n## Findings\n\nA substantive comparison with bounded confidence and explicit limitations.\n\n## Sources\n\n- {observed}\n- {unobserved}\n\n## Limitations\n\nConfidence is limited to observed evidence.\n"
);
let html = deep_research_completed_report_html("Runtime report", &markdown);
let diagnostic = deep_research_report_source_trace_diagnostic(
&markdown,
&html,
"Runtime report",
&workflow_output,
None,
)
.expect_err("an unobserved citation must be rejected with a diagnostic");
assert!(diagnostic.contains(unobserved), "{diagnostic}");
assert!(
diagnostic.contains("not observed in this run"),
"{diagnostic}"
);
}
#[test]
fn generated_report_sanitizes_one_unobserved_url_without_discarding_the_report() {
let observed = "https://example.com/observed";
let mistyped = "https://example.com/obesrved";
let workflow_output = observed_workflow_output(&[observed]);
let markdown = format!(
"# Runtime report\n\n\
## Findings\n\nA supported finding cites [the observed source]({observed}), while the readable label from [a mistyped duplicate]({mistyped}) should remain without an unsafe link.\n\n\
## Sources\n\n\
- [Observed source]({observed})\n\
- [Mistyped duplicate]({mistyped})\n\n\
## Limitations\n\nConfidence is bounded by the one observed source and the unavailable corroboration.\n"
);
let cleaned = sanitize_unobserved_markdown_http_citations(
&markdown,
"Runtime report",
&workflow_output,
None,
);
assert!(cleaned.contains(observed), "{cleaned}");
assert!(!cleaned.contains(mistyped), "{cleaned}");
assert!(cleaned.contains("a mistyped duplicate"), "{cleaned}");
assert!(cleaned.contains("- Mistyped duplicate"), "{cleaned}");
let html = deep_research_completed_report_html("Runtime report", &cleaned);
deep_research_report_source_trace_diagnostic(
&cleaned,
&html,
"Runtime report",
&workflow_output,
None,
)
.expect("the remaining report should still pass the complete source trace gate");
}
#[test]
fn generated_report_sanitizes_an_unobserved_autolink_inside_bold_disclosure() {
let observed = "https://example.com/observed";
let unavailable = "https://github.com/launchbadge/sqlx/issues/1669";
let workflow_output = observed_workflow_output(&[observed]);
let markdown = format!(
"# Runtime report\n\n\
> [!CAUTION]\n\
> **Evidence boundaries**\n\
>\n\
> - **Fetch retained no substantive text for {unavailable}.** — The unavailable page remains an explicit evidence gap.\n\n\
## Findings\n\nA substantive comparison remains supported by [the observed source]({observed}).\n\n\
## Sources\n\n- [Observed source]({observed})\n\n\
## Limitations\n\nConfidence is bounded by the unavailable corroboration.\n"
);
let cleaned = sanitize_unobserved_markdown_http_citations(
&markdown,
"Runtime report",
&workflow_output,
None,
);
assert!(cleaned.contains(observed), "{cleaned}");
assert!(!cleaned.contains(unavailable), "{cleaned}");
assert!(
cleaned.contains("Fetch retained no substantive text"),
"{cleaned}"
);
let html = deep_research_completed_report_html("Runtime report", &cleaned);
deep_research_report_source_trace_diagnostic(
&cleaned,
&html,
"Runtime report",
&workflow_output,
None,
)
.expect("bold evidence-boundary prose must not create an unobserved citation");
}
#[test]
fn internal_status_text_has_a_specific_rejection_diagnostic() {
let workflow_output = observed_workflow_output(&["https://example.com/observed"]);
let answer = "# Runtime report\n\n## Findings\n\nDynamicWorkflowRuntime output: an internal transport record that must never be published. This deliberately contains enough additional text to pass the length boundary.\n\n## Sources\n\n- https://example.com/observed\n\n## Limitations\n\nConfidence is bounded.\n";
let diagnostic = deep_research_report_rejection_diagnostic_from_answer_text(
"Runtime report",
answer,
&workflow_output,
None,
)
.expect("internal status text must have a rejection diagnostic");
assert!(
diagnostic.contains("internal workflow or tool-status"),
"{diagnostic}"
);
}