diff --git a/docs/cli.md b/docs/cli.md
index 20177909..00d2583f 100644
--- a/docs/cli.md
+++ b/docs/cli.md
@@ -152,6 +152,28 @@ nyx scan --engine-profile deep --no-smt --explain-engine

+### Dynamic verification
+
+Available with `--features dynamic`. See [dynamic.md](dynamic.md) for the full pipeline and verdict semantics.
+
+| Flag | Default | Description |
+|------|---------|-------------|
+| `--verify` | on | Enable dynamic verification (default when built with `dynamic`). Conflicts with `--no-verify` |
+| `--no-verify` | off | Skip verification for this run. Useful for fast static-only scans without editing config |
+| `--verify-all-confidence` | off | Also verify findings below `Confidence >= Medium`. Slower; intended for payload tuning |
+| `--backend ` | `auto` | Sandbox backend: `auto` (docker if available, else process), `docker` (required), `process` (in-process runner) |
+| `--unsafe-sandbox` | off | Force the process backend. Equivalent to `--backend process`. Cannot combine with `--backend docker` |
+| `--harden ` | `standard` | Process-backend lockdown: `standard` (no-new-privs + rlimit on Linux) or `strict` (namespaces + chroot + seccomp on Linux; `sandbox-exec` on macOS) |
+| `--verbose` | off | Flush the per-finding `VerifyTrace` to stderr after each verdict. Same stream that lands in `expected/trace.jsonl` in the repro bundle |
+
+### Baseline / patch validation
+
+| Flag | Default | Description |
+|------|---------|-------------|
+| `--baseline ` | *(none)* | Read a prior scan's JSON (or a stripped `.nyx/baseline.json`) and diff it against this scan on `stable_hash`. Reports `New` / `Resolved` / `FlippedConfirmed` / `FlippedNotConfirmed` transitions |
+| `--baseline-write ` | *(none)* | After scanning, write a stripped baseline (only `stable_hash`, `dynamic_verdict`, `severity`, `path`, `rule_id`; no source). Safe to commit |
+| `--gate ` | *(none)* | CI gate to enforce when `--baseline` is active. `no-new-confirmed` exits 2 on any new Confirmed finding; `resolve-all-confirmed` exits 2 if any baseline-Confirmed finding is not fully resolved |
+
### Examples
```bash
@@ -248,6 +270,44 @@ Remove index data.
---
+## `nyx surface`
+
+Print the project's attack-surface map.
+
+```
+nyx surface [PATH] [--format ] [--build]
+```
+
+Loads the `SurfaceMap` persisted by the most recent indexed scan when available; otherwise runs the per-language framework probes against the on-disk source to produce an entry-points-only map. Pass `--build` to force a full inline build (pass-1 summary extraction + call-graph construction) on an unscanned project, which adds `DataStore` / `ExternalService` / `DangerousLocal` nodes the entry-points-only fallback omits.
+
+| Flag | Default | Description |
+|------|---------|-------------|
+| `--format ` | `text` | Output format: `text` (indented tree), `json` (canonical SurfaceMap), `dot` (Graphviz source), or `svg` (spawns `dot` locally) |
+| `--build` | off | Force a full SurfaceMap build inline when no indexed scan exists. Same cost as `nyx index build` |
+
+Pipe `dot` output through `dot -Tsvg` for a renderable graph, or use `--format svg` for a one-step render when graphviz is installed.
+
+---
+
+## `nyx verify-feedback`
+
+Record a correction or confirmation against a dynamic-verifier verdict. Requires `--features dynamic`.
+
+```
+nyx verify-feedback [--wrong | --right] [--upload]
+```
+
+| Argument/Flag | Description |
+|---------------|-------------|
+| `FINDING_ID` | Stable 16-char hex id shown in `nyx scan --verify` output |
+| `--wrong ` | Mark the verdict wrong and record the reason. Conflicts with `--right` |
+| `--right` | Confirm the verdict. Conflicts with `--wrong` |
+| `--upload` | Reserved; uploading to Nyx telemetry is not yet implemented |
+
+Feedback is written to the local telemetry log under the platform cache dir.
+
+---
+
## `nyx config`
Manage configuration.
diff --git a/src/callgraph.rs b/src/callgraph.rs
index 4393a0e6..884b3ace 100644
--- a/src/callgraph.rs
+++ b/src/callgraph.rs
@@ -29,7 +29,6 @@ use std::path::{Path, PathBuf};
pub struct CallEdge {
/// The raw callee string as it appeared in source (e.g. `"env::var"`).
/// Preserved for diagnostics, **not** the normalized form used for resolution.
- #[allow(dead_code)] // used for future diagnostics and path display
pub call_site: String,
}
@@ -56,7 +55,6 @@ pub struct AmbiguousCallee {
pub struct CallGraph {
pub graph: DiGraph,
/// `FuncKey → NodeIndex` for quick lookup.
- #[allow(dead_code)] // used for future topo-ordered analysis and call-graph queries
pub index: HashMap,
/// Callee strings that could not be resolved to any [`FuncKey`].
pub unresolved_not_found: Vec,
@@ -262,19 +260,6 @@ impl ClassMethodIndex {
}
}
- /// Number of distinct `(lang, container, method)` keys. Exposed
- /// for diagnostics / tests; production code uses [`Self::resolve`].
- #[allow(dead_code)]
- pub fn container_keys_len(&self) -> usize {
- self.by_container.len()
- }
-
- /// Number of distinct `(lang, method)` keys. Exposed for
- /// diagnostics / tests.
- #[allow(dead_code)]
- pub fn name_keys_len(&self) -> usize {
- self.by_name.len()
- }
}
// ── Type hierarchy index ────────────────────────────────────────────────
@@ -294,11 +279,6 @@ impl ClassMethodIndex {
pub struct TypeHierarchyIndex {
/// `(lang, super_type)` → distinct sub-type / impl container names.
by_super: HashMap<(Lang, String), SmallVec<[String; 4]>>,
- /// `(lang, sub_type)` → super-types this type extends / implements.
- /// Future use for `super.method()` resolution; populated for
- /// completeness today.
- #[allow(dead_code)]
- by_sub: HashMap<(Lang, String), SmallVec<[String; 2]>>,
}
impl TypeHierarchyIndex {
@@ -309,7 +289,6 @@ impl TypeHierarchyIndex {
/// summary) collapse via the membership check.
pub fn build(summaries: &GlobalSummaries) -> Self {
let mut by_super: HashMap<(Lang, String), SmallVec<[String; 4]>> = HashMap::new();
- let mut by_sub: HashMap<(Lang, String), SmallVec<[String; 2]>> = HashMap::new();
for (key, summary) in summaries.iter() {
let lang = key.lang;
@@ -321,14 +300,10 @@ impl TypeHierarchyIndex {
if !subs.iter().any(|s| s == sub) {
subs.push(sub.clone());
}
- let sups = by_sub.entry((lang, sub.clone())).or_default();
- if !sups.iter().any(|s| s == sup) {
- sups.push(sup.clone());
- }
}
}
- TypeHierarchyIndex { by_super, by_sub }
+ TypeHierarchyIndex { by_super }
}
/// Return the distinct sub-type / impl container names for
@@ -342,16 +317,6 @@ impl TypeHierarchyIndex {
.unwrap_or_default()
}
- /// Return the recorded super-types of `sub_type`. Empty when
- /// `sub_type` has no recorded super-types in this language.
- #[allow(dead_code)]
- pub fn supers_of(&self, lang: Lang, sub_type: &str) -> &[String] {
- self.by_sub
- .get(&(lang, sub_type.to_string()))
- .map(|v| v.as_slice())
- .unwrap_or_default()
- }
-
/// Number of distinct `(lang, super_type)` keys. Exposed for
/// diagnostics / tests.
#[allow(dead_code)]
diff --git a/src/cli.rs b/src/cli.rs
index 3d28e1ae..c116646a 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -359,7 +359,6 @@ pub enum Commands {
#[arg(long, help_heading = "Output")]
require_converged: bool,
- // ── Analysis engine toggles (override [analysis.engine] config) ───
/// Enable path-constraint solving (default: on)
#[arg(
long,
@@ -448,7 +447,6 @@ pub enum Commands {
#[arg(long, help_heading = "Limits")]
max_pointsto: Option,
- // ── Deprecated aliases (hidden) ─────────────────────────────────
/// Deprecated: use --index off
#[arg(long, hide = true)]
no_index: bool,
@@ -532,7 +530,6 @@ pub enum Commands {
)]
harden: Option,
- // Baseline / patch-validation
/// Read a previous scan's JSON output (or a stripped .nyx/baseline.json)
/// and diff it against the current scan on stable_hash.
///