use scc_context::startup::allocate_startup_budget;
use scc_context::surface::{build_surface, SurfacePolicy, SurfaceRequest, SurfaceMode};
use scc_core::{entity_id, estimate_tokens, relationship_id, symbol_id, kinds, predicates, ContextBudget};
use scc_core::{Entity, Provenance, Relationship};
use scc_store::Store;
struct Fixture {
_dir: tempfile::TempDir,
store: Store,
}
fn fixture() -> Fixture {
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();
Fixture { _dir: dir, store }
}
#[allow(clippy::too_many_arguments)] fn add_symbol(
f: &Fixture,
rid: &mut u64,
path: &str,
comp_id: &str,
name: &str,
sig: Option<&str>,
exported: bool,
extra: impl FnOnce(&mut Entity),
) -> String {
let repo = f.store.repo_id.clone();
let fid = entity_id(&repo, kinds::FILE, path);
if f.store.get_entity(&fid).unwrap().is_none() {
f.store.insert_entity(&Entity::new(fid.clone(), kinds::FILE, path), &[path.to_string()]).unwrap();
f.store.insert_relationship(
&Relationship::new(relationship_id(*rid), comp_id.to_string(), predicates::CONTAINS, fid.clone(), Provenance::Extracted),
path,
).unwrap();
*rid += 1;
}
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("exported", serde_json::json!(exported));
e.attr("start_line", serde_json::json!(1u32));
e.attr("end_line", serde_json::json!(10u32));
if let Some(s) = sig {
e.attr("signature", serde_json::json!(s));
}
extra(&mut e);
f.store.insert_entity(&e, &[path.to_string()]).unwrap();
*rid += 1;
f.store.insert_relationship(
&Relationship::new(relationship_id(*rid), fid.clone(), predicates::CONTAINS, id.clone(), Provenance::Extracted),
path,
).unwrap();
id
}
fn compiler(f: &Fixture) -> scc_context::ContextCompiler<'_> {
let graph = Box::leak(Box::new(scc_graph::RealityGraph::load(&f.store).unwrap()));
scc_context::ContextCompiler::new(&f.store, graph, Default::default(), Vec::new())
}
#[test]
fn hard_max_holds_when_header_overhead_dominates() {
let f = fixture();
let repo = f.store.repo_id.clone();
let mut rid: u64 = 1;
for i in 0..800usize {
let comp_id = entity_id(&repo, kinds::COMPONENT, &format!("c{i}"));
f.store.replace_components(&[Entity::new(comp_id.clone(), kinds::COMPONENT, format!("comp{i}"))]).unwrap();
add_symbol(&f, &mut rid, &format!("m{i}/a.py"), &comp_id, &format!("fn{i}"), Some("def fn(i): pass"), true, |_| ());
}
let ctx = compiler(&f);
let budget = 900;
let policy = SurfacePolicy::defaults(budget);
let result = build_surface(&ctx, SurfaceRequest {
mode: SurfaceMode::Global,
budget,
explain: false,
policy,
semantic: None,
});
assert!(
estimate_tokens(&result.text) <= policy.hard_max,
"final render {} exceeded hard_max {}",
estimate_tokens(&result.text),
policy.hard_max
);
}
#[test]
fn enormous_required_signature_is_compressed_to_fit() {
let f = fixture();
let repo = f.store.repo_id.clone();
let comp_id = entity_id(&repo, kinds::COMPONENT, "api");
f.store.replace_components(&[Entity::new(comp_id.clone(), kinds::COMPONENT, "api")]).unwrap();
let mut rid: u64 = 1;
let huge = format!("pub fn mega({}) -> Result<(), Error> {{}}", "arg: VeryLongTypeName, ".repeat(600));
let mega_id = add_symbol(&f, &mut rid, "api/huge.py", &comp_id, "mega", Some(&huge), true, |_| ());
let route_id = entity_id(&repo, kinds::ROUTE, "rt-mega");
let mut rt = Entity::new(route_id, kinds::ROUTE, "rt-mega");
rt.attr("handler", serde_json::json!(mega_id));
rt.attr("method", serde_json::json!("GET"));
rt.attr("path", serde_json::json!("/mega"));
f.store.insert_entity(&rt, &[]).unwrap();
for i in 0..20 {
add_symbol(&f, &mut rid, "api/fill.py", &comp_id, &format!("fill{i}"), Some("def fill(): pass"), true, |_| ());
}
let ctx = compiler(&f);
let budget = 400;
let policy = SurfacePolicy::defaults(budget);
let result = build_surface(&ctx, SurfaceRequest {
mode: SurfaceMode::Global,
budget,
explain: false,
policy,
semantic: None,
});
assert!(
estimate_tokens(&result.text) <= policy.hard_max,
"enormous required signature blew the hard max: {} > {}",
estimate_tokens(&result.text),
policy.hard_max
);
}
#[test]
fn overflowing_required_set_yields_critical_drops() {
let f = fixture();
let repo = f.store.repo_id.clone();
let comp_id = entity_id(&repo, kinds::COMPONENT, "api");
f.store.replace_components(&[Entity::new(comp_id.clone(), kinds::COMPONENT, "api")]).unwrap();
let mut rid: u64 = 1;
let big = format!("pub fn big({}) -> () {{}}", "a: LongParamName, ".repeat(120));
let mut ids = Vec::new();
for i in 0..12 {
let id = add_symbol(&f, &mut rid, &format!("api/r{i}.py"), &comp_id, &format!("req{i}"), Some(&big), true, |_| ());
let route_id = entity_id(&repo, kinds::ROUTE, &format!("rt{i}"));
let mut rt = Entity::new(route_id, kinds::ROUTE, format!("rt{i}"));
rt.attr("handler", serde_json::json!(id));
rt.attr("method", serde_json::json!("GET"));
rt.attr("path", serde_json::json!(format!("/r{i}")));
f.store.insert_entity(&rt, &[]).unwrap();
ids.push(id);
}
let _ = ids;
let ctx = compiler(&f);
let budget = 300;
let policy = SurfacePolicy::defaults(budget);
let result = build_surface(&ctx, SurfaceRequest {
mode: SurfaceMode::Global,
budget,
explain: false,
policy,
semantic: None,
});
assert!(
estimate_tokens(&result.text) <= policy.hard_max,
"critical-drop path exceeded hard max: {} > {}",
estimate_tokens(&result.text),
policy.hard_max
);
assert!(
!result.rendered_ids.is_empty() || !result.critical_drops.is_empty(),
"pathological overflow must keep at least the top required entry"
);
}
#[test]
fn startup_allocator_default_is_adaptive_and_flow_aware() {
let f = fixture();
let repo = f.store.repo_id.clone();
let comp_id = entity_id(&repo, kinds::COMPONENT, "api");
f.store.replace_components(&[Entity::new(comp_id.clone(), kinds::COMPONENT, "api")]).unwrap();
let mut rid: u64 = 1;
for i in 0..40 {
let flow_id = entity_id(&repo, kinds::FLOW, &format!("flow{i}"));
f.store.insert_entity(&Entity::new(flow_id, kinds::FLOW, format!("flow{i}")), &[]).unwrap();
}
for i in 0..50 {
add_symbol(&f, &mut rid, "api/a.py", &comp_id, &format!("s{i}"), None, true, |_| ());
}
let ctx = compiler(&f);
let none_budget = allocate_startup_budget(&ctx, None);
let configured = allocate_startup_budget(&ctx, Some(ctx.settings.startup_tokens));
assert_eq!(none_budget.total, ctx.settings.startup_tokens, "None must use the configured startup ceiling, not the hardcoded default");
assert_eq!(none_budget, configured, "None must run the SAME adaptive split over the configured total");
assert_ne!(
none_budget.total,
ContextBudget::default().total,
"regression: the configured ceiling (6000 in fixtures) must differ from the hardcoded default total (20000), or this test cannot tell them apart"
);
let arch = ContextBudget::adaptive(20_000, 92, 2, 41, 10);
assert!(
arch.atlas as f64 / arch.total as f64 >= 0.65,
"architecture-heavy repo should give the atlas >=65%: got {}",
arch.atlas as f64 / arch.total as f64
);
let tiny = ContextBudget::adaptive(20_000, 92, 2, 0, 10);
assert!(
tiny.surface > arch.surface,
"flow-heavy repo must shift share toward the atlas"
);
let small = allocate_startup_budget(&ctx, Some(8_000));
assert_eq!(small.total, 8_000);
assert!(small.atlas + small.surface <= 8_000 + 1);
let tiny = ContextBudget::adaptive(20_000, 100, 2, 0, 10);
assert!(tiny.surface > arch.surface, "tiny repos keep the larger surface share");
}
#[test]
fn fused_startup_respects_final_hard_max() {
let f = fixture();
let repo = f.store.repo_id.clone();
let mut rid: u64 = 1;
for c in 0..12usize {
let comp_id = entity_id(&repo, kinds::COMPONENT, &format!("c{c}"));
f.store.replace_components(&[Entity::new(comp_id.clone(), kinds::COMPONENT, format!("comp{c}"))]).unwrap();
for s in 0..5usize {
let sig = format!("def fn_{c}_{s}(arg_{s}: VeryLongTypeName_{s}, other: AnotherDescender) -> Result<(), Error>: ...");
add_symbol(&f, &mut rid, &format!("pkg{c}/mod{s}.py"), &comp_id, &format!("sym{c}_{s}"), Some(&sig), true, |_| ());
}
}
let ctx = compiler(&f);
let budget = ContextBudget { total: 1024, atlas: 900, surface: 900, task_delta: 0, structural_source: 0 };
let startup = scc_context::startup::build_startup(&ctx, &budget, scc_context::startup::RENDERER_VERSION);
let hard_max = budget.total.saturating_add((budget.total / 5).max(500));
let actual = estimate_tokens(&startup.artifact.text);
eprintln!("IMP={} SURF={} ATLAS={} OM={:?}", startup.important.len(), startup.surface.len(), startup.atlas.len(), startup.omissions);
assert!(
actual <= hard_max,
"fused startup artifact {} tokens exceeds hard_max {} (headers included)",
actual,
hard_max
);
if !startup.surface_render.omitted_ids.is_empty() {
let omission_text: String = startup.omissions.join("\n");
assert!(
omission_text.contains("lower-ranked definitions omitted"),
"OMISSIONS must report the omitted count when ids were dropped: {:?}",
startup.omissions
);
}
assert!(
startup.artifact.text.contains(&startup.surface),
"artifact text must embed the final surface render"
);
}