use crate::context_ledger::novelty_penalty;
use crate::rank::{term_match, terms};
use crate::ContextCompiler;
use scc_core::{
estimate_tokens, kinds, predicates, ContextItem, ContextLedger, Provenance,
SemanticParameter, SemanticSignature, SourceRange, SurfaceEntry, SurfaceKind,
SurfaceOmission, SurfaceRank, SystemSurfaceMap, TaskSeed, Visibility,
};
use std::collections::{BTreeMap, BTreeSet, HashMap};
const SYMBOL_KINDS: [&str; 9] = [
"function", "method", "class", "interface", "trait", "type", "const", "enum", "module",
];
const REDISTRIBUTION_SCALE: f64 = 1.0 / (1.0 - crate::pagerank::SEMANTIC_WEIGHT);
const MAX_COMPRESSION: u8 = 3;
pub fn compile_surface_map(compiler: &ContextCompiler) -> SystemSurfaceMap {
let view = &compiler.view;
let mut symbol_comp_id: BTreeMap<String, String> = BTreeMap::new();
let mut comp_names: BTreeMap<String, String> = BTreeMap::new();
for c in view.components() {
comp_names.insert(c.id.clone(), c.name.clone());
for r in sorted_rels(view.out_pred(&c.id, predicates::CONTAINS)) {
for sr in sorted_rels(view.out_pred(&r.object, predicates::CONTAINS)) {
symbol_comp_id.insert(sr.object.clone(), c.id.clone());
}
}
}
let mut subsys_of_comp: BTreeMap<String, String> = BTreeMap::new();
for kind in [kinds::SUBSYSTEM, kinds::SERVICE] {
for e in view.entities_of_kind(kind) {
for r in sorted_rels(view.out_pred(&e.id, predicates::CONTAINS)) {
subsys_of_comp
.entry(r.object.clone())
.or_insert_with(|| e.name.clone());
}
}
}
let surfaces = scc_graph::flows::invocation_surfaces(view.graph);
let mut surface_by_symbol: BTreeMap<String, Vec<(String, String)>> = BTreeMap::new();
for s in surfaces {
surface_by_symbol
.entry(s.symbol.clone())
.or_default()
.push((s.kind.as_str().to_string(), s.trigger.clone()));
}
let all_flows: Vec<scc_core::Flow> = view.flows();
let mut flows_by_actor: HashMap<&str, Vec<&str>> = HashMap::new();
let mut all_actors: Vec<&str> = Vec::new();
for f in &all_flows {
for s in &f.steps {
if let Some(v) = flows_by_actor.get_mut(s.actor.as_str()) {
if !v.contains(&f.name.as_str()) {
v.push(f.name.as_str());
}
} else {
all_actors.push(s.actor.as_str());
flows_by_actor.insert(s.actor.as_str(), vec![f.name.as_str()]);
}
}
}
let mut flows_by_actor_file: HashMap<String, Vec<String>> = HashMap::new();
let mut routes_by_handler: HashMap<&str, Vec<(String, String)>> = HashMap::new();
for r in view.entities_of_kind(kinds::ROUTE) {
if let (Some(h), Some(m), Some(path)) = (
r.attributes.get("handler").and_then(|v| v.as_str()),
r.attributes.get("method").and_then(|v| v.as_str()),
r.attributes.get("path").and_then(|v| v.as_str()),
) {
if !path.is_empty() {
routes_by_handler
.entry(h)
.or_default()
.push((m.to_string(), path.to_string()));
}
}
}
let mut entries: Vec<SurfaceEntry> = Vec::new();
for e in view.entities_of_kind(kinds::SYMBOL) {
let Some(kind_str) = e.attributes.get("kind").and_then(|v| v.as_str()) else {
continue;
};
if !SYMBOL_KINDS.contains(&kind_str) {
continue;
}
entries.push(build_entry(
compiler,
e,
kind_str,
&symbol_comp_id,
&comp_names,
&subsys_of_comp,
&surface_by_symbol,
&flows_by_actor,
&all_actors,
&mut flows_by_actor_file,
&routes_by_handler,
));
}
entries.sort_by(|a, b| {
a.qualified_name
.cmp(&b.qualified_name)
.then_with(|| a.id.cmp(&b.id))
});
let store = compiler.store;
let mut map = SystemSurfaceMap {
repository: store.repository().name,
revision: compiler.revision(),
epoch: store
.cache_epoch()
.unwrap_or_else(|_| "no-epoch".into()),
entries,
token_count: 0,
omitted: Vec::new(),
};
let full = render_surface_map(&map, None);
map.token_count = estimate_tokens(&full);
map
}
pub fn render_surface_map(map: &SystemSurfaceMap, budget_tokens: Option<usize>) -> String {
let budget_chars = budget_tokens.map(|t| t.saturating_mul(4));
let (body, omitted) = render_entry_groups(&map.entries, budget_chars);
let mut out = String::from("SCC SYSTEM SURFACE MAP\n\n");
out.push_str(&body);
if !omitted.is_empty() {
out.push('\n');
out.push_str("OMITTED (token budget exceeded):\n");
for (kind, count) in &omitted {
out.push_str(&format!(" {count} lower-ranked {kind} definitions\n"));
}
}
out
}
fn render_entry_groups(
entries: &[SurfaceEntry],
budget_chars: Option<usize>,
) -> (String, BTreeMap<String, usize>) {
group_and_render(entries, budget_chars, 0, false)
}
fn group_and_render(
entries: &[SurfaceEntry],
budget_chars: Option<usize>,
level: u8,
explain: bool,
) -> (String, BTreeMap<String, usize>) {
let mut groups: BTreeMap<(String, String, String), Vec<&SurfaceEntry>> = BTreeMap::new();
for e in entries {
let comp = e.component.clone().unwrap_or_else(|| "(unattributed)".to_string());
let sub = e.subsystem.clone().unwrap_or_default();
groups.entry((comp, sub, e.path.clone())).or_default().push(e);
}
let mut out = String::new();
let mut total_chars = 0usize;
let mut omitted: BTreeMap<String, usize> = BTreeMap::new();
let mut cut = false;
for ((comp, sub, path), mut es) in groups {
es.sort_by(|a, b| entry_order(a, b));
let header = group_header(&comp, &sub, &path);
let mut blocks: Vec<String> = Vec::new();
let mut block_chars: usize = 0;
for e in es {
if cut {
*omitted.entry(e.kind.as_str().to_string()).or_insert(0) += 1;
continue;
}
let rank = if explain { Some(&e.rank) } else { None };
let block = render_entry_opt(e, level, rank);
let bc = block.chars().count();
if fits(total_chars + header.chars().count() + block_chars + bc, budget_chars) {
blocks.push(block);
block_chars += bc;
} else {
cut = true;
*omitted.entry(e.kind.as_str().to_string()).or_insert(0) += 1;
}
}
if !blocks.is_empty() {
out.push_str(&header);
for b in blocks {
out.push_str(&b);
}
total_chars += header.chars().count() + block_chars;
}
}
(out, omitted)
}
pub fn surface_quotas() -> Vec<(String, f64)> {
vec![
("public".to_string(), 0.30),
("core".to_string(), 0.25),
("types".to_string(), 0.15),
("state".to_string(), 0.10),
("contract".to_string(), 0.10),
("flow".to_string(), 0.10),
]
}
fn quota_kind(e: &SurfaceEntry) -> &'static str {
if e.exported || e.visibility == Visibility::Public || !e.invocation_surfaces.is_empty() {
"public"
} else if !e.state_authorities.is_empty() {
"state"
} else if !e.contracts.is_empty() {
"contract"
} else if !e.flows.is_empty() {
"flow"
} else if matches!(
e.kind,
SurfaceKind::Class
| SurfaceKind::Interface
| SurfaceKind::Trait
| SurfaceKind::Enum
| SurfaceKind::Type
) {
"types"
} else {
"core"
}
}
fn invariant_names(view: &scc_graph::TrustedGraphView) -> Vec<String> {
let mut names: Vec<String> = Vec::new();
for inv in view.invariants() {
let name = inv.id.rsplit('/').next().unwrap_or(&inv.id).to_string();
names.push(name);
names.push(inv.statement.clone());
}
names
}
pub fn required_ids(map: &SystemSurfaceMap, compiler: &ContextCompiler) -> BTreeSet<String> {
let view = &compiler.view;
let mut required: BTreeSet<String> = BTreeSet::new();
let inv_names = invariant_names(view);
let mut critical_state: BTreeSet<String> = BTreeSet::new();
for inv in view.invariants() {
for scope_id in &inv.scope {
if let Some(e) = view.entity(scope_id) {
if e.kind == kinds::STATE {
critical_state.insert(scope_id.clone());
}
}
}
}
let state_name_to_id: BTreeMap<String, String> = view
.entities_of_kind(kinds::STATE)
.into_iter()
.map(|e| (e.name.clone(), e.id.clone()))
.collect();
let mut primary_eps: BTreeSet<String> = BTreeSet::new();
for f in view.flows() {
let triggered = f.trigger.as_deref().map(|t| !t.is_empty()).unwrap_or(false);
if triggered {
if let Some(ep) = f.attributes.get("entrypoint").and_then(|v| v.as_str()) {
primary_eps.insert(ep.to_string());
}
}
}
for e in &map.entries {
let mut req = e
.invocation_surfaces
.iter()
.any(|s| !s.starts_with("public_api:"));
if !req && primary_eps.contains(&e.symbol_id) {
req = true;
}
if !req {
req = e.contracts.iter().any(|c| {
inv_names
.iter()
.any(|n| !n.is_empty() && c.to_lowercase().contains(&n.to_lowercase()))
});
}
if !req {
req = e.state_authorities.iter().any(|auth| {
state_name_to_id
.get(auth)
.map(|id| critical_state.contains(id))
.unwrap_or(false)
});
}
if req {
required.insert(e.id.clone());
}
}
required
}
fn entry_reasons(
e: &SurfaceEntry,
goal: Option<&str>,
seed_ids: &BTreeSet<String>,
inv_names: &[String],
changed: bool,
) -> Vec<String> {
let mut reasons: Vec<String> = Vec::new();
if seed_ids.contains(&e.symbol_id) {
let label = e
.component
.as_deref()
.filter(|c| !c.is_empty())
.unwrap_or(goal.unwrap_or("task"));
reasons.push(format!("task seed: {label}"));
}
if !e.flows.is_empty() {
reasons.push("primary flow participant".into());
}
if e.exported || e.visibility == Visibility::Public {
reasons.push("public component surface".into());
}
for s in &e.state_authorities {
reasons.push(format!("owns {s}"));
}
if e.contracts.iter().any(|c| {
inv_names
.iter()
.any(|n| !n.is_empty() && c.to_lowercase().contains(&n.to_lowercase()))
}) {
reasons.push("invariant-enforcing".into());
}
if !e.invocation_surfaces.is_empty() {
reasons.push("concrete invocation surface".into());
}
if changed {
reasons.push("change risk: modified path".into());
}
reasons
}
fn render_selected(entries: &[SurfaceEntry], level: u8, explain: bool) -> String {
let (body, _) = group_and_render(entries, None, level, explain);
let mut out = String::from("SCC SYSTEM SURFACE MAP\n\n");
if explain {
out.push_str("selection scores shown per entry\n\n");
}
out.push_str(&body);
out
}
pub(crate) fn file_importance(path: &str) -> f64 {
let base = path.rsplit('/').next().unwrap_or(path);
let important = [
"package.json", "pnpm-workspace.yaml", "yarn.lock", "Cargo.toml",
"Cargo.lock", "go.mod", "pyproject.toml", "setup.py", "setup.cfg",
"requirements.txt", "pom.xml", "build.gradle", "build.gradle.kts",
"settings.gradle", "settings.gradle.kts", "gradlew", "Makefile",
"CMakeLists.txt", "mix.exs", "Gemfile", "composer.json",
"Dockerfile", "docker-compose.yml", "docker-compose.yaml",
"compose.yml", "compose.yaml", ".dockerignore",
".github/workflows/ci.yml", ".github/workflows/main.yml",
".gitlab-ci.yml", "Jenkinsfile", "azure-pipelines.yml",
".circleci/config.yml", "buildkite.yml",
"main.py", "main.go", "main.ts", "index.ts", "index.js",
"app.py", "server.py", "server.ts", "server.js", "cli.py",
"cli.ts", "cli.go", "src/main.rs", "bin/main.rs", "app.js",
"app.ts",
];
if important.contains(&base) || important.contains(&path) {
return 1.0;
}
if path.starts_with(".github/workflows/") {
return 1.0;
}
0.0
}
pub fn entry_lexical(e: &SurfaceEntry, goal_terms: &BTreeSet<String>) -> f64 {
if goal_terms.is_empty() {
return 0.0;
}
let name_terms = terms(&e.qualified_name);
let sig_terms = terms(&e.source_signature);
let name_hits = goal_terms
.iter()
.filter(|g| name_terms.iter().any(|n| term_match(g, n)))
.count();
let sig_hits = goal_terms
.iter()
.filter(|g| sig_terms.iter().any(|n| term_match(g, n)))
.count();
(name_hits * 2 + sig_hits) as f64
}
fn finish_selection(
map: &SystemSurfaceMap,
ranked: Vec<(String, f64)>,
required: &BTreeSet<String>,
budget: usize,
policy: &SurfacePolicy,
stages: &SurfacePipelineStages,
explain: bool,
) -> scc_core::SurfaceRenderResult {
let entry_of: BTreeMap<String, &SurfaceEntry> =
map.entries.iter().map(|e| (e.id.clone(), e)).collect();
let mut required_items: Vec<(String, f64)> = Vec::new();
let mut pool: Vec<(String, f64)> = Vec::new();
for (id, imp) in ranked {
if policy.coverage && required.contains(&id) {
required_items.push((id, imp));
} else {
pool.push((id, imp));
}
}
let required_tokens_full: usize = required_items
.iter()
.filter_map(|(id, _)| entry_of.get(id))
.map(|e| estimate_tokens(&render_entry(e)))
.sum();
let compress = policy.coverage && required_tokens_full > policy.hard_max;
let mut pre_cap_critical_drops: Vec<String> = Vec::new();
if policy.coverage {
let cost_of_c = |id: &str| -> usize {
entry_of
.get(id)
.map(|e| estimate_tokens(&render_entry_compressed(e)))
.unwrap_or(1)
};
let mut spent_c: usize = 0;
let mut capped: Vec<(String, f64)> = Vec::new();
for (id, imp) in &required_items {
let c = cost_of_c(id);
if spent_c + c > policy.hard_max && !capped.is_empty() {
pre_cap_critical_drops.push(id.clone());
continue;
}
spent_c += c;
capped.push((id.clone(), *imp));
}
if capped.is_empty() && !required_items.is_empty() {
capped.push(required_items[0].clone());
for (id, _) in &required_items[1..] {
if !pre_cap_critical_drops.contains(id) {
pre_cap_critical_drops.push(id.clone());
}
}
}
if capped.len() < required_items.len() {
required_items = capped;
}
}
let cost_of = |id: &str| -> usize {
match (entry_of.get(id), compress) {
(Some(e), true) => estimate_tokens(&render_entry_compressed(e)),
(Some(e), false) => estimate_tokens(&render_entry(e)),
_ => 1,
}
};
let required_spent: usize = required_items.iter().map(|(id, _)| cost_of(id)).sum();
let available = budget.saturating_sub(required_spent);
let pool_avg = if pool.is_empty() {
1
} else {
(pool.iter().map(|(id, _)| cost_of(id)).sum::<usize>() / pool.len()).max(1)
};
let mmr_budget = available
.saturating_div(pool_avg)
.max(1)
.min(pool.len());
let diversified: Vec<(String, f64)> = if stages.mmr && policy.mmr {
let mut comp_ids: HashMap<&str, u32> = HashMap::new();
let mut path_ids: HashMap<&str, u32> = HashMap::new();
let mut group_of: HashMap<&str, (u32, u32)> = HashMap::new();
for (id, e) in &entry_of {
let c = match &e.component {
Some(c) => {
let n = comp_ids.len() as u32;
*comp_ids.entry(c.as_str()).or_insert(n + 1)
}
None => 0,
};
let g = if e.path.is_empty() {
0
} else {
let n = path_ids.len() as u32;
*path_ids.entry(e.path.as_str()).or_insert(n + 1)
};
group_of.insert(id.as_str(), (c, g));
}
let sim = |a: &str, b: &str| -> f64 {
match (group_of.get(a), group_of.get(b)) {
(Some((ca, pa)), Some((cb, pb)))
if (*ca != 0 && *ca == *cb) || (*pa != 0 && *pa == *pb) =>
{
1.0
}
_ => 0.0,
}
};
let pool_by_id: BTreeMap<String, f64> = pool.iter().cloned().collect();
crate::selector::mmr_diversify(&pool, sim, 0.5, mmr_budget)
.into_iter()
.filter_map(|id| pool_by_id.get(&id).map(|v| (id.clone(), *v)))
.collect()
} else {
pool.clone()
};
let quota_filtered: Vec<(String, f64)> = if stages.quotas && policy.quotas {
let kind_of: BTreeMap<String, &'static str> = map
.entries
.iter()
.map(|e| (e.id.clone(), quota_kind(e)))
.collect();
let ids = crate::selector::enforce_quotas(
&diversified,
|id| kind_of.get(id).copied().unwrap_or("core"),
&surface_quotas(),
available,
|id| cost_of(id),
);
let id_set: BTreeSet<String> = ids.into_iter().collect();
diversified
.into_iter()
.filter(|(id, _)| id_set.contains(id))
.collect()
} else {
diversified
};
let mut items: Vec<ContextItem> = Vec::new();
for (id, imp) in &required_items {
items.push(ContextItem {
id: id.clone(),
value: *imp,
token_cost: cost_of(id),
required: true,
group: Some("api".into()),
});
}
for (id, imp) in "a_filtered {
items.push(ContextItem {
id: id.clone(),
value: *imp,
token_cost: cost_of(id),
required: false,
group: Some("api".into()),
});
}
let selected = if stages.optimizer {
crate::selector::select_with_budget(&items, budget, policy.hard_max)
} else {
crate::selector::select_in_order(&items, budget, policy.hard_max)
};
let mut rendered_ids: Vec<String> = Vec::new();
let mut selected_entries: Vec<SurfaceEntry> = Vec::new();
for &idx in &selected {
if idx >= items.len() {
continue; }
let id = items[idx].id.clone();
if let Some(e) = entry_of.get(&id) {
rendered_ids.push(id.clone());
selected_entries.push((*e).clone());
}
}
let mut level: u8 = if compress { 1 } else { 0 };
let mut critical_drops: Vec<String> = pre_cap_critical_drops;
let mut overflow_drops: usize = 0;
let mut text = render_selected(&selected_entries, level, explain);
let mut token_count = estimate_tokens(&text);
while token_count > policy.hard_max {
if level < MAX_COMPRESSION {
level += 1;
} else {
let Some(dropped) = selected_entries.pop() else {
break; };
rendered_ids.retain(|id| id != &dropped.id);
if required.contains(&dropped.id) {
critical_drops.push(dropped.id.clone());
} else {
overflow_drops += 1;
}
}
text = render_selected(&selected_entries, level, explain);
token_count = estimate_tokens(&text);
}
let rendered_set: BTreeSet<String> = rendered_ids.iter().cloned().collect();
let mut omitted_ids: Vec<String> = Vec::new();
let mut by_kind: BTreeMap<String, usize> = BTreeMap::new();
for e in &map.entries {
if rendered_set.contains(&e.id) {
continue;
}
omitted_ids.push(e.id.clone());
*by_kind.entry(e.kind.as_str().to_string()).or_insert(0) += 1;
}
let mut omissions: Vec<SurfaceOmission> = by_kind
.into_iter()
.map(|(kind, count)| SurfaceOmission {
count,
kind,
reason: "not selected within budget (diversity/quotas/token budget)".into(),
})
.collect();
if overflow_drops > 0 {
omissions.push(SurfaceOmission {
count: overflow_drops,
kind: "required-overflow".into(),
reason: "hard-max invariant on final rendered text (lowest-value entries dropped after full compression)".into(),
});
}
scc_core::SurfaceRenderResult {
text,
rendered_ids,
rendered_entries: selected_entries,
omitted_ids,
omissions,
token_count,
critical_drops,
}
}
#[derive(Debug, Clone, Copy)]
pub enum SurfaceMode<'a> {
Global,
Task {
goal: &'a str,
visible: Option<&'a ContextLedger>,
},
}
#[derive(Clone, Copy)]
pub struct SurfaceRequest<'a> {
pub mode: SurfaceMode<'a>,
pub budget: usize,
pub explain: bool,
pub policy: SurfacePolicy,
pub semantic: Option<&'a dyn crate::rank::SemanticScorer>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SurfacePolicy {
pub quotas: bool,
pub mmr: bool,
pub coverage: bool,
pub hard_max: usize,
}
impl SurfacePolicy {
pub fn defaults(budget: usize) -> Self {
SurfacePolicy {
quotas: true,
mmr: true,
coverage: true,
hard_max: budget
.saturating_add(budget / 5)
.max(budget.saturating_add(500)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SurfacePipelineStages {
pub lexical: bool,
pub global_ppr: bool,
pub task_ppr: bool,
pub mmr: bool,
pub quotas: bool,
pub optimizer: bool,
}
impl Default for SurfacePipelineStages {
fn default() -> Self {
SurfacePipelineStages {
lexical: true,
global_ppr: true,
task_ppr: true,
mmr: true,
quotas: true,
optimizer: true,
}
}
}
pub fn build_surface(
compiler: &ContextCompiler,
request: SurfaceRequest<'_>,
) -> scc_core::SurfaceRenderResult {
build_surface_staged(compiler, request, &SurfacePipelineStages::default())
}
pub fn build_surface_staged(
compiler: &ContextCompiler,
request: SurfaceRequest<'_>,
stages: &SurfacePipelineStages,
) -> scc_core::SurfaceRenderResult {
build_surface_staged_inner(compiler, request, stages, &mut None)
}
pub fn build_surface_cached(
compiler: &ContextCompiler,
request: SurfaceRequest<'_>,
cache: &mut Option<crate::startup::GlobalRankCache>,
) -> scc_core::SurfaceRenderResult {
build_surface_staged_inner(
compiler,
request,
&SurfacePipelineStages::default(),
cache,
)
}
fn build_surface_staged_inner(
compiler: &ContextCompiler,
request: SurfaceRequest<'_>,
stages: &SurfacePipelineStages,
cache: &mut Option<crate::startup::GlobalRankCache>,
) -> scc_core::SurfaceRenderResult {
let (goal, visible): (Option<&str>, Option<&ContextLedger>) = match &request.mode {
SurfaceMode::Global => (None, None),
SurfaceMode::Task { goal, visible } => (Some(goal), *visible),
};
let goal_terms = goal.map(terms).unwrap_or_default();
let mut seeds: Vec<TaskSeed> = Vec::new();
let mut seed_ids: BTreeSet<String> = BTreeSet::new();
if stages.task_ppr {
if let Some(g) = goal {
let candidates = crate::rank::collect_lexical_candidates(
compiler.store,
&compiler.view,
g,
&[],
16,
);
seeds = candidates
.iter()
.map(|c| TaskSeed {
kind: c.kind.clone(),
id: c.id.clone(),
weight: c.score,
})
.collect();
seed_ids = seeds.iter().map(|s| s.id.clone()).collect();
}
}
let mut map = compile_surface_map(compiler);
let mut global_of: BTreeMap<String, f64> = BTreeMap::new();
let mut task_ranker: Option<crate::pagerank::SystemRanker<'_>> = None;
if stages.global_ppr {
if let Some(c) = cache.as_ref() {
global_of = c.node_symbol_map.clone();
} else {
let ranker = crate::pagerank::SystemRanker::new(&compiler.view);
let gv = ranker.global_vector();
global_of = ranker.project_to_symbols(&gv).into_iter().collect();
*cache = Some(crate::startup::GlobalRankCache {
epoch: compiler
.store
.cache_epoch()
.unwrap_or_else(|_| "no-epoch".into()),
policy: crate::startup::trust_policy_str(compiler.view.policy()),
salt: compiler.settings.rank_salt.clone(),
global_vector: gv,
node_symbol_map: global_of.clone(),
candidates_epoch: map.epoch.clone(),
candidate_ids: map.entries.iter().map(|e| e.id.clone()).collect(),
hits: 0,
});
task_ranker = Some(ranker);
}
}
let task_of: BTreeMap<String, f64> = if stages.task_ppr && !seeds.is_empty() {
let ranker = match task_ranker {
Some(r) => r,
None => crate::pagerank::SystemRanker::new(&compiler.view),
};
ranker
.project_to_symbols(&ranker.task_vector(&seeds))
.into_iter()
.collect()
} else {
BTreeMap::new()
};
let required = required_ids(&map, compiler);
let has_task = !seeds.is_empty();
let inv_names = invariant_names(&compiler.view);
let mut ranked: Vec<(String, f64)> = Vec::new();
let mut ranks: BTreeMap<String, SurfaceRank> = BTreeMap::new();
for e in &map.entries {
let changed = compiler.is_stale_path(&e.path);
let novelty = match visible {
Some(ledger) => novelty_penalty(ledger, &e.symbol_id, changed),
None => 1.0,
};
if novelty < 1.0 {
continue;
}
let task_ppr = task_of.get(&e.symbol_id).copied().unwrap_or(0.0);
let global_ppr = global_of.get(&e.symbol_id).copied().unwrap_or(0.0);
let lexical = entry_lexical(e, &goal_terms);
let criticality = if seed_ids.contains(&e.symbol_id) || required.contains(&e.id) {
1.0
} else {
crate::surface::file_importance(&e.path) * 0.5
};
let change_risk = if changed { 1.0 } else { 0.0 };
let semantic = match request.semantic {
Some(scorer) => compiler
.view
.entity(&e.symbol_id)
.map(|en| scorer.score(goal.unwrap_or(""), en))
.unwrap_or(0.0)
.clamp(0.0, 1.0),
None => 0.0,
};
let (importance, semantic_component) = if stages.lexical {
let blend = crate::pagerank::final_importance(
task_ppr,
global_ppr,
lexical,
semantic,
e.confidence as f64,
criticality,
change_risk,
0.0,
has_task,
);
let total = match request.semantic {
Some(_) => blend + crate::pagerank::NOVELTY_WEIGHT * novelty,
None => blend * REDISTRIBUTION_SCALE + crate::pagerank::NOVELTY_WEIGHT * novelty,
};
(total, semantic)
} else {
(lexical, 0.0)
};
if importance <= 0.0 && !required.contains(&e.id) {
continue;
}
ranks.insert(
e.id.clone(),
SurfaceRank {
task_ppr,
global_ppr,
lexical,
semantic: semantic_component,
confidence: e.confidence as f64,
criticality,
change_risk,
novelty,
total: importance,
reasons: entry_reasons(e, goal, &seed_ids, &inv_names, changed),
},
);
ranked.push((e.id.clone(), importance));
}
for e in &mut map.entries {
if let Some(r) = ranks.get(&e.id) {
e.rank = r.clone();
e.importance = Some(importance_profile(e, r));
}
}
ranked.sort_by(|a, b| {
b.1.partial_cmp(&a.1)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| a.0.cmp(&b.0))
});
finish_selection(
&map,
ranked,
&required,
request.budget,
&request.policy,
stages,
request.explain,
)
}
pub fn select_and_render_global(
compiler: &ContextCompiler,
budget: usize,
) -> scc_core::SurfaceRenderResult {
build_surface(
compiler,
SurfaceRequest {
mode: SurfaceMode::Global,
budget,
explain: false,
policy: SurfacePolicy::defaults(budget),
semantic: None,
},
)
}
pub fn important_symbols(
compiler: &ContextCompiler,
mode: SurfaceMode<'_>,
limit: usize,
) -> Vec<SurfaceEntry> {
let mut map = compile_surface_map(compiler);
let ranker = crate::pagerank::SystemRanker::new(&compiler.view);
let gv = ranker.global_vector();
let global_of: BTreeMap<String, f64> =
ranker.project_to_symbols(&gv).into_iter().collect();
let task_of: BTreeMap<String, f64> = match &mode {
SurfaceMode::Task { goal, .. } => {
let cands =
crate::rank::collect_lexical_candidates(compiler.store, &compiler.view, goal, &[], 16);
let seeds: Vec<TaskSeed> = cands
.iter()
.map(|c| TaskSeed {
kind: c.kind.clone(),
id: c.id.clone(),
weight: c.score,
})
.collect();
if seeds.is_empty() {
BTreeMap::new()
} else {
ranker
.project_to_symbols(&ranker.task_vector(&seeds))
.into_iter()
.collect()
}
}
SurfaceMode::Global => BTreeMap::new(),
};
let tasked = !task_of.is_empty();
for e in &mut map.entries {
let task_ppr = task_of.get(&e.symbol_id).copied().unwrap_or(0.0);
let global_ppr = global_of.get(&e.symbol_id).copied().unwrap_or(0.0);
let score = if tasked { task_ppr } else { global_ppr };
let r = SurfaceRank {
task_ppr,
global_ppr,
lexical: 0.0,
semantic: 0.0,
confidence: e.confidence as f64,
criticality: 0.0,
change_risk: 0.0,
novelty: 1.0,
total: score,
reasons: Vec::new(),
};
e.rank = r.clone();
e.importance = Some(importance_profile(e, &r));
}
map.entries
.sort_by(|a, b| {
b.rank
.total
.partial_cmp(&a.rank.total)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| a.id.cmp(&b.id))
});
if limit > 0 {
map.entries.truncate(limit);
}
map.entries
}
pub fn render_important(entries: &[SurfaceEntry], task_mode: bool) -> String {
let mut out = String::new();
out.push_str(if task_mode {
"## TASK-CRITICAL SYMBOLS
"
} else {
"## SYSTEM-CRITICAL SYMBOLS
"
});
if entries.is_empty() {
out.push_str("(no ranked symbols)
");
return out;
}
for (i, e) in entries.iter().enumerate() {
let imp = e.importance.as_ref();
let badges = imp
.map(|p| {
if p.badges.is_empty() {
String::new()
} else {
format!(" {}", p.badges.join(" \u{00B7} "))
}
})
.unwrap_or_default();
let name = &e.qualified_name;
out.push_str(&format!("{}. {name}{}
", i + 1, badges));
out.push_str(&format!(" {}:{}-{}
", e.path, e.range.start_line, e.range.end_line));
let cc = imp.map(|p| p.caller_count).unwrap_or(e.caller_count);
let ce = imp.map(|p| p.callee_count).unwrap_or(e.callee_count);
out.push_str(&format!(
" Called by {cc} symbols \u{00B7} calls {ce} \u{00B7} flows {} \u{00B7} contracts {} \u{00B7} importance {:.2}
",
e.flows.len(),
e.contracts.len(),
e.rank.total
));
}
out
}
pub fn select_and_render_task(
compiler: &ContextCompiler,
goal: &str,
budget: usize,
visible: &ContextLedger,
) -> scc_core::SurfaceRenderResult {
build_surface(
compiler,
SurfaceRequest {
mode: SurfaceMode::Task {
goal,
visible: Some(visible),
},
budget,
explain: false,
policy: SurfacePolicy::defaults(budget),
semantic: None,
},
)
}
#[allow(clippy::too_many_arguments)]
fn importance_profile(e: &SurfaceEntry, r: &SurfaceRank) -> scc_core::ImportanceProfile {
let mut badges: Vec<String> = Vec::new();
let entrypoint = !e.invocation_surfaces.is_empty();
let dependent_count = e.caller_count;
if entrypoint {
badges.push("ENTRYPOINT".into());
}
if e.exported {
badges.push("PUBLIC API".into());
}
if !e.state_authorities.is_empty() {
badges.push("STATE OWNER".into());
}
if !e.contracts.is_empty() {
badges.push("CONTRACT BOUNDARY".into());
}
if !e.flows.is_empty() {
badges.push("FLOW CRITICAL".into());
}
if e.caller_count >= 50 {
badges.push("HIGH FAN-IN".into());
}
if e.callee_count >= 10 {
badges.push("HUB".into());
}
if r.global_ppr >= 0.01 {
badges.push("HIGH IMPACT".into());
}
if r.change_risk >= 0.5 {
badges.push("CHANGE HOTSPOT".into());
}
if r.global_ppr >= 0.005
&& (entrypoint || e.exported || !e.state_authorities.is_empty() || !e.contracts.is_empty() || !e.flows.is_empty())
{
badges.insert(0, "CORE".into());
}
scc_core::ImportanceProfile {
overall: r.total,
caller_count: e.caller_count,
callee_count: e.callee_count,
global_ppr: r.global_ppr,
task_ppr: r.task_ppr,
entrypoint,
exported: e.exported,
flow_count: e.flows.len(),
contract_count: e.contracts.len(),
state_read_count: 0,
state_write_count: e.state_authorities.len(),
dependent_count,
change_risk: r.change_risk,
badges,
}
}
#[allow(clippy::too_many_arguments)]
fn build_entry(
compiler: &ContextCompiler,
e: &scc_core::Entity,
kind_str: &str,
symbol_comp_id: &BTreeMap<String, String>,
comp_names: &BTreeMap<String, String>,
subsys_of_comp: &BTreeMap<String, String>,
surface_by_symbol: &BTreeMap<String, Vec<(String, String)>>,
flows_by_actor: &HashMap<&str, Vec<&str>>,
all_actors: &[&str],
flows_by_actor_file: &mut HashMap<String, Vec<String>>,
routes_by_handler: &HashMap<&str, Vec<(String, String)>>,
) -> SurfaceEntry {
let view = &compiler.view;
let name = e.name.clone();
let simple = name.rsplit('.').next().unwrap_or(&name).to_string();
let parent = attr_str(e, "parent");
let exported = e.attributes.get("exported").and_then(|v| v.as_bool()) == Some(true);
let file = attr_str(e, "file").unwrap_or_default();
let start = attr_u32(e, "start_line");
let end = attr_u32(e, "end_line");
let decl = attr_str(e, "decl_header").unwrap_or_default();
let source_sig = if decl.trim().is_empty() {
attr_str(e, "signature").unwrap_or_default()
} else {
decl
};
let source_signature = if source_sig.trim().is_empty() {
synthesized_signature(kind_str, &simple)
} else {
source_sig
};
let parsed_inner = parse_sig_inner(&source_signature);
let parsed_sig = parse_signature(&source_signature, &name, parent.as_deref());
let overload = e
.attributes
.get("overload_index")
.and_then(|v| v.as_u64())
.map(|n| n as usize);
let (entry_id, symbol_id) = match overload {
Some(n) => {
let logical = if n >= 1 {
e.id.trim_end_matches(&format!("#{n}")).to_string()
} else {
e.id.clone()
};
(format!("{}#overload{}", logical, n), logical)
}
None => (e.id.clone(), e.id.clone()),
};
let kind = map_kind(kind_str, &name, parent.as_deref());
let qualified = if kind_str == "method" {
match &parent {
Some(p) if !p.is_empty() => format!("{}.{}", p, simple),
_ => name.clone(),
}
} else {
name.clone()
};
let visibility = entry_visibility(
exported,
parent.as_deref(),
&parsed_inner.modifiers,
parsed_inner.ret_before_name.as_deref(),
);
const SURFACE_MODIFIERS: [&str; 5] = ["async", "static", "final", "abstract", "readonly"];
let mut modifiers: Vec<String> = parsed_inner
.modifiers
.iter()
.filter(|m| SURFACE_MODIFIERS.contains(&m.as_str()))
.cloned()
.collect();
if parsed_sig.parameters.iter().any(|p| p.variadic)
&& !modifiers.iter().any(|m| m == "variadic")
{
modifiers.push("variadic".into());
}
let mut annotations: Vec<String> = Vec::new();
for r in sorted_rels(view.in_pred(&e.id, predicates::ANNOTATES)) {
if let Some(a) = view.entity(&r.subject) {
annotations.push(a.name.clone());
}
}
annotations.sort();
annotations.dedup();
let mut flows: BTreeSet<String> = BTreeSet::new();
for key in [&e.id, &name, &qualified] {
if let Some(names) = flows_by_actor.get(key.as_str()) {
flows.extend(names.iter().map(|s| s.to_string()));
}
}
if !file.is_empty() {
let cached = flows_by_actor_file.entry(file.clone()).or_insert_with(|| {
let mut names: Vec<String> = Vec::new();
for actor in all_actors.iter() {
if actor.contains(file.as_str()) {
if let Some(fs) = flows_by_actor.get(*actor) {
names.extend(fs.iter().map(|s| s.to_string()));
}
}
}
names.sort();
names.dedup();
names
});
flows.extend(cached.iter().cloned());
}
let mut contracts: BTreeSet<String> = BTreeSet::new();
if let Some(routes) = routes_by_handler.get(e.id.as_str()) {
for (m, path) in routes {
contracts.insert(format!("http: {}", format!("{m} {path}").trim()));
}
}
if let Some(flags) = e.attributes.get("cli_flags").and_then(|v| v.as_array()) {
for f in flags {
if let Some(s) = f.as_str() {
contracts.insert(format!("cli: {}", s));
}
}
}
for pred in [predicates::CONSUMES, predicates::PUBLISHES] {
for rel in sorted_rels(view.out_pred(&e.id, pred)) {
if let Some(t) = view.entity(&rel.object) {
if t.kind == kinds::TOPIC {
contracts.insert(format!("event: {}", t.name));
}
}
}
}
for rel in sorted_rels(view.out_pred(&e.id, predicates::REGISTERS)) {
if let Some(t) = view.entity(&rel.object) {
if t.kind == kinds::CONTRACT {
contracts.insert(format!("register:{}", view.name_of(&t.id)));
}
}
}
for rel in sorted_rels(view.out_pred(&e.id, predicates::DEFINES)) {
if let Some(t) = view.entity(&rel.object) {
if t.kind == kinds::SCHEMA {
contracts.insert(format!("schema:{}", t.name));
}
}
}
let mut state_authorities: Vec<String> = Vec::new();
for rel in sorted_rels(view.out_pred(&e.id, predicates::OWNS)) {
if let Some(t) = view.entity(&rel.object) {
if t.kind == kinds::STATE || t.kind == kinds::REACTIVE {
state_authorities.push(t.name.clone());
}
}
}
state_authorities.sort();
state_authorities.dedup();
let mut inv: Vec<String> = Vec::new();
if let Some(surfs) = surface_by_symbol.get(&e.id) {
for (kind, trigger) in surfs {
inv.push(format!("{}: {}", kind, trigger));
}
}
if let Some(eps) = e.attributes.get("entrypoints").and_then(|v| v.as_array()) {
for ep in eps {
if let Some(s) = ep.as_str() {
inv.push(format!("entrypoint:{}", s));
}
}
}
inv.sort();
let mut all_callers: Vec<String> = Vec::new();
for r in sorted_rels(view.in_pred(&e.id, predicates::CALLS)) {
all_callers.push(view.name_of(&r.subject));
}
all_callers.sort();
all_callers.dedup();
let caller_count = all_callers.len();
let mut callers = all_callers;
callers.truncate(12);
let mut all_callees: Vec<String> = Vec::new();
for r in sorted_rels(view.out_pred(&e.id, predicates::CALLS)) {
all_callees.push(view.name_of(&r.object));
}
all_callees.sort();
all_callees.dedup();
let callee_count = all_callees.len();
let mut callees = all_callees;
callees.truncate(12);
let has_resolved_call = view
.out_pred(&e.id, predicates::CALLS)
.iter()
.any(|r| r.provenance == Provenance::Resolved);
let provenance = if has_resolved_call {
Provenance::Resolved
} else {
Provenance::Extracted
};
let confidence: f32 = if has_resolved_call { 1.0 } else { 0.85 };
let component = symbol_comp_id
.get(&e.id)
.and_then(|cid| comp_names.get(cid))
.cloned();
let subsystem = symbol_comp_id
.get(&e.id)
.and_then(|cid| subsys_of_comp.get(cid))
.cloned();
SurfaceEntry {
id: entry_id,
symbol_id,
qualified_name: qualified,
kind,
path: file.clone(),
range: SourceRange::new(file, start, end),
source_signature: source_signature.clone(),
canonical_signature: canonicalize(&source_signature),
semantic_signature: parsed_sig,
visibility,
exported,
modifiers,
annotations,
component,
subsystem,
flows: flows.into_iter().collect(),
contracts: contracts.into_iter().collect(),
state_authorities,
invocation_surfaces: inv,
callers,
callees,
caller_count,
callee_count,
importance: None,
provenance,
confidence,
rank: SurfaceRank::default(),
}
}
#[derive(Debug, Default)]
struct ParsedSignature {
modifiers: Vec<String>,
async_: bool,
name: String,
owner: Option<String>,
ret_before_name: Option<String>,
params: Vec<String>,
generic_parameters: Vec<String>,
returns: Option<String>,
constraints: Vec<String>,
}
fn parse_signature(sig: &str, fallback_name: &str, parent: Option<&str>) -> SemanticSignature {
let p = parse_sig_inner(sig);
let name = if p.name.is_empty() {
fallback_name.to_string()
} else {
p.name
};
let mut parameters: Vec<SemanticParameter> = Vec::new();
for raw in &p.params {
if let Some(sp) = parse_param(raw) {
parameters.push(sp);
}
}
let mut generic_parameters = p.generic_parameters;
generic_parameters.sort();
generic_parameters.dedup();
SemanticSignature {
name,
owner: p.owner.or_else(|| parent.map(|s| s.to_string())),
visibility: visibility_from_modifiers(&p.modifiers),
async_: p.async_,
generic_parameters,
parameters,
returns: p.returns,
constraints: p.constraints,
}
}
fn parse_sig_inner(sig: &str) -> ParsedSignature {
let mut p = ParsedSignature::default();
let s = sig.trim();
if s.is_empty() {
return p;
}
let mut rest: &str = s;
let mut consumed_keyword: Option<String> = None;
while let Some((word, after)) = leading_word(rest) {
let is_mod = is_modifier_word(&word);
let is_kw = !is_mod && is_callable_keyword(&word);
if !is_mod && !is_kw {
break;
}
let mut after = after;
let token = if after.starts_with('(') {
match take_group(after, '(', ')') {
Some((g, r)) => {
after = r;
format!("{}({})", word, g)
}
None => word.clone(),
}
} else {
word.clone()
};
if is_mod {
if word == "async" {
p.async_ = true;
}
if !p.modifiers.iter().any(|m| m == &token) {
p.modifiers.push(token);
}
} else {
consumed_keyword = Some(word);
}
rest = after.trim_start();
}
let is_go = matches!(consumed_keyword.as_deref(), Some("func") | Some("function"));
if is_go && rest.starts_with('(') {
if let Some((group, after)) = take_group(rest, '(', ')') {
p.owner = receiver_owner(&group);
rest = after.trim_start();
}
}
let (prefix, params, tail) = match split_params(rest) {
Some(x) => (x.0, x.1, x.2),
None => {
if let Some((w, _)) = leading_word(rest) {
if is_identifier(&w) {
p.name = w;
}
}
return p;
}
};
p.params = params;
let prefix = prefix.trim();
let (name_region, generics) = if prefix.ends_with('>') {
match find_matching_open(prefix, '<', '>') {
Some(idx) => (&prefix[..idx], Some(&prefix[idx..])),
None => (prefix, None),
}
} else {
(prefix, None)
};
let words: Vec<&str> = name_region.split_whitespace().collect();
if let Some(last) = words.last() {
if is_identifier(last) {
p.name = last.to_string();
if words.len() > 1 {
p.ret_before_name = Some(words[..words.len() - 1].join(" "));
}
} else if let Some(first) = words.first() {
if is_identifier(first) {
p.name = first.to_string();
}
}
}
if let Some(g) = generics {
let inner = g.trim_start_matches('<').trim_end_matches('>');
let mut seen: BTreeSet<String> = BTreeSet::new();
for item in split_top(inner, ',') {
let item = item.trim();
if item.is_empty() {
continue;
}
let (name_part, bound) = match item.find(':') {
Some(idx) => (&item[..idx], Some(item[idx + 1..].trim())),
None => (item, None),
};
let gn = name_part.trim();
if gn.is_empty() {
continue;
}
if seen.insert(gn.to_string()) {
p.generic_parameters.push(gn.to_string());
}
if let Some(b) = bound {
let c = format!("{}: {}", gn, b);
if !c.is_empty() && seen.insert(c.clone()) {
p.constraints.push(c);
}
}
}
}
let (ret_text, constraints) = split_tail(tail.trim());
p.returns = parse_return(&ret_text, p.ret_before_name.as_deref());
if let Some(cs) = constraints {
for c in split_top(&cs, ',') {
let c = c.trim();
if !c.is_empty() && !p.constraints.iter().any(|x| x == c) {
p.constraints.push(c.to_string());
}
}
}
p
}
fn split_tail(tail: &str) -> (String, Option<String>) {
let t = tail.trim();
for marker in ["where ", "throws ", " where ", " throws "] {
if let Some(idx) = find_depth0_pattern(t, marker) {
let before = if idx == 0 {
String::new()
} else {
t[..idx].trim().to_string()
};
let after = t[idx + marker.len()..]
.trim()
.trim_end_matches(',')
.trim()
.to_string();
return (before, Some(after));
}
}
(t.to_string(), None)
}
fn parse_return(text: &str, ret_before: Option<&str>) -> Option<String> {
let t = text
.trim()
.trim_start_matches(':')
.trim()
.trim_end_matches(';')
.trim()
.to_string();
if t.is_empty() {
return ret_before.map(|s| s.to_string());
}
for arrow in ["->", "=>"] {
if let Some(idx) = find_depth0_pattern(&t, arrow) {
let mut r = t[idx + arrow.len()..]
.trim()
.trim_end_matches(':')
.trim()
.trim_end_matches(';')
.trim()
.to_string();
if let Some((g, _)) = take_group(&r, '(', ')') {
r = g;
}
if !r.is_empty() {
while let Some(stripped) = r.strip_prefix('*').or_else(|| r.strip_prefix('&')) {
r = stripped.trim().to_string();
}
return Some(r);
}
return ret_before.map(|s| s.to_string());
}
}
if t.starts_with('(') {
if let Some((g, _)) = take_group(&t, '(', ')') {
return Some(g);
}
}
if let Some(rb) = ret_before {
return Some(rb.to_string());
}
if t.chars().all(|c| c.is_whitespace() || matches!(c, ':' | ';' | ',')) {
return None;
}
let mut r = t;
while let Some(stripped) = r.strip_prefix('*').or_else(|| r.strip_prefix('&')) {
r = stripped.trim().to_string();
}
if r.is_empty() { None } else { Some(r) }
}
fn parse_param(raw: &str) -> Option<SemanticParameter> {
let mut s = raw.trim().to_string();
if s.is_empty() {
return None;
}
let variadic = s.contains("...") || s.starts_with('*') || s.starts_with("**");
for pfx in ["&mut ", "&", "*", "mut ", "ref ", "..."] {
if let Some(after) = s.strip_prefix(pfx) {
s = after.trim().to_string();
break;
}
}
let head = leading_word(&s).map(|(w, _)| w).unwrap_or_default();
if head == "self" || head == "this" || head == "Self" {
return Some(SemanticParameter {
name: head,
ty: None,
receiver: true,
default: None,
variadic,
});
}
let (left, default) = match find_depth0_char(&s, '=') {
Some(idx) => (s[..idx].trim().to_string(), Some(s[idx + 1..].trim().to_string())),
None => (s, None),
};
if left.is_empty() {
return None;
}
let (mut name, ty) = if let Some(idx) = find_depth0_char(&left, ':') {
(left[..idx].trim().to_string(), Some(left[idx + 1..].trim().to_string()))
} else {
split_name_type(&left)
};
while let Some(stripped) = name.strip_prefix('&').or_else(|| name.strip_prefix('*')) {
name = stripped.trim().to_string();
}
if let Some(stripped) = name.strip_prefix("mut ") {
name = stripped.trim().to_string();
}
name = name.trim_end_matches('?').trim().to_string();
if name.is_empty() {
return None;
}
let receiver = name == "self" || name == "this";
Some(SemanticParameter {
name,
ty,
receiver,
default,
variadic,
})
}
fn split_name_type(left: &str) -> (String, Option<String>) {
let words: Vec<&str> = left.split_whitespace().collect();
if words.is_empty() {
return (String::new(), None);
}
if words.len() == 1 {
return (words[0].to_string(), None);
}
let first = words[0];
let last = words[words.len() - 1];
let first_is_type = is_type_word(first)
|| first.chars().next().map(|c| !c.is_ascii_lowercase()).unwrap_or(false)
|| first.contains('<')
|| first.contains('[')
|| first.contains('.')
|| first.ends_with("[]");
let last_is_plain = is_identifier(last) && !is_type_word(last);
if first_is_type && last_is_plain {
(last.to_string(), Some(words[..words.len() - 1].join(" ")))
} else {
(first.to_string(), Some(words[1..].join(" ")))
}
}
fn visibility_from_modifiers(mods: &[String]) -> Option<Visibility> {
if mods.iter().any(|m| m == "pub" || m == "public") {
Some(Visibility::Public)
} else if mods.iter().any(|m| m == "protected") {
Some(Visibility::Protected)
} else if mods.iter().any(|m| m == "private") {
Some(Visibility::Private)
} else {
None
}
}
fn entry_visibility(
exported: bool,
parent: Option<&str>,
mods: &[String],
ret_before_name: Option<&str>,
) -> Visibility {
if exported {
return Visibility::Public;
}
if let Some(v) = visibility_from_modifiers(mods) {
return v;
}
if parent.is_some() && ret_before_name.is_some() {
return Visibility::Package;
}
Visibility::Private
}
fn map_kind(kind_str: &str, name: &str, parent: Option<&str>) -> SurfaceKind {
match kind_str {
"method" => {
let simple = name.rsplit('.').next().unwrap_or(name);
if parent.map(|p| simple == p).unwrap_or(false) || simple == "__init__" {
SurfaceKind::Constructor
} else {
SurfaceKind::Method
}
}
"function" => SurfaceKind::Function,
"class" => SurfaceKind::Class,
"interface" => SurfaceKind::Interface,
"trait" => SurfaceKind::Trait,
"enum" => SurfaceKind::Enum,
"type" => SurfaceKind::Type,
"const" => SurfaceKind::Const,
"module" => SurfaceKind::Module,
_ => SurfaceKind::Function,
}
}
fn canonicalize(sig: &str) -> String {
sig.split_whitespace().collect::<Vec<_>>().join(" ").to_lowercase()
}
fn synthesized_signature(kind_str: &str, simple: &str) -> String {
match kind_str {
"class" | "interface" | "trait" | "enum" | "module" => format!("{} {}", kind_str, simple),
"type" => format!("type {}", simple),
_ => simple.to_string(),
}
}
fn sorted_rels(rels: Vec<&scc_core::Relationship>) -> Vec<&scc_core::Relationship> {
let mut v = rels;
v.sort_by(|a, b| {
a.id.cmp(&b.id)
.then_with(|| a.subject.cmp(&b.subject))
.then_with(|| a.object.cmp(&b.object))
});
v
}
fn attr_str(e: &scc_core::Entity, key: &str) -> Option<String> {
e.attributes.get(key).and_then(|v| match v {
serde_json::Value::String(s) => Some(s.clone()),
_ => None,
})
}
fn attr_u32(e: &scc_core::Entity, key: &str) -> u32 {
e.attributes
.get(key)
.and_then(|v| v.as_u64())
.map(|n| n.min(u32::MAX as u64) as u32)
.unwrap_or(0)
}
fn fits(total_chars: usize, budget_chars: Option<usize>) -> bool {
budget_chars.is_none_or(|b| total_chars <= b)
}
fn entry_tier(e: &SurfaceEntry) -> u8 {
if e.exported || e.visibility == Visibility::Public || !e.invocation_surfaces.is_empty() {
0
} else if e.rank.total > 0.0 {
1
} else {
2
}
}
fn entry_order(a: &SurfaceEntry, b: &SurfaceEntry) -> std::cmp::Ordering {
entry_tier(a)
.cmp(&entry_tier(b))
.then_with(|| b.rank.total.partial_cmp(&a.rank.total).unwrap_or(std::cmp::Ordering::Equal))
.then_with(|| a.kind.as_str().cmp(b.kind.as_str()))
.then_with(|| a.qualified_name.cmp(&b.qualified_name))
.then_with(|| a.id.cmp(&b.id))
}
fn render_entry(e: &SurfaceEntry) -> String {
render_entry_opt(e, 0, None)
}
fn render_entry_compressed(e: &SurfaceEntry) -> String {
render_entry_opt(e, 1, None)
}
fn render_entry_opt(e: &SurfaceEntry, level: u8, rank: Option<&SurfaceRank>) -> String {
let mut out = String::new();
let name = e.qualified_name.rsplit('.').next().unwrap_or(&e.qualified_name);
out.push_str(&format!(" {} {}\n\n", e.kind.as_str(), name));
if (1..3).contains(&level) {
let sig = match level {
2 => e.canonical_signature.split('\n').next().unwrap_or(""),
_ => e.source_signature.split('\n').next().unwrap_or(""),
};
if !sig.is_empty() {
let sig: String = sig.chars().take(160).collect();
out.push_str(" ");
out.push_str(&sig);
out.push('\n');
}
} else if level == 0 {
let sig_lines: Vec<&str> = e.source_signature.split('\n').collect();
for line in &sig_lines {
out.push_str(" ");
out.push_str(line);
out.push('\n');
}
}
if level == 0 {
let sections: [(&str, &[String]); 6] = [
("Used by", &e.callers),
("Calls", &e.callees),
("Participates in", &e.flows),
("Contracts", &e.contracts),
("Owns", &e.state_authorities),
("Invocation", &e.invocation_surfaces),
];
for (label, vals) in sections {
if vals.is_empty() {
continue;
}
out.push('\n');
out.push_str(&format!(" {label}:\n {}\n", vals.join(", ")));
}
if e.caller_count > e.callers.len() || e.callee_count > e.callees.len() {
out.push('\n');
if e.caller_count > e.callers.len() {
out.push_str(&format!(" Called by {} symbols (showing {})\n", e.caller_count, e.callers.len()));
}
if e.callee_count > e.callees.len() {
out.push_str(&format!(" Calls {} symbols (showing {})\n", e.callee_count, e.callees.len()));
}
}
if let Some(imp) = &e.importance {
if !imp.badges.is_empty() {
out.push('\n');
out.push_str(&format!(" Badges: {}\n", imp.badges.join(" \u{00B7} ")));
}
}
}
if let Some(rank) = rank {
out.push('\n');
out.push_str(&format!(" importance: {:.3}\n", rank.total));
out.push_str(&format!(" task_ppr: {:.3}\n", rank.task_ppr));
out.push_str(&format!(" global_ppr: {:.3}\n", rank.global_ppr));
out.push_str(&format!(" lexical: {:.3}\n", rank.lexical));
out.push_str(&format!(" semantic: {:.3}\n", rank.semantic));
out.push_str(&format!(" confidence: {:.3}\n", rank.confidence));
out.push_str(&format!(" criticality: {:.3}\n", rank.criticality));
out.push_str(&format!(" change_risk: {:.3}\n", rank.change_risk));
out.push_str(&format!(" novelty: {:.3}\n", rank.novelty));
if !rank.reasons.is_empty() {
out.push_str(" because:\n");
for r in &rank.reasons {
out.push_str(&format!(" {r}\n"));
}
}
}
out.push('\n');
out
}
fn group_header(comp: &str, sub: &str, path: &str) -> String {
let mut h = String::new();
h.push('\n');
h.push_str(&comp.to_uppercase());
h.push_str("\n\n");
if sub.is_empty() {
h.push_str(path);
} else {
h.push_str(&format!("{} [{}]", path, sub));
}
h.push_str("\n\n");
h
}
fn is_modifier_word(w: &str) -> bool {
matches!(
w,
"async" | "await" | "static" | "final" | "abstract" | "readonly"
| "sealed" | "override" | "virtual" | "synchronized" | "native"
| "extern" | "unsafe" | "inline" | "const" | "var" | "let" | "mutable"
| "pub" | "public" | "private" | "protected" | "package" | "internal"
| "open" | "suspend" | "operator" | "export" | "default" | "declare"
| "data" | "value"
)
}
fn is_callable_keyword(w: &str) -> bool {
matches!(
w,
"fn" | "def" | "func" | "function" | "class" | "struct" | "interface"
| "trait" | "enum" | "type" | "module"
)
}
fn is_type_word(w: &str) -> bool {
matches!(
w,
"int" | "long" | "short" | "byte" | "char" | "float" | "double"
| "bool" | "boolean" | "string" | "str" | "void" | "unsigned"
| "signed" | "usize" | "isize" | "u8" | "u16" | "u32" | "u64"
| "u128" | "i8" | "i16" | "i32" | "i64" | "i128" | "any"
| "object" | "Option" | "Result" | "Vec" | "Map" | "List" | "Set"
)
}
fn is_identifier(w: &str) -> bool {
let mut chars = w.chars();
match chars.next() {
Some(c) if c.is_ascii_alphabetic() || c == '_' || c == '$' => {}
_ => return false,
}
chars.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == '$' || c == '?')
}
fn leading_word(s: &str) -> Option<(String, &str)> {
let s = s.trim_start();
let mut end = 0;
for (i, ch) in s.char_indices() {
if ch.is_ascii_alphanumeric() || ch == '_' || ch == '$' || ch == '?' {
end = i + ch.len_utf8();
} else {
break;
}
}
if end == 0 {
return None;
}
Some((s[..end].to_string(), &s[end..]))
}
fn take_group(text: &str, open: char, close: char) -> Option<(String, &str)> {
if !text.starts_with(open) {
return None;
}
let mut depth = 0i32;
let mut quote: Option<char> = None;
for (i, ch) in text.char_indices() {
if let Some(q) = quote {
if ch == q {
quote = None;
}
continue;
}
match ch {
'"' | '\'' | '`' => quote = Some(ch),
c if c == open => depth += 1,
c if c == close => {
depth -= 1;
if depth == 0 {
return Some((text[1..i].to_string(), &text[i + ch.len_utf8()..]));
}
}
_ => {}
}
}
None
}
fn find_matching_open(text: &str, open: char, close: char) -> Option<usize> {
let mut depth = 0i32;
for (i, ch) in text.char_indices().rev() {
if ch == close {
depth += 1;
} else if ch == open {
depth -= 1;
if depth == 0 {
return Some(i);
}
}
}
None
}
fn split_params(rest: &str) -> Option<(String, Vec<String>, String)> {
let mut depth = 0i32;
let mut quote: Option<char> = None;
let mut open: Option<usize> = None;
for (i, ch) in rest.char_indices() {
if let Some(q) = quote {
if ch == q {
quote = None;
}
continue;
}
match ch {
'"' | '\'' | '`' => quote = Some(ch),
'(' if depth == 0 => {
open = Some(i);
break;
}
')' if depth == 0 => return None,
'(' => depth += 1,
')' => depth -= 1,
_ => {}
}
}
let i0 = open?;
let (inner, after) = take_group(&rest[i0..], '(', ')')?;
let prefix = rest[..i0].to_string();
let params = split_top(&inner, ',');
Some((prefix, params, after.trim().to_string()))
}
fn split_top(text: &str, sep: char) -> Vec<String> {
let mut out: Vec<String> = Vec::new();
let mut paren_depth = 0i32;
let mut angle_depth = 0i32;
let mut quote: Option<char> = None;
let mut prev: Option<char> = None;
let mut cur = String::new();
for ch in text.chars() {
if let Some(q) = quote {
cur.push(ch);
if ch == q {
quote = None;
}
prev = Some(ch);
continue;
}
match ch {
'"' | '\'' | '`' => {
quote = Some(ch);
cur.push(ch);
}
'(' | '[' | '{' => {
paren_depth += 1;
cur.push(ch);
}
')' | ']' | '}' => {
paren_depth -= 1;
cur.push(ch);
}
'<' if angle_depth == 0 && prev.map(|p| p.is_alphanumeric() || p == '_' || p == '>').unwrap_or(false) => {
angle_depth += 1;
cur.push(ch);
}
'>' if angle_depth > 0 && prev != Some('-') => {
angle_depth -= 1;
cur.push(ch);
}
c if c == sep && paren_depth == 0 && angle_depth == 0 => {
out.push(std::mem::take(&mut cur));
}
_ => cur.push(ch),
}
prev = Some(ch);
}
out.push(cur);
out.into_iter().map(|s| s.trim().to_string()).collect()
}
fn find_depth0_pattern(text: &str, pat: &str) -> Option<usize> {
let mut depth = 0i32;
let mut quote: Option<char> = None;
for (i, ch) in text.char_indices() {
if let Some(q) = quote {
if ch == q {
quote = None;
}
continue;
}
match ch {
'"' | '\'' | '`' => quote = Some(ch),
'(' | '[' | '{' => depth += 1,
')' | ']' | '}' => depth -= 1,
_ => {}
}
if depth == 0 && text[i..].starts_with(pat) {
return Some(i);
}
}
None
}
fn find_depth0_char(text: &str, target: char) -> Option<usize> {
let mut paren_depth = 0i32;
let mut angle_depth = 0i32;
let mut quote: Option<char> = None;
let mut prev: Option<char> = None;
for (i, ch) in text.char_indices() {
if let Some(q) = quote {
if ch == q {
quote = None;
}
prev = Some(ch);
continue;
}
match ch {
'"' | '\'' | '`' => quote = Some(ch),
'(' | '[' | '{' => paren_depth += 1,
')' | ']' | '}' => paren_depth -= 1,
'<' if angle_depth == 0 && prev.map(|p| p.is_alphanumeric() || p == '_' || p == '>').unwrap_or(false) => angle_depth += 1,
'>' if angle_depth > 0 && prev != Some('-') => angle_depth -= 1,
c if c == target && paren_depth == 0 && angle_depth == 0 => return Some(i),
_ => {}
}
prev = Some(ch);
}
None
}
fn receiver_owner(group: &str) -> Option<String> {
let inner = group.trim();
if inner.is_empty() {
return None;
}
let words: Vec<&str> = inner.split_whitespace().collect();
if words.is_empty() {
return None;
}
let t = if words.len() <= 1 {
words[0]
} else {
words[words.len() - 1]
};
let t = t.trim_start_matches('*').trim_start_matches('&');
let seg = t.rsplit('.').next().unwrap_or(t);
let seg = seg.trim().trim_start_matches('*');
if seg.is_empty() {
None
} else {
Some(seg.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
use scc_core::{
entity_id, relationship_id, symbol_id, ContextLedger, Entity, Flow, FlowKind,
FlowStep, Relationship,
};
use scc_store::Store;
fn fixture_store() -> (tempfile::TempDir, Store) {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
let store = Store::open(&dir.path().join("scc.db"), &root).unwrap();
let repo = store.repo_id.clone();
let path = "api/app.py";
let fid = entity_id(&repo, kinds::FILE, path);
store.insert_entity(&Entity::new(fid.clone(), kinds::FILE, path), &[path.to_string()]).unwrap();
let comp_id = entity_id(&repo, kinds::COMPONENT, "api");
store.replace_components(&[Entity::new(comp_id.clone(), kinds::COMPONENT, "api")]).unwrap();
store.insert_relationship(
&Relationship::new(relationship_id(1), comp_id.clone(), predicates::CONTAINS, fid.clone(), Provenance::Extracted),
path,
).unwrap();
let svc_id = entity_id(&repo, kinds::SERVICE, "core");
store.insert_entity(&Entity::new(svc_id.clone(), kinds::SERVICE, "core"), &[path.to_string()]).unwrap();
store.insert_relationship(
&Relationship::new(relationship_id(2), svc_id, predicates::CONTAINS, comp_id.clone(), Provenance::Extracted),
path,
).unwrap();
let mut rid: u64 = 3;
let mut sym = |name: &str, kind: &str, sig: Option<&str>, exported: bool, parent: Option<&str>| -> String {
let id = symbol_id(&repo, path, name);
let mut e = Entity::new(id.clone(), kinds::SYMBOL, name);
e.attr("kind", serde_json::json!(kind));
e.attr("file", serde_json::json!(path));
if let Some(s) = sig { e.attr("signature", serde_json::json!(s)); }
e.attr("exported", serde_json::json!(exported));
e.attr("start_line", serde_json::json!(1u32));
e.attr("end_line", serde_json::json!(10u32));
if let Some(p) = parent { e.attr("parent", serde_json::json!(p)); }
store.insert_entity(&e, &[path.to_string()]).unwrap();
rid += 1;
store.insert_relationship(
&Relationship::new(relationship_id(rid), fid.clone(), predicates::CONTAINS, id.clone(), Provenance::Extracted),
path,
).unwrap();
id
};
let _ = sym("UserService", "class", None, true, None);
let _ = sym("UserService.UserService", "method", Some("public UserService(String name)"), false, Some("UserService"));
let get_id = sym("UserService.get", "method", Some("public User get(String id) throws NotFound"), false, Some("UserService"));
let _ = sym("UserService.hash", "method", Some("String hash()"), false, Some("UserService"));
let update_id = sym("UserService.update", "method", Some("async fn update(&mut self, patch: Json) -> bool"), false, Some("UserService"));
let create_id = sym("create_user", "function", Some("def create_user(name: str, age: int = 0) -> User"), true, None);
let db_id = sym("db", "function", Some("func db() *DB"), false, None);
let ann_id = entity_id(&repo, kinds::ANNOTATION, "RestController");
store.insert_entity(&Entity::new(ann_id.clone(), kinds::ANNOTATION, "RestController"), &[path.to_string()]).unwrap();
rid += 1;
store.insert_relationship(
&Relationship::new(relationship_id(rid), ann_id, predicates::ANNOTATES, get_id.clone(), Provenance::Extracted),
path,
).unwrap();
let route_id = entity_id(&repo, kinds::ROUTE, "GET /api/users");
let mut re = Entity::new(route_id.clone(), kinds::ROUTE, "GET /api/users");
re.attr("method", serde_json::json!("GET"));
re.attr("path", serde_json::json!("/api/users"));
re.attr("handler", serde_json::json!(create_id.clone()));
store.insert_entity(&re, &[path.to_string()]).unwrap();
rid += 1;
store.insert_relationship(
&Relationship::new(relationship_id(rid), create_id.clone(), predicates::CALLS, get_id.clone(), Provenance::Extracted),
path,
).unwrap();
rid += 1;
store.insert_relationship(
&Relationship::new(relationship_id(rid), db_id.clone(), predicates::CALLS, create_id.clone(), Provenance::Resolved),
path,
).unwrap();
let state_id = entity_id(&repo, kinds::STATE, "sessions");
store.insert_entity(&Entity::new(state_id.clone(), kinds::STATE, "sessions"), &[path.to_string()]).unwrap();
rid += 1;
store.insert_relationship(
&Relationship::new(relationship_id(rid), db_id.clone(), predicates::OWNS, state_id, Provenance::Extracted),
path,
).unwrap();
let rx_id = entity_id(&repo, kinds::REACTIVE, "cursor");
store.insert_entity(&Entity::new(rx_id.clone(), kinds::REACTIVE, "cursor"), &[path.to_string()]).unwrap();
rid += 1;
store.insert_relationship(
&Relationship::new(relationship_id(rid), update_id.clone(), predicates::OWNS, rx_id, Provenance::Extracted),
path,
).unwrap();
store.replace_flows(&[Flow {
id: entity_id(&repo, kinds::FLOW, "signup"),
kind: FlowKind::Workflow,
name: "signup".into(),
trigger: Some("http".into()),
steps: vec![
FlowStep {
id: "step:1".into(),
order: 1,
actor: get_id.clone(),
operation: "load user".into(),
condition: None,
r#async: None,
timeout_ms: None,
retry_policy: None,
failure_outcome: None,
provenance: Some(Provenance::Extracted),
evidence: vec![],
},
FlowStep {
id: "step:2".into(),
order: 2,
actor: "db".into(),
operation: "persist".into(),
condition: None,
r#async: None,
timeout_ms: None,
retry_policy: None,
failure_outcome: None,
provenance: Some(Provenance::Extracted),
evidence: vec![],
},
],
attributes: std::collections::BTreeMap::new(),
}]).unwrap();
let _ = (get_id, create_id, db_id, update_id);
(dir, store)
}
fn entry<'a>(map: &'a SystemSurfaceMap, qn: &str) -> &'a SurfaceEntry {
map.entries.iter().find(|e| e.qualified_name == qn).expect("entry not found")
}
fn make_ctx<'a>(store: &'a Store) -> ContextCompiler<'a> {
let graph = Box::leak(Box::new(scc_graph::RealityGraph::load(store).unwrap()));
ContextCompiler::new(store, graph, crate::ContextSettings::default(), Vec::new())
}
fn zeta_alpha_fixture() -> (tempfile::TempDir, Store) {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
let store = Store::open(&dir.path().join("scc.db"), &root).unwrap();
let repo = store.repo_id.clone();
for (path, prefix) in [("a/mod.py", "zeta"), ("b/mod.py", "alpha")] {
for i in 0..20 {
let name = format!("{prefix}_{i:02}");
let id = symbol_id(&repo, path, &name);
let mut e = Entity::new(id.clone(), kinds::SYMBOL, name);
e.attr("kind", serde_json::json!("function"));
e.attr("file", serde_json::json!(path));
e.attr("signature", serde_json::json!("def f(x): ..."));
e.attr("exported", serde_json::json!(false));
e.attr("start_line", serde_json::json!(1u32));
e.attr("end_line", serde_json::json!(10u32));
store.insert_entity(&e, &[path.to_string()]).unwrap();
}
}
(dir, store)
}
fn huge_signature_fixture() -> (tempfile::TempDir, Store) {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
let store = Store::open(&dir.path().join("scc.db"), &root).unwrap();
let repo = store.repo_id.clone();
let path = "api/app.py";
let id = symbol_id(&repo, path, "big_fn");
let mut e = Entity::new(id.clone(), kinds::SYMBOL, "big_fn".to_string());
e.attr("kind", serde_json::json!("function"));
e.attr("file", serde_json::json!(path));
let mut decl = String::from("def big_fn(\n");
for i in 0..400 {
decl.push_str(&format!(" arg_{i:03}: str,\n"));
}
decl.push_str(") -> None:\n");
e.attr("decl_header", serde_json::json!(decl));
e.attr("exported", serde_json::json!(true));
e.attr("start_line", serde_json::json!(1u32));
e.attr("end_line", serde_json::json!(10u32));
e.attr("entrypoints", serde_json::json!(["http: POST /big"]));
store.insert_entity(&e, &[path.to_string()]).unwrap();
(dir, store)
}
#[test]
fn compiles_surface_map_with_attribution() {
let (_dir, store) = fixture_store();
let ctx = make_ctx(&store);
let map = compile_surface_map(&ctx);
assert_eq!(map.entries.len(), 7);
assert_eq!(map.repository, "repo");
assert_eq!(map.revision, "not-indexed");
assert!(map.token_count > 0);
let cls = entry(&map, "UserService");
assert_eq!(cls.kind, SurfaceKind::Class);
assert_eq!(cls.visibility, Visibility::Public);
assert!(cls.exported);
assert_eq!(cls.source_signature, "class UserService");
assert_eq!(cls.range.path, "api/app.py");
assert_eq!(cls.component.as_deref(), Some("api"));
assert_eq!(cls.subsystem.as_deref(), Some("core"));
let ctor = entry(&map, "UserService.UserService");
assert_eq!(ctor.kind, SurfaceKind::Constructor);
assert_eq!(ctor.visibility, Visibility::Public);
assert_eq!(ctor.semantic_signature.parameters[0].name, "name");
assert_eq!(ctor.semantic_signature.parameters[0].ty.as_deref(), Some("String"));
let get = entry(&map, "UserService.get");
assert_eq!(get.kind, SurfaceKind::Method);
assert_eq!(get.visibility, Visibility::Public);
assert_eq!(get.annotations, vec!["RestController"]);
assert_eq!(get.flows, vec!["signup"]);
assert_eq!(get.callers, vec!["create_user"]);
assert!(get.callees.is_empty());
let gs = &get.semantic_signature;
assert_eq!(gs.parameters[0].name, "id");
assert_eq!(gs.parameters[0].ty.as_deref(), Some("String"));
assert!(!gs.parameters[0].receiver);
assert_eq!(gs.returns.as_deref(), Some("User"));
assert!(gs.constraints.iter().any(|c| c == "NotFound"));
assert_eq!(get.provenance, Provenance::Extracted);
assert_eq!(get.confidence, 0.85);
let hash = entry(&map, "UserService.hash");
assert_eq!(hash.visibility, Visibility::Package);
let update = entry(&map, "UserService.update");
assert_eq!(update.visibility, Visibility::Private);
assert_eq!(update.modifiers, vec!["async"]);
assert_eq!(update.state_authorities, vec!["cursor"]);
let us = &update.semantic_signature;
assert!(us.async_);
assert!(us.parameters[0].receiver);
assert_eq!(us.parameters[1].name, "patch");
assert_eq!(us.returns.as_deref(), Some("bool"));
let create = entry(&map, "create_user");
assert_eq!(create.kind, SurfaceKind::Function);
assert_eq!(create.visibility, Visibility::Public);
assert!(create.exported);
assert_eq!(create.canonical_signature, "def create_user(name: str, age: int = 0) -> user");
assert_eq!(create.contracts, vec!["http: GET /api/users"]);
assert_eq!(create.callees, vec!["UserService.get"]);
assert_eq!(create.invocation_surfaces, vec![
"http: GET /api/users",
"public_api: export:create_user (function)",
]);
assert_eq!(create.semantic_signature.parameters[1].name, "age");
assert_eq!(create.semantic_signature.parameters[1].default.as_deref(), Some("0"));
assert_eq!(create.semantic_signature.returns.as_deref(), Some("User"));
let db = entry(&map, "db");
assert_eq!(db.visibility, Visibility::Private);
assert_eq!(db.state_authorities, vec!["sessions"]);
assert_eq!(db.provenance, Provenance::Resolved);
assert_eq!(db.confidence, 1.0);
assert_eq!(db.semantic_signature.returns.as_deref(), Some("DB"));
assert_eq!(db.flows, vec!["signup"]);
}
#[test]
fn renderer_groups_and_budget_cuts() {
let (_dir, store) = fixture_store();
let ctx = make_ctx(&store);
let map = compile_surface_map(&ctx);
let full = render_surface_map(&map, None);
assert!(full.starts_with("SCC SYSTEM SURFACE MAP\n\n"));
assert!(full.contains("API\n\napi/app.py [core]"));
assert!(full.contains(" class UserService\n"));
assert!(full.contains(" function create_user\n"));
assert!(full.contains(" constructor UserService\n"));
assert!(full.contains("Used by:"));
assert!(full.contains("http: GET /api/users"));
assert!(!full.contains("OMITTED"));
assert_eq!(map.token_count, estimate_tokens(&full));
let tiny = render_surface_map(&map, Some(1));
assert!(tiny.contains("OMITTED (token budget exceeded):"));
assert!(tiny.contains("3 lower-ranked method definitions"));
assert!(tiny.contains("1 lower-ranked class definitions"));
assert!(tiny.contains("1 lower-ranked constructor definitions"));
assert!(tiny.contains("2 lower-ranked function definitions"));
assert!(!tiny.contains(" class UserService\n"));
}
#[test]
fn semantic_parser_never_panics() {
for sig in &["", " ", "(", ")", "()", "=>", "->", "(((", "fn", "public", "= 42"] {
let s = parse_signature(sig, "fallback", None);
assert_eq!(s.name, "fallback");
}
}
#[test]
fn semantic_parser_language_tolerant() {
let s = parse_signature(
"pub async fn render<T: Bound>(&self, x: T) -> String where T: Clone + Send",
"render",
Some("Widget"),
);
assert_eq!(s.name, "render");
assert!(s.async_);
assert!(s.generic_parameters.contains(&"T".to_string()));
assert!(s.constraints.contains(&"T: Bound".to_string()));
assert!(s.constraints.contains(&"T: Clone + Send".to_string()));
assert_eq!(s.visibility, Some(Visibility::Public));
assert_eq!(s.returns.as_deref(), Some("String"));
assert!(s.parameters[0].receiver);
assert_eq!(s.parameters[1].ty.as_deref(), Some("T"));
assert_eq!(s.owner.as_deref(), Some("Widget"));
let g = parse_signature(
"func (s *Store) Get(ctx context.Context) (User, error)",
"Get",
Some("Store"),
);
assert_eq!(g.name, "Get");
assert_eq!(g.owner.as_deref(), Some("Store"));
assert_eq!(g.parameters[0].ty.as_deref(), Some("context.Context"));
assert_eq!(g.returns.as_deref(), Some("User, error"));
}
#[test]
fn global_render_selects_within_budget_and_reports_omissions() {
let (_dir, store) = fixture_store();
let ctx = make_ctx(&store);
let map = compile_surface_map(&ctx);
let n = map.entries.len();
assert!(n >= 5);
let big = select_and_render_global(&ctx, 100_000);
assert_eq!(big.rendered_ids.len(), n);
assert!(big.omitted_ids.is_empty());
assert!(big.omissions.is_empty());
assert!(big.text.starts_with("SCC SYSTEM SURFACE MAP"));
assert!(big.token_count > 0);
let tiny = select_and_render_global(&ctx, 1);
assert!(
!tiny.rendered_ids.is_empty(),
"required (invocation-surface) entries must survive a tiny budget"
);
for id in &tiny.rendered_ids {
assert!(map.entries.iter().any(|e| &e.id == id), "{id} must be a candidate");
}
assert_eq!(tiny.rendered_ids.len() + tiny.omitted_ids.len(), n);
for id in &tiny.omitted_ids {
assert!(!tiny.rendered_ids.contains(id), "{id} both rendered and omitted");
}
let omitted_total: usize = tiny.omissions.iter().map(|o| o.count).sum();
assert_eq!(omitted_total, tiny.omitted_ids.len());
let tiny2 = select_and_render_global(&ctx, 1);
assert_eq!(tiny2.text, tiny.text);
assert_eq!(tiny2.rendered_ids, tiny.rendered_ids);
assert_eq!(tiny2.omitted_ids, tiny.omitted_ids);
}
#[test]
fn task_render_skips_visible_unchanged_entries() {
let (_dir, store) = fixture_store();
let ctx = make_ctx(&store);
let map = compile_surface_map(&ctx);
let n = map.entries.len();
let create = entry(&map, "create_user");
let mut visible = ContextLedger::default();
visible.visible_symbols.insert(create.symbol_id.clone());
let out = select_and_render_task(&ctx, "create user", 100_000, &visible);
assert!(
!out.rendered_ids.contains(&create.id),
"visible unchanged entries must not be re-injected"
);
assert_eq!(out.rendered_ids.len(), n - 1);
assert_eq!(out.omitted_ids.len(), 1);
assert!(out.omitted_ids.contains(&create.id));
assert!(out.text.starts_with("SCC SYSTEM SURFACE MAP"));
}
#[test]
fn task_render_never_omits_required_even_at_zero_budget() {
let (_dir, store) = fixture_store();
let ctx = make_ctx(&store);
let out = select_and_render_task(&ctx, "user", 0, &ContextLedger::default());
assert!(!out.rendered_ids.is_empty());
assert!(!out.omissions.is_empty() || out.omitted_ids.is_empty());
let rendered: BTreeSet<String> = out.rendered_ids.iter().cloned().collect();
for id in &out.omitted_ids {
assert!(!rendered.contains(id));
}
}
#[test]
fn file_importance_boosts_manifest_symbols_without_injecting_text() {
assert_eq!(file_importance("package.json"), 1.0);
assert_eq!(file_importance("Dockerfile"), 1.0);
assert_eq!(file_importance(".github/workflows/ci.yml"), 1.0);
assert_eq!(file_importance("src/main.rs"), 1.0);
assert_eq!(file_importance("src/util.rs"), 0.0);
assert_eq!(file_importance("src/main.py"), 1.0);
assert_eq!(file_importance("Makefile"), 1.0);
assert_eq!(file_importance("services/transcripts.py"), 0.0);
}
#[test]
fn build_surface_global_matches_historical_pipeline() {
let (_dir, store) = fixture_store();
let ctx = make_ctx(&store);
let map = compile_surface_map(&ctx);
let n = map.entries.len();
assert!(n >= 5);
let req = |budget: usize| SurfaceRequest {
mode: SurfaceMode::Global,
budget,
explain: false,
policy: SurfacePolicy::defaults(budget),
semantic: None,
};
let big = build_surface(&ctx, req(100_000));
let legacy = select_and_render_global(&ctx, 100_000);
assert_eq!(big.text, legacy.text);
assert_eq!(big.rendered_ids, legacy.rendered_ids);
assert_eq!(big.omitted_ids, legacy.omitted_ids);
let mut big_ids = big.rendered_ids.clone();
big_ids.sort();
let mut map_ids: Vec<String> = map.entries.iter().map(|e| e.id.clone()).collect();
map_ids.sort();
assert_eq!(big_ids, map_ids, "the selected subset must cover every candidate");
assert_eq!(big.rendered_ids.len(), n);
assert!(big.omitted_ids.is_empty());
let tiny = build_surface(&ctx, req(1));
assert!(!tiny.rendered_ids.is_empty());
assert_eq!(tiny.rendered_ids.len() + tiny.omitted_ids.len(), n);
let tiny2 = build_surface(&ctx, req(1));
assert_eq!(tiny.text, tiny2.text);
assert_eq!(tiny.rendered_ids, tiny2.rendered_ids);
}
#[test]
fn build_surface_task_applies_novelty_suppression() {
let (_dir, store) = fixture_store();
let ctx = make_ctx(&store);
let map = compile_surface_map(&ctx);
let create = entry(&map, "create_user");
let mut visible = ContextLedger::default();
visible.visible_symbols.insert(create.symbol_id.clone());
let out = build_surface(
&ctx,
SurfaceRequest {
mode: SurfaceMode::Task {
goal: "create user",
visible: Some(&visible),
},
budget: 100_000,
explain: false,
policy: SurfacePolicy::defaults(100_000),
semantic: None,
},
);
assert!(!out.rendered_ids.contains(&create.id));
assert_eq!(out.rendered_ids.len(), map.entries.len() - 1);
assert!(out.omitted_ids.contains(&create.id));
let legacy = select_and_render_task(&ctx, "create user", 100_000, &visible);
assert_eq!(out.text, legacy.text);
assert_eq!(out.rendered_ids, legacy.rendered_ids);
let full = build_surface(
&ctx,
SurfaceRequest {
mode: SurfaceMode::Task {
goal: "create user",
visible: None,
},
budget: 100_000,
explain: false,
policy: SurfacePolicy::defaults(100_000),
semantic: None,
},
);
assert_eq!(full.rendered_ids.len(), map.entries.len());
}
#[test]
fn token_aware_quotas_cap_the_dominant_kind() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
let store = Store::open(&dir.path().join("scc.db"), &root).unwrap();
let repo = store.repo_id.clone();
let path = "api/app.py";
let mut rel_id: u64 = 10_000;
for i in 0..900 {
let name = format!("core_fn_{i:04}");
let id = symbol_id(&repo, path, &name);
let mut e = Entity::new(id.clone(), kinds::SYMBOL, name);
e.attr("kind", serde_json::json!("function"));
e.attr("file", serde_json::json!(path));
e.attr("signature", serde_json::json!("def f(x): ..."));
e.attr("exported", serde_json::json!(false));
e.attr("start_line", serde_json::json!(1u32));
e.attr("end_line", serde_json::json!(10u32));
store.insert_entity(&e, &[path.to_string()]).unwrap();
}
for i in 0..100 {
let name = format!("state_fn_{i:04}");
let id = symbol_id(&repo, path, &name);
let mut e = Entity::new(id.clone(), kinds::SYMBOL, name);
e.attr("kind", serde_json::json!("function"));
e.attr("file", serde_json::json!(path));
e.attr("signature", serde_json::json!("def f(x): ..."));
e.attr("exported", serde_json::json!(false));
e.attr("start_line", serde_json::json!(1u32));
e.attr("end_line", serde_json::json!(10u32));
store.insert_entity(&e, &[path.to_string()]).unwrap();
let state_id = entity_id(&repo, kinds::STATE, &format!("st{i:04}"));
store
.insert_entity(
&Entity::new(state_id.clone(), kinds::STATE, format!("st{i:04}")),
&[path.to_string()],
)
.unwrap();
rel_id += 1;
store
.insert_relationship(
&Relationship::new(
relationship_id(rel_id),
id,
predicates::OWNS,
state_id,
Provenance::Extracted,
),
path,
)
.unwrap();
}
let ctx = make_ctx(&store);
let map = compile_surface_map(&ctx);
assert_eq!(map.entries.len(), 1000);
let budget = 2000usize;
let hard_max = SurfacePolicy::defaults(budget).hard_max;
let req = |quotas: bool| SurfaceRequest {
mode: SurfaceMode::Global,
budget,
explain: false,
policy: SurfacePolicy {
quotas,
mmr: false,
coverage: true,
hard_max,
},
semantic: None,
};
let naive = build_surface(&ctx, req(false));
let balanced = build_surface(&ctx, req(true));
let count = |r: &scc_core::SurfaceRenderResult, prefix: &str| {
r.rendered_ids.iter().filter(|id| id.contains(prefix)).count()
};
let naive_core = count(&naive, "core_fn_");
let bal_core = count(&balanced, "core_fn_");
let bal_state = count(&balanced, "state_fn_");
assert!(
bal_core < naive_core,
"quotas must cut the dominant kind: {bal_core} !< {naive_core}"
);
assert!(bal_state > 0, "quotas must admit the under-represented kind");
}
#[test]
fn hard_max_soft_overflow_renders_but_required_overflow_compresses() {
let (_dir, store) = fixture_store();
let ctx = make_ctx(&store);
let soft = build_surface(
&ctx,
SurfaceRequest {
mode: SurfaceMode::Global,
budget: 5,
explain: false,
policy: SurfacePolicy::defaults(5), semantic: None,
},
);
assert!(!soft.rendered_ids.is_empty());
assert!(
soft.text.contains("Used by:"),
"under the hard max the full entry blocks must render"
);
assert!(soft.token_count > 5, "required may exceed the soft budget");
assert!(soft.token_count <= 505, "required never exceeds the hard max");
let (_dir2, store2) = huge_signature_fixture();
let ctx2 = make_ctx(&store2);
let hard = build_surface(
&ctx2,
SurfaceRequest {
mode: SurfaceMode::Global,
budget: 100,
explain: false,
policy: SurfacePolicy::defaults(100), semantic: None,
},
);
assert_eq!(hard.rendered_ids.len(), 1, "the required entry is never dropped");
assert!(
hard.text.contains("function big_fn"),
"the compressed entry keeps its identity"
);
assert!(!hard.text.contains("Used by:"), "metadata sections are dropped");
assert!(hard.token_count <= 600, "the compressed render fits the hard max");
}
#[test]
fn staged_toggles_change_output_deterministically() {
let (_dir, store) = zeta_alpha_fixture();
let ctx = make_ctx(&store);
let budget = 80usize;
let hard_max = SurfacePolicy::defaults(budget).hard_max;
let req = |_stages: &SurfacePipelineStages| SurfaceRequest {
mode: SurfaceMode::Task {
goal: "zeta",
visible: None,
},
budget,
explain: false,
policy: SurfacePolicy {
quotas: false,
mmr: true,
coverage: true,
hard_max,
},
semantic: None,
};
let render =
|stages: &SurfacePipelineStages| build_surface_staged(&ctx, req(stages), stages);
let has_b = |r: &scc_core::SurfaceRenderResult| {
r.rendered_ids.iter().any(|id| id.contains("b/mod.py"))
};
let full = render(&SurfacePipelineStages::default());
let full2 = render(&SurfacePipelineStages::default());
assert_eq!(full.text, full2.text);
assert_eq!(full.rendered_ids, full2.rendered_ids);
let no_mmr_stages = SurfacePipelineStages {
mmr: false,
..SurfacePipelineStages::default()
};
let no_mmr = render(&no_mmr_stages);
assert_ne!(full.text, no_mmr.text);
assert!(has_b(&full), "MMR must diversify across paths");
assert!(!has_b(&no_mmr), "rank-order cut must stay on the first path");
let no_lex_stages = SurfacePipelineStages {
lexical: false,
..SurfacePipelineStages::default()
};
let no_lex = build_surface_staged(
&ctx,
SurfaceRequest {
mode: SurfaceMode::Task {
goal: "zeta",
visible: None,
},
budget: 100_000,
explain: false,
policy: SurfacePolicy::defaults(100_000),
semantic: None,
},
&no_lex_stages,
);
let lex_on = build_surface_staged(
&ctx,
SurfaceRequest {
mode: SurfaceMode::Task {
goal: "zeta",
visible: None,
},
budget: 100_000,
explain: false,
policy: SurfacePolicy::defaults(100_000),
semantic: None,
},
&SurfacePipelineStages::default(),
);
assert_eq!(
no_lex.rendered_ids.len(),
20,
"pure lexical skips unmatched entries"
);
assert_eq!(lex_on.rendered_ids.len(), 40, "the PPR blend ranks the full pool");
assert_ne!(no_lex.text, lex_on.text);
}
#[test]
fn overload_entries_get_distinct_ids_and_logical_symbol_id() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
let store = Store::open(&dir.path().join("scc.db"), &root).unwrap();
let repo = store.repo_id.clone();
let path = "api/app.py";
let base = symbol_id(&repo, path, "handle");
for (n, id) in [(0u64, base.clone()), (1, format!("{}#1", base))] {
let mut e = Entity::new(id.clone(), kinds::SYMBOL, "handle");
e.attr("kind", serde_json::json!("function"));
e.attr("file", serde_json::json!(path));
e.attr("signature", serde_json::json!("def handle(x): ..."));
e.attr("exported", serde_json::json!(true));
e.attr("start_line", serde_json::json!(1u32));
e.attr("end_line", serde_json::json!(10u32));
e.attr("overload_index", serde_json::json!(n));
store.insert_entity(&e, &[path.to_string()]).unwrap();
}
let ctx = make_ctx(&store);
let map = compile_surface_map(&ctx);
let handles: Vec<&SurfaceEntry> = map
.entries
.iter()
.filter(|e| e.qualified_name == "handle")
.collect();
assert_eq!(handles.len(), 2, "same-name overloads stay separate entries");
let mut ids: Vec<String> = handles.iter().map(|e| e.id.clone()).collect();
ids.sort();
assert_eq!(
ids,
vec![format!("{}#overload0", base), format!("{}#overload1", base)]
);
for e in handles {
assert_eq!(e.symbol_id, base, "symbol_id stays the logical symbol");
}
}
#[test]
fn decl_header_wins_over_legacy_signature() {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
let store = Store::open(&dir.path().join("scc.db"), &root).unwrap();
let repo = store.repo_id.clone();
let path = "api/app.py";
let id = symbol_id(&repo, path, "process");
let mut e = Entity::new(id.clone(), kinds::SYMBOL, "process");
e.attr("kind", serde_json::json!("function"));
e.attr("file", serde_json::json!(path));
e.attr("signature", serde_json::json!("def process(x) -> str"));
e.attr(
"decl_header",
serde_json::json!("async def process(\n x: int,\n) -> str:"),
);
e.attr("exported", serde_json::json!(true));
e.attr("start_line", serde_json::json!(1u32));
e.attr("end_line", serde_json::json!(10u32));
store.insert_entity(&e, &[path.to_string()]).unwrap();
let ctx = make_ctx(&store);
let map = compile_surface_map(&ctx);
let proc = entry(&map, "process");
assert_eq!(
proc.source_signature,
"async def process(\n x: int,\n) -> str:",
"decl_header (exact header) must win over the legacy signature attr"
);
assert_eq!(proc.modifiers, vec!["async"]);
}
fn symmetric_two_fn_fixture() -> (tempfile::TempDir, Store) {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
let store = Store::open(&dir.path().join("scc.db"), &root).unwrap();
let repo = store.repo_id.clone();
let path = "api/app.py";
for name in ["alpha_fn", "beta_fn"] {
let id = symbol_id(&repo, path, name);
let mut e = Entity::new(id.clone(), kinds::SYMBOL, name.to_string());
e.attr("kind", serde_json::json!("function"));
e.attr("file", serde_json::json!(path));
e.attr("signature", serde_json::json!("def f(x): ..."));
e.attr("exported", serde_json::json!(false));
e.attr("start_line", serde_json::json!(1u32));
e.attr("end_line", serde_json::json!(10u32));
store.insert_entity(&e, &[path.to_string()]).unwrap();
}
(dir, store)
}
fn pathological_signature_fixture() -> (tempfile::TempDir, Store) {
let dir = tempfile::TempDir::new().unwrap();
let root = dir.path().join("repo");
std::fs::create_dir_all(&root).unwrap();
let store = Store::open(&dir.path().join("scc.db"), &root).unwrap();
let repo = store.repo_id.clone();
let path = "api/app.py";
let id = symbol_id(&repo, path, "big_fn");
let mut e = Entity::new(id.clone(), kinds::SYMBOL, "big_fn".to_string());
e.attr("kind", serde_json::json!("function"));
e.attr("file", serde_json::json!(path));
let mut decl = String::from("def big_fn(");
for i in 0..400 {
decl.push_str(&format!("arg_{i:03}: str, "));
}
decl.push_str(") -> None:");
e.attr("decl_header", serde_json::json!(decl));
e.attr("exported", serde_json::json!(true));
e.attr("start_line", serde_json::json!(1u32));
e.attr("end_line", serde_json::json!(10u32));
e.attr("entrypoints", serde_json::json!(["http: POST /big"]));
store.insert_entity(&e, &[path.to_string()]).unwrap();
(dir, store)
}
struct ZeroScorer;
impl crate::rank::SemanticScorer for ZeroScorer {
fn score(&self, _goal: &str, _entity: &scc_core::Entity) -> f64 {
0.0
}
}
struct NameScorer {
target: &'static str,
score: f64,
}
impl crate::rank::SemanticScorer for NameScorer {
fn score(&self, _goal: &str, entity: &scc_core::Entity) -> f64 {
if entity.name.contains(self.target) {
self.score
} else {
0.0
}
}
}
fn explain_blocks(text: &str) -> Vec<(String, BTreeMap<String, f64>)> {
const KINDS: [&str; 11] = [
"function", "method", "constructor", "class", "interface",
"trait", "type", "enum", "const", "module", "record",
];
let mut blocks: Vec<(String, BTreeMap<String, f64>)> = Vec::new();
for line in text.lines() {
if !line.starts_with(" ") {
if let Some(rest) = line.strip_prefix(" ") {
let first = rest.split_whitespace().next().unwrap_or("");
if KINDS.contains(&first) {
let name = rest.split_whitespace().nth(1).unwrap_or("").to_string();
blocks.push((name, BTreeMap::new()));
continue;
}
}
}
if let Some((_, comps)) = blocks.last_mut() {
if let Some((k, v)) = line.trim_start().split_once(':') {
if let Ok(num) = v.trim().parse::<f64>() {
comps.insert(k.trim().to_string(), num);
}
}
}
}
blocks
}
#[test]
fn explain_renders_full_score_decomposition() {
let (_dir, store) = fixture_store();
let ctx = make_ctx(&store);
let request = SurfaceRequest {
mode: SurfaceMode::Task {
goal: "create user",
visible: None,
},
budget: 100_000,
explain: true,
policy: SurfacePolicy::defaults(100_000),
semantic: None,
};
let out = build_surface(&ctx, request);
for key in [
"importance:",
"task_ppr:",
"global_ppr:",
"lexical:",
"semantic:",
"confidence:",
"criticality:",
"change_risk:",
"novelty:",
"because:",
] {
assert!(out.text.contains(key), "explain must render {key:?}");
}
assert!(out.text.contains("task seed:"), "seed evidence -> reason");
assert!(out.text.contains("primary flow participant"), "flow evidence -> reason");
assert!(out.text.contains("public component surface"), "visibility evidence -> reason");
assert!(out.text.contains("owns "), "state-authority evidence -> reason");
assert!(out.text.contains("concrete invocation surface"), "invocation evidence -> reason");
for (_, comps) in explain_blocks(&out.text) {
assert_eq!(comps.get("semantic").copied().unwrap_or(-1.0), 0.0);
}
let out2 = build_surface(&ctx, request);
assert_eq!(out.text, out2.text);
}
#[test]
fn semantic_none_redistributes_and_some_reranks() {
let (_dir, store) = symmetric_two_fn_fixture();
let ctx = make_ctx(&store);
let alpha = symbol_id(&store.repo_id, "api/app.py", "alpha_fn");
let beta = symbol_id(&store.repo_id, "api/app.py", "beta_fn");
let none = build_surface(
&ctx,
SurfaceRequest {
mode: SurfaceMode::Global,
budget: 100_000,
explain: true,
policy: SurfacePolicy::defaults(100_000),
semantic: None,
},
);
let zero = build_surface(
&ctx,
SurfaceRequest {
mode: SurfaceMode::Global,
budget: 100_000,
explain: true,
policy: SurfacePolicy::defaults(100_000),
semantic: Some(&ZeroScorer),
},
);
let none_blocks = explain_blocks(&none.text);
let zero_blocks = explain_blocks(&zero.text);
assert!(!none_blocks.is_empty());
assert_eq!(none_blocks.len(), zero_blocks.len());
for ((nname, ncomps), (zname, zcomps)) in none_blocks.iter().zip(&zero_blocks) {
assert_eq!(nname, zname);
let n = ncomps.get("importance").copied().unwrap();
let z = zcomps.get("importance").copied().unwrap();
assert!(
n > z,
"renormalized total must exceed the phantom-hole total for {nname}"
);
let blend = crate::pagerank::final_importance(
ncomps.get("task_ppr").copied().unwrap_or(0.0),
ncomps.get("global_ppr").copied().unwrap_or(0.0),
ncomps.get("lexical").copied().unwrap_or(0.0),
0.0,
ncomps.get("confidence").copied().unwrap_or(0.0),
ncomps.get("criticality").copied().unwrap_or(0.0),
ncomps.get("change_risk").copied().unwrap_or(0.0),
0.0,
false, );
let expected = blend * REDISTRIBUTION_SCALE
+ crate::pagerank::NOVELTY_WEIGHT
* ncomps.get("novelty").copied().unwrap_or(0.0);
assert!(
(n - expected).abs() < 0.002,
"{nname}: rendered {n:.6} != renormalized {expected:.6} (blend {blend:.6})"
);
}
let real = build_surface(
&ctx,
SurfaceRequest {
mode: SurfaceMode::Global,
budget: 100_000,
explain: true,
policy: SurfacePolicy::defaults(100_000),
semantic: Some(&NameScorer {
target: "beta_fn",
score: 1.0,
}),
},
);
let blocks = explain_blocks(&real.text);
assert_eq!(blocks.len(), 2);
assert_eq!(blocks[0].0, "beta_fn", "semantic 10% must rerank beta first");
let a = blocks
.iter()
.find(|(n, _)| *n == "alpha_fn")
.and_then(|(_, c)| c.get("importance").copied())
.unwrap();
let b = blocks
.iter()
.find(|(n, _)| *n == "beta_fn")
.and_then(|(_, c)| c.get("importance").copied())
.unwrap();
assert!(
(b - a - crate::pagerank::SEMANTIC_WEIGHT).abs() < 0.002,
"beta must lead alpha by the real 10%: {b:.6} - {a:.6}"
);
assert_eq!(none_blocks[0].0, "alpha_fn");
assert_eq!(none.rendered_ids[0], alpha);
assert_eq!(real.rendered_ids[0], beta);
}
#[test]
fn pathological_required_entry_compresses_to_symbol_identity() {
let (_dir, store) = pathological_signature_fixture();
let ctx = make_ctx(&store);
let hard_max = 20usize;
let out = build_surface(
&ctx,
SurfaceRequest {
mode: SurfaceMode::Global,
budget: 1,
explain: false,
policy: SurfacePolicy {
quotas: true,
mmr: true,
coverage: true,
hard_max,
},
semantic: None,
},
);
assert_eq!(out.rendered_ids.len(), 1, "the required entry is never dropped");
assert!(out.text.contains("function big_fn"), "identity line must render");
assert!(
!out.text.contains("def big_fn("),
"the 400-arg signature must be dropped at the identity level"
);
assert!(
out.token_count <= hard_max,
"hard-max invariant on the rendered text: {} > {hard_max}",
out.token_count
);
}
}