codegraph-engine 2.1.2__py3-none-any.whl → 2.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. codegraph/__init__.py +1 -1
  2. codegraph/agent_brain.py +1961 -0
  3. codegraph/agent_capabilities.py +3500 -0
  4. codegraph/agent_rules.py +530 -0
  5. codegraph/architecture.py +48 -5
  6. codegraph/binding_resolver.py +616 -0
  7. codegraph/cli.py +345 -5
  8. codegraph/config.py +2 -0
  9. codegraph/context.py +845 -93
  10. codegraph/database/__init__.py +58 -0
  11. codegraph/database/extractor.py +2956 -0
  12. codegraph/database/interrogation.py +1085 -0
  13. codegraph/database/models.py +310 -0
  14. codegraph/epistemic.py +95 -0
  15. codegraph/errors.py +7 -0
  16. codegraph/evidence/citations.py +22 -1
  17. codegraph/evidence_contract.py +455 -0
  18. codegraph/frameworks.py +372 -11
  19. codegraph/git.py +92 -10
  20. codegraph/graph/models.py +15 -0
  21. codegraph/graph/traversal.py +680 -121
  22. codegraph/indexing/__init__.py +15 -1
  23. codegraph/indexing/classifier.py +343 -58
  24. codegraph/indexing/indexer.py +1515 -141
  25. codegraph/indexing/models.py +75 -0
  26. codegraph/indexing/parser.py +1843 -70
  27. codegraph/indexing/scanner.py +4 -1
  28. codegraph/indexing/telemetry.py +326 -0
  29. codegraph/installer.py +1652 -0
  30. codegraph/interrogation.py +708 -122
  31. codegraph/mcp/server.py +525 -107
  32. codegraph/mcp_diagnostics.py +879 -0
  33. codegraph/models.py +14 -0
  34. codegraph/monorepo.py +922 -0
  35. codegraph/observability.py +113 -2
  36. codegraph/optimizer.py +647 -42
  37. codegraph/ranking.py +61 -16
  38. codegraph/resolver.py +2006 -77
  39. codegraph/resources/monitor.py +1 -1
  40. codegraph/retrieval_policy.py +96 -17
  41. codegraph/route_composer.py +363 -0
  42. codegraph/runtime/__init__.py +32 -0
  43. codegraph/runtime/ingestor.py +672 -0
  44. codegraph/runtime/models.py +130 -0
  45. codegraph/runtime/reconciliation.py +492 -0
  46. codegraph/search/__init__.py +2 -0
  47. codegraph/search/hybrid.py +572 -53
  48. codegraph/security/__init__.py +50 -2
  49. codegraph/security/paths.py +162 -8
  50. codegraph/security/redaction.py +633 -0
  51. codegraph/semantic_decorators.py +341 -0
  52. codegraph/target_resolver.py +6 -6
  53. codegraph/tool_selection_eval.py +1158 -0
  54. codegraph_engine-2.1.7.dist-info/METADATA +617 -0
  55. codegraph_engine-2.1.7.dist-info/RECORD +84 -0
  56. {codegraph_engine-2.1.2.dist-info → codegraph_engine-2.1.7.dist-info}/licenses/LICENSE +1 -1
  57. codegraph_engine-2.1.2.dist-info/METADATA +0 -336
  58. codegraph_engine-2.1.2.dist-info/RECORD +0 -63
  59. {codegraph_engine-2.1.2.dist-info → codegraph_engine-2.1.7.dist-info}/WHEEL +0 -0
  60. {codegraph_engine-2.1.2.dist-info → codegraph_engine-2.1.7.dist-info}/entry_points.txt +0 -0
  61. {codegraph_engine-2.1.2.dist-info → codegraph_engine-2.1.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1961 @@
1
+ """Deep Agent Brain Generator, Relationship Metadata & Automated Documentation Validator (Phase 13).
2
+
3
+ Derives the three-layer Agent Brain documentation from authoritative code sources:
4
+ - `TOOL_CAPABILITY_REGISTRY`, `CAPABILITY_MATRIX`, `MCP_PROFILE_RECOMMENDATIONS` (`agent_capabilities.py`)
5
+ - `ALLOWED_EVIDENCE_CLASSES`, `ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX` (`evidence_contract.py`)
6
+ - `RETRIEVAL_POLICIES` (`retrieval_policy.py`)
7
+ - Actual MCP server tool signatures (`mcp/server.py`)
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import inspect
12
+ import re
13
+ import tempfile
14
+ from dataclasses import dataclass
15
+ from pathlib import Path
16
+
17
+ from codegraph import __version__
18
+ from codegraph.agent_capabilities import (
19
+ CAPABILITY_MATRIX,
20
+ MCP_PROFILE_RECOMMENDATIONS,
21
+ TOOL_CAPABILITY_REGISTRY,
22
+ AgentTaskCategory,
23
+ ToolCapabilitySpec,
24
+ )
25
+ from codegraph.evidence_contract import (
26
+ ALLOWED_EVIDENCE_CLASSES,
27
+ ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX,
28
+ )
29
+ from codegraph.retrieval_policy import RETRIEVAL_POLICIES
30
+
31
+
32
+ @dataclass(frozen=True)
33
+ class RelationshipSemanticsSpec:
34
+ """Authoritative documentation metadata for an actual relationship type in `ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX`."""
35
+
36
+ relationship: str
37
+ meaning: str
38
+ typical_source: str
39
+ typical_target: str
40
+ proves: str
41
+ does_not_prove: str
42
+ common_tool: str
43
+ example: str
44
+
45
+
46
+ RELATIONSHIP_SEMANTICS_REGISTRY: dict[str, RelationshipSemanticsSpec] = {
47
+ "CALLS": RelationshipSemanticsSpec(
48
+ relationship="CALLS",
49
+ meaning="Direct executable function, method, or constructor invocation proven by AST or conservative dataflow.",
50
+ typical_source="Function, method, or route handler symbol",
51
+ typical_target="Callee function, method, or class constructor",
52
+ proves="A call expression in the source symbol statically targets the callee symbol.",
53
+ does_not_prove="Does not prove that a conditional runtime branch is taken on a specific input.",
54
+ common_tool="get_callers / get_callees / trace_path",
55
+ example="`AuthService.authenticate` -> `CALLS` (`AST_VERIFIED`) -> `verify_password`",
56
+ ),
57
+ "CALLED_BY": RelationshipSemanticsSpec(
58
+ relationship="CALLED_BY",
59
+ meaning="Inverse of a verified `CALLS` edge (target is invoked by source caller).",
60
+ typical_source="Callee symbol",
61
+ typical_target="Caller symbol",
62
+ proves="The target symbol contains a verified call site invoking the source symbol.",
63
+ does_not_prove="Does not prove runtime execution frequency.",
64
+ common_tool="get_callers / analyze_impact",
65
+ example="`verify_password` -> `CALLED_BY` (`AST_VERIFIED`) -> `AuthService.authenticate`",
66
+ ),
67
+ "POSSIBLE_CALLS": RelationshipSemanticsSpec(
68
+ relationship="POSSIBLE_CALLS",
69
+ meaning="Candidate or dynamically dispatched call edge that is plausible (`POSSIBLE`) or unresolved (`UNKNOWN`).",
70
+ typical_source="Caller symbol using dynamic dispatch, interface, or conditional binding",
71
+ typical_target="Candidate target symbol or `<dynamic_target>`",
72
+ proves="A call site exists where static analysis found a candidate or unresolved dynamic target.",
73
+ does_not_prove="Never proves an authoritative `CALLS` edge without targeted source inspection.",
74
+ common_tool="get_callers / get_callees / get_context",
75
+ example="`dispatch_action` -> `POSSIBLE_CALLS` (`POSSIBLE`) -> `RefundHandler.handle`",
76
+ ),
77
+ "IMPORTS": RelationshipSemanticsSpec(
78
+ relationship="IMPORTS",
79
+ meaning="Module or symbol import statement extracted from syntax tree.",
80
+ typical_source="Importing file or module",
81
+ typical_target="Imported module or symbol",
82
+ proves="The source module contains an explicit import statement for the target.",
83
+ does_not_prove="Does not prove that the imported symbol is called at runtime.",
84
+ common_tool="get_imports / get_dependents",
85
+ example="`src/auth/routes.py` -> `IMPORTS` (`AST_VERIFIED`) -> `src.auth.service.AuthService`",
86
+ ),
87
+ "MOUNTS": RelationshipSemanticsSpec(
88
+ relationship="MOUNTS",
89
+ meaning="Application or parent router mounts a child router or sub-application under a URL prefix.",
90
+ typical_source="Root application or parent router (`app`, `api_router`)",
91
+ typical_target="Mounted sub-router (`auth_router`, `v1_router`)",
92
+ proves="Framework router composition (`include_router`, `register_blueprint`, `app.use`).",
93
+ does_not_prove="Does not prove direct function call semantics (`MOUNTS` is never collapsed into `CALLS`).",
94
+ common_tool="list_routes / get_architecture / trace_path",
95
+ example="`app` -> `MOUNTS` (`FRAMEWORK_VERIFIED`, prefix=`/api/v1`) -> `auth_router`",
96
+ ),
97
+ "ROUTE_HANDLER": RelationshipSemanticsSpec(
98
+ relationship="ROUTE_HANDLER",
99
+ meaning="Framework route decorator or registration binds an HTTP/RPC endpoint to its handler function.",
100
+ typical_source="Router or endpoint declaration",
101
+ typical_target="Handler function or controller method",
102
+ proves="The route is bound to the handler via recognized framework syntax.",
103
+ does_not_prove="Does not prove external reverse-proxy rewrites.",
104
+ common_tool="list_routes / get_context",
105
+ example="`POST /api/v1/auth/login` -> `ROUTE_HANDLER` (`FRAMEWORK_VERIFIED`) -> `login_endpoint`",
106
+ ),
107
+ "HANDLED_BY": RelationshipSemanticsSpec(
108
+ relationship="HANDLED_BY",
109
+ meaning="Canonical endpoint node is handled by the designated route handler symbol.",
110
+ typical_source="HTTP endpoint (`POST /api/v1/auth/login`)",
111
+ typical_target="Handler symbol (`login_endpoint`)",
112
+ proves="Requests matching the route path and HTTP method are routed to the handler.",
113
+ does_not_prove="Does not prove middleware short-circuiting prior to the handler.",
114
+ common_tool="list_routes / trace_path / get_context",
115
+ example="`POST /api/v1/auth/login` -> `HANDLED_BY` (`FRAMEWORK_VERIFIED`) -> `login_endpoint`",
116
+ ),
117
+ "ROUTES_TO": RelationshipSemanticsSpec(
118
+ relationship="ROUTES_TO",
119
+ meaning="URL dispatcher or route table entry routes a path pattern to a view or controller.",
120
+ typical_source="Route table or URL pattern",
121
+ typical_target="View function or class-based view",
122
+ proves="Static URL routing table connects the pattern to the target view.",
123
+ does_not_prove="Does not prove runtime query parameter validation.",
124
+ common_tool="list_routes / trace_path",
125
+ example="`/users/<id>` -> `ROUTES_TO` (`FRAMEWORK_VERIFIED`) -> `UserDetailView`",
126
+ ),
127
+ "REGISTERS": RelationshipSemanticsSpec(
128
+ relationship="REGISTERS",
129
+ meaning="Symbol or module registers a handler, plugin, or key into a registry or handler map.",
130
+ typical_source="Decorator, registration call, or module initializer",
131
+ typical_target="Registered handler symbol or registry container",
132
+ proves="Static registration into a registry object (`@registry.register`, `REGISTRY[k] = fn`).",
133
+ does_not_prove="Never proves a direct `CALLS` edge at registration time.",
134
+ common_tool="get_references / get_context",
135
+ example="`command_registry` -> `REGISTERS` (`DATAFLOW_VERIFIED`) -> `CreateInvoiceHandler`",
136
+ ),
137
+ "REGISTERED_HANDLER": RelationshipSemanticsSpec(
138
+ relationship="REGISTERED_HANDLER",
139
+ meaning="Links a registry key or registry container to the handler symbol registered for it.",
140
+ typical_source="Registry or dispatch key",
141
+ typical_target="Handler function or class",
142
+ proves="The handler is statically associated with the registry entry.",
143
+ does_not_prove="Does not prove when or how often the registry is invoked.",
144
+ common_tool="get_references / get_context",
145
+ example="`payment_registry['stripe']` -> `REGISTERED_HANDLER` (`DATAFLOW_VERIFIED`) -> `StripeGateway`",
146
+ ),
147
+ "DISPATCHES_TO": RelationshipSemanticsSpec(
148
+ relationship="DISPATCHES_TO",
149
+ meaning="Dispatcher function or registry lookup dispatches execution to a registered handler.",
150
+ typical_source="Dispatcher function (`dispatch_command`, `bus.publish`)",
151
+ typical_target="Target handler symbol (or `<dynamic_dispatch>` when key is runtime-only)",
152
+ proves="Dispatch mechanism connects the dispatcher to the registered target(s).",
153
+ does_not_prove="When `evidence_class='POSSIBLE'` or `'UNKNOWN'`, does not guarantee which runtime key is passed.",
154
+ common_tool="trace_path / get_references / get_context",
155
+ example="`dispatch_order_event` -> `DISPATCHES_TO` (`DATAFLOW_VERIFIED`) -> `on_order_created`",
156
+ ),
157
+ "EVENT_LISTENER": RelationshipSemanticsSpec(
158
+ relationship="EVENT_LISTENER",
159
+ meaning="Function or method subscribes to an event channel, signal, or domain event type.",
160
+ typical_source="Event type, signal, or event bus (`OrderCreated`, `user_logged_in`)",
161
+ typical_target="Listener function (`send_receipt_on_order`)",
162
+ proves="Framework or event-bus decorator/subscription binds the listener to the event.",
163
+ does_not_prove="Does not prove synchronous vs asynchronous runtime broker delivery.",
164
+ common_tool="get_references / trace_path / get_context",
165
+ example="`OrderCreated` -> `EVENT_LISTENER` (`FRAMEWORK_VERIFIED`) -> `notify_warehouse`",
166
+ ),
167
+ "TASK_HANDLER": RelationshipSemanticsSpec(
168
+ relationship="TASK_HANDLER",
169
+ meaning="Background task decorator (`@app.task`, `@shared_task`, `@dramatiq.actor`) marks a task entrypoint.",
170
+ typical_source="Task queue / broker decorator or `.delay` / `.apply_async` site",
171
+ typical_target="Task handler function (`send_welcome_email`)",
172
+ proves="The function is registered as an executable background task handler.",
173
+ does_not_prove="Does not prove broker queue availability at runtime.",
174
+ common_tool="trace_path / get_context / get_references",
175
+ example="`celery_app.task` -> `TASK_HANDLER` (`FRAMEWORK_VERIFIED`) -> `send_welcome_email`",
176
+ ),
177
+ "COMMAND_HANDLER": RelationshipSemanticsSpec(
178
+ relationship="COMMAND_HANDLER",
179
+ meaning="CLI or command-bus decorator (`@app.command`, `@click.command`) binds a CLI command to its handler.",
180
+ typical_source="CLI application or command group",
181
+ typical_target="Command handler function",
182
+ proves="CLI command registration in Typer, Click, or argparse.",
183
+ does_not_prove="Does not prove runtime CLI flag values.",
184
+ common_tool="get_context / get_references / trace_path",
185
+ example="`cli_app.command('migrate')` -> `COMMAND_HANDLER` (`FRAMEWORK_VERIFIED`) -> `run_migrations`",
186
+ ),
187
+ "INJECTS": RelationshipSemanticsSpec(
188
+ relationship="INJECTS",
189
+ meaning="Consumer endpoint, class, or function declares an injected dependency parameter (`Depends(provider)`, `@inject`).",
190
+ typical_source="Consumer function/class (`login_endpoint`, `UserController`)",
191
+ typical_target="Dependency provider or token (`get_auth_service`, `AuthService`)",
192
+ proves="The consumer receives the dependency through framework or container injection.",
193
+ does_not_prove="Never implies the consumer directly calls the provider as a normal helper (`INJECTS != CALLS`).",
194
+ common_tool="get_context / get_references / trace_path",
195
+ example="`login_endpoint` -> `INJECTS` (`FRAMEWORK_VERIFIED`) -> `get_auth_service`",
196
+ ),
197
+ "PROVIDES": RelationshipSemanticsSpec(
198
+ relationship="PROVIDES",
199
+ meaning="Dependency provider function or factory constructs/yields a concrete service or resource type.",
200
+ typical_source="Provider function or container binding (`get_auth_service`)",
201
+ typical_target="Provided type or implementation (`AuthService`)",
202
+ proves="The provider supplies instances of the target type to DI consumers.",
203
+ does_not_prove="Does not prove singleton vs request-scoped lifetime unless inspected in source.",
204
+ common_tool="get_context / get_references / trace_path",
205
+ example="`get_auth_service` -> `PROVIDES` (`FRAMEWORK_VERIFIED`) -> `AuthService`",
206
+ ),
207
+ "RESOLVES_DEPENDENCY": RelationshipSemanticsSpec(
208
+ relationship="RESOLVES_DEPENDENCY",
209
+ meaning="DI container or binding map resolves an abstract interface/token to a concrete implementation.",
210
+ typical_source="Interface, protocol, or DI token (`PaymentGateway`)",
211
+ typical_target="Concrete implementation (`StripePaymentGateway`)",
212
+ proves="Container binding (`container.bind`, `app.dependency_overrides`) maps token to implementation.",
213
+ does_not_prove="When multiple conditional bindings exist (`POSSIBLE`), does not prove which env branch is active.",
214
+ common_tool="get_context / get_references / trace_path",
215
+ example="`PaymentGateway` -> `RESOLVES_DEPENDENCY` (`DATAFLOW_VERIFIED`) -> `StripePaymentGateway`",
216
+ ),
217
+ "CONFIGURES": RelationshipSemanticsSpec(
218
+ relationship="CONFIGURES",
219
+ meaning="Settings object, environment config, or module initializer configures a service, router, or container.",
220
+ typical_source="Config class or initializer (`Settings`, `configure_di`)",
221
+ typical_target="Configured component or service",
222
+ proves="Static configuration wiring between config symbols and target components.",
223
+ does_not_prove="Does not expose secret `.env` values (sensitive files are blocked).",
224
+ common_tool="get_context / get_references",
225
+ example="`DatabaseSettings` -> `CONFIGURES` (`DATAFLOW_VERIFIED`) -> `create_engine_pool`",
226
+ ),
227
+ "DI_CYCLE": RelationshipSemanticsSpec(
228
+ relationship="DI_CYCLE",
229
+ meaning="Circular dependency detected across DI providers (`A -> B -> A`).",
230
+ typical_source="Provider symbol participating in cycle",
231
+ typical_target="Provider symbol completing the cycle",
232
+ proves="A static cycle exists in the provider dependency graph.",
233
+ does_not_prove="Does not prove whether lazy runtime resolution breaks the cycle.",
234
+ common_tool="get_context / get_references",
235
+ example="`provide_a` -> `DI_CYCLE` (`DATAFLOW_VERIFIED`) -> `provide_b`",
236
+ ),
237
+ "DEPENDS_ON_PACKAGE": RelationshipSemanticsSpec(
238
+ relationship="DEPENDS_ON_PACKAGE",
239
+ meaning="Manifest-backed workspace package declares a dependency on another workspace package.",
240
+ typical_source="Consumer workspace package (`@acme/api`, `apps/api`)",
241
+ typical_target="Target workspace package (`@acme/auth`, `packages/auth`)",
242
+ proves="Explicit dependency in `package.json`, `pyproject.toml`, `Cargo.toml`, or `go.mod`.",
243
+ does_not_prove="Never inferred from directory names alone without manifest evidence.",
244
+ common_tool="get_architecture / get_context / get_dependents",
245
+ example="`@acme/api` -> `DEPENDS_ON_PACKAGE` (`AST_VERIFIED`) -> `@acme/shared`",
246
+ ),
247
+ "PACKAGE_IMPORTS": RelationshipSemanticsSpec(
248
+ relationship="PACKAGE_IMPORTS",
249
+ meaning="Package-level rollup of source imports targeting another workspace package.",
250
+ typical_source="Source workspace package",
251
+ typical_target="Imported workspace package",
252
+ proves="Files inside the source package import modules owned by the target package.",
253
+ does_not_prove="Does not prove public API stability.",
254
+ common_tool="get_architecture / get_imports",
255
+ example="`packages/orders` -> `PACKAGE_IMPORTS` (`AST_VERIFIED`) -> `packages/shared`",
256
+ ),
257
+ "CROSS_PACKAGE_IMPORT": RelationshipSemanticsSpec(
258
+ relationship="CROSS_PACKAGE_IMPORT",
259
+ meaning="A source file in one workspace package imports a symbol or file across a package boundary.",
260
+ typical_source="Source file in Package A",
261
+ typical_target="Target file/symbol in Package B",
262
+ proves="Cross-package import crossing manifest-verified package boundaries.",
263
+ does_not_prove="Does not prove whether the import violates custom linter rules unless inspected.",
264
+ common_tool="get_imports / get_context",
265
+ example="`apps/web/src/client.ts` -> `CROSS_PACKAGE_IMPORT` (`AST_VERIFIED`) -> `packages/auth/src/index.ts`",
266
+ ),
267
+ "CONTAINS_PACKAGE": RelationshipSemanticsSpec(
268
+ relationship="CONTAINS_PACKAGE",
269
+ meaning="Workspace root or monorepo manifest contains a member workspace package.",
270
+ typical_source="Workspace root",
271
+ typical_target="Member package ID",
272
+ proves="Workspace membership declared by workspace configuration (`pnpm-workspace.yaml`, `package.json`, `pyproject.toml`).",
273
+ does_not_prove="Does not prove inter-package runtime calls.",
274
+ common_tool="get_architecture",
275
+ example="`workspace:root` -> `CONTAINS_PACKAGE` (`AST_VERIFIED`) -> `@acme/auth`",
276
+ ),
277
+ "TESTS": RelationshipSemanticsSpec(
278
+ relationship="TESTS",
279
+ meaning="Test function or test module exercises a production symbol or file.",
280
+ typical_source="Test function (`test_login_flow`)",
281
+ typical_target="Production symbol (`AuthService.authenticate`)",
282
+ proves="Static call, import, fixture, or route link from test to target symbol.",
283
+ does_not_prove="Does not prove that the test passes or covers 100% of branches.",
284
+ common_tool="find_related_tests / get_git_impact / get_context",
285
+ example="`test_login_route_flow` -> `TESTS` (`AST_VERIFIED`) -> `login_endpoint`",
286
+ ),
287
+ "TESTS_SYMBOL": RelationshipSemanticsSpec(
288
+ relationship="TESTS_SYMBOL",
289
+ meaning="Test function directly invokes or asserts against a production function, method, or class.",
290
+ typical_source="Test function",
291
+ typical_target="Production symbol",
292
+ proves="AST-verified call or reference from the test body to the production symbol.",
293
+ does_not_prove="Never fabricated from filename similarity alone.",
294
+ common_tool="find_related_tests / get_context",
295
+ example="`test_charge_card` -> `TESTS_SYMBOL` (`AST_VERIFIED`) -> `BillingService.charge_card`",
296
+ ),
297
+ "TESTS_ROUTE": RelationshipSemanticsSpec(
298
+ relationship="TESTS_ROUTE",
299
+ meaning="Test function sends an HTTP client request (`client.post('/api/v1/auth/login')`) to an indexed route.",
300
+ typical_source="Test function",
301
+ typical_target="Route endpoint or route handler",
302
+ proves="Test client call path matches an indexed framework route.",
303
+ does_not_prove="Does not prove external network integration.",
304
+ common_tool="find_related_tests / get_context",
305
+ example="`test_login_endpoint` -> `TESTS_ROUTE` (`FRAMEWORK_VERIFIED`) -> `POST /api/v1/auth/login`",
306
+ ),
307
+ "TESTS_PROVIDER": RelationshipSemanticsSpec(
308
+ relationship="TESTS_PROVIDER",
309
+ meaning="Test overrides or exercises a DI provider (`app.dependency_overrides[get_db] = ...`).",
310
+ typical_source="Test function or fixture",
311
+ typical_target="DI provider symbol",
312
+ proves="Test explicitly references or overrides the DI provider.",
313
+ does_not_prove="Does not prove production database behavior when provider is mocked.",
314
+ common_tool="find_related_tests / get_context",
315
+ example="`test_profile_with_mock_user` -> `TESTS_PROVIDER` (`FRAMEWORK_VERIFIED`) -> `get_current_user`",
316
+ ),
317
+ "TESTS_EVENT_HANDLER": RelationshipSemanticsSpec(
318
+ relationship="TESTS_EVENT_HANDLER",
319
+ meaning="Test publishes an event or directly invokes an event/task/command handler.",
320
+ typical_source="Test function",
321
+ typical_target="Event listener, task handler, or command handler",
322
+ proves="Static link between test and event/task handler.",
323
+ does_not_prove="Does not prove live message broker delivery.",
324
+ common_tool="find_related_tests / get_context",
325
+ example="`test_order_created_listener` -> `TESTS_EVENT_HANDLER` (`FRAMEWORK_VERIFIED`) -> `on_order_created`",
326
+ ),
327
+ "EXPORTS": RelationshipSemanticsSpec(
328
+ relationship="EXPORTS",
329
+ meaning="Module or package entrypoint explicitly exports a symbol (`__all__`, `export { X }`).",
330
+ typical_source="Module or package index file",
331
+ typical_target="Exported symbol",
332
+ proves="Public export declaration in module AST.",
333
+ does_not_prove="Does not prove external consumption outside the repo.",
334
+ common_tool="get_file / get_symbol",
335
+ example="`packages/auth/src/index.ts` -> `EXPORTS` (`AST_VERIFIED`) -> `AuthClient`",
336
+ ),
337
+ "REEXPORTS": RelationshipSemanticsSpec(
338
+ relationship="REEXPORTS",
339
+ meaning="Barrel file or `__init__.py` re-exports a symbol imported from an internal module.",
340
+ typical_source="Barrel module (`__init__.py`, `index.ts`)",
341
+ typical_target="Original symbol definition",
342
+ proves="Explicit re-export binding across modules.",
343
+ does_not_prove="Does not prove runtime execution.",
344
+ common_tool="resolve_symbol / get_imports",
345
+ example="`src/auth/__init__.py` -> `REEXPORTS` (`AST_VERIFIED`) -> `src/auth/service.py:AuthService`",
346
+ ),
347
+ "EXTENDS": RelationshipSemanticsSpec(
348
+ relationship="EXTENDS",
349
+ meaning="Class or interface inherits from a base class (`class Child(Base)` / `extends`).",
350
+ typical_source="Subclass symbol",
351
+ typical_target="Base class symbol",
352
+ proves="AST-verified class inheritance.",
353
+ does_not_prove="Does not prove dynamic metaclass mutation.",
354
+ common_tool="get_symbol / get_references",
355
+ example="`AdminUser` -> `EXTENDS` (`AST_VERIFIED`) -> `BaseUser`",
356
+ ),
357
+ "IMPLEMENTS": RelationshipSemanticsSpec(
358
+ relationship="IMPLEMENTS",
359
+ meaning="Class implements an interface, protocol, or abstract base class.",
360
+ typical_source="Concrete class symbol",
361
+ typical_target="Interface or Protocol symbol",
362
+ proves="Static `implements` or protocol inheritance relationship.",
363
+ does_not_prove="Does not prove structural duck-typing unless declared.",
364
+ common_tool="get_references / get_context",
365
+ example="`StripeGateway` -> `IMPLEMENTS` (`AST_VERIFIED`) -> `PaymentGateway`",
366
+ ),
367
+ "DEFINES": RelationshipSemanticsSpec(
368
+ relationship="DEFINES",
369
+ meaning="File or parent scope defines a class, function, method, or variable symbol.",
370
+ typical_source="Source file or parent class",
371
+ typical_target="Defined symbol",
372
+ proves="Exact AST declaration coordinates (`file`, `start_line`, `end_line`).",
373
+ does_not_prove="Does not prove who calls the symbol.",
374
+ common_tool="resolve_symbol / get_file / get_symbol",
375
+ example="`src/auth/service.py` -> `DEFINES` (`AST_VERIFIED`) -> `AuthService`",
376
+ ),
377
+ "CONTAINS": RelationshipSemanticsSpec(
378
+ relationship="CONTAINS",
379
+ meaning="Parent class or module scope lexically contains a child method or nested symbol.",
380
+ typical_source="Class or module symbol",
381
+ typical_target="Method or nested function symbol",
382
+ proves="Lexical AST scope containment.",
383
+ does_not_prove="Does not prove call order.",
384
+ common_tool="get_symbol / get_file",
385
+ example="`AuthService` -> `CONTAINS` (`AST_VERIFIED`) -> `AuthService.authenticate`",
386
+ ),
387
+ "RESOLVES_TO": RelationshipSemanticsSpec(
388
+ relationship="RESOLVES_TO",
389
+ meaning="Alias, import binding, or target reference resolves to its canonical symbol definition.",
390
+ typical_source="Local alias or imported reference",
391
+ typical_target="Canonical symbol definition",
392
+ proves="Deterministic name/dataflow resolution to a canonical target.",
393
+ does_not_prove="Does not prove runtime invocation.",
394
+ common_tool="resolve_symbol / get_references",
395
+ example="`auth_svc.authenticate` -> `RESOLVES_TO` (`DATAFLOW_VERIFIED`) -> `AuthService.authenticate`",
396
+ ),
397
+ "BINDS_TO": RelationshipSemanticsSpec(
398
+ relationship="BINDS_TO",
399
+ meaning="Local variable, attribute (`self.repo`), or parameter annotation binds to a concrete type or symbol.",
400
+ typical_source="Variable or attribute (`self.repo`)",
401
+ typical_target="Bound class or symbol (`UserRepository`)",
402
+ proves="Conservative intra-file or constructor dataflow binding.",
403
+ does_not_prove="Does not prove external runtime monkey-patching of the attribute.",
404
+ common_tool="get_context / get_references",
405
+ example="`AuthService.self.repo` -> `BINDS_TO` (`DATAFLOW_VERIFIED`) -> `UserRepository`",
406
+ ),
407
+ "ALIASED_TO": RelationshipSemanticsSpec(
408
+ relationship="ALIASED_TO",
409
+ meaning="Symbol or import is assigned an explicit alias (`import X as Y`, `HandlerAlias = RealHandler`).",
410
+ typical_source="Alias identifier",
411
+ typical_target="Original symbol",
412
+ proves="Static alias assignment in module or function scope.",
413
+ does_not_prove="Does not prove runtime reassignment if mutated dynamically.",
414
+ common_tool="resolve_symbol / get_references",
415
+ example="`LoginHandler` -> `ALIASED_TO` (`AST_VERIFIED`) -> `login_endpoint`",
416
+ ),
417
+ "REFERENCES": RelationshipSemanticsSpec(
418
+ relationship="REFERENCES",
419
+ meaning="Source symbol references another symbol (type annotation, constant read, decorator argument).",
420
+ typical_source="Referencing symbol",
421
+ typical_target="Referenced symbol",
422
+ proves="Static identifier reference in AST.",
423
+ does_not_prove="Does not prove an executable function call (`REFERENCES != CALLS`).",
424
+ common_tool="get_references",
425
+ example="`create_order` -> `REFERENCES` (`AST_VERIFIED`) -> `OrderCreateSchema`",
426
+ ),
427
+ "USES": RelationshipSemanticsSpec(
428
+ relationship="USES",
429
+ meaning="Symbol uses a type, trait, mixin, or configuration constant.",
430
+ typical_source="Consumer symbol",
431
+ typical_target="Used type or constant",
432
+ proves="Static usage in type signature or body.",
433
+ does_not_prove="Does not prove direct call execution.",
434
+ common_tool="get_references / get_context",
435
+ example="`TokenEncoder` -> `USES` (`AST_VERIFIED`) -> `JWT_ALGORITHM`",
436
+ ),
437
+ "DEPENDS_ON": RelationshipSemanticsSpec(
438
+ relationship="DEPENDS_ON",
439
+ meaning="General structural dependency edge between symbols or modules.",
440
+ typical_source="Dependent symbol or module",
441
+ typical_target="Dependency symbol or module",
442
+ proves="Static dependency backed by import, call, or DI evidence.",
443
+ does_not_prove="Check specific relationship subtype (`IMPORTS`, `INJECTS`, `CALLS`) for exact mechanism.",
444
+ common_tool="get_dependents / get_context",
445
+ example="`OrderService` -> `DEPENDS_ON` (`AST_VERIFIED`) -> `InventoryClient`",
446
+ ),
447
+ "UNRESOLVED_REFERENCE": RelationshipSemanticsSpec(
448
+ relationship="UNRESOLVED_REFERENCE",
449
+ meaning="A call, dispatch, or dependency site whose target could not be statically resolved (`UNKNOWN` or `POSSIBLE`).",
450
+ typical_source="Source symbol containing dynamic/unresolved expression",
451
+ typical_target="`<unresolved>` or candidate symbol name",
452
+ proves="A dynamic or unindexed reference exists at the cited file and line.",
453
+ does_not_prove="Never proves that no relationship exists at runtime.",
454
+ common_tool="get_context / get_references",
455
+ example="`PluginLoader.load` -> `UNRESOLVED_REFERENCE` (`UNKNOWN`) -> `<dynamic_getattr>`",
456
+ ),
457
+ "MAPS_TO_TABLE": RelationshipSemanticsSpec(
458
+ relationship="MAPS_TO_TABLE",
459
+ meaning="ORM model class maps to a canonical database table entity.",
460
+ typical_source="ORM model class (`User`, `Product`)",
461
+ typical_target="Canonical database table (`db.postgres.public.users`)",
462
+ proves="Explicit (`__tablename__`, `db_table`, `@@map`) or framework-inferred model-to-table mapping.",
463
+ does_not_prove="Does not prove that the table exists on an external unindexed database server.",
464
+ common_tool="find_db_models / get_db_table / find_db_relationships",
465
+ example="`Product` -> `MAPS_TO_TABLE` (`FRAMEWORK_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.products`",
466
+ ),
467
+ "MAPS_TO_COLUMN": RelationshipSemanticsSpec(
468
+ relationship="MAPS_TO_COLUMN",
469
+ meaning="ORM model attribute or field maps to a database table column.",
470
+ typical_source="ORM model field (`Product.shop_id`)",
471
+ typical_target="Canonical database column (`db.UNKNOWN.UNKNOWN.products.shop_id`)",
472
+ proves="Static ORM column declaration (`Column`, `mapped_column`, `models.Field`, `Field`).",
473
+ does_not_prove="Does not prove runtime column value constraints.",
474
+ common_tool="find_db_columns / get_db_table",
475
+ example="`Product.shop_id` -> `MAPS_TO_COLUMN` (`FRAMEWORK_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.products.shop_id`",
476
+ ),
477
+ "READS_TABLE": RelationshipSemanticsSpec(
478
+ relationship="READS_TABLE",
479
+ meaning="Function, method, or query reads rows from a database table (`SELECT`, `.query()`, `.objects.filter()`, `.findMany()`).",
480
+ typical_source="Function, repository method, or route handler",
481
+ typical_target="Canonical database table (`db.<dialect>.<schema>.<table>`)",
482
+ proves="Static SQL `SELECT` or ORM read query targeting the table (or `RUNTIME_OBSERVED` when seen in runtime traces).",
483
+ does_not_prove="Does not prove runtime cache hits or row counts.",
484
+ common_tool="find_db_readers / find_db_callers / find_db_queries / get_db_table",
485
+ example="`get_product` -> `READS_TABLE` (`FRAMEWORK_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.products`",
486
+ ),
487
+ "WRITES_TABLE": RelationshipSemanticsSpec(
488
+ relationship="WRITES_TABLE",
489
+ meaning="Function, method, or query mutates rows in a database table (`INSERT`, `UPDATE`, `DELETE`, `.add()`, `.create()`, `.save()`).",
490
+ typical_source="Service, repository method, or route handler",
491
+ typical_target="Canonical database table (`db.<dialect>.<schema>.<table>`)",
492
+ proves="Static SQL mutation or ORM write call targeting the table (or `RUNTIME_OBSERVED` in traces).",
493
+ does_not_prove="Does not prove whether a transaction commits or rolls back at runtime.",
494
+ common_tool="find_db_writers / find_db_callers / find_db_queries / get_db_impact",
495
+ example="`create_order` -> `WRITES_TABLE` (`STATIC_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.orders`",
496
+ ),
497
+ "READS_COLUMN": RelationshipSemanticsSpec(
498
+ relationship="READS_COLUMN",
499
+ meaning="Query or function explicitly selects or filters on a specific database column.",
500
+ typical_source="Function or query site",
501
+ typical_target="Canonical database column (`db.<dialect>.<schema>.<table>.<column>`)",
502
+ proves="Column reference in `SELECT` projection, `WHERE` filter, or ORM field access.",
503
+ does_not_prove="Does not prove index utilization at runtime.",
504
+ common_tool="find_db_readers / get_db_impact",
505
+ example="`find_by_email` -> `READS_COLUMN` (`STATIC_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.users.email`",
506
+ ),
507
+ "WRITES_COLUMN": RelationshipSemanticsSpec(
508
+ relationship="WRITES_COLUMN",
509
+ meaning="Query or function explicitly inserts or updates a specific database column.",
510
+ typical_source="Function or mutation query site",
511
+ typical_target="Canonical database column (`db.<dialect>.<schema>.<table>.<column>`)",
512
+ proves="Column assignment in `INSERT`, `UPDATE ... SET`, or ORM attribute mutation.",
513
+ does_not_prove="Does not expose literal parameter values (redacted for security).",
514
+ common_tool="find_db_writers / get_db_impact",
515
+ example="`update_stock` -> `WRITES_COLUMN` (`STATIC_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.inventory.quantity`",
516
+ ),
517
+ "REFERENCES_TABLE": RelationshipSemanticsSpec(
518
+ relationship="REFERENCES_TABLE",
519
+ meaning="Schema constraint, view, or query references a database table.",
520
+ typical_source="Table, view, or symbol",
521
+ typical_target="Referenced database table",
522
+ proves="Static table reference in DDL, view, or ORM declaration.",
523
+ does_not_prove="Does not prove direct row mutation (`REFERENCES_TABLE != WRITES_TABLE`).",
524
+ common_tool="find_db_relationships / get_db_table",
525
+ example="`order_summary_view` -> `REFERENCES_TABLE` (`STATIC_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.orders`",
526
+ ),
527
+ "REFERENCES_COLUMN": RelationshipSemanticsSpec(
528
+ relationship="REFERENCES_COLUMN",
529
+ meaning="Constraint, index, or foreign key references a specific database column.",
530
+ typical_source="ForeignKey, Index, or ORM field",
531
+ typical_target="Referenced database column",
532
+ proves="Static column reference in constraint or index definition.",
533
+ does_not_prove="Does not prove runtime cascade execution.",
534
+ common_tool="find_db_relationships / find_db_columns",
535
+ example="`idx_users_email` -> `REFERENCES_COLUMN` (`STATIC_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.users.email`",
536
+ ),
537
+ "FOREIGN_KEY_TO": RelationshipSemanticsSpec(
538
+ relationship="FOREIGN_KEY_TO",
539
+ meaning="Database column or ORM field declares a foreign-key reference to a target table/column.",
540
+ typical_source="Source column (`db.UNKNOWN.UNKNOWN.orders.user_id`)",
541
+ typical_target="Target column or table (`db.UNKNOWN.UNKNOWN.users.id`)",
542
+ proves="Static `ForeignKey(...)` or SQL `REFERENCES` constraint.",
543
+ does_not_prove="Does not prove whether foreign key checks are enabled in SQLite PRAGMA at runtime.",
544
+ common_tool="find_db_relationships / get_db_table / get_db_schema",
545
+ example="`db.UNKNOWN.UNKNOWN.orders.user_id` -> `FOREIGN_KEY_TO` (`FRAMEWORK_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.users.id`",
546
+ ),
547
+ "HAS_PRIMARY_KEY": RelationshipSemanticsSpec(
548
+ relationship="HAS_PRIMARY_KEY",
549
+ meaning="Database table declares a primary-key column or constraint.",
550
+ typical_source="Canonical database table",
551
+ typical_target="Primary key column (`db.<dialect>.<schema>.<table>.<column>`)",
552
+ proves="Static `primary_key=True`, `@id`, or SQL `PRIMARY KEY` declaration.",
553
+ does_not_prove="Does not prove auto-increment sequence values.",
554
+ common_tool="get_db_table / find_db_columns / find_db_relationships",
555
+ example="`db.UNKNOWN.UNKNOWN.users` -> `HAS_PRIMARY_KEY` (`FRAMEWORK_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.users.id`",
556
+ ),
557
+ "HAS_INDEX": RelationshipSemanticsSpec(
558
+ relationship="HAS_INDEX",
559
+ meaning="Database table declares a secondary index (`Index(...)`, `index=True`, `CREATE INDEX`, `@@index`).",
560
+ typical_source="Canonical database table",
561
+ typical_target="Index entity or indexed column",
562
+ proves="Static index declaration in ORM model, SQL DDL, or migration.",
563
+ does_not_prove="Does not prove query planner index selection at runtime.",
564
+ common_tool="get_db_table / find_db_relationships",
565
+ example="`db.UNKNOWN.UNKNOWN.users` -> `HAS_INDEX` (`FRAMEWORK_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.users.email`",
566
+ ),
567
+ "HAS_UNIQUE_CONSTRAINT": RelationshipSemanticsSpec(
568
+ relationship="HAS_UNIQUE_CONSTRAINT",
569
+ meaning="Database table or column declares a uniqueness constraint (`unique=True`, `UniqueConstraint`, `UNIQUE`, `@unique`).",
570
+ typical_source="Canonical database table",
571
+ typical_target="Constrained column or constraint entity",
572
+ proves="Static unique constraint in ORM model, SQL schema, or migration.",
573
+ does_not_prove="Does not prove absence of duplicate legacy data prior to migration.",
574
+ common_tool="get_db_table / find_db_columns / find_db_relationships",
575
+ example="`db.UNKNOWN.UNKNOWN.users` -> `HAS_UNIQUE_CONSTRAINT` (`FRAMEWORK_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.users.email`",
576
+ ),
577
+ "HAS_CHECK_CONSTRAINT": RelationshipSemanticsSpec(
578
+ relationship="HAS_CHECK_CONSTRAINT",
579
+ meaning="Database table declares a `CheckConstraint` or SQL `CHECK (...)` expression.",
580
+ typical_source="Canonical database table",
581
+ typical_target="Check constraint entity",
582
+ proves="Static check constraint declaration in ORM or SQL schema.",
583
+ does_not_prove="Does not prove application-level validation.",
584
+ common_tool="get_db_table / find_db_relationships",
585
+ example="`db.UNKNOWN.UNKNOWN.products` -> `HAS_CHECK_CONSTRAINT` (`STATIC_VERIFIED`) -> `check_price_positive`",
586
+ ),
587
+ "MIGRATES_TABLE": RelationshipSemanticsSpec(
588
+ relationship="MIGRATES_TABLE",
589
+ meaning="Database migration file (Alembic, Django migration, Prisma migration, or SQL migration) creates, alters, or drops a table.",
590
+ typical_source="Migration revision or file (`migrations/0001_initial.py`)",
591
+ typical_target="Canonical database table",
592
+ proves="Static migration operation (`op.create_table`, `migrations.CreateModel`, `CREATE TABLE`, `ALTER TABLE`).",
593
+ does_not_prove="Does not prove whether the migration has been applied to a live deployment.",
594
+ common_tool="get_db_table / get_db_schema / get_db_impact",
595
+ example="`migrations/versions/001_init.py` -> `MIGRATES_TABLE` (`STATIC_VERIFIED`) -> `db.UNKNOWN.UNKNOWN.users`",
596
+ ),
597
+ "QUERIES_DATABASE": RelationshipSemanticsSpec(
598
+ relationship="QUERIES_DATABASE",
599
+ meaning="Function or module executes a database query through a session, cursor, or engine.",
600
+ typical_source="Function or method symbol",
601
+ typical_target="Database entity or query target",
602
+ proves="Database execution call (`cursor.execute`, `session.execute`, `conn.fetch`) at the cited lines.",
603
+ does_not_prove="When target table is dynamic, pair with `POSSIBLE_TABLE` or `UNKNOWN_TABLE`.",
604
+ common_tool="find_db_queries / get_runtime_trace",
605
+ example="`run_report` -> `QUERIES_DATABASE` (`AST_VERIFIED`) -> `db.UNKNOWN.UNKNOWN`",
606
+ ),
607
+ "ORM_RELATION": RelationshipSemanticsSpec(
608
+ relationship="ORM_RELATION",
609
+ meaning="ORM model declares a high-level association (`relationship()`, `ForeignKey` relation, `@relation`) to another ORM model.",
610
+ typical_source="Source ORM model (`Product`)",
611
+ typical_target="Target ORM model (`Shop`)",
612
+ proves="Framework-verified one-to-one, one-to-many, or many-to-many model association.",
613
+ does_not_prove="Does not prove eager vs lazy loading behavior unless inspected via `get_file`.",
614
+ common_tool="find_db_relationships / find_db_models / get_db_table",
615
+ example="`Product` -> `ORM_RELATION` (`FRAMEWORK_VERIFIED`) -> `Shop`",
616
+ ),
617
+ "POSSIBLE_TABLE": RelationshipSemanticsSpec(
618
+ relationship="POSSIBLE_TABLE",
619
+ meaning="Query references a candidate database table via conditional logic or partial string interpolation (`evidence_class='POSSIBLE'`).",
620
+ typical_source="Function or query site",
621
+ typical_target="Candidate table name or `db.UNKNOWN.UNKNOWN.<candidate>`",
622
+ proves="Plausible static table candidate that is not statically guaranteed.",
623
+ does_not_prove="Never proves an unconditional `READS_TABLE` or `WRITES_TABLE` edge without source verification.",
624
+ common_tool="find_db_queries / find_db_tables / get_context",
625
+ example="`query_partition` -> `POSSIBLE_TABLE` (`POSSIBLE`) -> `db.UNKNOWN.UNKNOWN.events_archive`",
626
+ ),
627
+ "UNKNOWN_TABLE": RelationshipSemanticsSpec(
628
+ relationship="UNKNOWN_TABLE",
629
+ meaning="Database query executes a dynamically constructed SQL string or table identifier that cannot be statically resolved (`evidence_class='UNKNOWN'`).",
630
+ typical_source="Function executing dynamic SQL",
631
+ typical_target="`db.UNKNOWN.UNKNOWN.UNKNOWN`",
632
+ proves="A database query occurs at the cited location whose target table is statically unresolvable.",
633
+ does_not_prove="Never means no table is accessed; inspect the call site with `get_file` or runtime traces.",
634
+ common_tool="find_db_queries / get_context",
635
+ example="`execute_raw_dynamic` -> `UNKNOWN_TABLE` (`UNKNOWN`) -> `db.UNKNOWN.UNKNOWN.UNKNOWN`",
636
+ ),
637
+ "READS_ENV": RelationshipSemanticsSpec(
638
+ relationship="READS_ENV",
639
+ meaning="Module or function reads an environment variable (`os.getenv`, `os.environ.get`, `process.env`) for database or service configuration.",
640
+ typical_source="File or symbol",
641
+ typical_target="Environment variable name (`env:DATABASE_URL`) — never the secret value",
642
+ proves="Static environment variable lookup by key name.",
643
+ does_not_prove="Never exposes or stores the runtime environment variable's secret value.",
644
+ common_tool="get_db_schema / get_context",
645
+ example="`src/config.py` -> `READS_ENV` (`AST_VERIFIED`) -> `env:DATABASE_URL`",
646
+ ),
647
+ }
648
+
649
+
650
+ @dataclass(frozen=True)
651
+ class ComplexWorkflowExample:
652
+ """Structured specification for one of the 25+ canonical complex workflows in Section 20 / Section 39."""
653
+
654
+ workflow_id: int
655
+ title: str
656
+ developer_request: str
657
+ task_classification: str
658
+ why_codegraph: str
659
+ first_tool: str
660
+ arguments: str
661
+ expected_result_interpretation: str
662
+ followup_tool: str
663
+ stop_condition: str
664
+ source_read_fallback: str
665
+ final_evidence_handling: str
666
+
667
+
668
+ COMPLEX_WORKFLOW_EXAMPLES: tuple[ComplexWorkflowExample, ...] = (
669
+ ComplexWorkflowExample(
670
+ workflow_id=1,
671
+ title="Authentication route trace",
672
+ developer_request="Trace how POST /api/v1/auth/login authenticates a user and queries the database.",
673
+ task_classification="TRACE",
674
+ why_codegraph="Route strings may be split across mounted routers (`MOUNTS`), handlers (`HANDLED_BY`), DI providers (`INJECTS`/`PROVIDES`), and services (`CALLS`).",
675
+ first_tool="list_routes",
676
+ arguments='list_routes(method="POST", path="/api/v1/auth/login")',
677
+ expected_result_interpretation="Identify `handler_name` (e.g., `login_endpoint`), `canonical_id`, and `evidence_class='FRAMEWORK_VERIFIED'`.",
678
+ followup_tool='trace_path(from_symbol="login_endpoint", to_symbol="find_by_email", max_depth=4)',
679
+ stop_condition="Stop once the ordered hop chain from `POST /api/v1/auth/login` -> `login_endpoint` -> `AuthService.authenticate` -> `UserRepository.find_by_email` is verified.",
680
+ source_read_fallback='Call `read_file(path="src/auth/service.py", start_line=10, end_line=40)` only if password comparison branch details are needed.',
681
+ final_evidence_handling="Cite each hop with its relationship (`HANDLED_BY`, `INJECTS`, `CALLS`) and `evidence_class`.",
682
+ ),
683
+ ComplexWorkflowExample(
684
+ workflow_id=2,
685
+ title="Login handler -> service -> repository",
686
+ developer_request="How does login_endpoint reach UserRepository.find_by_email?",
687
+ task_classification="TRACE",
688
+ why_codegraph="Both endpoint and target symbol names are known, making multi-hop graph path tracing deterministic.",
689
+ first_tool="resolve_symbol",
690
+ arguments='resolve_symbol(symbol="login_endpoint")',
691
+ expected_result_interpretation="Confirm canonical ID `src/auth/routes.py:login_endpoint` and `ambiguity_state='CLEAR'`.",
692
+ followup_tool='trace_path(from_symbol="login_endpoint", to_symbol="find_by_email", max_depth=4)',
693
+ stop_condition="Stop as soon as `trace_path` returns the verified hop chain connecting the two symbols.",
694
+ source_read_fallback="If any hop is marked `POSSIBLE`, use `read_file` on that hop's `file` and `start_line`.",
695
+ final_evidence_handling="Present the exact hop sequence with file:line coordinates.",
696
+ ),
697
+ ComplexWorkflowExample(
698
+ workflow_id=3,
699
+ title="DI provider resolution",
700
+ developer_request="Which provider supplies AuthService to login_endpoint?",
701
+ task_classification="DEBUG",
702
+ why_codegraph="CodeGraph extracts `INJECTS`, `PROVIDES`, and `RESOLVES_DEPENDENCY` relationships without collapsing them into `CALLS`.",
703
+ first_tool="resolve_symbol",
704
+ arguments='resolve_symbol(symbol="login_endpoint")',
705
+ expected_result_interpretation="Obtain canonical ID for `login_endpoint`.",
706
+ followup_tool='get_context(query="Which provider supplies AuthService to login_endpoint", intent="DEBUG", max_tokens=4000)',
707
+ stop_condition="Stop when `INJECTS` (`login_endpoint` -> `get_auth_service`) and `PROVIDES` (`get_auth_service` -> `AuthService`) edges are retrieved.",
708
+ source_read_fallback="Call `read_file` on `dependencies.py` only if constructor arguments inside `get_auth_service` need inspection.",
709
+ final_evidence_handling="Distinguish `INJECTS` and `PROVIDES` (`FRAMEWORK_VERIFIED`) from direct `CALLS`.",
710
+ ),
711
+ ComplexWorkflowExample(
712
+ workflow_id=4,
713
+ title="FastAPI dependency chain",
714
+ developer_request="Trace the FastAPI Depends() chain from get_current_active_user down to get_db_session.",
715
+ task_classification="DEBUG",
716
+ why_codegraph="Nested FastAPI `Depends()` parameters form multi-hop `INJECTS` and `PROVIDES` chains across files.",
717
+ first_tool="resolve_symbol",
718
+ arguments='resolve_symbol(symbol="get_current_active_user")',
719
+ expected_result_interpretation="Confirm canonical definition of `get_current_active_user`.",
720
+ followup_tool='get_context(query="FastAPI dependency chain get_current_active_user to get_db_session", intent="DEBUG", max_tokens=4000)',
721
+ stop_condition="Stop when all nested `INJECTS`/`PROVIDES` hops to `get_db_session` are present in the `ContextPacket`.",
722
+ source_read_fallback="Use `read_file` on `get_current_active_user` lines if HTTPException status codes are needed.",
723
+ final_evidence_handling="Report each nested dependency link with its `FRAMEWORK_VERIFIED` evidence class.",
724
+ ),
725
+ ComplexWorkflowExample(
726
+ workflow_id=5,
727
+ title="Registry handler lookup",
728
+ developer_request="What handlers are registered in command_registry and where does command_registry dispatch?",
729
+ task_classification="RELATIONSHIP",
730
+ why_codegraph="CodeGraph tracks `REGISTERS`, `REGISTERED_HANDLER`, and `DISPATCHES_TO` distinctly from `CALLS`.",
731
+ first_tool="resolve_symbol",
732
+ arguments='resolve_symbol(symbol="command_registry")',
733
+ expected_result_interpretation="Resolve canonical ID of `command_registry`.",
734
+ followup_tool='get_references(symbol="command_registry")',
735
+ stop_condition="Stop once all `REGISTERS` and `DISPATCHES_TO` edges referencing `command_registry` are listed.",
736
+ source_read_fallback="If any registration is conditional (`POSSIBLE`), read the cited registration lines with `read_file`.",
737
+ final_evidence_handling="Never report `REGISTERS` edges as direct `CALLS`; preserve `REGISTERS` and `DISPATCHES_TO` labels.",
738
+ ),
739
+ ComplexWorkflowExample(
740
+ workflow_id=6,
741
+ title="Event listener discovery",
742
+ developer_request="Which event listeners subscribe to OrderCreated across the repository?",
743
+ task_classification="RELATIONSHIP",
744
+ why_codegraph="Event listeners are decoupled from publishers and connected via `EVENT_LISTENER` edges.",
745
+ first_tool="resolve_symbol",
746
+ arguments='resolve_symbol(symbol="OrderCreated")',
747
+ expected_result_interpretation="Obtain canonical ID of the `OrderCreated` event symbol.",
748
+ followup_tool='get_references(symbol="OrderCreated")',
749
+ stop_condition="Stop after collecting all `EVENT_LISTENER` and `DISPATCHES_TO` edges tied to `OrderCreated`.",
750
+ source_read_fallback="Use `read_file` on listener spans if side-effect details (e.g., email template) are needed.",
751
+ final_evidence_handling="Cite each listener with `EVENT_LISTENER` and its `evidence_class`.",
752
+ ),
753
+ ComplexWorkflowExample(
754
+ workflow_id=7,
755
+ title="Celery task tracing",
756
+ developer_request="Trace how Celery task send_welcome_email is registered and what SMTP client it calls.",
757
+ task_classification="TRACE",
758
+ why_codegraph="Celery tasks combine `TASK_HANDLER` decorator semantics with downstream `CALLS` edges.",
759
+ first_tool="resolve_symbol",
760
+ arguments='resolve_symbol(symbol="send_welcome_email")',
761
+ expected_result_interpretation="Locate `send_welcome_email` definition and confirm `TASK_HANDLER` metadata.",
762
+ followup_tool='get_callees(symbol="send_welcome_email")',
763
+ stop_condition="Stop once downstream `CALLS` to the SMTP client symbol are identified.",
764
+ source_read_fallback="Call `read_file` on the task function span if retry/backoff decorator arguments are needed.",
765
+ final_evidence_handling="Report `TASK_HANDLER` (`FRAMEWORK_VERIFIED`) for task registration and `CALLS` (`AST_VERIFIED`) for outgoing calls.",
766
+ ),
767
+ ComplexWorkflowExample(
768
+ workflow_id=8,
769
+ title="CLI command handler lookup",
770
+ developer_request="Which function handles the CLI command `mcp doctor`?",
771
+ task_classification="SYMBOL_LOOKUP",
772
+ why_codegraph="CLI commands decorated with `@app.command` or `@mcp_app.command` produce `COMMAND_HANDLER` and symbol definitions.",
773
+ first_tool="search_symbols",
774
+ arguments='search_symbols(query="mcp_doctor", top_k=10)',
775
+ expected_result_interpretation="Locate the CLI command handler symbol and its file/line coordinates.",
776
+ followup_tool='get_symbol(symbol="src/codegraph/cli.py:mcp_doctor")',
777
+ stop_condition="Stop once the command handler signature, decorators, and callees are identified.",
778
+ source_read_fallback="Use `read_file` on the handler line range if CLI option defaults need inspection.",
779
+ final_evidence_handling="Cite `COMMAND_HANDLER` / `DEFINES` evidence with exact file and line numbers.",
780
+ ),
781
+ ComplexWorkflowExample(
782
+ workflow_id=9,
783
+ title="Related tests discovery",
784
+ developer_request="What tests cover BillingService.charge_card?",
785
+ task_classification="TEST_DISCOVERY",
786
+ why_codegraph="`find_related_tests` uses static call, import, fixture, and route links (`TESTS_SYMBOL`, `TESTS_ROUTE`, `TESTS_PROVIDER`) without lexical guessing.",
787
+ first_tool="resolve_symbol",
788
+ arguments='resolve_symbol(symbol="BillingService.charge_card")',
789
+ expected_result_interpretation="Confirm canonical ID of `BillingService.charge_card`.",
790
+ followup_tool='find_related_tests(symbol="BillingService.charge_card")',
791
+ stop_condition="Stop when the statically linked test functions and their linking relationships are returned.",
792
+ source_read_fallback="Call `read_file` on a returned test function only if specific assertion values need inspection.",
793
+ final_evidence_handling="Report each test with its specific link type (`TESTS_SYMBOL`, `TESTS_ROUTE`, etc.) and `evidence_class`.",
794
+ ),
795
+ ComplexWorkflowExample(
796
+ workflow_id=10,
797
+ title="Change impact analysis on Git range",
798
+ developer_request="Analyze the blast radius and affected tests for commits between HEAD~1 and HEAD.",
799
+ task_classification="CHANGE_IMPACT",
800
+ why_codegraph="`get_git_impact` maps Git diff hunks to AST symbol spans, downstream callers, workspace packages, and covering tests.",
801
+ first_tool="get_git_impact",
802
+ arguments='get_git_impact(base="HEAD~1", head="HEAD")',
803
+ expected_result_interpretation="Inspect `modified_symbols`, `impacted_callers`, `affected_packages`, and `related_tests`.",
804
+ followup_tool="find_related_tests (only if additional transitive symbol tests are needed)",
805
+ stop_condition="Stop when `get_git_impact` returns the complete modified symbol, caller, package, and test sets.",
806
+ source_read_fallback="Use `read_file` on modified symbol spans if exact diff logic needs line-by-line review.",
807
+ final_evidence_handling="Present modified symbols, affected callers/packages, and static test coverage links.",
808
+ ),
809
+ ComplexWorkflowExample(
810
+ workflow_id=11,
811
+ title="Package dependency inspection",
812
+ developer_request="What workspace packages does @acme/orders depend on in this monorepo?",
813
+ task_classification="PACKAGE",
814
+ why_codegraph="CodeGraph derives `DEPENDS_ON_PACKAGE` and `CROSS_PACKAGE_IMPORT` from actual manifest files (`package.json`, `pyproject.toml`, etc.).",
815
+ first_tool="get_architecture",
816
+ arguments="get_architecture()",
817
+ expected_result_interpretation="Inspect `packages` and `package_dependencies` for `@acme/orders`.",
818
+ followup_tool='get_context(query="workspace package dependencies of @acme/orders", intent="ARCHITECTURE", max_tokens=4000)',
819
+ stop_condition="Stop once direct and bounded transitive `DEPENDS_ON_PACKAGE` edges for `@acme/orders` are identified.",
820
+ source_read_fallback="Read `packages/orders/package.json` via `read_file` only if exact version semver strings are needed.",
821
+ final_evidence_handling="Cite manifest-backed `DEPENDS_ON_PACKAGE` edges; never infer packages from directory names alone.",
822
+ ),
823
+ ComplexWorkflowExample(
824
+ workflow_id=12,
825
+ title="Monorepo architecture overview",
826
+ developer_request="Explain the overall package boundaries, services, and entrypoints of this monorepo.",
827
+ task_classification="ARCHITECTURE",
828
+ why_codegraph="`get_architecture` summarizes manifest-verified packages, entrypoints, routes, and inter-package dependencies in one call.",
829
+ first_tool="get_architecture",
830
+ arguments="get_architecture()",
831
+ expected_result_interpretation="Review `packages`, `package_dependencies`, `entrypoints`, and `routes`.",
832
+ followup_tool='get_context(query="monorepo architecture overview and entrypoints", intent="ARCHITECTURE", max_tokens=4000)',
833
+ stop_condition="Stop after `get_architecture` (and optional `get_context`) provides the package and entrypoint topology.",
834
+ source_read_fallback="Avoid reading dozens of files; only read top-level manifest if workspace globs need manual check.",
835
+ final_evidence_handling="Report manifest-verified packages and entrypoints with their `AST_VERIFIED`/`FRAMEWORK_VERIFIED` evidence.",
836
+ ),
837
+ ComplexWorkflowExample(
838
+ workflow_id=13,
839
+ title="Ambiguous symbol disambiguation",
840
+ developer_request="What calls validate() in the payments module?",
841
+ task_classification="RELATIONSHIP",
842
+ why_codegraph="Generic method names like `validate` often exist in multiple classes; `resolve_symbol` surfaces `AMBIGUOUS` alternatives explicitly.",
843
+ first_tool="resolve_symbol",
844
+ arguments='resolve_symbol(symbol="validate")',
845
+ expected_result_interpretation="Observe `ambiguity_state='AMBIGUOUS'` and inspect `alternatives` for the candidate in the `payments` module/package.",
846
+ followup_tool='get_callers(symbol="src/payments/validator.py:PaymentValidator.validate")',
847
+ stop_condition="Stop once callers of the disambiguated `canonical_id` are returned (or report ambiguity if context is insufficient).",
848
+ source_read_fallback="Use `read_file` on candidate definitions if module names alone do not disambiguate.",
849
+ final_evidence_handling="Never pick `matches[0]` blindly; state how the canonical symbol was disambiguated.",
850
+ ),
851
+ ComplexWorkflowExample(
852
+ workflow_id=14,
853
+ title="UNKNOWN dynamic dispatch handling",
854
+ developer_request="What function does run_dynamic_hook(hook_name) call?",
855
+ task_classification="RELATIONSHIP",
856
+ why_codegraph="Dynamic `getattr(hooks, hook_name)()` cannot be proven statically and is surfaced as `POSSIBLE_CALLS` / `UNRESOLVED_REFERENCE` with `evidence_class='UNKNOWN'`.",
857
+ first_tool="resolve_symbol",
858
+ arguments='resolve_symbol(symbol="run_dynamic_hook")',
859
+ expected_result_interpretation="Locate `run_dynamic_hook` canonical ID and line span.",
860
+ followup_tool='get_callees(symbol="run_dynamic_hook")',
861
+ stop_condition="Observe `evidence_class='UNKNOWN'` (or empty static callees with `unknowns` in `get_context`), then perform one targeted `read_file`.",
862
+ source_read_fallback='Call `read_file(path="src/hooks/runner.py", start_line=1, end_line=50)` to inspect the `getattr` dispatch mechanism.',
863
+ final_evidence_handling="State clearly that static analysis returned `UNKNOWN` due to runtime `getattr`; never claim 'run_dynamic_hook calls nothing'.",
864
+ ),
865
+ ComplexWorkflowExample(
866
+ workflow_id=15,
867
+ title="POSSIBLE registry target verification",
868
+ developer_request="Which handler does dispatch_webhook invoke when event_type is conditional?",
869
+ task_classification="TRACE",
870
+ why_codegraph="Conditional or multi-branch registry bindings are labeled `evidence_class='POSSIBLE'` so the agent treats them as leads to verify.",
871
+ first_tool="resolve_symbol",
872
+ arguments='resolve_symbol(symbol="dispatch_webhook")',
873
+ expected_result_interpretation="Resolve `dispatch_webhook` canonical ID.",
874
+ followup_tool='get_context(query="dispatch_webhook handler targets", intent="TRACE", max_tokens=4000)',
875
+ stop_condition="Identify `DISPATCHES_TO` edges marked `POSSIBLE`, then verify the branch condition via targeted `read_file`.",
876
+ source_read_fallback="Call `read_file` on the cited registration/dispatch lines to check the `if/elif` or dict lookup condition.",
877
+ final_evidence_handling="Report the target as `POSSIBLE` until confirmed by the targeted source read.",
878
+ ),
879
+ ComplexWorkflowExample(
880
+ workflow_id=16,
881
+ title="Generated and bundle code suppression",
882
+ developer_request="Where is UserClient defined? Ignore generated SDKs and minified bundles.",
883
+ task_classification="SYMBOL_LOOKUP",
884
+ why_codegraph="CodeGraph classifies files into `SOURCE`, `TEST`, `GENERATED`, `BUNDLE`, `MINIFIED`, `VENDOR`, and `BUILD_ARTIFACT` and prioritizes authored `SOURCE`.",
885
+ first_tool="resolve_symbol",
886
+ arguments='resolve_symbol(symbol="UserClient")',
887
+ expected_result_interpretation="Verify that the primary resolved symbol comes from authored `SOURCE` rather than `dist/` or `generated/`.",
888
+ followup_tool='get_file(path="src/client/user_client.ts")',
889
+ stop_condition="Stop once the authored `SOURCE` definition is confirmed.",
890
+ source_read_fallback="Use `read_file` on the authored source file only if implementation lines are needed.",
891
+ final_evidence_handling="Prefer `SOURCE` artifacts; note if duplicate generated/bundle copies were suppressed.",
892
+ ),
893
+ ComplexWorkflowExample(
894
+ workflow_id=17,
895
+ title="Stale index detection and fallback",
896
+ developer_request="After editing src/auth/service.py on disk, check what AuthService.authenticate calls.",
897
+ task_classification="DIAGNOSTIC",
898
+ why_codegraph="`get_repository_status` and tool responses report `freshness='STALE'` when on-disk files have changed since the last index generation.",
899
+ first_tool="get_repository_status",
900
+ arguments="get_repository_status()",
901
+ expected_result_interpretation="Observe `freshness='STALE'` and `modified_files=['src/auth/service.py']`.",
902
+ followup_tool='read_file(path="src/auth/service.py", start_line=1, end_line=100)',
903
+ stop_condition="Stop after verifying the modified file directly with `read_file` (or re-indexing via CLI).",
904
+ source_read_fallback="Always use `read_file` on files listed in `modified_files` when `freshness == 'STALE'`.",
905
+ final_evidence_handling="Do not present stale cached graph edges from modified files as current truth without verifying on-disk lines.",
906
+ ),
907
+ ComplexWorkflowExample(
908
+ workflow_id=18,
909
+ title="Debugging a runtime exception across files",
910
+ developer_request="Debug why PaymentProcessor.capture raises CurrencyMismatchError during checkout.",
911
+ task_classification="DEBUG",
912
+ why_codegraph="`get_context(intent='DEBUG')` gathers the target method, upstream callers, downstream callees, DI providers, and covering tests in one bounded packet.",
913
+ first_tool="resolve_symbol",
914
+ arguments='resolve_symbol(symbol="PaymentProcessor.capture")',
915
+ expected_result_interpretation="Confirm canonical ID and file:line location of `PaymentProcessor.capture`.",
916
+ followup_tool='get_context(query="Debug CurrencyMismatchError in PaymentProcessor.capture", intent="DEBUG", max_tokens=4000)',
917
+ stop_condition="Stop graph interrogation once `ContextPacket` provides callers (`process_checkout`) and callees; read exact exception line if needed.",
918
+ source_read_fallback="Call `read_file` on the exact line range of `PaymentProcessor.capture` and `process_checkout` where currency is passed.",
919
+ final_evidence_handling="Combine verified caller/callee graph evidence with the exact source lines raising the exception.",
920
+ ),
921
+ ComplexWorkflowExample(
922
+ workflow_id=19,
923
+ title="Refactoring a shared symbol safely",
924
+ developer_request="We want to add a required `tenant_id` parameter to OrderRepository.save. What needs to be updated?",
925
+ task_classification="CHANGE_IMPACT",
926
+ why_codegraph="`analyze_impact` computes direct callers, transitive callers, affected routes, dependent files, and related tests.",
927
+ first_tool="resolve_symbol",
928
+ arguments='resolve_symbol(symbol="OrderRepository.save")',
929
+ expected_result_interpretation="Confirm canonical ID `OrderRepository.save`.",
930
+ followup_tool='analyze_impact(symbol="OrderRepository.save", max_depth=3)',
931
+ stop_condition="Stop graph traversal once `direct_callers`, `affected_routes`, and `related_tests` are enumerated.",
932
+ source_read_fallback="Use `read_file` on each direct caller's call-site line span to plan the parameter update.",
933
+ final_evidence_handling="List every direct caller, affected route, and test file with exact line coordinates.",
934
+ ),
935
+ ComplexWorkflowExample(
936
+ workflow_id=20,
937
+ title="Finding affected tests before a commit",
938
+ developer_request="Which pytest tests should we run after modifying TokenValidator.verify?",
939
+ task_classification="TEST_DISCOVERY",
940
+ why_codegraph="`find_related_tests` identifies tests linked via `TESTS_SYMBOL`, `TESTS_ROUTE`, or `TESTS_PROVIDER`.",
941
+ first_tool="resolve_symbol",
942
+ arguments='resolve_symbol(symbol="TokenValidator.verify")',
943
+ expected_result_interpretation="Confirm canonical ID of `TokenValidator.verify`.",
944
+ followup_tool='find_related_tests(symbol="TokenValidator.verify", max_results=20)',
945
+ stop_condition="Stop as soon as the linked test functions and files are returned.",
946
+ source_read_fallback="No `read_file` needed unless a test fails and its assertion lines must be inspected.",
947
+ final_evidence_handling="Return the list of test functions and their static evidence classes.",
948
+ ),
949
+ ComplexWorkflowExample(
950
+ workflow_id=21,
951
+ title="Route-to-provider-to-repository trace",
952
+ developer_request="Trace GET /api/v1/users/me through its FastAPI dependency provider to the database repository.",
953
+ task_classification="TRACE",
954
+ why_codegraph="Connects `HANDLED_BY` -> `INJECTS` -> `PROVIDES` -> `CALLS` across multiple files.",
955
+ first_tool="list_routes",
956
+ arguments='list_routes(method="GET", path="/api/v1/users/me")',
957
+ expected_result_interpretation="Identify the route handler symbol (e.g., `get_me_endpoint`).",
958
+ followup_tool='get_context(query="Trace GET /api/v1/users/me handler dependency provider and repository", intent="TRACE", max_tokens=4000)',
959
+ stop_condition="Stop once the route, handler, injected provider (`get_current_user`), and repository call are present in the packet.",
960
+ source_read_fallback="Use `read_file` only if token parsing details inside `get_current_user` are needed.",
961
+ final_evidence_handling="Present the complete chain preserving `HANDLED_BY`, `INJECTS`, `PROVIDES`, and `CALLS`.",
962
+ ),
963
+ ComplexWorkflowExample(
964
+ workflow_id=22,
965
+ title="Architecture explanation for onboarding",
966
+ developer_request="Give a concise architectural overview of this service, its entrypoints, and its core modules.",
967
+ task_classification="ARCHITECTURE",
968
+ why_codegraph="`get_architecture` provides a deterministic structural summary without scanning every file manually.",
969
+ first_tool="get_architecture",
970
+ arguments="get_architecture()",
971
+ expected_result_interpretation="Inspect modules, entrypoints, routes, and package boundaries.",
972
+ followup_tool='list_routes() (if detailed HTTP endpoint inventory is desired)',
973
+ stop_condition="Stop once high-level modules, entrypoints, and routes are summarized.",
974
+ source_read_fallback="Do not read individual implementation files unless asked about a specific module.",
975
+ final_evidence_handling="Summarize the architecture using only AST- and manifest-verified facts.",
976
+ ),
977
+ ComplexWorkflowExample(
978
+ workflow_id=23,
979
+ title="Large repository multi-file feature investigation",
980
+ developer_request="Where is rate limiting implemented and how is it wired into API endpoints?",
981
+ task_classification="MULTI_FILE_INVESTIGATION",
982
+ why_codegraph="Combining `search_symbols` -> `resolve_symbol` -> `get_context` avoids blind grep across hundreds of files.",
983
+ first_tool="search_symbols",
984
+ arguments='search_symbols(query="rate_limit", top_k=10)',
985
+ expected_result_interpretation="Identify the primary rate limiter class/dependency (e.g., `RateLimiter` or `check_rate_limit`).",
986
+ followup_tool='get_context(query="How rate limiting is implemented and wired into API endpoints", intent="UNDERSTAND", max_tokens=4000)',
987
+ stop_condition="Stop when the rate limiter definition, its `INJECTS`/`CALLS` usages on routes, and tests are in the `ContextPacket`.",
988
+ source_read_fallback="Use `read_file` on the rate limiter algorithm lines if token-bucket math details are requested.",
989
+ final_evidence_handling="Cite definition coordinates and route wiring edges (`INJECTS` / `CALLS`).",
990
+ ),
991
+ ComplexWorkflowExample(
992
+ workflow_id=24,
993
+ title="One-file local edit bypass",
994
+ developer_request="Fix a typo in the docstring of format_currency in src/utils/money.py.",
995
+ task_classification="LOCAL_EDIT",
996
+ why_codegraph="CodeGraph is NOT needed for trivial single-file edits where relationships do not matter.",
997
+ first_tool="read_file",
998
+ arguments='read_file(path="src/utils/money.py", start_line=1, end_line=60)',
999
+ expected_result_interpretation="Read the exact docstring lines of `format_currency`.",
1000
+ followup_tool="None (apply edit directly)",
1001
+ stop_condition="Stop immediately after reading the target lines and applying the edit; make 0 graph calls.",
1002
+ source_read_fallback="Direct `read_file` is the primary tool for `LOCAL_EDIT`.",
1003
+ final_evidence_handling="Confirm the docstring edit directly in `src/utils/money.py`.",
1004
+ ),
1005
+ ComplexWorkflowExample(
1006
+ workflow_id=25,
1007
+ title="MCP unavailable or disconnected fallback",
1008
+ developer_request="Find all callers of verify_token when the CodeGraph MCP server is offline.",
1009
+ task_classification="RELATIONSHIP",
1010
+ why_codegraph="Normally handled by `resolve_symbol` -> `get_callers`, but when MCP is `DISCONNECTED` or `SERVER_FAILED`, safe fallback rules apply.",
1011
+ first_tool="read_file",
1012
+ arguments='read_file(path="src/auth/tokens.py", start_line=1, end_line=120)',
1013
+ expected_result_interpretation="Recognize MCP unavailability (`evaluate_fallback_policy(mcp_state='DISCONNECTED')`), use workspace search/targeted `read_file`.",
1014
+ followup_tool="Targeted `read_file` on candidate caller files found via search",
1015
+ stop_condition="Stop once candidate call sites are manually inspected in source files.",
1016
+ source_read_fallback="Direct search + `read_file` is the required fallback when MCP is disconnected.",
1017
+ final_evidence_handling="Explicitly note that results were verified via direct source inspection while CodeGraph MCP was offline.",
1018
+ ),
1019
+ )
1020
+
1021
+
1022
+ def _format_tool_reference_section(spec: ToolCapabilitySpec) -> str:
1023
+ """Render Section 6 / Section 41 complete tool reference entry for a single tool."""
1024
+ req_str = ", ".join(f"`{p}`" for p in spec.required_inputs) if spec.required_inputs else "None"
1025
+ opt_str = ", ".join(f"`{p}`" for p in spec.optional_inputs) if spec.optional_inputs else "None"
1026
+ rels_str = ", ".join(f"`{r}`" for r in spec.relationship_types_returned) if spec.relationship_types_returned else "None (non-edge output)"
1027
+ profs_str = ", ".join(f"`{p}`" for p in spec.profiles)
1028
+ fields_str = ", ".join(f"`{f}`" for f in spec.result_fields) if spec.result_fields else "`status`, payload fields"
1029
+ use_lines = "\n".join(f"- {u}" for u in spec.useful_situations)
1030
+ avoid_lines = "\n".join(f"- {a}" for a in spec.avoid_when)
1031
+ mistake_lines = (
1032
+ "\n".join(f"- {m}" for m in spec.common_mistakes)
1033
+ if spec.common_mistakes
1034
+ else "- Calling this tool redundantly when the answer is already in context."
1035
+ )
1036
+
1037
+ return f"""### `{spec.tool_name}`
1038
+
1039
+ - **Capability**: `{spec.capability}`
1040
+ - **Profiles**: {profs_str}
1041
+ - **Task Categories**: {", ".join(f"`{t}`" for t in spec.task_types)}
1042
+
1043
+ #### Purpose
1044
+ {spec.description}
1045
+
1046
+ #### Use when
1047
+ {use_lines}
1048
+
1049
+ #### Avoid when
1050
+ {avoid_lines}
1051
+
1052
+ #### Required inputs
1053
+ {req_str}
1054
+
1055
+ #### Optional inputs
1056
+ {opt_str}
1057
+
1058
+ #### Minimal invocation
1059
+ ```python
1060
+ {spec.minimal_invocation or f"{spec.tool_name}()"}
1061
+ ```
1062
+
1063
+ #### Advanced invocation
1064
+ ```python
1065
+ {spec.advanced_invocation or spec.minimal_invocation or f"{spec.tool_name}()"}
1066
+ ```
1067
+
1068
+ #### Result interpretation
1069
+ - **Output Type**: `{spec.expected_output_type}`
1070
+ - **Key Fields**: {fields_str}
1071
+ - **Relationships Emitted**: {rels_str}
1072
+
1073
+ #### Evidence meaning
1074
+ {spec.evidence_guarantees}
1075
+
1076
+ #### Non-guarantees
1077
+ {spec.does_not_prove}
1078
+
1079
+ #### Typical follow-up
1080
+ {spec.typical_followup or "Stop if the question is answered, or perform a targeted `read_file`."}
1081
+
1082
+ #### Common mistakes
1083
+ {mistake_lines}
1084
+
1085
+ #### Example
1086
+ - **Developer request**: "{spec.example_request}"
1087
+ - **Call**: `{spec.example_call}`
1088
+ - **Interpretation**: {spec.example_interpretation}
1089
+ """
1090
+
1091
+
1092
+ def render_deep_agent_brain() -> str:
1093
+ """Render `docs/agent-brain.md` (Layer 3 Deep Agent Operating Manual) from code-derived registries."""
1094
+ # Build task classification table from CAPABILITY_MATRIX
1095
+ task_rows: list[str] = []
1096
+ for cat in AgentTaskCategory:
1097
+ rule = CAPABILITY_MATRIX[cat]
1098
+ seq_str = " -> ".join(f"`{s}`" for s in rule.recommended_sequence)
1099
+ primary_str = f"`{rule.primary_tool}`" if rule.primary_tool else "None (bypass CodeGraph)"
1100
+ task_rows.append(
1101
+ f"| `{cat.value}` | `{rule.should_use_codegraph}` | {primary_str} | {seq_str} | {rule.rationale} |"
1102
+ )
1103
+ task_table = "\n".join(task_rows)
1104
+
1105
+ # Build retrieval policies table from RETRIEVAL_POLICIES
1106
+ policy_rows: list[str] = []
1107
+ for intent_name, pol in sorted(RETRIEVAL_POLICIES.items()):
1108
+ valid_rels = sorted(r for r in pol.allowed_relationship_types if r in ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX)
1109
+ rels_preview = ", ".join(f"`{r}`" for r in valid_rels[:8])
1110
+ if len(valid_rels) > 8:
1111
+ rels_preview += ", ..."
1112
+ flow_str = " -> ".join(pol.preferred_flow)
1113
+ policy_rows.append(
1114
+ f"| `{intent_name}` | `{pol.max_graph_depth}` | {flow_str} | {rels_preview} |"
1115
+ )
1116
+ policy_table = "\n".join(policy_rows)
1117
+
1118
+ # Build relationship vocabulary section from ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX
1119
+ rel_sections: list[str] = []
1120
+ for rel_name in sorted(ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX.keys()):
1121
+ allowed_ev = ", ".join(f"`{e}`" for e in sorted(ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX[rel_name]))
1122
+ sem = RELATIONSHIP_SEMANTICS_REGISTRY[rel_name]
1123
+ rel_sections.append(
1124
+ f"#### `{rel_name}`\n"
1125
+ f"- **Meaning**: {sem.meaning}\n"
1126
+ f"- **Allowed Evidence Classes**: {allowed_ev}\n"
1127
+ f"- **Typical Source**: {sem.typical_source}\n"
1128
+ f"- **Typical Target**: {sem.typical_target}\n"
1129
+ f"- **What It Proves**: {sem.proves}\n"
1130
+ f"- **What It Does Not Prove**: {sem.does_not_prove}\n"
1131
+ f"- **Common Tool**: `{sem.common_tool}`\n"
1132
+ f"- **Example**: {sem.example}\n"
1133
+ )
1134
+ relationships_block = "\n".join(rel_sections)
1135
+
1136
+ # Build MCP profiles table from MCP_PROFILE_RECOMMENDATIONS
1137
+ profile_rows: list[str] = []
1138
+ for prof_name in ("agent", "core", "graph", "minimal", "developer", "full"):
1139
+ pinfo = MCP_PROFILE_RECOMMENDATIONS[prof_name]
1140
+ tools_list = ", ".join(f"`{t}`" for t in pinfo["included_tools"]) # type: ignore[attr-defined]
1141
+ profile_rows.append(
1142
+ f"| `{prof_name}` | `{pinfo['tool_count']}` | {pinfo['recommended_for']} | {tools_list} |"
1143
+ )
1144
+ profiles_table = "\n".join(profile_rows)
1145
+
1146
+ # Build 25 Complex Workflows section
1147
+ workflow_blocks: list[str] = []
1148
+ for wf in COMPLEX_WORKFLOW_EXAMPLES:
1149
+ workflow_blocks.append(
1150
+ f"### Workflow {wf.workflow_id}: {wf.title}\n"
1151
+ f"- **Developer request**: \"{wf.developer_request}\"\n"
1152
+ f"- **Task classification**: `{wf.task_classification}`\n"
1153
+ f"- **Why CodeGraph is appropriate**: {wf.why_codegraph}\n"
1154
+ f"- **First tool**: `{wf.first_tool}`\n"
1155
+ f"- **Arguments**: `{wf.arguments}`\n"
1156
+ f"- **Expected result interpretation**: {wf.expected_result_interpretation}\n"
1157
+ f"- **Follow-up tool**: `{wf.followup_tool}`\n"
1158
+ f"- **Stop condition**: {wf.stop_condition}\n"
1159
+ f"- **Source-read fallback**: {wf.source_read_fallback}\n"
1160
+ f"- **Final evidence handling**: {wf.final_evidence_handling}\n"
1161
+ )
1162
+ workflows_section = "\n".join(workflow_blocks)
1163
+
1164
+ # Build Complete Tool Reference section
1165
+ tool_ref_blocks: list[str] = []
1166
+ for spec in sorted(TOOL_CAPABILITY_REGISTRY, key=lambda s: s.tool_name):
1167
+ tool_ref_blocks.append(_format_tool_reference_section(spec))
1168
+ complete_tool_reference = "\n".join(tool_ref_blocks)
1169
+
1170
+ return f"""# CodeGraph Deep Agent Brain & Operating Manual (v{__version__})
1171
+
1172
+ > **Canonical Reference (`docs/agent-brain.md`)**
1173
+ > Generated deterministically from `src/codegraph/agent_capabilities.py`, `src/codegraph/evidence_contract.py`, `src/codegraph/retrieval_policy.py`, and `src/codegraph/mcp/server.py`.
1174
+ > Package: `codegraph-engine` (`v{__version__}`) | CLI: `codegraph` | MCP Command: `codegraph mcp serve`
1175
+
1176
+ ---
1177
+
1178
+ ## 1. CodeGraph Mental Model
1179
+
1180
+ CodeGraph is a **deterministic, local-first repository intelligence engine** exposed over the Model Context Protocol (MCP).
1181
+
1182
+ ```
1183
+ understand architecture -> get_architecture / get_context
1184
+ |
1185
+ find exact text/file -> find_symbol / search_code / find_routes
1186
+ |
1187
+ open targeted source -> get_file(path, start_line, end_line)
1188
+ |
1189
+ reason with evidence -> find_callers / find_callees / trace_path / find_tests
1190
+ |
1191
+ edit the repository -> IDE / editor write tools
1192
+ ```
1193
+
1194
+ CodeGraph parses source files into an SQLite-backed symbol, relationship, route, dependency-injection (DI), registry/dispatch, package-boundary, and test-coverage graph (Schema v8), paired with a deterministic literal/text search layer (`search_code`) and bounded source inspection (`get_file`). Every fact returned by CodeGraph carries explicit source coordinates (`file`, `start_line`, `end_line`), a canonical relationship type, and an epistemic `evidence_class`.
1195
+
1196
+ ---
1197
+
1198
+ ## 2. Agent Responsibility vs CodeGraph Responsibility
1199
+
1200
+ | Dimension | AI Coding Agent Responsibility | CodeGraph Engine Responsibility |
1201
+ | :--- | :--- | :--- |
1202
+ | **Intent & Planning** | Understands developer intent, classifies the task category, and selects the smallest sufficient tool via `ROUTING_MANIFEST`. | Normalizes task targets (`TargetResolver`), expands ambiguous generic names (`QueryExpansion`), and applies intent-specific `RetrievalPolicy`. |
1203
+ | **Interrogation** | Calls targeted MCP tools (`find_symbol`, `search_code`, `find_callers`, `find_callees`, `trace_path`, `find_routes`, `find_tests`, `get_file`, `get_context`, etc.). | Queries AST, framework, dataflow indices, and non-binary text files deterministically in sub-second warm latency. |
1204
+ | **Epistemic Honesty** | Preserves `UNKNOWN`, `POSSIBLE`, and `AMBIGUOUS` states; never invents graph edges or fabricates coverage from `search_code` text matches. | Enforces `ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX` via `RelationshipRecord` fail-closed validation and keeps text search strictly separate from semantic graph edges. |
1205
+ | **Source Code Inspection** | Uses `get_file(path, start_line, end_line, max_lines)` (or `read_file`) on narrow line ranges when exact implementation statements are needed. | Identifies the exact files and line spans where symbols, calls, routes, DI bindings, and literal strings live. |
1206
+ | **Code Modification** | Synthesizes the final explanation or edits source files safely. | Never executes repository code, never mutates user source files, and blocks sensitive file reads. |
1207
+
1208
+ ---
1209
+
1210
+ ## 3. Repository Intelligence Model
1211
+
1212
+ CodeGraph models a repository across eight deterministic intelligence layers:
1213
+
1214
+ 1. **Epistemic Symbol & Relationship Graph**: Canonical symbols (`canonical_id`, `qualified_name`, `kind`, `signature`) connected by typed `RelationshipRecord` edges.
1215
+ 2. **Route & Mount Composition**: HTTP/RPC routes (`HANDLED_BY`, `ROUTE_HANDLER`, `ROUTES_TO`) and nested router prefix mounts (`MOUNTS`) across FastAPI, Flask, Django, Express, and NestJS.
1216
+ 3. **Conservative Dataflow & Binding**: Intra-file and constructor attribute bindings (`BINDS_TO`, `RESOLVES_TO`, `ALIASED_TO`).
1217
+ 4. **Registry, Dispatch & Event Intelligence**: Explicit separation of registration (`REGISTERS`, `REGISTERED_HANDLER`), dispatch (`DISPATCHES_TO`), and event subscription (`EVENT_LISTENER`).
1218
+ 5. **Semantic Decorators, Tasks & Commands**: Background tasks (`TASK_HANDLER`) and CLI commands (`COMMAND_HANDLER`).
1219
+ 6. **Dependency Injection & Configuration**: FastAPI `Depends`, `Annotated`, container bindings, and provider factories (`INJECTS`, `PROVIDES`, `RESOLVES_DEPENDENCY`, `CONFIGURES`, `DI_CYCLE`).
1220
+ 7. **Test Intelligence & Deterministic Change Impact**: Static test links (`TESTS`, `TESTS_SYMBOL`, `TESTS_ROUTE`, `TESTS_PROVIDER`, `TESTS_EVENT_HANDLER`) and Git diff blast radius (`get_git_impact`, `analyze_impact`).
1221
+ 8. **Monorepo, Workspace & Artifact Intelligence**: Manifest-backed workspace packages (`DEPENDS_ON_PACKAGE`, `CROSS_PACKAGE_IMPORT`, `PACKAGE_IMPORTS`, `CONTAINS_PACKAGE`) and artifact suppression (`SOURCE` vs `GENERATED`/`BUNDLE`/`MINIFIED`/`VENDOR`).
1222
+
1223
+ ---
1224
+
1225
+ ## 4. Evidence Model
1226
+
1227
+ CodeGraph enforces nine canonical `evidence_class` values defined in `ALLOWED_EVIDENCE_CLASSES`:
1228
+
1229
+ - **`AST_VERIFIED`**: Supported directly by static syntax/AST evidence (e.g., function definition, direct call expression, explicit import statement).
1230
+ - **`STATIC_VERIFIED`**: Supported directly by static SQL DDL/DML parsing, schema files, or migration scripts (`CREATE TABLE`, `INSERT INTO`, `op.create_table`).
1231
+ - **`FRAMEWORK_VERIFIED`**: Proven by recognized deterministic framework semantics (e.g., `@router.post('/login')`, `app.include_router(..., prefix='/api/v1')`, `Depends(get_db)`, SQLAlchemy/Django/SQLModel/Prisma ORM mappings, `@celery.task`).
1232
+ - **`DATAFLOW_VERIFIED`**: Proven by conservative deterministic data-flow analysis (e.g., `self.repo = repo` in `__init__` followed by `self.repo.find_by_email()`, factory return binding `svc = get_inventory_service()` -> `svc.place_order()`, or static dictionary registry assignment `HANDLERS['create'] = handle_create`).
1233
+ - **`RUNTIME_OBSERVED`**: Observed in an ingested runtime trace (OpenTelemetry JSON, JSONL runtime events, or SQL query logs) with `observation_count`, `first_seen`, `last_seen`, and `runtime_generation`. Never converted into static `AST_VERIFIED` proof.
1234
+ - **`RUNTIME_UNOBSERVED`**: Static relationship was not observed in the ingested runtime trace sample (`NOT_OBSERVED_AT_RUNTIME`). Never proves that the path cannot execute.
1235
+ - **`POSSIBLE`**: Plausible static candidate that is not statically guaranteed (e.g., conditional registration inside an `if` branch, dynamic SQL table interpolation `POSSIBLE_TABLE`, multiple interface implementations, or heuristic match).
1236
+ - **`UNKNOWN`**: Static analysis could not establish the target (e.g., `getattr(module, dynamic_name)()`, `eval()`, opaque SQL string `UNKNOWN_TABLE`, or unresolvable database dialect/schema).
1237
+ - **`AMBIGUOUS`**: Multiple candidate symbols or database tables match the target name across modules or schemas; requires disambiguation via `alternatives`.
1238
+
1239
+ ### Non-Negotiable Epistemic Rules
1240
+ 1. **`UNKNOWN != no relationship`**: `UNKNOWN` means static analysis could not prove the target—never claim "there is no relationship" from `UNKNOWN`.
1241
+ 2. **`POSSIBLE != verified`**: Treat `POSSIBLE` as a lead requiring a targeted `get_file` / `read_file` check before stating as fact.
1242
+ 3. **`AMBIGUOUS != choose first candidate`**: When multiple symbols match, inspect `alternatives` and disambiguate by module/package/caller context.
1243
+ 4. **Static vs Runtime Separation**: Never convert `RUNTIME_OBSERVED` into static `AST_VERIFIED` proof, never convert static inference into runtime fact, and never treat `NOT_OBSERVED_AT_RUNTIME` (`RUNTIME_UNOBSERVED`) as proof of dead code.
1244
+ 5. **Fail-Closed Contract**: `CALLS` and `CALLED_BY` can only be `AST_VERIFIED`, `DATAFLOW_VERIFIED`, or `RUNTIME_OBSERVED`. Uncertain call edges must use `POSSIBLE_CALLS` with `POSSIBLE` or `UNKNOWN`.
1245
+ 6. **Text Search != Semantic Edge**: `search_code` text matches across HTML, Jinja, JS, CSS, or config files NEVER create `CALLS`, `REFERENCES`, `IMPORTS`, `ROUTES`, or `DEPENDS_ON_PACKAGE` graph edges.
1246
+
1247
+ ---
1248
+
1249
+ ## 5. Relationship Model
1250
+
1251
+ CodeGraph enforces the 56 canonical relationship types in `ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX`. It **never** collapses framework routing, database operations, registry registration, or dependency injection into generic `CALLS` or `DEPENDS_ON`.
1252
+
1253
+ {relationships_block}
1254
+
1255
+ ---
1256
+
1257
+ ## 6. Task Classification & Routing Manifest
1258
+
1259
+ CodeGraph classifies developer requests into 13 canonical `AgentTaskCategory` values and provides a deterministic `ROUTING_MANIFEST`:
1260
+
1261
+ | Category | Use CodeGraph? | Primary Tool | Recommended Sequence | Rationale |
1262
+ | :--- | :--- | :--- | :--- | :--- |
1263
+ {task_table}
1264
+
1265
+ ### Deterministic `ROUTING_MANIFEST`
1266
+ - `symbol_definition` -> `find_symbol`
1267
+ - `symbol_details` -> `get_symbol`
1268
+ - `text_or_template_search` -> `search_code`
1269
+ - `file_inspection` -> `get_file`
1270
+ - `callers` -> `find_callers`
1271
+ - `callees` -> `find_callees`
1272
+ - `references` -> `find_references`
1273
+ - `routes` -> `find_routes`
1274
+ - `tests` -> `find_tests`
1275
+ - `execution_trace` -> `trace_path`
1276
+ - `architecture` -> `get_architecture`
1277
+ - `task_context` -> `get_context`
1278
+ - `git_impact` -> `get_git_impact`
1279
+
1280
+ ---
1281
+
1282
+ ## 7. Decision Tree
1283
+
1284
+ Use this deterministic decision tree before invoking any tool:
1285
+
1286
+ 1. **Developer asks: "Change this one local variable / Fix a typo in a docstring in a known file."**
1287
+ - **Classification**: `LOCAL_EDIT`
1288
+ - **Decision**: Bypass CodeGraph -> use `get_file` / `read_file` / editor tools directly.
1289
+ - **Why**: Single-file local edits do not depend on cross-file relationships; calling graph tools wastes tokens and latency.
1290
+ 2. **Developer asks: "Where is symbol X defined?"**
1291
+ - **Classification**: `SYMBOL_LOOKUP`
1292
+ - **Decision**: Call `find_symbol(symbol="X")` (or `resolve_symbol(symbol="X")`), then `get_symbol(symbol=...)` if signature/decorators are needed.
1293
+ - **Why**: Grounds `X` into a canonical symbol ID and surfaces any homonym ambiguity immediately.
1294
+ 3. **Developer asks: "Where does literal text, button label, HTML id, or template string Y appear?"**
1295
+ - **Classification**: `text_or_template_search`
1296
+ - **Decision**: Call `search_code(query="Y")` -> `get_file(path=..., start_line=..., end_line=...)`.
1297
+ - **Why**: Searches `.py`, `.html`, `.jinja`, `.jinja2`, `.js`, `.jsx`, `.ts`, `.tsx`, `.css`, `.json`, `.yaml`, `.yml`, and `.md` files deterministically without polluting the semantic graph.
1298
+ 4. **Developer asks: "What calls X?" or "What does X call?"**
1299
+ - **Classification**: `RELATIONSHIP`
1300
+ - **Decision**: Call `find_callers(symbol="X")` or `find_callees(symbol="X")` (`get_callers` and `get_callees` are also supported).
1301
+ - **Why**: Returns AST- and dataflow-verified call edges (`CALLS`) distinct from lexical text matches.
1302
+ 5. **Developer asks: "Which route handles `/api/v1/auth/login` and how does it reach the database?"**
1303
+ - **Classification**: `ROUTE_DISCOVERY` / `TRACE`
1304
+ - **Decision**: Call `find_routes(path="/api/v1/auth/login")` (or `list_routes`) -> `trace_path(from_symbol=..., to_symbol=...)` (or `get_context(query=..., intent="TRACE")`).
1305
+ - **Why**: Composes mounted router prefixes (`MOUNTS`) with `HANDLED_BY`, `INJECTS`, and `CALLS`.
1306
+ 6. **Developer asks: "Why does this fail?" or "How does this dependency get injected?"**
1307
+ - **Classification**: `DEBUG`
1308
+ - **Decision**: Call `get_context(query=..., intent="DEBUG")`, followed by targeted `get_file(path, start_line, end_line)` on specific lines if needed.
1309
+ - **Why**: Compiles target symbol, callers, callees, DI providers (`INJECTS`, `PROVIDES`, `RESOLVES_DEPENDENCY`), and covering tests in one token-bounded packet.
1310
+ 7. **Developer asks: "What breaks if we change X?" or "What is the impact of recent commits?"**
1311
+ - **Classification**: `CHANGE_IMPACT`
1312
+ - **Decision**: Call `get_git_impact(base="HEAD~1", head="HEAD")` (for Git diffs) or `analyze_impact(symbol=...)` (for symbol edits).
1313
+ - **Why**: Computes downstream callers, affected routes, affected packages, and covering tests deterministically.
1314
+ 8. **Developer asks: "What tests cover X?"**
1315
+ - **Classification**: `TEST_DISCOVERY`
1316
+ - **Decision**: Call `find_tests(symbol="X")` (or `find_related_tests(symbol="X")`).
1317
+ - **Why**: Links tests via static call, import, fixture, or route invocation (`TESTS_SYMBOL`, `TESTS_ROUTE`, `TESTS_PROVIDER`, `TESTS_EVENT_HANDLER`).
1318
+ 9. **Developer asks: "How is the whole system or monorepo structured?"**
1319
+ - **Classification**: `ARCHITECTURE` / `PACKAGE`
1320
+ - **Decision**: Call `get_architecture()` -> `get_context(query=..., intent="ARCHITECTURE")`.
1321
+ - **Why**: Extracts manifest-backed workspace packages (`DEPENDS_ON_PACKAGE`), entrypoints, and module boundaries without dumping the entire repository.
1322
+
1323
+ ---
1324
+
1325
+ ## 8. Symbol Resolution
1326
+
1327
+ Always ground bare symbol names with `find_symbol(symbol=...)` or `resolve_symbol(symbol=...)` before querying relationships when exact canonical identity is unknown (`canonical_id` and `name` are also accepted as explicit compatibility aliases).
1328
+
1329
+ - **Resolution Order (`TargetResolver`)**:
1330
+ 1. Exact `canonical_id` (`CANONICAL_ID`, `HIGH` confidence)
1331
+ 2. Exact `qualified_name` (`EXACT_QUALIFIED`, `HIGH` confidence)
1332
+ 3. Exact route path or endpoint ID (`ROUTE_MATCH`, `HIGH` confidence)
1333
+ 4. `module.symbol` resolution (`MODULE_SYMBOL`, `HIGH`/`MEDIUM` confidence)
1334
+ 5. `Class.method` resolution (`CLASS_METHOD`, `HIGH` confidence)
1335
+ 6. Exact filename match (`FILENAME`, `HIGH` confidence)
1336
+ 7. Short name match (`LEXICAL`: `MEDIUM` if unique, `AMBIGUOUS` / `LOW` if multiple definitions exist)
1337
+ 8. No match (`UNKNOWN`)
1338
+ - **Rule**: Once you have a `canonical_id` in the current turn, pass that identifier via `symbol=...` (or `canonical_id=...`) directly to `find_callers`, `find_callees`, `find_references`, or `get_symbol`. Never call `resolve_symbol` repeatedly for the same symbol.
1339
+
1340
+ ---
1341
+
1342
+ ## 9. Search / Discovery (`find_symbol` vs `search_code`)
1343
+
1344
+ CodeGraph provides two distinct discovery layers that must never be conflated:
1345
+
1346
+ 1. **Semantic Symbol Discovery (`find_symbol(symbol)` / `search_symbols(query, top_k=20)`)**:
1347
+ - Searches indexed AST symbol declarations (`class`, `function`, `method`, `interface`).
1348
+ - Use when looking for where a Python/TS/JS/Go/Rust symbol or identifier is defined.
1349
+ 2. **Repository Text Search (`search_code(query, path_filter=None, file_types=None, include_tests=True, include_configs=True, max_results=20)`)**:
1350
+ - Searches literal text, exact phrases, identifiers, route strings, HTML ids/classes, UI button text, Jinja template blocks, CSS selectors, config keys, and markdown across `.py`, `.html`, `.jinja`, `.jinja2`, `.js`, `.jsx`, `.ts`, `.tsx`, `.css`, `.json`, `.yaml`, `.yml`, and `.md` files.
1351
+ - Respects sensitive-file exclusions, binary exclusions, `.gitignore`/`.codegraphignore`, and artifact policies.
1352
+ - Returns deterministic results (`path`, `line`, `matched_text`, `snippet`, `category`, `score`, `reason`) ordered by `(-score, path, line)`.
1353
+ - **Strict Separation Rule**: `search_code` is for literal/text discovery only. It never creates semantic graph edges (`CALLS`, `REFERENCES`, `IMPORTS`, `ROUTES`, `DEPENDS_ON_PACKAGE`) and never pollutes `get_context` graph relationships.
1354
+
1355
+ ---
1356
+
1357
+ ## 10. Symbol & File Inspection (`get_symbol` & `get_file`)
1358
+
1359
+ - **`get_symbol(symbol=...)`** (or `canonical_id=...`): Inspects a symbol's declaration metadata (`canonical_id`, `qualified_name`, `kind`, `signature`, `decorators`, `file`, `start_line`, `end_line`, `snippet`) without reading the entire file.
1360
+ - **`get_file(path=..., start_line=None, end_line=None, max_lines=200, include_content=False)`**:
1361
+ - Opens a file's AST symbol outline AND/OR reads a bounded line range (`start_line`..`end_line`, capped by `max_lines`) across any readable repository text file (`.py`, `.html`, `.jinja`, `.js`, `.ts`, `.css`, `.yaml`, `.json`, `.md`).
1362
+ - Returns `path`, `start_line`, `end_line`, `content`, `truncated: bool`, and `category` (`SOURCE`, `TEST`, `CONFIG`, etc.).
1363
+
1364
+ ---
1365
+
1366
+ ## 11. References
1367
+
1368
+ Use `get_references(symbol=...)` or `find_references(symbol=...)` (alias `canonical_id=...`) to find structured references to a symbol across the repository:
1369
+ - `get_references` returns references with explicit `relationship` (`CALLS`, `IMPORTS`, `REGISTERS`, `DISPATCHES_TO`, `EVENT_LISTENER`, `INJECTS`, `PROVIDES`, `RESOLVES_DEPENDENCY`, `REFERENCES`) and `evidence_class`.
1370
+
1371
+ ---
1372
+
1373
+ ## 12. Callers / Callees
1374
+
1375
+ - **`find_callers(symbol=...)` / `get_callers(symbol=...)`** (alias `canonical_id=...`): Returns upstream symbols that call `symbol`.
1376
+ - **`find_callees(symbol=...)` / `get_callees(symbol=...)`** (alias `canonical_id=...`): Returns downstream symbols called by `symbol`.
1377
+ - **Symmetric Factory & Dataflow Resolution**:
1378
+ - Forward (`find_callees`, `get_callees`), reverse (`find_callers`, `get_callers`), and path (`trace_path`) traversal share the same conservative dataflow and factory resolution engine. When a caller invokes `svc = get_inventory_service()` and calls `svc.place_order()`, both forward and reverse traversal agree on `CALLS` (`DATAFLOW_VERIFIED`, `confidence="HIGH"`).
1379
+ - **Epistemic Distinction**:
1380
+ - `relationship="CALLS"` with `evidence_class="AST_VERIFIED"` or `"DATAFLOW_VERIFIED"` proves a static call site.
1381
+ - `relationship="POSSIBLE_CALLS"` with `evidence_class="POSSIBLE"` or `"UNKNOWN"` indicates a candidate or dynamic call site that requires source verification via `get_file` / `read_file`.
1382
+
1383
+ ---
1384
+
1385
+ ## 13. Graph Tracing
1386
+
1387
+ - **`trace_path(from_symbol=..., to_symbol=..., max_depth=5)`**: Computes deterministic shortest/ranked relationship paths connecting `from_symbol` to `to_symbol`. Traverses `HANDLED_BY`, `MOUNTS`, `CALLS`, `INJECTS`, `PROVIDES`, `RESOLVES_DEPENDENCY`, `DISPATCHES_TO`, `TASK_HANDLER`, `COMMAND_HANDLER`, and `EVENT_LISTENER`.
1388
+ - **`trace_flow(symbol=..., depth=2, callers=True, callees=False, both=False)`** (and alias `trace_call`): Explores directional call trees from a single symbol when only one endpoint is known.
1389
+ - **`get_call_graph(symbol=..., depth=2, max_results=100)`**: Computes the bounded local call neighborhood subgraph around `symbol`.
1390
+
1391
+ ---
1392
+
1393
+ ## 14. Routes / Frameworks
1394
+
1395
+ Use `find_routes(framework=None, method=None, path=None)` (or `list_routes`) to interrogate web/RPC entrypoints:
1396
+ - Supported frameworks include FastAPI, Flask, Django, Express, and NestJS.
1397
+ - **Mount Composition (`MOUNTS`)**: When `app.include_router(auth_router, prefix="/api/v1")` mounts a router whose route is `@router.post("/auth/login")`, CodeGraph composes the full path `/api/v1/auth/login` (`FRAMEWORK_VERIFIED`) and links the router via `MOUNTS` and the endpoint via `HANDLED_BY` / `ROUTE_HANDLER`.
1398
+ - Never grep for full URL paths in repositories that compose router prefixes; always call `find_routes` / `list_routes` first.
1399
+
1400
+ ---
1401
+
1402
+ ## 15. Registries
1403
+
1404
+ CodeGraph models handler registries and plugin tables explicitly:
1405
+ - **`REGISTERS`**: Emitted when a decorator (`@registry.register("key")`) or assignment (`REGISTRY["key"] = Handler`) registers a symbol into a registry.
1406
+ - **`REGISTERED_HANDLER`**: Connects the registry or key to the registered handler symbol.
1407
+ - **Rule**: Never convert `REGISTERS` into `CALLS`. Registration records that a handler was added to a registry; invocation occurs only at dispatch sites (`DISPATCHES_TO`).
1408
+ - **Overwrite & Conditional Behavior**:
1409
+ - If a registry key is conditionally registered (`if settings.USE_V2:`), CodeGraph assigns `evidence_class="POSSIBLE"`.
1410
+ - If multiple handlers register the same key or overwrite it, CodeGraph preserves all candidates and marks ambiguity rather than silently dropping earlier registrations.
1411
+
1412
+ ---
1413
+
1414
+ ## 16. Dispatch
1415
+
1416
+ - **`DISPATCHES_TO`**: Emitted when a dispatcher function looks up a handler in a known registry (`registry.dispatch(key)`, `HANDLERS[kind]()`) and invokes it.
1417
+ - **Known Static Key**: Marked `FRAMEWORK_VERIFIED` or `DATAFLOW_VERIFIED`.
1418
+ - **Ambiguous / Multiple Candidate Handlers**: Marked `POSSIBLE` with candidate targets preserved.
1419
+ - **Dynamic Runtime Key (`getattr`, opaque variable)**: Marked `UNKNOWN` (`UNRESOLVED_REFERENCE` / `POSSIBLE_CALLS`) so the agent knows static analysis reached a dynamic boundary.
1420
+
1421
+ ---
1422
+
1423
+ ## 17. Events
1424
+
1425
+ - **`EVENT_LISTENER`**: Emitted when a function or method subscribes to an event bus, signal, or event class (`@bus.on(OrderCreated)`, `signal.connect(handler)`).
1426
+ - Use `get_references(symbol="<EventName>")` or `get_context(query=..., intent="TRACE")` to discover all listeners subscribed to an event.
1427
+
1428
+ ---
1429
+
1430
+ ## 18. Tasks
1431
+
1432
+ - **`TASK_HANDLER`**: Emitted for background task declarations (`@app.task`, `@shared_task`, `@dramatiq.actor`).
1433
+ - When tracing `.delay(...)` or `.apply_async(...)` calls, CodeGraph links the task invocation to the `TASK_HANDLER` symbol with `FRAMEWORK_VERIFIED` evidence.
1434
+
1435
+ ---
1436
+
1437
+ ## 19. Commands
1438
+
1439
+ - **`COMMAND_HANDLER`**: Emitted for CLI command decorators (`@app.command()`, `@click.command()`).
1440
+ - Use `search_symbols` or `get_context` to locate the `COMMAND_HANDLER` and trace its downstream service calls.
1441
+
1442
+ ---
1443
+
1444
+ ## 20. Dependency Injection (DI)
1445
+
1446
+ CodeGraph models Dependency Injection through four dedicated relationship types—**never** collapsing DI into `CALLS`:
1447
+
1448
+ 1. **`INJECTS`**: Consumer endpoint/class declares a dependency (`login_endpoint` -> `INJECTS` -> `get_auth_service`).
1449
+ 2. **`PROVIDES`**: Provider function or factory returns/yields the service type (`get_auth_service` -> `PROVIDES` -> `AuthService`).
1450
+ 3. **`RESOLVES_DEPENDENCY`**: Container or override binds an interface/token to a concrete implementation (`PaymentGateway` -> `RESOLVES_DEPENDENCY` -> `StripeGateway`).
1451
+ 4. **`CONFIGURES`**: Configuration symbol wires settings into a provider or container (`AuthConfig` -> `CONFIGURES` -> `get_auth_service`).
1452
+
1453
+ ### Canonical DI Chain Example
1454
+ ```
1455
+ POST /api/v1/auth/login
1456
+ --[HANDLED_BY (FRAMEWORK_VERIFIED)]--> login_endpoint
1457
+ --[INJECTS (FRAMEWORK_VERIFIED)]-----> get_auth_service
1458
+ --[PROVIDES (FRAMEWORK_VERIFIED)]----> AuthService
1459
+ --[BINDS_TO (DATAFLOW_VERIFIED)]-----> UserRepository
1460
+ --[CALLS (AST_VERIFIED)]-------------> UserRepository.find_by_email
1461
+ ```
1462
+
1463
+ - **FastAPI `Depends` & `Annotated`**: Both `svc: AuthService = Depends(get_auth_service)` and `Annotated[AuthService, Depends(get_auth_service)]` emit `INJECTS` and `PROVIDES`.
1464
+ - **Router & App Dependencies**: `APIRouter(dependencies=[Depends(verify_api_key)])` attaches `INJECTS` edges at the router/route level.
1465
+ - **Multiple Providers / Ambiguity**: When multiple providers can satisfy the same token (e.g., prod vs test container bindings), CodeGraph marks the binding `POSSIBLE` or `AMBIGUOUS`.
1466
+ - **Cycles (`DI_CYCLE`)**: Circular provider dependencies (`A -> B -> A`) emit `DI_CYCLE` so debugging tools surface the cycle immediately.
1467
+
1468
+ ---
1469
+
1470
+ ## 21. Providers
1471
+
1472
+ When investigating a provider symbol (such as `get_db`, `get_current_user`, or a container factory):
1473
+ - Call `resolve_symbol` -> `get_references(symbol=...)` or `get_context(query=..., intent="DEBUG")` to see:
1474
+ - What type the provider `PROVIDES`.
1475
+ - Which endpoints/services `INJECTS` the provider.
1476
+ - Which tests override or exercise the provider via `TESTS_PROVIDER`.
1477
+
1478
+ ---
1479
+
1480
+ ## 22. Package / Workspace Intelligence
1481
+
1482
+ CodeGraph detects monorepo and workspace boundaries strictly from **manifest evidence** (`package.json`, `pnpm-workspace.yaml`, `pyproject.toml`, `Cargo.toml`, `go.mod`)—**never** from directory names like `apps/`, `packages/`, or `services/` alone.
1483
+
1484
+ - **Traversal Order**:
1485
+ `target package` -> `direct package dependencies (DEPENDS_ON_PACKAGE)` -> `bounded transitive dependencies (max_package_depth)`.
1486
+ - **Key Concepts**:
1487
+ - **Owning Package**: The nearest manifest-backed package containing a file.
1488
+ - **Package ID & Type**: Canonical package identifier (e.g., `@acme/auth`) and manifest type (`npm`, `python`, `cargo`, `go`).
1489
+ - **Cross-Package Imports (`CROSS_PACKAGE_IMPORT`, `PACKAGE_IMPORTS`)**: Proven when a file in Package A imports a file/symbol owned by Package B.
1490
+ - **Unresolved External Dependency**: Third-party imports outside the workspace are recorded as external imports and never confused with internal workspace packages.
1491
+
1492
+ ---
1493
+
1494
+ ## 23. Tests
1495
+
1496
+ CodeGraph links tests to production symbols via `find_tests(symbol=...)` (and `find_related_tests(symbol=...)`) across five verified relationship types:
1497
+ - `TESTS`: General verified test-to-symbol coverage link.
1498
+ - `TESTS_SYMBOL`: Direct AST call or reference from a test function to a production symbol.
1499
+ - `TESTS_ROUTE`: Test client request (`client.get("/api/...")`) matching an indexed route.
1500
+ - `TESTS_PROVIDER`: Test fixture or dependency override targeting a DI provider.
1501
+ - `TESTS_EVENT_HANDLER`: Test exercising an event listener, task handler, or command handler.
1502
+
1503
+ > **Hard Rule**: CodeGraph never fabricates test coverage from lexical filename similarity alone when static call/import/route/fixture evidence is absent.
1504
+
1505
+ ---
1506
+
1507
+ ## 24. Change Impact
1508
+
1509
+ Use `get_git_impact(base="HEAD~1", head="HEAD")` (for Git commit ranges) or `analyze_impact(symbol=..., max_depth=3)` (for planned symbol edits):
1510
+ - Computes modified symbols, direct and transitive callers, affected routes, affected workspace packages, and covering tests.
1511
+ - Combine `analyze_impact` with `find_tests` / `find_related_tests` before refactoring any public method signature.
1512
+
1513
+ ---
1514
+
1515
+ ## 25. Architecture
1516
+
1517
+ Use `get_architecture()` as the first tool for macro-level questions:
1518
+ - Returns indexed modules, manifest-backed workspace packages, `DEPENDS_ON_PACKAGE` edges, entrypoints, and framework routes.
1519
+ - Do not dump all files with `get_project_structure()` or read dozens of files when `get_architecture()` answers the structural question in one call.
1520
+
1521
+ ---
1522
+
1523
+ ## 26. Debugging
1524
+
1525
+ For bug investigations (`AgentTaskCategory.DEBUG`):
1526
+ 1. Ground the failing symbol or endpoint via `find_symbol` / `resolve_symbol` (or `find_routes` / `list_routes`).
1527
+ 2. Call `get_context(query=..., intent="DEBUG", max_tokens=4000)` to assemble the target definition, callers, callees, error paths, DI bindings, and related tests.
1528
+ 3. Call `get_file(path, start_line, end_line)` (or `read_file`) on the exact line range where the fault occurs to inspect statement-level logic.
1529
+
1530
+ ---
1531
+
1532
+ ## 27. Context Compilation
1533
+
1534
+ `get_context` compiles a token-bounded, coverage-optimized `ContextPacket`:
1535
+
1536
+ ```
1537
+ Repository -> Candidate Facts -> Task-Aware Filtering (RetrievalPolicy)
1538
+ -> Relationship-Aware Ranking -> Redundancy Elimination
1539
+ -> Coverage-Aware Selection -> ContextPacket
1540
+ ```
1541
+
1542
+ ### Intent-Specific Retrieval Policies (`RETRIEVAL_POLICIES`)
1543
+
1544
+ | Intent | Max Depth | Preferred Coverage Flow | Allowed Relationships (Sample) |
1545
+ | :--- | :--- | :--- | :--- |
1546
+ {policy_table}
1547
+
1548
+ - **Hard Invariants & Output Boundaries of `get_context`**:
1549
+ - Primary input is `query` (`task` is also supported as a string or `TaskSpec` dict alias).
1550
+ - Enforces strict output boundaries BEFORE MCP serialization: `max_tokens` (default `4000`, hard cap `20000`), `max_files` (default `15`, hard cap `30`), and `max_lines` (default `500`, hard cap `1500`).
1551
+ - Returns explicit budget metadata: `selected_tokens`, `candidate_tokens`, `selected_files`, `selected_lines`, `coverage_score`, and `truncated`.
1552
+ - Preserves `unknowns` and `ambiguities` explicitly—never drops uncertainty to save tokens.
1553
+ - Compresses duplicate `(source, target, relationship)` edges into a single record with `occurrence_count` and `supporting_locations`.
1554
+ - Enforces hierarchical exclusions (`TaskSpec.exclusions`).
1555
+
1556
+ ---
1557
+
1558
+ ## 28. Artifact Handling
1559
+
1560
+ CodeGraph classifies every file into an `ArtifactType`:
1561
+ - **`SOURCE`**: Authored production source code (prioritized by default).
1562
+ - **`TEST`**: Test suites and fixtures (included for test/debug/impact intents).
1563
+ - **`CONFIG`**: Configuration and manifest files.
1564
+ - **`GENERATED`**: Code-generated files (OpenAPI clients, protobufs, migrations)—suppressed by default unless requested.
1565
+ - **`BUILD_ARTIFACT`**: Compiled outputs (`dist/`, `build/`, `.next/`).
1566
+ - **`BUNDLE`** / **`MINIFIED`**: Webpack/Rollup/esbuild bundles and `.min.js` files.
1567
+ - **`VENDOR`**: Third-party vendor trees (`vendor/`, `third_party/`).
1568
+ - **`BINARY`** / **`UNKNOWN`**: Non-text or unrecognized files (never read by `get_file` or `read_file`).
1569
+
1570
+ **Agent Rule**: Always prefer authored `SOURCE` symbols over `GENERATED`, `BUNDLE`, `MINIFIED`, or `VENDOR` copies.
1571
+
1572
+ ---
1573
+
1574
+ ## 29. Source Reads (`get_file` & `read_file`)
1575
+
1576
+ - **Division of Labor**:
1577
+ - **CodeGraph** tells you **WHERE** symbols and literal strings live and **HOW** symbols relate across files (`file`, `start_line`, `end_line`, `relationship`, `evidence_class`).
1578
+ - **`get_file(path, start_line, end_line, max_lines)`** (or `read_file(path, start_line, end_line)`) tells you **EXACTLY** what implementation statements or template lines exist inside those lines.
1579
+ - **Policy**:
1580
+ 1. Never invent implementation details from graph edges alone.
1581
+ 2. Use CodeGraph (`find_symbol`, `search_code`, `find_routes`, `get_context`) first to narrow a 500-file repository down to the 1–2 relevant files and exact line spans.
1582
+ 3. Call `get_file(path, start_line=..., end_line=..., max_lines=200)` with bounded ranges across `.py`, `.html`, `.jinja`, `.js`, `.ts`, `.css`, `.yaml`, `.json`, or `.md`.
1583
+ 4. Never attempt to read `.env`, private keys (`id_rsa`, `.pem`), or credentials—CodeGraph blocks sensitive paths with `SecurityError`.
1584
+
1585
+ ---
1586
+
1587
+ ## 30. `UNKNOWN` Handling Workflow
1588
+
1589
+ When a CodeGraph tool returns `evidence_class="UNKNOWN"` or an entry in `unknowns`:
1590
+ 1. **Understand what could not be proven**: Read the `reason` field (e.g., dynamic `getattr`, `eval`, unindexed external call).
1591
+ 2. **Never claim absence**: Do **not** state "X does not call Y" or "no relationship exists." `UNKNOWN` means static analysis could not establish the relationship.
1592
+ 3. **Perform a targeted source read**: Call `get_file(path, start_line, end_line)` (or `read_file`) on the cited call site to inspect how the dynamic target is constructed.
1593
+ 4. **Preserve uncertainty**: If the target depends on runtime input or external configuration, report the relationship as statically `UNKNOWN` and explain the runtime condition.
1594
+
1595
+ ---
1596
+
1597
+ ## 31. `POSSIBLE` Handling Workflow
1598
+
1599
+ When a CodeGraph tool returns `evidence_class="POSSIBLE"` or `relationship="POSSIBLE_CALLS"`:
1600
+ 1. **Treat as a lead, not a proven fact**: Do not present `POSSIBLE` edges as `AST_VERIFIED` truth.
1601
+ 2. **Inspect supporting locations**: Check `file`, `start_line`, and `reason`.
1602
+ 3. **Verify with `get_file` / `read_file`**: Read the cited lines to confirm whether the conditional binding, interface implementation, or registry target applies to the user's scenario.
1603
+ 4. **Upgrade or reject**: Only make a definitive claim after source verification confirms the behavior.
1604
+
1605
+ ---
1606
+
1607
+ ## 32. `AMBIGUOUS` Handling Workflow
1608
+
1609
+ When `resolve_symbol`, `find_symbol`, `compile_task`, or `get_context` returns `ambiguity_state="AMBIGUOUS"`:
1610
+ 1. **Inspect `alternatives`**: Examine all candidate symbols returned in `alternatives` / `matches`.
1611
+ 2. **Compare `canonical_id` and `file`**: Check which workspace package and module each candidate belongs to.
1612
+ 3. **Check caller/route context**: If the prompt mentions a route, package, or caller, match the candidate in that scope.
1613
+ 4. **Never pick `candidates[0]` arbitrarily**: Only select a candidate when contextual evidence disambiguates it; otherwise report the ambiguity or ask the user to clarify.
1614
+
1615
+ ---
1616
+
1617
+ ## 33. Stale Index Handling
1618
+
1619
+ CodeGraph tracks repository index freshness via `generation` and `freshness` (`FRESH` vs `STALE`):
1620
+ - **How to check**: Inspect the `freshness` field in `get_repository_status()`, `get_context()`, or interrogation tool outputs.
1621
+ - **When `freshness == "STALE"`**:
1622
+ - One or more files on disk (`modified_files` / `deleted_files`) have changed since the index was built.
1623
+ - Do **not** present cached graph relationships from modified files as current truth.
1624
+ - Either verify the modified files directly with `get_file` / `read_file` or refresh the index (`codegraph index`).
1625
+
1626
+ ---
1627
+
1628
+ ## 34. MCP Profiles
1629
+
1630
+ CodeGraph supports six deterministic tool profiles (`codegraph mcp serve --profile <profile>`), including the focused 14-tool `agent` profile (`DISCOVERY`: `find_symbol`, `search_code`, `find_references`, `find_callers`, `find_callees`, `find_tests`, `find_routes`; `DETAILS`: `get_symbol`, `get_file`, `get_context`, `get_architecture`, `get_git_impact`; `GRAPH`: `trace_path`, `trace_flow`):
1631
+
1632
+ | Profile | Tool Count | Recommended Use Case | Included Tools |
1633
+ | :--- | :--- | :--- | :--- |
1634
+ {profiles_table}
1635
+
1636
+ ---
1637
+
1638
+ ## 35. Fallback Behavior
1639
+
1640
+ CodeGraph defines deterministic fallback rules (`evaluate_fallback_policy` in `src/codegraph/agent_capabilities.py`):
1641
+
1642
+ | Condition | Epistemic Status | Fallback Allowed? | Required Agent Action |
1643
+ | :--- | :--- | :--- | :--- |
1644
+ | MCP `DISCONNECTED` / `SERVER_FAILED` | `DISCONNECTED` | `True` | Use direct repository search and `read_file`; verify claims manually. |
1645
+ | Index `freshness == "STALE"` | `STALE` | `True` | Verify modified files with `get_file` / `read_file` or re-index before relying on stale edges. |
1646
+ | `ambiguity_state == "AMBIGUOUS"` | `AMBIGUOUS` | `True` | Inspect `alternatives` and disambiguate by module/package; never guess `matches[0]`. |
1647
+ | `evidence_class == "UNKNOWN"` | `UNKNOWN` | `True` | Treat as unprovable statically (NOT "no relationship"); inspect call site with `get_file` / `read_file`. |
1648
+ | `evidence_class == "POSSIBLE"` | `POSSIBLE` | `True` | Report as candidate lead and confirm via targeted `get_file` / `read_file`. |
1649
+ | `AST_VERIFIED` / `FRAMEWORK_VERIFIED` / `DATAFLOW_VERIFIED` | `VERIFIED` | `False` | Rely on verified CodeGraph evidence; use `get_file` / `read_file` only if statement-level details are needed. |
1650
+
1651
+ ---
1652
+
1653
+ ## 36. Error Handling
1654
+
1655
+ - **Invalid Arguments (`ValueError`)**: Raised when required inputs (e.g., `query`, `symbol`, `task`) are empty or conflicting aliases (`symbol` vs `canonical_id`, `query` vs `task`) disagree. Fix the argument and retry once.
1656
+ - **Sensitive Path Blocked (`SecurityError`)**: Raised when attempting to read `.env`, `.pem`, `id_rsa`, credentials, or paths outside the repository root. Never attempt to bypass security boundaries.
1657
+ - **Symbol Not Found (`status="not_found"` / `UNKNOWN`)**: Do not retry `resolve_symbol` with the exact same spelling; call `search_symbols(query=...)` or `search_code(query=...)` with a broader stem.
1658
+
1659
+ ---
1660
+
1661
+ ## 37. Anti-Patterns
1662
+
1663
+ Never commit any of the following 14 anti-patterns:
1664
+
1665
+ 1. **Using CodeGraph for trivial one-line edits (`LOCAL_EDIT`)**: Calling `get_context` or `resolve_symbol` just to fix a typo in an already-known file.
1666
+ 2. **Calling all tools indiscriminately**: Invoking 6+ CodeGraph tools when `find_symbol` -> `find_callers` or a single `get_context` call suffices.
1667
+ 3. **Repeated symbol resolution**: Calling `resolve_symbol(symbol="X")` multiple times after `canonical_id` is already known.
1668
+ 4. **Reading the entire repository first**: Calling `get_file` / `read_file` across 10+ files before asking CodeGraph for symbol locations, text matches, or relationships.
1669
+ 5. **Treating `UNKNOWN` as absent**: Claiming "Function A does not call Function B" when CodeGraph reported `UNKNOWN` due to dynamic dispatch.
1670
+ 6. **Treating `POSSIBLE` as verified**: Reporting a `POSSIBLE` edge as a guaranteed `AST_VERIFIED` fact without reading the cited lines.
1671
+ 7. **Choosing the first ambiguous candidate (`matches[0]`)**: Arbitrarily picking the first match when `ambiguity_state == "AMBIGUOUS"`.
1672
+ 8. **Treating `REGISTERS` as `CALLS`**: Claiming a module calls a handler merely because it registers the handler into a dictionary or decorator registry.
1673
+ 9. **Treating DI (`INJECTS` / `PROVIDES`) as `CALLS`**: Confusing framework dependency injection with direct function invocation.
1674
+ 10. **Trusting a `STALE` index**: Presenting cached relationships from files modified on disk without checking `get_file` / `read_file` or re-indexing.
1675
+ 11. **Trusting generated/bundle matches over authored source**: Citing `dist/bundle.js` or generated client code when authored `SOURCE` exists.
1676
+ 12. **Ignoring package boundaries**: Inferring monorepo packages from folder names (`apps/`, `packages/`) without checking `DEPENDS_ON_PACKAGE` manifest evidence.
1677
+ 13. **Continuing graph traversal after sufficient evidence**: Expanding further hops after the question is already answered with verified evidence.
1678
+ 14. **Using lexical similarity (`search_code`) as causal proof**: Claiming a test covers a symbol or a function calls another based solely on matching words in `search_code`.
1679
+
1680
+ ---
1681
+
1682
+ ## 38. Tool Sequences (Tool Chain Playbook)
1683
+
1684
+ Every tool chain has an explicit **STOP condition**:
1685
+
1686
+ 1. **SYMBOL LOOKUP**:
1687
+ `find_symbol` / `resolve_symbol` (or `search_symbols` if partial) -> `get_symbol` (if signature/decorators needed) -> **STOP** once canonical file, line span, and signature are known.
1688
+ 2. **TEXT / TEMPLATE / UI DISCOVERY**:
1689
+ `search_code(query=...)` -> `get_file(path=..., start_line=..., end_line=...)` -> **STOP** once the target template/config/text lines are inspected.
1690
+ 3. **CALLERS**:
1691
+ `find_symbol` -> `find_callers` (or `get_callers`) -> **STOP** once verified callers are listed (use `get_file` only if call-site arguments need inspection).
1692
+ 4. **CALLEES**:
1693
+ `find_symbol` -> `find_callees` (or `get_callees`) -> **STOP** once outgoing calls are listed.
1694
+ 5. **TRACE**:
1695
+ `find_routes` / `list_routes` (if starting from HTTP endpoint) -> `find_symbol` -> `trace_path` -> `get_context(intent="TRACE")` (only if broader hop context is needed) -> targeted `get_file` (only if branch conditions matter) -> **STOP**.
1696
+ 6. **DEBUG**:
1697
+ `find_symbol` -> `get_context(intent="DEBUG")` -> targeted `get_file(path, start_line, end_line)` on fault line span -> **STOP**.
1698
+ 7. **CHANGE IMPACT**:
1699
+ `find_symbol` -> `analyze_impact` (or `get_git_impact` for commit diffs) -> `find_tests` / `find_related_tests` -> targeted `get_file` on direct callers to update -> **STOP**.
1700
+ 8. **DEPENDENCY INJECTION (DI)**:
1701
+ `find_symbol` -> `get_context(intent="DEBUG")` (or `get_references`) -> inspect `INJECTS` -> `PROVIDES` -> `RESOLVES_DEPENDENCY` -> `find_tests` (`TESTS_PROVIDER`) -> **STOP**.
1702
+ 9. **ARCHITECTURE & PACKAGES**:
1703
+ `get_architecture` -> `get_context(intent="ARCHITECTURE")` (or `get_imports` / `get_dependents` for specific package) -> **STOP**.
1704
+ 10. **TEST DISCOVERY**:
1705
+ `find_symbol` -> `find_tests` / `find_related_tests` -> **STOP** once covering test functions and `TESTS_*` evidence classes are returned.
1706
+
1707
+ ---
1708
+
1709
+ ## 39. Complex Workflows (25 Canonical End-to-End Playbooks)
1710
+
1711
+ {workflows_section}
1712
+
1713
+ ---
1714
+
1715
+ ## 40. Troubleshooting
1716
+
1717
+ | Symptom / Diagnostic Issue | Root Cause | Resolution |
1718
+ | :--- | :--- | :--- |
1719
+ | `codegraph mcp doctor` reports `COMMAND_NOT_FOUND` | The `codegraph` binary is not on the environment `PATH` used by the IDE/agent. | Install the wheel (`pip install codegraph-engine`) or point `mcpServers.codegraph.command` to the venv's `codegraph` executable. |
1720
+ | `get_repository_status` reports `files_indexed: 0` | Repository has not been indexed yet. | Run `codegraph index` in the repository root. |
1721
+ | `freshness` is `"STALE"` | Source files were edited or deleted after the last index run. | Run `codegraph index` or use `get_file` / `read_file` on `modified_files`. |
1722
+ | `resolve_symbol` / `find_symbol` returns `ambiguity_state="AMBIGUOUS"` | Multiple symbols share the same short name across modules/packages. | Pass the qualified name (`module.Class.method`) or select the matching `canonical_id` from `alternatives`. |
1723
+ | `get_file` / `read_file` raises `SecurityError` | Requested path is outside the repository, is a sensitive credential file (`.env`, `.pem`), or exceeds `max_read_bytes`. | Do not read sensitive or out-of-tree files; inspect safe source files only. |
1724
+ | Route not found in `search_code` | Route path is composed across `include_router(..., prefix=...)` mounts. | Use `find_routes()` / `list_routes()` which composes `MOUNTS` prefixes deterministically. |
1725
+
1726
+ ---
1727
+
1728
+ ## 41. Complete Tool Reference (All {len(TOOL_CAPABILITY_REGISTRY)} Exposed MCP Tools)
1729
+
1730
+ {complete_tool_reference}
1731
+ """
1732
+
1733
+
1734
+ def render_tool_capabilities_summary() -> str:
1735
+ """Render `agent-rules/tool-capabilities-summary.md` (Section 24 compact capability summary)."""
1736
+ return f"""# CodeGraph MCP — Tool Capabilities Summary (v{__version__})
1737
+
1738
+ > Compact task-to-tool routing table derived from `src/codegraph/agent_capabilities.py` (`ROUTING_MANIFEST`) and `src/codegraph/evidence_contract.py`.
1739
+
1740
+ ## Task Routing & Evidence Expectations
1741
+
1742
+ | Task / Domain | Preferred First Tool | Common Follow-Up Tool(s) | Evidence Expectations & Relationship Types |
1743
+ | :--- | :--- | :--- | :--- |
1744
+ | **`LOCAL_EDIT`** (Single-file typo / local variable) | `get_file` / `read_file` (Bypass CodeGraph) | Apply edit directly | Direct on-disk source lines; 0 graph calls needed. |
1745
+ | **`SYMBOL_LOOKUP`** (Where is X defined?) | `find_symbol` / `resolve_symbol` | `get_symbol` -> `get_file` | `DEFINES`, `CONTAINS`, `RESOLVES_TO` (`AST_VERIFIED`) + explicit `AMBIGUOUS` alternatives. |
1746
+ | **`TEXT / TEMPLATE SEARCH`** (Literal text, HTML id, UI label) | `search_code` | `get_file(path, start_line, end_line)` | Deterministic text match across `.py`, `.html`, `.jinja`, `.js`, `.ts`, `.css`, `.yaml`, `.json`, `.md` (never emits semantic edges). |
1747
+ | **`FILE_INSPECTION`** (Show lines N..M of a file) | `get_file(path, start_line, end_line)` | `find_symbol` / `find_callers` | Bounded source lines (`content`, `truncated`, `category`) + AST symbol outline. |
1748
+ | **`CALLERS / CALLEES`** (Who calls X / What does X call?) | `find_callers` / `find_callees` | `get_callers` / `get_callees` | `CALLS` (`AST_VERIFIED`, `DATAFLOW_VERIFIED`) vs `POSSIBLE_CALLS` (`POSSIBLE`, `UNKNOWN`). |
1749
+ | **`TRACE`** (End-to-end execution path) | `find_routes` / `find_symbol` | `trace_path` -> `get_context(intent="TRACE")` | Ordered hop chain (`HANDLED_BY`, `MOUNTS`, `INJECTS`, `PROVIDES`, `DISPATCHES_TO`, `CALLS`) + uncertainty preservation. |
1750
+ | **`ROUTE_DISCOVERY`** (HTTP/RPC endpoints & mounts) | `find_routes` / `list_routes` | `find_symbol` -> `trace_path` | Composed route paths via `MOUNTS`, `HANDLED_BY`, `ROUTE_HANDLER`, `ROUTES_TO` (`FRAMEWORK_VERIFIED`). |
1751
+ | **`DI`** (Dependency Injection & Providers) | `find_symbol` / `resolve_symbol` | `get_context(intent="DEBUG")` / `get_references` | `INJECTS`, `PROVIDES`, `RESOLVES_DEPENDENCY`, `CONFIGURES`, `DI_CYCLE` (never collapsed into `CALLS`). |
1752
+ | **`REGISTRY / DISPATCH`** (Plugin & handler maps) | `find_symbol` / `resolve_symbol` | `get_references` / `get_context` | `REGISTERS`, `REGISTERED_HANDLER`, `DISPATCHES_TO` (`AST_VERIFIED`, `DATAFLOW_VERIFIED`, `POSSIBLE`, `UNKNOWN`). |
1753
+ | **`EVENTS / TASKS / COMMANDS`** | `find_symbol` / `resolve_symbol` | `get_references` / `trace_path` | `EVENT_LISTENER`, `TASK_HANDLER`, `COMMAND_HANDLER` (`FRAMEWORK_VERIFIED`, `DATAFLOW_VERIFIED`). |
1754
+ | **`TEST_DISCOVERY`** (What tests cover X?) | `find_tests` / `find_related_tests` | `get_file(path, start_line, end_line)` | `TESTS`, `TESTS_SYMBOL`, `TESTS_ROUTE`, `TESTS_PROVIDER`, `TESTS_EVENT_HANDLER` (never fabricated from lexical similarity). |
1755
+ | **`CHANGE_IMPACT`** (Blast radius & Git diff impact) | `get_git_impact` / `analyze_impact` | `find_tests` -> `get_file` | Modified symbols, downstream `CALLS`/`IMPORTS`, affected `DEPENDS_ON_PACKAGE`, and covering `TESTS`. |
1756
+ | **`PACKAGE`** (Monorepo & workspace boundaries) | `get_architecture` | `get_context(intent="ARCHITECTURE")` / `get_dependents` | Manifest-backed `DEPENDS_ON_PACKAGE`, `PACKAGE_IMPORTS`, `CROSS_PACKAGE_IMPORT`, `CONTAINS_PACKAGE`. |
1757
+ | **`ARCHITECTURE`** (System & module overview) | `get_architecture` | `get_context(intent="ARCHITECTURE")` | Modules, workspace packages, entrypoints, and routes. |
1758
+ | **`DATABASE`** (Tables, columns, ORM models, queries, impact) | `find_db_tables` / `get_db_table` | `find_db_callers` / `find_db_writers` / `get_db_impact` | `MAPS_TO_TABLE`, `MAPS_TO_COLUMN`, `READS_TABLE`, `WRITES_TABLE`, `FOREIGN_KEY_TO`, `MIGRATES_TABLE`, `POSSIBLE_TABLE`, `UNKNOWN_TABLE`. |
1759
+ | **`RUNTIME`** (Traces & static-vs-runtime reconciliation) | `get_runtime_trace` / `reconcile_static_runtime` | `ingest_runtime_traces` -> `get_file` | `RUNTIME_OBSERVED` vs `RUNTIME_UNOBSERVED` (`CONFIRMED_RUNTIME_PATH`, `STATIC_RUNTIME_CONFLICT`, `NOT_OBSERVED_AT_RUNTIME`, `RUNTIME_ONLY_OBSERVED`). |
1760
+ | **`DEBUG`** (Bug & exception investigation) | `get_context(intent="DEBUG")` | `get_file(path, start_line, end_line)` | Bounded `ContextPacket` (target + callers + callees + DI + database + runtime + tests) followed by targeted `get_file`. |
1761
+ | **`DIAGNOSTIC`** (Index freshness & health) | `get_repository_status` | `get_resource_status` / `verify_evidence` | Index `generation`, `freshness` (`FRESH` vs `STALE`), `modified_files`, and SHA-256 evidence verification. |
1762
+
1763
+ ## Epistemic Status Quick Reference
1764
+
1765
+ | Evidence / State | Meaning | Required Agent Behavior |
1766
+ | :--- | :--- | :--- |
1767
+ | **`AST_VERIFIED`** | Proven directly by syntax tree | Rely on relationship as verified static fact. |
1768
+ | **`STATIC_VERIFIED`** | Proven by static SQL DDL/DML or migration parsing | Rely on table/column/query/migration relationship as verified static fact. |
1769
+ | **`FRAMEWORK_VERIFIED`** | Proven by deterministic framework rules | Rely on route/ORM/DI/task/event relationship as verified framework fact. |
1770
+ | **`DATAFLOW_VERIFIED`** | Proven by conservative local/container binding | Rely on resolved target as verified dataflow fact. |
1771
+ | **`RUNTIME_OBSERVED`** | Observed in an ingested runtime trace (`observation_count >= 1`) | Treat as verified runtime execution fact; never promote to static `AST_VERIFIED` proof. |
1772
+ | **`RUNTIME_UNOBSERVED`** | Not observed in the ingested runtime trace sample | Never claim the static path is dead code or impossible at runtime. |
1773
+ | **`POSSIBLE`** | Plausible candidate, not statically guaranteed | Treat as lead; verify with targeted `get_file` / `read_file` before claiming as fact. |
1774
+ | **`UNKNOWN`** | Static analysis could not prove target | **Never** claim "no relationship exists"; inspect call site with `get_file` / `read_file`. |
1775
+ | **`AMBIGUOUS`** | Multiple symbols or tables match the target name | Inspect `alternatives` and disambiguate by module/package/schema; never pick `matches[0]` blindly. |
1776
+ | **`STALE`** | Disk files changed since index generation | Verify `modified_files` with `get_file` / `read_file` or re-index (`codegraph index`). |
1777
+ """
1778
+
1779
+
1780
+ def validate_agent_documentation(repo_root: Path | None = None) -> dict[str, object]:
1781
+ """Automated documentation validator (Section 25).
1782
+
1783
+ Verifies that:
1784
+ 1. Every tool in `TOOL_CAPABILITY_REGISTRY` and documented in `docs/agent-brain.md`,
1785
+ `.agents/skills/codegraph/SKILL.md`, and `agent-rules/` exists in `create_server(profile='full')`.
1786
+ 2. Every documented parameter (`required_inputs` + `optional_inputs`) exists in the actual MCP tool signature.
1787
+ 3. Every documented relationship exists in `ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX`.
1788
+ 4. Every documented evidence class exists in `ALLOWED_EVIDENCE_CLASSES`.
1789
+ 5. Every documented profile exists in `MCP_PROFILE_RECOMMENDATIONS`.
1790
+ 6. Command names (`codegraph mcp serve`, `codegraph mcp doctor`, `codegraph mcp capabilities`,
1791
+ `codegraph mcp rules`) and package name (`codegraph-engine`) are current with zero stale names.
1792
+ 7. All 41 required sections and 25+ complex workflows exist in `docs/agent-brain.md`.
1793
+ 8. All 10 steps and required matrices exist in `.agents/skills/codegraph/SKILL.md`.
1794
+ """
1795
+ from codegraph.agent_rules import render_agent_rules, render_antigravity_skill
1796
+ from codegraph.mcp.server import create_server
1797
+
1798
+ errors: list[str] = []
1799
+
1800
+ with tempfile.TemporaryDirectory() as tmp:
1801
+ srv = create_server(Path(tmp), profile="full")
1802
+ mcp_tools: dict[str, object] = getattr(srv._tool_manager, "_tools", {})
1803
+
1804
+ actual_tool_names = set(mcp_tools.keys())
1805
+ registry_tool_names = {spec.tool_name for spec in TOOL_CAPABILITY_REGISTRY}
1806
+
1807
+ # 1. Exact tool set parity between MCP server and TOOL_CAPABILITY_REGISTRY
1808
+ if actual_tool_names != registry_tool_names:
1809
+ missing_in_reg = sorted(actual_tool_names - registry_tool_names)
1810
+ extra_in_reg = sorted(registry_tool_names - actual_tool_names)
1811
+ errors.append(
1812
+ f"Tool set mismatch: missing_in_registry={missing_in_reg}, extra_in_registry={extra_in_reg}"
1813
+ )
1814
+
1815
+ # 2. Exact parameter parity for every tool
1816
+ for spec in TOOL_CAPABILITY_REGISTRY:
1817
+ tool_obj = mcp_tools.get(spec.tool_name)
1818
+ if tool_obj is None:
1819
+ errors.append(f"Tool '{spec.tool_name}' not found in MCP server")
1820
+ continue
1821
+ fn = getattr(tool_obj, "fn", None)
1822
+ if fn is None:
1823
+ errors.append(f"Tool '{spec.tool_name}' has no underlying function")
1824
+ continue
1825
+ sig_params = set(inspect.signature(fn).parameters.keys())
1826
+ doc_params = set(spec.required_inputs) | set(spec.optional_inputs)
1827
+ if sig_params != doc_params:
1828
+ errors.append(
1829
+ f"Parameter mismatch on '{spec.tool_name}': documented={sorted(doc_params)} vs actual={sorted(sig_params)}"
1830
+ )
1831
+ # Check relationship types returned by tool
1832
+ for rel in spec.relationship_types_returned:
1833
+ if rel not in ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX:
1834
+ errors.append(f"Tool '{spec.tool_name}' documents unknown relationship '{rel}'")
1835
+ # Check profiles
1836
+ for prof in spec.profiles:
1837
+ if prof not in MCP_PROFILE_RECOMMENDATIONS:
1838
+ errors.append(f"Tool '{spec.tool_name}' documents unknown profile '{prof}'")
1839
+
1840
+ # 3. Relationship semantics registry parity with ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX
1841
+ if set(RELATIONSHIP_SEMANTICS_REGISTRY.keys()) != set(ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX.keys()):
1842
+ diff1 = sorted(set(ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX.keys()) - set(RELATIONSHIP_SEMANTICS_REGISTRY.keys()))
1843
+ diff2 = sorted(set(RELATIONSHIP_SEMANTICS_REGISTRY.keys()) - set(ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX.keys()))
1844
+ errors.append(f"Relationship semantics registry mismatch: missing={diff1}, extra={diff2}")
1845
+
1846
+ # 4. Inspect rendered documentation texts
1847
+ brain_text = render_deep_agent_brain()
1848
+ skill_text = render_antigravity_skill()
1849
+ summary_text = render_tool_capabilities_summary()
1850
+ rules_text = render_agent_rules("antigravity")
1851
+
1852
+ # Verify all 39 tools have a dedicated `### \`<tool_name>\`` heading in docs/agent-brain.md
1853
+ for tname in sorted(actual_tool_names):
1854
+ if f"### `{tname}`" not in brain_text:
1855
+ errors.append(f"docs/agent-brain.md is missing tool reference section for '{tname}'")
1856
+
1857
+ # Verify no invented `### \`<tool>\`` headings in Section 41 of docs/agent-brain.md
1858
+ sec41_split = brain_text.split("## 41. Complete Tool Reference", 1)
1859
+ if len(sec41_split) != 2:
1860
+ errors.append("docs/agent-brain.md is missing '## 41. Complete Tool Reference'")
1861
+ else:
1862
+ documented_tool_headings = re.findall(r"^### `([a-z0-9_]+)`", sec41_split[1], flags=re.MULTILINE)
1863
+ for doc_t in documented_tool_headings:
1864
+ if doc_t not in actual_tool_names:
1865
+ errors.append(f"docs/agent-brain.md documents non-existent tool '{doc_t}'")
1866
+
1867
+ # Verify all 41 numbered sections exist in docs/agent-brain.md
1868
+ for sec_num in range(1, 42):
1869
+ if not re.search(rf"^## {sec_num}\.\s+", brain_text, flags=re.MULTILINE):
1870
+ errors.append(f"docs/agent-brain.md is missing required Section {sec_num}")
1871
+
1872
+ # Verify at least 25 complex workflows exist in docs/agent-brain.md
1873
+ workflow_headings = re.findall(r"^### Workflow (\d+):", brain_text, flags=re.MULTILINE)
1874
+ if len(workflow_headings) < 25:
1875
+ errors.append(f"docs/agent-brain.md has only {len(workflow_headings)} workflows (expected >= 25)")
1876
+
1877
+ # Verify all 5 canonical evidence classes are documented
1878
+ for ev_cls in ALLOWED_EVIDENCE_CLASSES:
1879
+ for label, txt in (("agent-brain.md", brain_text), ("SKILL.md", skill_text), ("tool-capabilities-summary.md", summary_text)):
1880
+ if ev_cls not in txt:
1881
+ errors.append(f"Evidence class '{ev_cls}' missing from {label}")
1882
+
1883
+ # Verify all 5 MCP profiles are documented
1884
+ for prof_name in MCP_PROFILE_RECOMMENDATIONS:
1885
+ if f"`{prof_name}`" not in brain_text:
1886
+ errors.append(f"MCP profile '{prof_name}' missing from docs/agent-brain.md")
1887
+
1888
+ # Verify SKILL.md contains STEP 1 .. STEP 10 and required matrices
1889
+ for step_idx in range(1, 11):
1890
+ if f"STEP {step_idx}" not in skill_text:
1891
+ errors.append(f"SKILL.md is missing 'STEP {step_idx}'")
1892
+ for req_heading in (
1893
+ "## When to activate",
1894
+ "## When NOT to activate",
1895
+ "## Tool selection matrix",
1896
+ "## Evidence matrix",
1897
+ "## Relationship matrix",
1898
+ "## Common workflows",
1899
+ "## Failure/fallback workflow",
1900
+ "## Stop conditions",
1901
+ ):
1902
+ if req_heading not in skill_text:
1903
+ errors.append(f"SKILL.md is missing required heading '{req_heading}'")
1904
+
1905
+ # Verify compact rules remain concise (2 KB .. 6 KB)
1906
+ if not (1500 <= len(rules_text) < 6000):
1907
+ errors.append(f"Compact agent rule length {len(rules_text)} outside bounds [1500, 6000)")
1908
+
1909
+ # Verify current package and CLI command names and absence of stale names
1910
+ stale_terms = (
1911
+ "codegraph-mcp-server",
1912
+ "mcp-codegraph",
1913
+ "codegraph serve-mcp",
1914
+ "get_symbol_details",
1915
+ "find_all_callers",
1916
+ "search_repository",
1917
+ )
1918
+ for doc_name, txt in (
1919
+ ("agent-brain.md", brain_text),
1920
+ ("SKILL.md", skill_text),
1921
+ ("tool-capabilities-summary.md", summary_text),
1922
+ ("rules", rules_text),
1923
+ ):
1924
+ for stale in stale_terms:
1925
+ if stale in txt:
1926
+ errors.append(f"Stale identifier '{stale}' found in {doc_name}")
1927
+
1928
+ # If repo_root is provided, verify on-disk files match generated content
1929
+ if repo_root is not None:
1930
+ disk_checks = {
1931
+ "docs/agent-brain.md": brain_text,
1932
+ ".agents/skills/codegraph/SKILL.md": skill_text,
1933
+ "agent-rules/tool-capabilities-summary.md": summary_text,
1934
+ ".agents/rules/codegraph.md": render_agent_rules("antigravity"),
1935
+ "agent-rules/AGENTS.md": render_agent_rules("agents"),
1936
+ "agent-rules/GEMINI.md": render_agent_rules("gemini"),
1937
+ "agent-rules/claude.md": render_agent_rules("claude"),
1938
+ "agent-rules/cursor.md": render_agent_rules("cursor"),
1939
+ "agent-rules/codex.md": render_agent_rules("codex"),
1940
+ "agent-rules/cline.md": render_agent_rules("cline"),
1941
+ "agent-rules/antigravity.md": render_agent_rules("antigravity"),
1942
+ }
1943
+ for rel_path, expected_content in disk_checks.items():
1944
+ fpath = repo_root / rel_path
1945
+ if not fpath.exists():
1946
+ errors.append(f"Required output file '{rel_path}' is missing on disk")
1947
+ else:
1948
+ actual_disk = fpath.read_text(encoding="utf-8")
1949
+ if actual_disk != expected_content:
1950
+ errors.append(f"On-disk file '{rel_path}' is out of sync with canonical generator")
1951
+
1952
+ return {
1953
+ "valid": len(errors) == 0,
1954
+ "tools_documented": len(actual_tool_names),
1955
+ "task_categories_documented": len(AgentTaskCategory),
1956
+ "relationships_documented": len(ALLOWED_RELATIONSHIP_EVIDENCE_MATRIX),
1957
+ "evidence_classes_documented": len(ALLOWED_EVIDENCE_CLASSES),
1958
+ "workflows_documented": len(COMPLEX_WORKFLOW_EXAMPLES),
1959
+ "profiles_documented": len(MCP_PROFILE_RECOMMENDATIONS),
1960
+ "errors": errors,
1961
+ }