axiom_graph_drift_query

axiom_graph.mcp.server.axiom_graph_drift_query(project_root, filter=None, location_glob=None, group_by=None, format=None, page=0, limit=100, include_frozen=False)

Filtered/grouped/paginated projection over the persisted staleness inventory.

This is the read-only companion to axiom_graph_check. check answers “how much drift is there?” in one summary line; this answers “what are the specific drifted nodes (or distribution / IDs)?” with pagination so large drift volumes don’t overflow the tool-result cap.

Parameters:
project_root str

Absolute path to the indexed project.

filter str | None

Status filter. None (all own + link problem statuses), "staleness" (own + LINKED_STALE only), "links" (LINKED_STALE + BROKEN_LINK), "all" (every own + link problem status), or any individual status name (CONTENT_UPDATED, DESC_UPDATED, RENAMED, NOT_FOUND, LINKED_STALE, BROKEN_LINK). The DOC_SECTION_LONG advisory is not addressable here – it lives on a different table and is summarised by axiom_graph_check.

location_glob str | None

fnmatch-style path glob (** for recursive) applied to nodes.level_3_location (falling back to location). E.g. "axiom_graph/viz/**". Filters BEFORE grouping; grouped counts reflect the post-filter slice.

group_by str | None

Optional grouping axis. One of:

  • None – flat row list (paginated).

  • "status" – group by own/link status pair.

  • "location_prefix" – group by 2-component path prefix (axiom_graph/viz, axiom_graph/index, …).

  • "feature" – group by inbound documents-edge feature ancestor (docs.features.{X} in the doc tree). Nodes with no inbound documents edge bucket as (undocumented); never silently dropped.

format str | None

Projection. None (the default) resolves to "full" when ungrouped and "counts" when group_by is set – so an aggregate call returns a compact distribution rather than dumping every full row. Explicit values:

  • "full"id, own_status, link_status, location, via.

  • "ids" – newline-delimited IDs (or {group, ids} per group when group_by is set).

  • "counts"{group, count} per group. Only valid with group_by.

page int

Zero-indexed page number (page * limit -> OFFSET). Applies to full and ids on both the flat and grouped paths; grouped pagination is over the flat (pre-group) row set ordered by id, then re-grouped within the page, so groups may span page boundaries. counts is a bounded distribution and is never paginated.

limit int

Page size (default 100).

include_frozen bool

When False (the default), rows under docs tagged in config.staleness.frozen_tags are excluded from output, except BROKEN_LINK rows which are retained with a [frozen-source] postfix on format='full'. When True all rows are returned, with a [frozen] postfix on frozen rows in format='full'. Markers never appear on format='ids' or format='counts'.

Returns:

Newline-delimited textual representation of the projection. The full and ids projections are prefixed with a [N of M drifted nodes] count header (with a (pass page=<next> for next page) hint when more rows remain), matching the sibling paginated tools. Shapes:

  • flat full: count header, # column header, then id  own/link  location  via=... per line.

  • flat ids: count header, then bare node IDs.

  • grouped counts: group  count per line (no header; unpaginated).

  • grouped ids: count header, then [group] + indented IDs.

  • grouped full: count header, # column header, then [group] + indented full rows.

Returns "(no matches)" when the post-filter slice is empty, and "(page out of range)" when page paginates past the end of an otherwise non-empty slice (both the flat and grouped full/ids paths).

Raises:

ValueError – invalid filter, group_by, format, or format='counts' without group_by.

Return type:

str