From 458c879866ecb49aec317b3ca1bbbc9f55080fbe Mon Sep 17 00:00:00 2001 From: hardikuppal04 <262667963+hardikuppal04@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:16:13 +0530 Subject: [PATCH 1/2] refactor(intelligence): bound architecture snapshot reads (#133) --- apps/backend/app/analysis/architecture.py | 36 ++++----- .../backend/app/intelligence/query_service.py | 78 +++++++++++++------ .../tests/test_architecture_relationships.py | 40 ++++++++++ docs/architecture/REPOSITORY_INTELLIGENCE.md | 9 ++- 4 files changed, 118 insertions(+), 45 deletions(-) diff --git a/apps/backend/app/analysis/architecture.py b/apps/backend/app/analysis/architecture.py index 635bc04..a8259a2 100644 --- a/apps/backend/app/analysis/architecture.py +++ b/apps/backend/app/analysis/architecture.py @@ -1,7 +1,11 @@ import posixpath from app.intelligence.engine import RepositoryIntelligenceEngine -from app.intelligence.query_service import ArchitectureSnapshotFacts, SnapshotQueryService +from app.intelligence.query_service import ( + ARCHITECTURE_RELATIONSHIP_EDGE_TYPES, + ArchitectureSnapshotFacts, + SnapshotQueryService, +) from app.intelligence.models import RepositoryModule from app.models.repository import RepositoryRecord from app.models.snapshot import RiDiagnostic, RiEvidence, RiNode @@ -35,15 +39,6 @@ "unknown": "shared-library", } -RELATIONSHIP_EDGE_TYPES = { - "imports": "import", - "calls": "calls", - "routes_to": "api-call", - "implements": "dependency", - "depends_on": "dependency", -} - - class ArchitectureAnalyzer: def __init__( self, @@ -79,7 +74,12 @@ def build_architecture(self, record: RepositoryRecord) -> ArchitectureResponse: repository_intelligence.discovery.primary_language if repository_intelligence is not None else "Unknown" ) entry_points = repository_intelligence.discovery.entry_points if repository_intelligence is not None else [] - facts = self.snapshots.architecture_facts(record.id) if self.snapshots is not None else None + module_paths = {self._normalize_path(path) for module in modules for path in module.files} + facts = ( + self.snapshots.architecture_facts(record.id, module_paths=module_paths) + if self.snapshots is not None + else None + ) nodes = self._nodes_for_modules(modules) nodes.extend(self._dependency_nodes(facts)) edges, diagnostics, unresolved_node_ids, covered_paths = self._edges_for_modules(modules, nodes, facts) @@ -161,7 +161,7 @@ def _dependency_nodes(self, facts: ArchitectureSnapshotFacts | None) -> list[Arc relationship_keys = { key for edge in facts.edges - if edge.predicate in RELATIONSHIP_EDGE_TYPES + if edge.predicate in ARCHITECTURE_RELATIONSHIP_EDGE_TYPES for key in (edge.subject_key, edge.object_key) } result: list[ArchNode] = [] @@ -220,13 +220,7 @@ def _edges_for_modules( # Inventory-only file nodes prove that a path exists, not that a # relationship-capable extractor ran. Count only evidence emitted by a # syntax/manifest producer so unsupported files cannot look isolated. - covered_paths = { - item.path - for evidence_by_fact in (facts.node_evidence, facts.observation_evidence) - for evidence in evidence_by_fact.values() - for item in evidence - if item.extractor != "repository-inventory" - } + covered_paths = facts.covered_paths for item in facts.diagnostics: if item.code not in {"RI-RES-UNRESOLVED", "RI-RES-AMBIGUOUS"}: @@ -239,7 +233,7 @@ def _edges_for_modules( edges: list[ArchEdge] = [] for fact in facts.edges: - if fact.predicate not in RELATIONSHIP_EDGE_TYPES: + if fact.predicate not in ARCHITECTURE_RELATIONSHIP_EDGE_TYPES: continue evidence_rows = facts.edge_evidence.get(fact.id, []) source_ids = self._architecture_endpoint_ids( @@ -333,7 +327,7 @@ def _edges_for_modules( id=edge_id, source=source, target=target, - type=RELATIONSHIP_EDGE_TYPES[fact.predicate], # type: ignore[arg-type] + type=ARCHITECTURE_RELATIONSHIP_EDGE_TYPES[fact.predicate], # type: ignore[arg-type] label=fact.predicate.replace("_", " "), predicate=fact.predicate, truth_class="inferred", diff --git a/apps/backend/app/intelligence/query_service.py b/apps/backend/app/intelligence/query_service.py index cc0ebcc..5419ab4 100644 --- a/apps/backend/app/intelligence/query_service.py +++ b/apps/backend/app/intelligence/query_service.py @@ -1,6 +1,7 @@ """Read-only, owner-scoped queries over sealed ``ri.v1`` snapshots (#92).""" from collections import defaultdict +from collections.abc import Collection from dataclasses import dataclass from sqlalchemy import func, or_, select @@ -19,18 +20,27 @@ ) +ARCHITECTURE_RELATIONSHIP_EDGE_TYPES = { + "imports": "import", + "calls": "calls", + "routes_to": "api-call", + "implements": "dependency", + "depends_on": "dependency", +} +ARCHITECTURE_EVIDENCE_PATH_BATCH_SIZE = 500 + + @dataclass(frozen=True) class ArchitectureSnapshotFacts: """Persisted facts needed to build evidence-backed architecture relationships.""" snapshot: RiSnapshot nodes: list[RiNode] - observations: list[RiObservation] edges: list[RiEdge] node_evidence: dict[int, list[RiEvidence]] - observation_evidence: dict[int, list[RiEvidence]] edge_evidence: dict[int, list[RiEvidence]] diagnostics: list[RiDiagnostic] + covered_paths: set[str] class SnapshotQueryService: @@ -45,7 +55,12 @@ def __init__(self, db: Session, owner_id: str) -> None: def metadata(self, snapshot_id: str) -> RiSnapshot: return self._snapshot(snapshot_id) - def architecture_facts(self, repository_id: str) -> ArchitectureSnapshotFacts | None: + def architecture_facts( + self, + repository_id: str, + *, + module_paths: Collection[str], + ) -> ArchitectureSnapshotFacts | None: """Return the newest sealed snapshot facts for an owner-scoped repository. This internal consumer query uses the normalized store behind the public @@ -56,26 +71,27 @@ def architecture_facts(self, repository_id: str) -> ArchitectureSnapshotFacts | snapshot = self._latest_snapshot(repository_id) if snapshot is None: return None - nodes = list( - self.db.scalars( - select(RiNode) - .where(RiNode.snapshot_id == snapshot.snapshot_id) - .order_by(RiNode.stable_key, RiNode.id) - ).all() - ) edges = list( self.db.scalars( select(RiEdge) - .where(RiEdge.snapshot_id == snapshot.snapshot_id) + .where( + RiEdge.snapshot_id == snapshot.snapshot_id, + RiEdge.predicate.in_(ARCHITECTURE_RELATIONSHIP_EDGE_TYPES), + ) .order_by(RiEdge.subject_key, RiEdge.predicate, RiEdge.object_key, RiEdge.edge_id, RiEdge.id) ).all() ) - observations = list( - self.db.scalars( - select(RiObservation) - .where(RiObservation.snapshot_id == snapshot.snapshot_id) - .order_by(RiObservation.observation_id, RiObservation.id) - ).all() + endpoint_keys = {key for edge in edges for key in (edge.subject_key, edge.object_key)} + nodes = ( + list( + self.db.scalars( + select(RiNode) + .where(RiNode.snapshot_id == snapshot.snapshot_id, RiNode.stable_key.in_(endpoint_keys)) + .order_by(RiNode.stable_key, RiNode.id) + ).all() + ) + if endpoint_keys + else [] ) diagnostics = list( self.db.scalars( @@ -89,19 +105,15 @@ def architecture_facts(self, repository_id: str) -> ArchitectureSnapshotFacts | ) ).all() ) + covered_paths = self._architecture_covered_paths(snapshot, module_paths) return ArchitectureSnapshotFacts( snapshot=snapshot, nodes=nodes, - observations=observations, edges=edges, node_evidence=self._evidence_for(snapshot, "node_ref", [node.id for node in nodes]), - observation_evidence=self._evidence_for( - snapshot, - "observation_ref", - [observation.id for observation in observations], - ), edge_evidence=self._evidence_for(snapshot, "edge_ref", [edge.id for edge in edges]), diagnostics=diagnostics, + covered_paths=covered_paths, ) def symbols(self, snapshot_id: str, *, offset: int, limit: int) -> tuple[RiSnapshot, list[RiNode], int]: @@ -281,6 +293,26 @@ def _page(self, model, where: tuple, order_by: tuple, offset: int, limit: int): rows = self.db.scalars(select(model).where(*where).order_by(*order_by).offset(offset).limit(limit)).all() return list(rows), total + def _architecture_covered_paths(self, snapshot: RiSnapshot, module_paths: Collection[str]) -> set[str]: + """Return only module paths with non-inventory extraction evidence.""" + + paths = sorted(set(module_paths)) + covered_paths: set[str] = set() + for start in range(0, len(paths), ARCHITECTURE_EVIDENCE_PATH_BATCH_SIZE): + covered_paths.update( + self.db.scalars( + select(RiEvidence.path) + .where( + RiEvidence.snapshot_id == snapshot.snapshot_id, + RiEvidence.path.in_(paths[start : start + ARCHITECTURE_EVIDENCE_PATH_BATCH_SIZE]), + RiEvidence.extractor != "repository-inventory", + or_(RiEvidence.node_ref.is_not(None), RiEvidence.observation_ref.is_not(None)), + ) + .distinct() + ).all() + ) + return covered_paths + def _evidence_for(self, snapshot: RiSnapshot, column: str, ids: list[int]) -> dict[int, list[RiEvidence]]: if not ids: return {} diff --git a/apps/backend/tests/test_architecture_relationships.py b/apps/backend/tests/test_architecture_relationships.py index 5b8dace..b21bc06 100644 --- a/apps/backend/tests/test_architecture_relationships.py +++ b/apps/backend/tests/test_architecture_relationships.py @@ -7,6 +7,7 @@ from app.extraction.manifests import DependencyManifestExtractor from app.extraction.pipeline import ExtractionPipeline from app.extraction.typescript import TypeScriptExtractor +from app.intelligence.query_service import SnapshotQueryService from app.intelligence.resolution import RelationshipResolver from app.intelligence.snapshot_store import Evidence, Revision, SnapshotStore from app.models.repository import RepositoryRecord @@ -253,6 +254,45 @@ def test_architecture_reports_resolved_facts_without_module_mapping(auth_client) assert diagnostic["nodeIds"] == ["module:beta"] +def test_architecture_fact_query_excludes_irrelevant_large_snapshot_records(auth_client): + """Architecture reads relationship facts, not every stored snapshot record.""" + + sources = { + "src/alpha/index.ts": b"import { beta } from '../beta';\nexport const alpha = beta;\n", + "src/beta/index.ts": b"export function beta() { return 1; }\n", + } + snapshot_sources = { + **sources, + **{ + f"src/generated/{index}.ts": f"export const generated{index} = {index};\n".encode() + for index in range(64) + }, + } + repository = _upload(auth_client, sources) + _persist_snapshot(repository["id"], sources, snapshot_sources=snapshot_sources) + + from app.core.database import SessionLocal + + with SessionLocal() as session: + record = session.get(RepositoryRecord, repository["id"]) + assert record is not None + module_paths = set(sources) | {f"src/untracked/{index}.ts" for index in range(1_000)} + facts = SnapshotQueryService(session, record.owner_id).architecture_facts( + record.id, + module_paths=module_paths, + ) + + assert facts is not None + assert [edge.predicate for edge in facts.edges] == ["imports"] + assert {node.stable_key for node in facts.nodes} == { + "file:src/alpha/index.ts", + "file:src/beta/index.ts", + } + assert set(facts.node_evidence) == {node.id for node in facts.nodes} + assert set(facts.edge_evidence) == {edge.id for edge in facts.edges} + assert facts.covered_paths == set(sources) + + def test_architecture_without_snapshot_does_not_claim_isolation(auth_client): # Leave the analysis job queued (worker not drained) so no snapshot is sealed: # this exercises the genuine "no sealed snapshot" architecture response, which diff --git a/docs/architecture/REPOSITORY_INTELLIGENCE.md b/docs/architecture/REPOSITORY_INTELLIGENCE.md index 1ef2a44..dee27f2 100644 --- a/docs/architecture/REPOSITORY_INTELLIGENCE.md +++ b/docs/architecture/REPOSITORY_INTELLIGENCE.md @@ -148,7 +148,14 @@ the canonical graph hash, and seals the snapshot. Completed snapshots reject mutation. The query API exposes sealed snapshot metadata, symbols, stored resolved relationships, inferred assertions, file facts, and evidence spans. Architecture relationship construction uses its owner-scoped persisted-fact -query; other product consumers remain on the legacy model. +query; other product consumers remain on the legacy model. Its snapshot read is +bounded to resolved relationship predicates rendered by Architecture, their +endpoint nodes and evidence, all surfaced diagnostics, and distinct covered +module paths from non-inventory node or observation evidence, queried in bounded +path batches. It does not hydrate the full node, observation, or evidence +inventories for a large snapshot. The Architecture response remains proportional +to the relationships and diagnostics it exposes; this is a targeted read, not +API pagination. --- From 5e7a9defe671b920f0043f8008b5edeefdda161b Mon Sep 17 00:00:00 2001 From: hardikuppal04 <262667963+hardikuppal04@users.noreply.github.com> Date: Thu, 23 Jul 2026 11:56:13 +0530 Subject: [PATCH 2/2] fix(intelligence): batch architecture evidence reads --- apps/backend/app/analysis/architecture.py | 9 ++- .../backend/app/intelligence/query_service.py | 50 +++++++----- .../tests/test_architecture_relationships.py | 81 ++++++++++++++++++- docs/architecture/REPOSITORY_INTELLIGENCE.md | 12 +-- 4 files changed, 121 insertions(+), 31 deletions(-) diff --git a/apps/backend/app/analysis/architecture.py b/apps/backend/app/analysis/architecture.py index a8259a2..6c9b45c 100644 --- a/apps/backend/app/analysis/architecture.py +++ b/apps/backend/app/analysis/architecture.py @@ -2,6 +2,7 @@ from app.intelligence.engine import RepositoryIntelligenceEngine from app.intelligence.query_service import ( + ARCHITECTURE_DIAGNOSTIC_CODES, ARCHITECTURE_RELATIONSHIP_EDGE_TYPES, ArchitectureSnapshotFacts, SnapshotQueryService, @@ -215,7 +216,11 @@ def _edges_for_modules( modules_by_file.setdefault(self._normalize_path(path), []).append(module.id) snapshot_node_by_key = {item.stable_key: item for item in facts.nodes} node_ids = {node.id for node in nodes} - diagnostics = [self._architecture_diagnostic(item, modules_by_file, node_ids) for item in facts.diagnostics] + diagnostics = [ + self._architecture_diagnostic(item, modules_by_file, node_ids) + for item in facts.diagnostics + if item.code in ARCHITECTURE_DIAGNOSTIC_CODES + ] unresolved_node_ids: set[str] = set() # Inventory-only file nodes prove that a path exists, not that a # relationship-capable extractor ran. Count only evidence emitted by a @@ -223,7 +228,7 @@ def _edges_for_modules( covered_paths = facts.covered_paths for item in facts.diagnostics: - if item.code not in {"RI-RES-UNRESOLVED", "RI-RES-AMBIGUOUS"}: + if item.code not in ARCHITECTURE_DIAGNOSTIC_CODES: continue if item.path: unresolved_node_ids.update(modules_by_file.get(self._normalize_path(item.path), [])) diff --git a/apps/backend/app/intelligence/query_service.py b/apps/backend/app/intelligence/query_service.py index 5419ab4..917eb80 100644 --- a/apps/backend/app/intelligence/query_service.py +++ b/apps/backend/app/intelligence/query_service.py @@ -27,7 +27,8 @@ "implements": "dependency", "depends_on": "dependency", } -ARCHITECTURE_EVIDENCE_PATH_BATCH_SIZE = 500 +ARCHITECTURE_DIAGNOSTIC_CODES = frozenset({"RI-RES-UNRESOLVED", "RI-RES-AMBIGUOUS"}) +ARCHITECTURE_EVIDENCE_BATCH_SIZE = 500 @dataclass(frozen=True) @@ -96,7 +97,10 @@ def architecture_facts( diagnostics = list( self.db.scalars( select(RiDiagnostic) - .where(RiDiagnostic.snapshot_id == snapshot.snapshot_id) + .where( + RiDiagnostic.snapshot_id == snapshot.snapshot_id, + RiDiagnostic.code.in_(ARCHITECTURE_DIAGNOSTIC_CODES), + ) .order_by( RiDiagnostic.path, RiDiagnostic.span_start_line, @@ -298,13 +302,13 @@ def _architecture_covered_paths(self, snapshot: RiSnapshot, module_paths: Collec paths = sorted(set(module_paths)) covered_paths: set[str] = set() - for start in range(0, len(paths), ARCHITECTURE_EVIDENCE_PATH_BATCH_SIZE): + for start in range(0, len(paths), ARCHITECTURE_EVIDENCE_BATCH_SIZE): covered_paths.update( self.db.scalars( select(RiEvidence.path) .where( RiEvidence.snapshot_id == snapshot.snapshot_id, - RiEvidence.path.in_(paths[start : start + ARCHITECTURE_EVIDENCE_PATH_BATCH_SIZE]), + RiEvidence.path.in_(paths[start : start + ARCHITECTURE_EVIDENCE_BATCH_SIZE]), RiEvidence.extractor != "repository-inventory", or_(RiEvidence.node_ref.is_not(None), RiEvidence.observation_ref.is_not(None)), ) @@ -317,22 +321,26 @@ def _evidence_for(self, snapshot: RiSnapshot, column: str, ids: list[int]) -> di if not ids: return {} field = getattr(RiEvidence, column) - rows = self.db.scalars( - select(RiEvidence) - .where(RiEvidence.snapshot_id == snapshot.snapshot_id, field.in_(ids)) - .order_by( - RiEvidence.path, - RiEvidence.start_line, - RiEvidence.end_line, - RiEvidence.granularity, - RiEvidence.extractor, - RiEvidence.extractor_version, - RiEvidence.id, - ) - ).all() grouped: dict[int, list[RiEvidence]] = defaultdict(list) - for row in rows: - parent = getattr(row, column) - if parent is not None: - grouped[parent].append(row) + for start in range(0, len(ids), ARCHITECTURE_EVIDENCE_BATCH_SIZE): + rows = self.db.scalars( + select(RiEvidence) + .where( + RiEvidence.snapshot_id == snapshot.snapshot_id, + field.in_(ids[start : start + ARCHITECTURE_EVIDENCE_BATCH_SIZE]), + ) + .order_by( + RiEvidence.path, + RiEvidence.start_line, + RiEvidence.end_line, + RiEvidence.granularity, + RiEvidence.extractor, + RiEvidence.extractor_version, + RiEvidence.id, + ) + ).all() + for row in rows: + parent = getattr(row, column) + if parent is not None: + grouped[parent].append(row) return grouped diff --git a/apps/backend/tests/test_architecture_relationships.py b/apps/backend/tests/test_architecture_relationships.py index b21bc06..ba0ae29 100644 --- a/apps/backend/tests/test_architecture_relationships.py +++ b/apps/backend/tests/test_architecture_relationships.py @@ -4,10 +4,12 @@ import shutil import zipfile +from sqlalchemy import event + from app.extraction.manifests import DependencyManifestExtractor from app.extraction.pipeline import ExtractionPipeline from app.extraction.typescript import TypeScriptExtractor -from app.intelligence.query_service import SnapshotQueryService +from app.intelligence.query_service import ARCHITECTURE_EVIDENCE_BATCH_SIZE, SnapshotQueryService from app.intelligence.resolution import RelationshipResolver from app.intelligence.snapshot_store import Evidence, Revision, SnapshotStore from app.models.repository import RepositoryRecord @@ -45,6 +47,7 @@ def _persist_snapshot( sources: dict[str, bytes], *, snapshot_sources: dict[str, bytes] | None = None, + extra_unrendered_diagnostics: int = 0, ) -> str: from app.core.database import SessionLocal @@ -101,6 +104,17 @@ def _persist_snapshot( details=diagnostic.details, ) RelationshipResolver(store).resolve(snapshot) + for index in range(extra_unrendered_diagnostics): + store.add_diagnostic( + snapshot, + code="RI-TS-PARSE", + category="syntax extraction", + severity="info", + message=f"Irrelevant parser diagnostic {index}.", + producer="relationship-resolver@1.0.0", + path=f"src/generated/{index}.ts", + span=(1, 1), + ) return store.seal(snapshot).snapshot_id @@ -269,7 +283,12 @@ def test_architecture_fact_query_excludes_irrelevant_large_snapshot_records(auth }, } repository = _upload(auth_client, sources) - _persist_snapshot(repository["id"], sources, snapshot_sources=snapshot_sources) + _persist_snapshot( + repository["id"], + sources, + snapshot_sources=snapshot_sources, + extra_unrendered_diagnostics=64, + ) from app.core.database import SessionLocal @@ -290,8 +309,66 @@ def test_architecture_fact_query_excludes_irrelevant_large_snapshot_records(auth } assert set(facts.node_evidence) == {node.id for node in facts.nodes} assert set(facts.edge_evidence) == {edge.id for edge in facts.edges} + assert facts.diagnostics == [] assert facts.covered_paths == set(sources) + response = auth_client.get(f"/analysis/{repository['id']}/architecture") + assert response.status_code == 200, response.text + assert not any(item["code"] == "RI-TS-PARSE" for item in response.json()["diagnostics"]) + + +def test_architecture_fact_query_batches_relevant_evidence_ids(auth_client): + """Architecture evidence reads stay below the configured SQL parameter bound.""" + + sources = { + "src/target.ts": b"export const target = 1;\n", + **{ + f"src/importers/{index}.ts": ( + b"import { target } from '../target';\n" + + f"export const importer{index} = target;\n".encode() + ) + for index in range(ARCHITECTURE_EVIDENCE_BATCH_SIZE + 1) + }, + } + repository = _upload(auth_client, sources, analyse=False) + _persist_snapshot(repository["id"], sources) + + from app.core.database import SessionLocal + + with SessionLocal() as session: + record = session.get(RepositoryRecord, repository["id"]) + assert record is not None + evidence_query_parameter_counts: list[int] = [] + + def record_evidence_batch(_conn, _cursor, statement, parameters, _context, _executemany): + if "FROM ri_evidence" not in statement: + return + if "ri_evidence.node_ref IN" not in statement and "ri_evidence.edge_ref IN" not in statement: + return + evidence_query_parameter_counts.append(len(parameters)) + + event.listen(session.bind, "before_cursor_execute", record_evidence_batch) + try: + facts = SnapshotQueryService(session, record.owner_id).architecture_facts( + record.id, + module_paths=sources, + ) + finally: + event.remove(session.bind, "before_cursor_execute", record_evidence_batch) + + assert facts is not None + assert len(facts.edges) == ARCHITECTURE_EVIDENCE_BATCH_SIZE + 1 + assert len(facts.nodes) == ARCHITECTURE_EVIDENCE_BATCH_SIZE + 2 + assert len(facts.node_evidence) == len(facts.nodes) + assert len(facts.edge_evidence) == len(facts.edges) + assert sorted(evidence_query_parameter_counts) == [ + 2, + 3, + ARCHITECTURE_EVIDENCE_BATCH_SIZE + 1, + ARCHITECTURE_EVIDENCE_BATCH_SIZE + 1, + ] + assert max(evidence_query_parameter_counts) <= ARCHITECTURE_EVIDENCE_BATCH_SIZE + 1 + def test_architecture_without_snapshot_does_not_claim_isolation(auth_client): # Leave the analysis job queued (worker not drained) so no snapshot is sealed: diff --git a/docs/architecture/REPOSITORY_INTELLIGENCE.md b/docs/architecture/REPOSITORY_INTELLIGENCE.md index dee27f2..d379520 100644 --- a/docs/architecture/REPOSITORY_INTELLIGENCE.md +++ b/docs/architecture/REPOSITORY_INTELLIGENCE.md @@ -150,12 +150,12 @@ resolved relationships, inferred assertions, file facts, and evidence spans. Architecture relationship construction uses its owner-scoped persisted-fact query; other product consumers remain on the legacy model. Its snapshot read is bounded to resolved relationship predicates rendered by Architecture, their -endpoint nodes and evidence, all surfaced diagnostics, and distinct covered -module paths from non-inventory node or observation evidence, queried in bounded -path batches. It does not hydrate the full node, observation, or evidence -inventories for a large snapshot. The Architecture response remains proportional -to the relationships and diagnostics it exposes; this is a targeted read, not -API pagination. +endpoint nodes and evidence, the resolution diagnostics Architecture renders, +and distinct covered module paths from non-inventory node or observation +evidence. Evidence ID and path queries use bounded batches. It does not hydrate +the full node, observation, evidence, or diagnostic inventories for a large +snapshot. The Architecture response remains proportional to the relationships +and diagnostics it exposes; this is a targeted read, not API pagination. ---