Skip to content

Add opt-in grouped/directory-based mode to get_architecture (#90) - #93

Merged
AliRezaTaleghani merged 2 commits into
mainfrom
architecture-grouped-navigation
Aug 27, 2026
Merged

AliRezaTaleghani merged 2 commits into
mainfrom
architecture-grouped-navigation

Conversation

@AliRezaTaleghani

Copy link
Copy Markdown
Contributor

What

Adds an opt-in grouped/directory-based mode to get_architecture (issue
#90): in addition to the existing flat node/edge summary, optionally
groups the graph by directory and reports per-directory node counts plus
which directories actually call into which.

Schema

get_architecture MCP tool gains two new optional parameters:

  • grouped (boolean, default false)
  • depth (integer, default 1, clamped via the existing
    clamp_depth/SERVER_MAX_DEPTH)

When grouped=false (the default): response is the exact same JSON the
tool has always returned, taking the exact same code path
(index::get_architecture) and cache key it always has.

When grouped=true: response gains a grouped object:

{
  "total_nodes": 42,
  "total_edges": 61,
  "busiest_files": [ ...unchanged... ],
  "language_breakdown": [ ...unchanged... ],
  "grouped": {
    "depth": 1,
    "groups": [
      { "path": "pkg/a", "total_nodes": 2, "node_counts": [{ "kind": "Function", "count": 2 }] },
      { "path": "pkg/b", "total_nodes": 1, "node_counts": [{ "kind": "Function", "count": 1 }] }
    ],
    "within_group_edges": 1,
    "cross_group_edges": [
      { "from": "pkg/a", "to": "pkg/b", "count": 1 }
    ]
  },
  "index_freshness": { ... }
}

Reuse, not a new subsystem

Per the issue's explicit guidance ("investigate what's cheaply derivable
from the existing graph without new indexing infrastructure... do not
attempt automatic subsystem/layer detection"), this builds entirely on
data already in nodes/edges:

  • GraphStore::directory_groups(depth) groups every node by the first
    depth components of its existing file_path's parent directory, and
    classifies every edge as within-group or cross-group by looking up its
    two endpoints' groups - one pass over nodes, one over edges, no new
    tables, no new extraction pass.
  • get_architecture_grouped(repo_path, depth) shares one GraphStore::open
    call with the flat summary via a factored-out architecture_summary
    helper, so both paths compute the flat half identically.
  • depth is named/clamped the same way trace_call_path/detect_changes's
    blast_radius mode ([Feature] Blast-radius mode for detect_changes (impact analysis) #89, in review as Add opt-in blast-radius mode to detect_changes (#89) #92) clamp their own depth
    parameter - no new bound was invented.
  • Grouping is purely path-based - path is always the literal directory
    string, never a guessed subsystem/layer label. See ADR 0017.

Default-behavior-unchanged guarantee

crates/nexus-index/src/queries.rs::get_architecture is now a thin
wrapper around a shared architecture_summary helper that also backs the
grouped path - get_architecture's own signature/behavior is otherwise
untouched. The MCP handler's grouped=false branch calls that same
get_architecture and never touches directory_groups at all, and uses
a distinct cache-key suffix so a grouped=true call can never serve a
stale flat-only cache entry or vice versa.

Verified by:

  • get_architecture_default_output_is_unchanged_by_the_grouped_mode_existing
    (crates/nexus-index/tests/path_security.rs) - asserts the plain
    get_architecture(&repo) call and the flat half of
    get_architecture_grouped(&repo, 2) agree exactly on a real graph.db.
  • The pre-existing get_architecture_enforces_allowed_roots integration
    test still passes unmodified; a matching
    get_architecture_grouped_enforces_allowed_roots test covers the new
    function.

Tests

  • directory_group_key_* - path-grouping boundary cases (nested depth,
    depth beyond actual nesting, no-parent-directory files).
  • groups_nodes_by_top_level_directory_with_per_kind_counts,
    counts_within_group_calls_separately_from_the_one_cross_group_call,
    a_directory_with_no_calls_reports_zero_cross_group_involvement
    (crates/nexus-index/src/graph.rs) - a synthetic three-directory
    fixture (pkg/a and pkg/b each with dense internal calls, one call
    crossing pkg/a -> pkg/b, pkg/c isolated) confirms grouping and
    cross-group edge counts are both correct.
  • grouped_mode_reports_the_dense_internal_and_single_cross_directory_call
    (crates/nexus-index/tests/path_security.rs) - the same shape exercised
    end to end through the public get_architecture_grouped function.

Verification

  • cargo build --workspace - clean
  • cargo test --workspace - all green
  • cargo fmt --all -- --check - clean
  • cargo clippy --workspace --all-targets -- -D warnings - clean

Docs

  • docs/NexusContext-Wiki/MCP-Tools.md - get_architecture row updated
    with the new parameter/response shape (git-host-agnostic language - no
    comparison to any specific hosting service's UI).
  • docs/NexusContext-Wiki/ADRs/0017-grouped-architecture-view-is-path-based-not-semantic.md -
    new ADR recording the path-based-only decision and explicitly scoping
    out semantic subsystem/layer inference, per the issue's own instruction.

Closes #90.

https://claude.ai/code/session_01D6ND42psexN5cWTKewSpBG

Reuses every node's existing file_path - no new indexing/extraction -
matching #89's established opt-in-parameter, default-unchanged pattern.

- nexus-index: GraphStore::directory_groups(depth) groups nodes by the
  first depth components of their file_path's parent directory, and
  classifies every edge as within-group or cross-group by looking up
  its two endpoints' groups. get_architecture_grouped(repo_path, depth)
  wraps this alongside the existing flat ArchitectureSummary via a
  shared architecture_summary helper, so both paths compute the flat
  half identically off one GraphStore::open.
- nexusd: get_architecture tool gains grouped (bool, default false) and
  depth (integer, default 1, clamped via the existing clamp_depth).
  grouped=false takes the untouched pre-existing code path and cache
  key - same response shape and cost as before. grouped=true adds a
  grouped object: groups (path/total_nodes/node_counts by kind),
  within_group_edges, and cross_group_edges (from/to/count).
- Tests: directory_group_key boundary cases; a three-directory fixture
  (two with dense internal calls, one call crossing between them, one
  isolated) confirms grouping and cross-group edge counts; an
  allowed_roots regression test for get_architecture_grouped; a
  default-output-unchanged regression test comparing get_architecture
  against the flat half of get_architecture_grouped.
- Docs: MCP-Tools.md updated; ADR 0017 records the path-based-only
  decision and explicitly scopes out semantic subsystem/layer
  inference, per the issue's own instruction.

Closes #90.

Claude-Session: https://claude.ai/code/session_01D6ND42psexN5cWTKewSpBG
…navigation

# Conflicts:
#	crates/nexus-index/src/lib.rs
#	docs/NexusContext-Wiki/ADRs/README.md
@AliRezaTaleghani
AliRezaTaleghani merged commit 9a6de55 into main Aug 27, 2026
5 checks passed
@AliRezaTaleghani
AliRezaTaleghani deleted the architecture-grouped-navigation branch August 27, 2026 17:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Structural/grouped architecture navigation (get_architecture)

1 participant