mod common;
#[test]
fn startup_artifact_has_all_sections_and_is_deterministic() {
let repo = common::copy_fixture("cli-service");
let dir = common::workdir(repo.path());
common::run_ok(&dir, &["index", "--quiet"]);
let first = common::run_ok(&dir, &["context", "startup"]);
for header in [
"# SCC SYSTEM CONTEXT",
"## SYSTEM ATLAS",
"## REPOSITORY SKELETON",
"## SYSTEM SURFACE MAP",
"## MODEL COVERAGE",
"## OMISSIONS",
] {
assert!(first.contains(header), "missing {header:?} in startup output");
}
assert!(
first.contains("sha256:"),
"startup must carry the artifact hash: {first}"
);
let second = common::run_ok(&dir, &["context", "startup"]);
assert_eq!(first, second, "startup must be byte-identical across runs");
}
#[test]
fn surface_shows_component_grouped_api_map() {
let repo = common::copy_fixture("cli-service");
let dir = common::workdir(repo.path());
common::run_ok(&dir, &["index", "--quiet"]);
let out = common::run_ok(&dir, &["surface"]);
assert!(out.contains("serve"), "surface must mention serve: {out}");
assert!(out.contains("deploy"), "surface must mention deploy: {out}");
assert!(!out.is_empty(), "surface output must not be empty");
}
#[test]
fn surface_task_personalizes_the_map() {
let repo = common::copy_fixture("cli-service");
let dir = common::workdir(repo.path());
common::run_ok(&dir, &["index", "--quiet"]);
let out = common::run_ok(&dir, &["surface", "--task", "serve"]);
assert!(
out.contains("task-personalized"),
"task surface must carry the personalized header: {out}"
);
assert!(out.contains("serve"), "task surface must mention serve: {out}");
}
#[test]
fn surface_explain_appends_rank_reasons() {
let repo = common::copy_fixture("cli-service");
let dir = common::workdir(repo.path());
common::run_ok(&dir, &["index", "--quiet"]);
let plain = common::run_ok(&dir, &["surface"]);
let explained = common::run_ok(&dir, &["surface", "--explain"]);
assert!(
explained.contains("importance:"),
"--explain must append per-entry importance: {explained}"
);
for key in [
"task_ppr:",
"global_ppr:",
"lexical:",
"semantic:",
"confidence:",
"criticality:",
"change_risk:",
"novelty:",
"because:",
] {
assert!(
explained.contains(key),
"--explain must render the {key:?} component: {explained}"
);
}
assert_ne!(
plain, explained,
"--explain output must differ from the plain render"
);
}
#[test]
fn context_task_appends_task_delta_when_goal_matches() {
let repo = common::copy_fixture("cli-service");
let dir = common::workdir(repo.path());
common::run_ok(&dir, &["index", "--quiet"]);
let out = common::run_ok(&dir, &["context", "task", "serve"]);
assert!(out.contains("# SCC TASK DELTA"), "missing TASK DELTA: {out}");
assert!(out.contains("TASK-FOCUS: serve"), "missing TASK-FOCUS: {out}");
}
fn with_cli_compiler<T>(
dir: &std::path::Path,
f: impl FnOnce(&scc_store::Store, &scc_cli::Compiler) -> T,
) -> T {
let store = scc_store::Store::open(&dir.join(".scc").join("scc.db"), dir).unwrap();
let comp = scc_cli::compiler(&store, &scc_indexer::Config::default(), Vec::new()).unwrap();
f(&store, &comp)
}
#[test]
fn startup_rank_cache_persists_and_is_reused_across_runs() {
let repo = common::copy_fixture("cli-service");
let dir = common::workdir(repo.path());
common::run_ok(&dir, &["index", "--quiet"]);
common::run_ok(&dir, &["context", "startup"]);
common::run_ok(&dir, &["context", "startup"]);
with_cli_compiler(&dir, |store, comp| {
let ctx = comp.ctx();
let cache = scc_context::startup::load_global_rank_cache(&ctx)
.expect("rank cache entry must exist after the first startup");
assert!(
cache.hits >= 1,
"the second startup must reuse the cache (hits marker {} >= 1)",
cache.hits
);
let epoch = store.cache_epoch().unwrap();
assert_eq!(cache.epoch, epoch, "cache epoch pins the model epoch");
assert_eq!(cache.candidates_epoch, epoch, "candidates are epoch-stable");
assert!(
!cache.candidate_ids.is_empty(),
"epoch-stable candidate id list cached"
);
assert!(
!cache.node_symbol_map.is_empty(),
"global projection map cached"
);
});
}
#[test]
fn important_lists_badged_symbols_with_exact_counts() {
let repo = common::copy_fixture("cli-service");
let dir = common::workdir(repo.path());
common::run_ok(&dir, &["index", "--quiet"]);
let out = common::run_ok(&dir, &["important", "--limit", "5"]);
assert!(out.contains("## SYSTEM-CRITICAL SYMBOLS"), "{out}");
let js = common::run_ok(&dir, &["important", "--limit", "5", "--json"]);
let entries: serde_json::Value = serde_json::from_str(&js).expect("json");
let arr = entries.as_array().expect("array");
assert!(!arr.is_empty(), "must rank symbols");
let first = &arr[0];
assert!(first.get("caller_count").and_then(|v| v.as_u64()).is_some(), "exact count kept");
assert!(first.get("importance").and_then(|v| v.get("badges")).and_then(|v| v.as_array()).is_some(), "badges derived");
let tout = common::run_ok(&dir, &["important", "--task", "serve http", "--limit", "3"]);
assert!(tout.contains("## TASK-CRITICAL SYMBOLS"), "{tout}");
let startup = common::run_ok(&dir, &["context", "startup"]);
assert!(startup.contains("## SYSTEM-CRITICAL SYMBOLS"), "{startup}");
}
#[test]
fn startup_ledger_records_the_same_render_it_printed() {
let repo = common::copy_fixture("cli-service");
let dir = common::workdir(repo.path());
common::run_ok(&dir, &["index", "--quiet"]);
let out = common::run_ok(&dir, &["context", "startup"]);
with_cli_compiler(&dir, |store, comp| {
let ctx = comp.ctx();
let budget = scc_context::startup::allocate_startup_budget(&ctx, None);
let sc = scc_context::startup::build_startup(
&ctx,
&budget,
scc_context::startup::RENDERER_VERSION,
);
assert_eq!(
out,
scc_context::startup::render_startup(&sc),
"CLI startup output must match the deterministic rebuild"
);
for id in &sc.surface_render.rendered_ids {
let symbol = id
.rsplit_once("#overload")
.map(|(l, _)| l)
.unwrap_or(id);
let name = symbol.rsplit('/').next().unwrap_or(symbol);
assert!(
out.contains(name),
"printed startup must contain rendered entry {id}"
);
}
let (syms, files, comps, flows) =
scc_context::startup::visible_ids_from_startup(&ctx, &sc);
let ledger_store = scc_context::context_ledger::ContextLedgerStore::new(store);
let led = ledger_store.load();
assert_eq!(
led.visible_symbols, syms,
"ledger symbols must match the render-derived visible set"
);
assert_eq!(
led.visible_files, files,
"ledger files must match the render-derived visible set"
);
assert_eq!(
led.visible_components, comps,
"ledger components must match the render-derived visible set"
);
assert_eq!(
led.visible_flows, flows,
"ledger flows must match the render-derived visible set"
);
});
}
#[test]
fn startup_budget_adapts_to_repo_complexity() {
let repo = common::copy_fixture("cli-service");
let dir = common::workdir(repo.path());
common::run_ok(&dir, &["index", "--quiet"]);
let out = common::run_ok(&dir, &["context", "startup", "--budget", "20000"]);
assert!(
out.contains("(budget 9000)"),
"tiny repo must get the 45% surface share (budget 9000): {out}"
);
let tiny = scc_core::ContextBudget::adaptive(20_000, 50, 2, 1, 10);
let large = scc_core::ContextBudget::adaptive(20_000, 6_000, 5, 1, 10);
assert_ne!(tiny.surface, large.surface, "tiny vs large splits differ");
assert!(
(tiny.surface as f64 / tiny.total as f64 - 0.45).abs() <= 0.01,
"tiny surface share is 45%"
);
assert!(
(large.surface as f64 / large.total as f64 - 0.35).abs() <= 0.01,
"large surface share is 35%"
);
}