///|
/// Intent Gate turns raw robots decisions into reviewable AI-crawler
/// acceptance evidence. It is the higher-level layer that checks why an
/// agent wants a URL, what data class is involved, and whether enough
/// authorization evidence exists before a crawl or model-training job ships.
pub(all) enum IntentPurpose {
PurposeSearchIndex
PurposeMonitoring
PurposeResearch
PurposeArchive
PurposeAiTraining
PurposeSecurityScan
PurposePriceComparison
PurposeUnknown
} derive(Eq, Debug)
///|
pub(all) enum IntentSensitivity {
SensitivityPublic
SensitivityAccount
SensitivityPersonalData
SensitivityCredential
SensitivityAdmin
SensitivityPaidContent
SensitivityTrainingCorpus
} derive(Eq, Debug)
///|
pub(all) enum ConsentMode {
ConsentNone
ConsentRobotsOnly
ConsentOwnerApproved
ConsentContractual
ConsentInternalTest
} derive(Eq, Debug)
///|
pub(all) enum IntentVerdict {
IntentPermitted
IntentNeedsReview
IntentDenied
} derive(Eq, Debug)
///|
pub(all) enum IntentRiskBand {
IntentRiskGreen
IntentRiskYellow
IntentRiskOrange
IntentRiskRed
} derive(Eq, Debug)
///|
pub(all) struct CrawlIntent {
label : String
user_agent : String
url_or_path : String
purpose : IntentPurpose
sensitivity : IntentSensitivity
consent : ConsentMode
expected_allowed : Bool?
retention_days : Int
evidence_id : String
note : String
} derive(Eq, Debug)
///|
pub(all) struct IntentReview {
intent : CrawlIntent
target_result : TargetAuditResult
verdict : IntentVerdict
risk_band : IntentRiskBand
risk_points : Int
robots_allowed : Bool
requires_human_review : Bool
blockers : Array[String]
obligations : Array[String]
evidence_line : String
tags : Array[String]
} derive(Eq, Debug)
///|
pub(all) struct IntentGateSummary {
total_intents : Int
permitted_intents : Int
denied_intents : Int
review_intents : Int
robots_allowed : Int
robots_blocked : Int
high_risk_intents : Int
missing_evidence : Int
explicit_authorization : Int
average_risk : Int
score : Int
notes : Array[String]
} derive(Eq, Debug)
///|
pub(all) struct IntentGateReport {
policy : RobotsPolicy
intents : Array[CrawlIntent]
reviews : Array[IntentReview]
summary : IntentGateSummary
target_summary : SiteAuditSummary
} derive(Eq, Debug)
///|
pub fn IntentPurpose::label(self : IntentPurpose) -> String {
match self {
PurposeSearchIndex => "search-index"
PurposeMonitoring => "monitoring"
PurposeResearch => "research"
PurposeArchive => "archive"
PurposeAiTraining => "ai-training"
PurposeSecurityScan => "security-scan"
PurposePriceComparison => "price-comparison"
PurposeUnknown => "unknown"
}
}
///|
pub fn IntentSensitivity::label(self : IntentSensitivity) -> String {
match self {
SensitivityPublic => "public"
SensitivityAccount => "account"
SensitivityPersonalData => "personal-data"
SensitivityCredential => "credential"
SensitivityAdmin => "admin"
SensitivityPaidContent => "paid-content"
SensitivityTrainingCorpus => "training-corpus"
}
}
///|
pub fn ConsentMode::label(self : ConsentMode) -> String {
match self {
ConsentNone => "none"
ConsentRobotsOnly => "robots-only"
ConsentOwnerApproved => "owner-approved"
ConsentContractual => "contractual"
ConsentInternalTest => "internal-test"
}
}
///|
pub fn IntentVerdict::label(self : IntentVerdict) -> String {
match self {
IntentPermitted => "permitted"
IntentNeedsReview => "needs-review"
IntentDenied => "denied"
}
}
///|
pub fn IntentRiskBand::label(self : IntentRiskBand) -> String {
match self {
IntentRiskGreen => "green"
IntentRiskYellow => "yellow"
IntentRiskOrange => "orange"
IntentRiskRed => "red"
}
}
///|
pub fn crawl_intent(
label : StringView,
user_agent : StringView,
url_or_path : StringView,
purpose : IntentPurpose,
sensitivity : IntentSensitivity,
consent : ConsentMode,
) -> CrawlIntent {
{
label: label.to_owned(),
user_agent: user_agent.to_owned(),
url_or_path: url_or_path.to_owned(),
purpose,
sensitivity,
consent,
expected_allowed: None,
retention_days: 0,
evidence_id: "",
note: "",
}
}
///|
pub fn CrawlIntent::with_expected(
self : CrawlIntent,
expected_allowed : Bool,
) -> CrawlIntent {
{
label: self.label,
user_agent: self.user_agent,
url_or_path: self.url_or_path,
purpose: self.purpose,
sensitivity: self.sensitivity,
consent: self.consent,
expected_allowed: Some(expected_allowed),
retention_days: self.retention_days,
evidence_id: self.evidence_id,
note: self.note,
}
}
///|
pub fn CrawlIntent::with_retention(
self : CrawlIntent,
retention_days : Int,
) -> CrawlIntent {
{
label: self.label,
user_agent: self.user_agent,
url_or_path: self.url_or_path,
purpose: self.purpose,
sensitivity: self.sensitivity,
consent: self.consent,
expected_allowed: self.expected_allowed,
retention_days,
evidence_id: self.evidence_id,
note: self.note,
}
}
///|
pub fn CrawlIntent::with_evidence(
self : CrawlIntent,
evidence_id : StringView,
) -> CrawlIntent {
{
label: self.label,
user_agent: self.user_agent,
url_or_path: self.url_or_path,
purpose: self.purpose,
sensitivity: self.sensitivity,
consent: self.consent,
expected_allowed: self.expected_allowed,
retention_days: self.retention_days,
evidence_id: evidence_id.to_owned(),
note: self.note,
}
}
///|
pub fn CrawlIntent::with_note(
self : CrawlIntent,
note : StringView,
) -> CrawlIntent {
{
label: self.label,
user_agent: self.user_agent,
url_or_path: self.url_or_path,
purpose: self.purpose,
sensitivity: self.sensitivity,
consent: self.consent,
expected_allowed: self.expected_allowed,
retention_days: self.retention_days,
evidence_id: self.evidence_id,
note: note.to_owned(),
}
}
///|
pub fn CrawlIntent::to_target(self : CrawlIntent) -> AuditTarget {
let item = match self.expected_allowed {
Some(expected) =>
expected_target(
self.label,
self.user_agent,
self.url_or_path,
expected,
self.importance(),
self.note,
)
None =>
target(self.label, self.user_agent, self.url_or_path)
.with_importance(self.importance())
.with_note(self.note)
}
item
}
///|
pub fn CrawlIntent::importance(self : CrawlIntent) -> TargetImportance {
match self.sensitivity {
SensitivityPublic => ImportanceNormal
SensitivityAccount => ImportanceHigh
SensitivityPersonalData => ImportanceCritical
SensitivityCredential => ImportanceCritical
SensitivityAdmin => ImportanceCritical
SensitivityPaidContent => ImportanceHigh
SensitivityTrainingCorpus => ImportanceHigh
}
}
///|
pub fn CrawlIntent::has_evidence(self : CrawlIntent) -> Bool {
!self.evidence_id.trim().is_empty()
}
///|
pub fn CrawlIntent::needs_explicit_authorization(self : CrawlIntent) -> Bool {
self.purpose == PurposeAiTraining ||
self.purpose == PurposePriceComparison ||
self.sensitivity == SensitivityPersonalData ||
self.sensitivity == SensitivityCredential ||
self.sensitivity == SensitivityAdmin ||
self.sensitivity == SensitivityPaidContent ||
self.sensitivity == SensitivityTrainingCorpus
}
///|
pub fn CrawlIntent::has_explicit_authorization(self : CrawlIntent) -> Bool {
self.consent == ConsentOwnerApproved ||
self.consent == ConsentContractual ||
self.consent == ConsentInternalTest
}
///|
pub fn CrawlIntent::purpose_summary(self : CrawlIntent) -> String {
self.purpose.label() +
"/" +
self.sensitivity.label() +
"/" +
self.consent.label()
}
///|
pub fn review_intent(
policy : RobotsPolicy,
intent : CrawlIntent,
) -> IntentReview {
let result = audit_target(policy, intent.to_target())
let blockers = intent_blockers(intent, result)
let obligations = intent_obligations(intent, result)
let risk_points = intent_risk_points(intent, result, blockers, obligations)
let risk_band = classify_intent_risk(risk_points)
let verdict = classify_intent_verdict(intent, result, blockers, risk_points)
let requires_human_review = verdict == IntentNeedsReview
let evidence_line = intent_evidence_line(intent, result, verdict, risk_points)
{
intent,
target_result: result,
verdict,
risk_band,
risk_points,
robots_allowed: result.decision.allowed,
requires_human_review,
blockers,
obligations,
evidence_line,
tags: intent_tags(intent, result, verdict, risk_band),
}
}
///|
pub fn review_intents(
policy : RobotsPolicy,
intents : Array[CrawlIntent],
) -> IntentGateReport {
let reviews : Array[IntentReview] = []
let targets : Array[AuditTarget] = []
for intent in intents {
targets.push(intent.to_target())
reviews.push(review_intent(policy, intent))
}
let target_report = audit_targets(policy, targets)
{
policy,
intents,
reviews,
summary: summarize_intent_reviews(reviews),
target_summary: target_report.summary,
}
}
///|
pub fn RobotsPolicy::review_intents(
self : RobotsPolicy,
intents : Array[CrawlIntent],
) -> IntentGateReport {
review_intents(self, intents)
}
///|
pub fn summarize_intent_reviews(
reviews : Array[IntentReview],
) -> IntentGateSummary {
let notes : Array[String] = []
let mut total_intents = 0
let mut permitted_intents = 0
let mut denied_intents = 0
let mut review_intents = 0
let mut robots_allowed = 0
let mut robots_blocked = 0
let mut high_risk_intents = 0
let mut missing_evidence = 0
let mut explicit_authorization = 0
let mut risk_sum = 0
for review in reviews {
total_intents = total_intents + 1
risk_sum = risk_sum + review.risk_points
match review.verdict {
IntentPermitted => permitted_intents = permitted_intents + 1
IntentNeedsReview => review_intents = review_intents + 1
IntentDenied => denied_intents = denied_intents + 1
}
if review.robots_allowed {
robots_allowed = robots_allowed + 1
} else {
robots_blocked = robots_blocked + 1
}
if review.risk_band == IntentRiskOrange || review.risk_band == IntentRiskRed {
high_risk_intents = high_risk_intents + 1
}
if !review.intent.has_evidence() {
missing_evidence = missing_evidence + 1
}
if review.intent.has_explicit_authorization() {
explicit_authorization = explicit_authorization + 1
}
}
let average_risk = if total_intents == 0 {
0
} else {
risk_sum / total_intents
}
let score = intent_gate_score(
total_intents, denied_intents, review_intents, high_risk_intents, missing_evidence,
)
if total_intents == 0 {
notes.push("no AI crawler intent was provided")
}
if denied_intents > 0 {
notes.push(
"some intents are denied by robots policy or authorization rules",
)
}
if review_intents > 0 {
notes.push("some intents require human review before release")
}
if missing_evidence > 0 {
notes.push("some intents lack a reusable evidence id")
}
if explicit_authorization == 0 && total_intents > 0 {
notes.push(
"no intent records explicit owner approval or contractual consent",
)
}
{
total_intents,
permitted_intents,
denied_intents,
review_intents,
robots_allowed,
robots_blocked,
high_risk_intents,
missing_evidence,
explicit_authorization,
average_risk,
score,
notes,
}
}
///|
pub fn IntentGateSummary::pass_rate_percent(self : IntentGateSummary) -> Int {
if self.total_intents == 0 {
0
} else {
self.permitted_intents * 100 / self.total_intents
}
}
///|
pub fn IntentGateSummary::is_release_ready(self : IntentGateSummary) -> Bool {
self.denied_intents == 0 &&
self.review_intents == 0 &&
self.missing_evidence == 0
}
///|
pub fn IntentGateSummary::to_line(self : IntentGateSummary) -> String {
"intents=" +
self.total_intents.to_string() +
" permitted=" +
self.permitted_intents.to_string() +
" review=" +
self.review_intents.to_string() +
" denied=" +
self.denied_intents.to_string() +
" score=" +
self.score.to_string()
}
///|
pub fn IntentGateSummary::to_markdown(self : IntentGateSummary) -> String {
let lines : Array[String] = []
lines.push("## Intent Gate Summary")
lines.push("")
lines.push("- Total intents: " + self.total_intents.to_string())
lines.push("- Permitted intents: " + self.permitted_intents.to_string())
lines.push("- Needs review: " + self.review_intents.to_string())
lines.push("- Denied intents: " + self.denied_intents.to_string())
lines.push("- Robots allowed: " + self.robots_allowed.to_string())
lines.push("- Robots blocked: " + self.robots_blocked.to_string())
lines.push("- High risk intents: " + self.high_risk_intents.to_string())
lines.push("- Missing evidence: " + self.missing_evidence.to_string())
lines.push(
"- Explicit authorization: " + self.explicit_authorization.to_string(),
)
lines.push("- Average risk: " + self.average_risk.to_string())
lines.push("- Pass rate: " + self.pass_rate_percent().to_string() + "%")
lines.push("- Score: " + self.score.to_string())
if self.notes.is_empty() {
lines.push("- Notes: none")
} else {
lines.push("- Notes: " + self.notes.join("; "))
}
lines.join("\n")
}
///|
pub fn IntentReview::to_markdown_row(self : IntentReview) -> String {
"| " +
intent_cell(self.intent.label) +
" | " +
intent_cell(self.intent.user_agent) +
" | " +
intent_cell(self.target_result.snapshot.normalized) +
" | " +
self.intent.purpose.label() +
" | " +
self.intent.sensitivity.label() +
" | " +
self.intent.consent.label() +
" | " +
(if self.robots_allowed { "allow" } else { "block" }) +
" | " +
self.verdict.label() +
" | " +
self.risk_band.label() +
" | " +
self.risk_points.to_string() +
" | " +
intent_cell(self.intent.evidence_id) +
" |"
}
///|
pub fn IntentReview::to_line(self : IntentReview) -> String {
self.verdict.label().to_upper() +
" " +
self.intent.label +
" " +
self.target_result.snapshot.normalized +
" risk=" +
self.risk_points.to_string() +
" evidence=" +
evidence_label(self.intent)
}
///|
pub fn IntentReview::has_blocker(
self : IntentReview,
blocker : StringView,
) -> Bool {
let expected = blocker.to_owned()
self.blockers.contains(expected)
}
///|
pub fn IntentGateReport::to_markdown(self : IntentGateReport) -> String {
let lines : Array[String] = []
lines.push("# RoboPolicy Intent Gate")
lines.push("")
lines.push(self.summary.to_markdown())
lines.push("")
lines.push("## Intent Reviews")
lines.push("")
lines.push(
"| Label | Agent | Path | Purpose | Sensitivity | Consent | Robots | Verdict | Risk Band | Risk | Evidence |",
)
lines.push(
"| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |",
)
for review in self.reviews {
lines.push(review.to_markdown_row())
}
lines.push("")
lines.push("## Evidence Lines")
lines.push("")
for review in self.reviews {
lines.push("- " + review.evidence_line)
}
lines.join("\n")
}
///|
pub fn IntentGateReport::to_csv(self : IntentGateReport) -> String {
let lines : Array[String] = []
lines.push(
"label,user_agent,path,purpose,sensitivity,consent,robots,verdict,risk_band,risk,evidence",
)
for review in self.reviews {
lines.push(review.to_csv_row())
}
lines.join("\n")
}
///|
pub fn IntentReview::to_csv_row(self : IntentReview) -> String {
intent_csv_cell(self.intent.label) +
"," +
intent_csv_cell(self.intent.user_agent) +
"," +
intent_csv_cell(self.target_result.snapshot.normalized) +
"," +
intent_csv_cell(self.intent.purpose.label()) +
"," +
intent_csv_cell(self.intent.sensitivity.label()) +
"," +
intent_csv_cell(self.intent.consent.label()) +
"," +
intent_csv_cell(if self.robots_allowed { "allow" } else { "block" }) +
"," +
intent_csv_cell(self.verdict.label()) +
"," +
intent_csv_cell(self.risk_band.label()) +
"," +
intent_csv_cell(self.risk_points.to_string()) +
"," +
intent_csv_cell(self.intent.evidence_id)
}
///|
pub fn IntentGateReport::to_json(self : IntentGateReport) -> String {
let rows : Array[String] = []
for review in self.reviews {
rows.push(review.to_json())
}
"{" +
"\"summary\":" +
self.summary.to_json() +
",\"reviews\":[" +
rows.join(",") +
"]}"
}
///|
pub fn IntentGateSummary::to_json(self : IntentGateSummary) -> String {
"{" +
"\"total_intents\":" +
self.total_intents.to_string() +
",\"permitted_intents\":" +
self.permitted_intents.to_string() +
",\"review_intents\":" +
self.review_intents.to_string() +
",\"denied_intents\":" +
self.denied_intents.to_string() +
",\"robots_allowed\":" +
self.robots_allowed.to_string() +
",\"robots_blocked\":" +
self.robots_blocked.to_string() +
",\"high_risk_intents\":" +
self.high_risk_intents.to_string() +
",\"missing_evidence\":" +
self.missing_evidence.to_string() +
",\"explicit_authorization\":" +
self.explicit_authorization.to_string() +
",\"average_risk\":" +
self.average_risk.to_string() +
",\"score\":" +
self.score.to_string() +
"}"
}
///|
pub fn IntentReview::to_json(self : IntentReview) -> String {
"{" +
"\"label\":\"" +
intent_json_escape(self.intent.label) +
"\",\"user_agent\":\"" +
intent_json_escape(self.intent.user_agent) +
"\",\"path\":\"" +
intent_json_escape(self.target_result.snapshot.normalized) +
"\",\"purpose\":\"" +
self.intent.purpose.label() +
"\",\"sensitivity\":\"" +
self.intent.sensitivity.label() +
"\",\"consent\":\"" +
self.intent.consent.label() +
"\",\"robots_allowed\":" +
self.robots_allowed.to_string() +
",\"verdict\":\"" +
self.verdict.label() +
"\",\"risk_band\":\"" +
self.risk_band.label() +
"\",\"risk_points\":" +
self.risk_points.to_string() +
",\"evidence\":\"" +
intent_json_escape(self.intent.evidence_id) +
"\"}"
}
///|
pub fn safe_public_ai_intent(
label : StringView,
user_agent : StringView,
url_or_path : StringView,
evidence_id : StringView,
) -> CrawlIntent {
crawl_intent(
label,
user_agent,
url_or_path,
PurposeMonitoring,
SensitivityPublic,
ConsentOwnerApproved,
)
.with_expected(true)
.with_retention(7)
.with_evidence(evidence_id)
}
///|
pub fn training_intent(
label : StringView,
user_agent : StringView,
url_or_path : StringView,
consent : ConsentMode,
evidence_id : StringView,
) -> CrawlIntent {
crawl_intent(
label,
user_agent,
url_or_path,
PurposeAiTraining,
SensitivityTrainingCorpus,
consent,
)
.with_expected(true)
.with_retention(30)
.with_evidence(evidence_id)
}
///|
pub fn blocked_private_intent(
label : StringView,
user_agent : StringView,
url_or_path : StringView,
) -> CrawlIntent {
crawl_intent(
label,
user_agent,
url_or_path,
PurposeResearch,
SensitivityPersonalData,
ConsentNone,
)
.with_expected(false)
.with_retention(0)
}
///|
pub fn sample_intents() -> Array[CrawlIntent] {
[
safe_public_ai_intent(
"public-docs-monitor", "ResearchBot", "/private/summary.html", "owner-ticket-42",
),
training_intent(
"training-corpus-review",
"ResearchBot",
"/private/summary.html",
ConsentRobotsOnly,
"dataset-plan-7",
),
blocked_private_intent(
"private-json-training", "ResearchBot", "/private/data.json",
),
]
}
///|
pub fn sample_intent_gate_markdown() -> String {
review_intents(parse(sample_robots()), sample_intents()).to_markdown()
}
///|
fn intent_blockers(
intent : CrawlIntent,
result : TargetAuditResult,
) -> Array[String] {
let blockers : Array[String] = []
if !result.decision.allowed {
blockers.push("robots.txt blocks this path")
}
if intent.needs_explicit_authorization() &&
!intent.has_explicit_authorization() {
blockers.push("explicit authorization is required for this intent")
}
if intent.sensitivity == SensitivityCredential ||
intent.sensitivity == SensitivityAdmin {
if intent.consent != ConsentInternalTest &&
intent.consent != ConsentOwnerApproved {
blockers.push("credential or admin surfaces require owner approval")
}
}
if intent.retention_days > 90 && intent.consent != ConsentContractual {
blockers.push("long retention requires contractual consent")
}
blockers
}
///|
fn intent_obligations(
intent : CrawlIntent,
result : TargetAuditResult,
) -> Array[String] {
let obligations : Array[String] = []
obligations.push("record normalized path " + result.snapshot.normalized)
if intent.has_evidence() {
obligations.push("attach evidence " + intent.evidence_id)
} else {
obligations.push("add reviewer-visible evidence id")
}
if intent.consent == ConsentOwnerApproved ||
intent.consent == ConsentContractual {
obligations.push("keep authorization proof with release notes")
}
if intent.purpose == PurposeAiTraining {
obligations.push("document dataset purpose and exclusion scope")
}
if intent.retention_days > 0 {
obligations.push(
"enforce retention " + intent.retention_days.to_string() + " days",
)
}
if result.snapshot.had_query || result.snapshot.had_fragment {
obligations.push("review query and fragment stripping before fetch")
}
obligations
}
///|
fn intent_risk_points(
intent : CrawlIntent,
result : TargetAuditResult,
blockers : Array[String],
obligations : Array[String],
) -> Int {
let mut risk = result.risk_points
risk = risk + intent_purpose_risk(intent.purpose)
risk = risk + intent_sensitivity_risk(intent.sensitivity)
risk = risk + intent_consent_risk(intent.consent)
risk = risk + blockers.length() * 6
risk = risk + obligations.length() / 3
if !intent.has_evidence() {
risk = risk + 4
}
if intent.retention_days > 30 {
risk = risk + 2
}
if intent.retention_days > 90 {
risk = risk + 4
}
if result.snapshot.had_query || result.snapshot.had_fragment {
risk = risk + 1
}
risk
}
///|
fn intent_purpose_risk(purpose : IntentPurpose) -> Int {
match purpose {
PurposeSearchIndex => 1
PurposeMonitoring => 1
PurposeResearch => 2
PurposeArchive => 2
PurposeAiTraining => 5
PurposeSecurityScan => 4
PurposePriceComparison => 4
PurposeUnknown => 6
}
}
///|
fn intent_sensitivity_risk(sensitivity : IntentSensitivity) -> Int {
match sensitivity {
SensitivityPublic => 0
SensitivityAccount => 4
SensitivityPersonalData => 7
SensitivityCredential => 9
SensitivityAdmin => 8
SensitivityPaidContent => 5
SensitivityTrainingCorpus => 5
}
}
///|
fn intent_consent_risk(consent : ConsentMode) -> Int {
match consent {
ConsentNone => 6
ConsentRobotsOnly => 3
ConsentOwnerApproved => 0
ConsentContractual => 0
ConsentInternalTest => 1
}
}
///|
fn classify_intent_risk(risk : Int) -> IntentRiskBand {
if risk >= 24 {
IntentRiskRed
} else if risk >= 14 {
IntentRiskOrange
} else if risk >= 7 {
IntentRiskYellow
} else {
IntentRiskGreen
}
}
///|
fn classify_intent_verdict(
intent : CrawlIntent,
result : TargetAuditResult,
blockers : Array[String],
risk_points : Int,
) -> IntentVerdict {
if !result.decision.allowed || blockers.length() >= 2 {
IntentDenied
} else if !intent.has_evidence() ||
!blockers.is_empty() ||
risk_points >= 14 ||
result.expectation_status == ExpectationMismatch {
IntentNeedsReview
} else {
IntentPermitted
}
}
///|
fn intent_tags(
intent : CrawlIntent,
result : TargetAuditResult,
verdict : IntentVerdict,
risk_band : IntentRiskBand,
) -> Array[String] {
let tags : Array[String] = []
tags.push(intent.purpose.label())
tags.push(intent.sensitivity.label())
tags.push(intent.consent.label())
tags.push(verdict.label())
tags.push(risk_band.label())
if result.decision.allowed {
tags.push("robots-allow")
} else {
tags.push("robots-block")
}
if intent.has_evidence() {
tags.push("has-evidence")
} else {
tags.push("missing-evidence")
}
if intent.needs_explicit_authorization() {
tags.push("explicit-auth-required")
}
tags
}
///|
fn intent_evidence_line(
intent : CrawlIntent,
result : TargetAuditResult,
verdict : IntentVerdict,
risk_points : Int,
) -> String {
intent.label +
" => " +
verdict.label() +
"; purpose=" +
intent.purpose.label() +
"; sensitivity=" +
intent.sensitivity.label() +
"; consent=" +
intent.consent.label() +
"; robots=" +
(if result.decision.allowed { "allow" } else { "block" }) +
"; path=" +
result.snapshot.normalized +
"; risk=" +
risk_points.to_string() +
"; evidence=" +
evidence_label(intent)
}
///|
fn evidence_label(intent : CrawlIntent) -> String {
if intent.has_evidence() {
intent.evidence_id
} else {
"missing"
}
}
///|
fn intent_gate_score(
total_intents : Int,
denied_intents : Int,
review_intents : Int,
high_risk_intents : Int,
missing_evidence : Int,
) -> Int {
if total_intents == 0 {
0
} else {
intent_clamp_score(
100 -
denied_intents * 24 -
review_intents * 12 -
high_risk_intents * 8 -
missing_evidence * 5,
)
}
}
///|
fn intent_clamp_score(score : Int) -> Int {
if score < 0 {
0
} else if score > 100 {
100
} else {
score
}
}
///|
fn intent_cell(value : String) -> String {
value.replace_all(old="|", new="\\|")
}
///|
fn intent_csv_cell(value : String) -> String {
"\"" + value.replace_all(old="\"", new="\"\"") + "\""
}
///|
fn intent_json_escape(value : String) -> String {
value
.replace_all(old="\\", new="\\\\")
.replace_all(old="\"", new="\\\"")
.replace_all(old="\n", new="\\n")
}