vigil-codeintel 0.1.0__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 (131) hide show
  1. vigil_codeintel-0.1.0.dist-info/METADATA +780 -0
  2. vigil_codeintel-0.1.0.dist-info/RECORD +131 -0
  3. vigil_codeintel-0.1.0.dist-info/WHEEL +5 -0
  4. vigil_codeintel-0.1.0.dist-info/entry_points.txt +3 -0
  5. vigil_codeintel-0.1.0.dist-info/licenses/LICENSE +21 -0
  6. vigil_codeintel-0.1.0.dist-info/top_level.txt +3 -0
  7. vigil_forensic/__init__.py +224 -0
  8. vigil_forensic/_git_utils.py +178 -0
  9. vigil_forensic/_shared.py +510 -0
  10. vigil_forensic/_stubs.py +156 -0
  11. vigil_forensic/gate_checks/__init__.py +1 -0
  12. vigil_forensic/gate_checks/_ast_helpers.py +629 -0
  13. vigil_forensic/gate_checks/_deployment_detector.py +573 -0
  14. vigil_forensic/gate_checks/atomic_write_checks.py +1143 -0
  15. vigil_forensic/gate_checks/authority_checks.py +95 -0
  16. vigil_forensic/gate_checks/boundary_breach_checks.py +202 -0
  17. vigil_forensic/gate_checks/broad_except_checks.py +301 -0
  18. vigil_forensic/gate_checks/broad_except_hidden_sentinel_checks.py +365 -0
  19. vigil_forensic/gate_checks/common.py +253 -0
  20. vigil_forensic/gate_checks/config_safety_checks.py +704 -0
  21. vigil_forensic/gate_checks/config_ssot_checks.py +78 -0
  22. vigil_forensic/gate_checks/conflict_checks.py +193 -0
  23. vigil_forensic/gate_checks/context_fallback_checks.py +697 -0
  24. vigil_forensic/gate_checks/context_health_checks.py +289 -0
  25. vigil_forensic/gate_checks/contract_shape_drift_checks.py +459 -0
  26. vigil_forensic/gate_checks/dirty_baseline_check.py +274 -0
  27. vigil_forensic/gate_checks/duplication_checks.py +387 -0
  28. vigil_forensic/gate_checks/embedded_string_checks.py +123 -0
  29. vigil_forensic/gate_checks/empty_output_checks.py +87 -0
  30. vigil_forensic/gate_checks/encoding_checks.py +847 -0
  31. vigil_forensic/gate_checks/export_completeness_checks.py +156 -0
  32. vigil_forensic/gate_checks/fallback_checks.py +41 -0
  33. vigil_forensic/gate_checks/file_proliferation_checks.py +171 -0
  34. vigil_forensic/gate_checks/fix_without_test_checks.py +69 -0
  35. vigil_forensic/gate_checks/forensic_cluster_runners/__init__.py +9 -0
  36. vigil_forensic/gate_checks/forensic_cluster_runners/_helpers.py +71 -0
  37. vigil_forensic/gate_checks/forensic_cluster_runners/advanced_checks.py +322 -0
  38. vigil_forensic/gate_checks/forensic_cluster_runners/core.py +273 -0
  39. vigil_forensic/gate_checks/forensic_cluster_runners/integrity_checks.py +203 -0
  40. vigil_forensic/gate_checks/forensic_cluster_runners/quality_checks.py +666 -0
  41. vigil_forensic/gate_checks/forensic_clusters/__init__.py +193 -0
  42. vigil_forensic/gate_checks/forensic_clusters/allowlist.py +426 -0
  43. vigil_forensic/gate_checks/forensic_clusters/allowlist_writer.py +302 -0
  44. vigil_forensic/gate_checks/forensic_clusters/api_protocol.py +231 -0
  45. vigil_forensic/gate_checks/forensic_clusters/async_quality.py +1156 -0
  46. vigil_forensic/gate_checks/forensic_clusters/code_style.py +808 -0
  47. vigil_forensic/gate_checks/forensic_clusters/core.py +319 -0
  48. vigil_forensic/gate_checks/forensic_clusters/data_quality.py +763 -0
  49. vigil_forensic/gate_checks/forensic_clusters/dead_code.py +480 -0
  50. vigil_forensic/gate_checks/forensic_clusters/edit_mutation.py +842 -0
  51. vigil_forensic/gate_checks/forensic_clusters/exception_boundary.py +240 -0
  52. vigil_forensic/gate_checks/forensic_clusters/legacy_debt.py +556 -0
  53. vigil_forensic/gate_checks/forensic_clusters/static_analysis.py +834 -0
  54. vigil_forensic/gate_checks/forensic_clusters/structural_quality.py +298 -0
  55. vigil_forensic/gate_checks/god_object_zones_checks.py +173 -0
  56. vigil_forensic/gate_checks/hallucination_checks.py +566 -0
  57. vigil_forensic/gate_checks/hunter_artifact_completeness_check.py +139 -0
  58. vigil_forensic/gate_checks/implementation_overfit_checks.py +380 -0
  59. vigil_forensic/gate_checks/import_integrity_checks.py +233 -0
  60. vigil_forensic/gate_checks/imports_in_function_checks.py +283 -0
  61. vigil_forensic/gate_checks/ml_checks.py +318 -0
  62. vigil_forensic/gate_checks/performance_checks.py +106 -0
  63. vigil_forensic/gate_checks/project_specific_runner.py +691 -0
  64. vigil_forensic/gate_checks/provider_capability_checks.py +73 -0
  65. vigil_forensic/gate_checks/refactor_completeness_checks.py +274 -0
  66. vigil_forensic/gate_checks/reliability_checks.py +389 -0
  67. vigil_forensic/gate_checks/reporting_checks.py +55 -0
  68. vigil_forensic/gate_checks/runtime_behavior_checks.py +220 -0
  69. vigil_forensic/gate_checks/security_injection_checks.py +332 -0
  70. vigil_forensic/gate_checks/semantic_intent_checks.py +139 -0
  71. vigil_forensic/gate_checks/size_complexity_checks.py +336 -0
  72. vigil_forensic/gate_checks/stuck_feature_flag_checks.py +354 -0
  73. vigil_forensic/gate_checks/syntax_validity_checks.py +217 -0
  74. vigil_forensic/gate_checks/temporal_freshness_checks.py +79 -0
  75. vigil_forensic/gate_checks/test_quality_checks.py +946 -0
  76. vigil_forensic/gate_checks/testing_checks.py +149 -0
  77. vigil_forensic/gate_checks/toctou_checks.py +367 -0
  78. vigil_forensic/gate_checks/type_checking_checks.py +316 -0
  79. vigil_forensic/gate_models.py +392 -0
  80. vigil_forensic/gate_packs/__init__.py +1 -0
  81. vigil_forensic/gate_packs/universal.py +179 -0
  82. vigil_forensic/gate_profile.json +31 -0
  83. vigil_forensic/gate_registry.py +21 -0
  84. vigil_forensic/language_profiles.py +219 -0
  85. vigil_forensic/meta_findings.py +207 -0
  86. vigil_forensic/self_audit.py +725 -0
  87. vigil_forensic/source_analysis.py +175 -0
  88. vigil_mapper/__init__.py +103 -0
  89. vigil_mapper/_ast_helpers_minimal.py +229 -0
  90. vigil_mapper/_extract_imports_impl.py +123 -0
  91. vigil_mapper/_file_count_guard.py +129 -0
  92. vigil_mapper/_git_utils.py +178 -0
  93. vigil_mapper/_runtime_ast.py +438 -0
  94. vigil_mapper/_runtime_dispatch.py +137 -0
  95. vigil_mapper/_seed_helpers.py +82 -0
  96. vigil_mapper/authority_builder.py +1102 -0
  97. vigil_mapper/cli_entry.py +731 -0
  98. vigil_mapper/conflict_builder.py +818 -0
  99. vigil_mapper/data_contract_builder.py +446 -0
  100. vigil_mapper/findings_builder.py +716 -0
  101. vigil_mapper/fingerprint.py +53 -0
  102. vigil_mapper/hotspot_builder.py +539 -0
  103. vigil_mapper/map_common.py +449 -0
  104. vigil_mapper/map_errors.py +55 -0
  105. vigil_mapper/map_models.py +431 -0
  106. vigil_mapper/map_models_ext.py +206 -0
  107. vigil_mapper/map_models_findings.py +130 -0
  108. vigil_mapper/map_storage.py +455 -0
  109. vigil_mapper/parse_cache.py +795 -0
  110. vigil_mapper/refactor_boundary_builder.py +266 -0
  111. vigil_mapper/runtime_builder.py +527 -0
  112. vigil_mapper/runtime_tracer.py +243 -0
  113. vigil_mapper/runtime_tracer_entry.py +199 -0
  114. vigil_mapper/semantic_diff.py +71 -0
  115. vigil_mapper/source_adapters/__init__.py +109 -0
  116. vigil_mapper/source_adapters/_base.py +264 -0
  117. vigil_mapper/source_adapters/_ir.py +156 -0
  118. vigil_mapper/source_adapters/_lexer.py +309 -0
  119. vigil_mapper/source_adapters/_patterns.py +212 -0
  120. vigil_mapper/source_adapters/_treesitter.py +182 -0
  121. vigil_mapper/source_adapters/go.py +553 -0
  122. vigil_mapper/source_adapters/java.py +541 -0
  123. vigil_mapper/source_adapters/javascript.py +626 -0
  124. vigil_mapper/source_adapters/python.py +325 -0
  125. vigil_mapper/source_adapters/typescript.py +749 -0
  126. vigil_mapper/structural_builder.py +586 -0
  127. vigil_mcp/__init__.py +1 -0
  128. vigil_mcp/_jobs.py +587 -0
  129. vigil_mcp/_paths.py +93 -0
  130. vigil_mcp/forensic_server.py +419 -0
  131. vigil_mcp/map_server.py +452 -0
@@ -0,0 +1,266 @@
1
+ """Generic refactor boundary loader -- reads from <project_dir>/.cortex/maps/70_refactor_boundaries.json.
2
+
3
+ ARCHITECTURE NOTE: Refactor boundaries are generated/loaded in two phases:
4
+
5
+ 1. AUTO-INFERRED BOUNDARIES (computed during map build):
6
+ - source: `.cortex/maps/70_refactor_boundaries.json`
7
+ - phase: "planning"
8
+ - recomputed on every build (Phase 4 will add auto-inference logic)
9
+ - include: SCC clusters, hotspot-scored files, canonical owners
10
+
11
+ 2. MANUAL SEED BOUNDARIES (user-authored, override auto-inferred):
12
+ - source: `.cortex/map_seeds/refactor_boundaries.json`
13
+ - phase: "seed" or higher (user-defined)
14
+ - override auto-inferred entries for same allowed_files/forbidden_files
15
+ - auto-inferred entries for files without seed are still included
16
+
17
+ LOADER BEHAVIOR:
18
+ - This module loads GENERATED boundaries from maps/70_refactor_boundaries.json
19
+ - Seed loading handled separately by main builder orchestrator
20
+ - merge strategy: seed entries + auto-inferred entries (seed wins on conflicts)
21
+ - If file missing: return empty list (not an error)
22
+
23
+ Design: generic, works on any project via project_dir parameter.
24
+ """
25
+ from __future__ import annotations
26
+
27
+ import json
28
+ import logging
29
+ from pathlib import Path
30
+
31
+ from .map_errors import MapIntegrityError
32
+ from .map_models_ext import RefactorBoundary
33
+
34
+ __all__ = [
35
+ "load_refactor_seeds",
36
+ "infer_refactor_boundaries",
37
+ ]
38
+
39
+ _log = logging.getLogger(__name__)
40
+
41
+
42
+ def infer_refactor_boundaries(repo_maps) -> list[RefactorBoundary]:
43
+ """Auto-infer refactor boundaries from conflict/hotspot/authority maps.
44
+
45
+ Algorithm:
46
+ 1. Group conflicts by SCC cluster → boundary candidates
47
+ 2. Hotspot scores: safe_refactor (score < 30), caution (30-60), do_not_touch (>= 60)
48
+ 3. Authority: canonical_owner matching domain
49
+ 4. Union-find: merge clusters with overlapping files
50
+ 5. Emit RefactorBoundary per cluster
51
+ """
52
+ import hashlib
53
+
54
+ boundaries: list[RefactorBoundary] = []
55
+
56
+ # Build hotspot index: file -> score + recommended_mode
57
+ hotspot_by_file: dict[str, dict] = {}
58
+ for h in repo_maps.hotspot:
59
+ target = getattr(h, "target", "")
60
+ score = getattr(h, "hotspot_score", 0)
61
+ mode = "do_not_touch" if score >= 60 else ("caution" if score >= 30 else "safe_refactor")
62
+ hotspot_by_file[target] = {
63
+ "score": score,
64
+ "mode": mode,
65
+ }
66
+
67
+ # Build authority index: domain -> canonical_owner
68
+ authority_by_domain: dict[str, str] = {}
69
+ for auth in repo_maps.authority:
70
+ domain = getattr(auth, "authority_domain", "")
71
+ owner = getattr(auth, "canonical_owner", "")
72
+ if domain:
73
+ authority_by_domain[domain] = owner
74
+
75
+ # Cluster candidates from conflict map (SCC clusters)
76
+ clusters: list[dict] = []
77
+ seen_files: set[str] = set()
78
+
79
+ for conflict in repo_maps.conflict:
80
+ domain = getattr(conflict, "domain", "")
81
+ if domain != "structural_cycles":
82
+ continue
83
+
84
+ # Parse sources to collect SCC member files
85
+ sources_parsed: list[dict] = []
86
+ sources_raw = getattr(conflict, "sources", [])
87
+ for src_raw in sources_raw:
88
+ try:
89
+ src = json.loads(src_raw) if isinstance(src_raw, str) else src_raw
90
+ if isinstance(src, dict):
91
+ sources_parsed.append(src)
92
+ except (json.JSONDecodeError, TypeError):
93
+ pass
94
+
95
+ scc_files = [s.get("file", "") for s in sources_parsed if s.get("file")]
96
+
97
+ # Skip if already clustered
98
+ if any(f in seen_files for f in scc_files):
99
+ continue
100
+
101
+ # Add new cluster
102
+ if scc_files:
103
+ clusters.append({
104
+ "files": scc_files,
105
+ "conflict": conflict,
106
+ "sources": sources_parsed,
107
+ })
108
+ seen_files.update(scc_files)
109
+
110
+ # Classify files by hotspot mode
111
+ def classify_file(f: str) -> str:
112
+ hs = hotspot_by_file.get(f, {})
113
+ return hs.get("mode", "unknown")
114
+
115
+ # Build boundaries
116
+ for cluster in clusters:
117
+ scc_files = cluster["files"]
118
+ conflict = cluster["conflict"]
119
+ sources = cluster["sources"]
120
+
121
+ # Partition by hotspot mode
122
+ safe_files = [f for f in scc_files if classify_file(f) == "safe_refactor"]
123
+ caution_files = [f for f in scc_files if classify_file(f) == "caution"]
124
+ forbidden_files = [f for f in scc_files if classify_file(f) == "do_not_touch"]
125
+
126
+ # Extract canonical owners (entrypoints) from authority
127
+ entrypoints: set[str] = set()
128
+ conflict_domain = getattr(conflict, "domain", "")
129
+ # Remove "structural_cycles" suffix if present to get domain name
130
+ domain_name = conflict_domain.replace("_cycles", "") if conflict_domain.endswith("_cycles") else conflict_domain
131
+
132
+ if domain_name in authority_by_domain:
133
+ owner = authority_by_domain[domain_name]
134
+ if owner:
135
+ entrypoints.add(owner)
136
+
137
+ # Generate stable ID
138
+ cluster_id = hashlib.sha256(
139
+ ",".join(sorted(scc_files)).encode("utf-8")
140
+ ).hexdigest()[:8]
141
+
142
+ max_fan_in = max((s.get("cluster_max_fan_in", 0) for s in sources), default=0)
143
+ boundary = RefactorBoundary(
144
+ boundary_id=f"auto_{cluster_id}",
145
+ goal=f"Decouple import cycle in cluster ({len(scc_files)} files, max fan_in={max_fan_in})",
146
+ phase="planning",
147
+ allowed_files=tuple(safe_files + caution_files), # Safe + caution can be refactored
148
+ watch_files=(),
149
+ forbidden_files=tuple(forbidden_files), # Do-not-touch files
150
+ entrypoints=tuple(entrypoints),
151
+ must_hold_invariants=(),
152
+ source="auto_inferred",
153
+ evidence=(),
154
+ confidence=0.75,
155
+ freshness="inferred",
156
+ status="inferred",
157
+ )
158
+ boundaries.append(boundary)
159
+
160
+ _log.info(
161
+ "infer_refactor_boundaries: inferred %d boundaries from %d SCC clusters",
162
+ len(boundaries), len(clusters),
163
+ )
164
+ return boundaries
165
+
166
+
167
+ def load_refactor_seeds(project_dir: Path) -> list[RefactorBoundary]:
168
+ """Load USER-AUTHORED manual seed boundaries from <project_dir>/.cortex/map_seeds/refactor_boundaries.json.
169
+
170
+ Manual seeds are persistent, user-authored refactor boundaries that override
171
+ auto-inferred boundaries for the same file sets. This function reads from the
172
+ seed directory (persistent, under version control). Auto-inferred boundaries
173
+ are computed separately and merged afterward.
174
+
175
+ IMPORTANT: This loads SEEDS only, not generated output. For generated output,
176
+ use infer_refactor_boundaries() which computes boundaries at build time.
177
+
178
+ Args:
179
+ project_dir: Absolute path to the target project root.
180
+
181
+ Returns:
182
+ list[RefactorBoundary]: Boundaries from the seed file, or [] if missing.
183
+
184
+ Raises:
185
+ MapIntegrityError: If JSON is corrupt, schema is invalid, or major version mismatch.
186
+ """
187
+ project_dir = Path(project_dir).resolve()
188
+ seeds_dir = project_dir / ".cortex" / "map_seeds"
189
+ boundaries_path = seeds_dir / "refactor_boundaries.json"
190
+
191
+ # Missing file — log and return empty
192
+ if not boundaries_path.exists():
193
+ _log.info(
194
+ "load_refactor_boundaries: no boundaries file at %s -- returning empty",
195
+ boundaries_path,
196
+ )
197
+ return []
198
+
199
+ # Read JSON
200
+ try:
201
+ import json
202
+ content = boundaries_path.read_text(encoding="utf-8")
203
+ payload = json.loads(content)
204
+ except (OSError, json.JSONDecodeError, UnicodeDecodeError) as exc:
205
+ raise MapIntegrityError(
206
+ f"Failed to read/parse {boundaries_path}: {exc}"
207
+ ) from exc
208
+
209
+ # Validate structure
210
+ if not isinstance(payload, dict):
211
+ raise MapIntegrityError(
212
+ f"Expected JSON object at root, got {type(payload).__name__}"
213
+ )
214
+
215
+ # Check schema_version
216
+ schema_version_raw = payload.get("schema_version")
217
+ if schema_version_raw is None:
218
+ raise MapIntegrityError("Missing required field: schema_version")
219
+
220
+ schema_version_str = str(schema_version_raw)
221
+ major_version_str = schema_version_str.split(".")[0] if "." in schema_version_str else schema_version_str
222
+ try:
223
+ major_version = int(major_version_str)
224
+ except ValueError:
225
+ raise MapIntegrityError(
226
+ f"Invalid schema_version format: {schema_version_str}"
227
+ ) from None
228
+
229
+ if major_version > 1:
230
+ raise MapIntegrityError(
231
+ f"Major version {major_version} > 1 -- incompatible schema"
232
+ )
233
+
234
+ # Parse entries
235
+ entries_raw = payload.get("entries", [])
236
+ if not isinstance(entries_raw, list):
237
+ raise MapIntegrityError(
238
+ f"Expected 'entries' to be a list, got {type(entries_raw).__name__}"
239
+ )
240
+
241
+ boundaries: list[RefactorBoundary] = []
242
+ for i, raw_entry in enumerate(entries_raw):
243
+ if not isinstance(raw_entry, dict):
244
+ _log.warning(
245
+ "load_refactor_boundaries: skipping entry %d (not a dict, got %s)",
246
+ i, type(raw_entry).__name__,
247
+ )
248
+ continue
249
+ try:
250
+ boundary = RefactorBoundary.from_dict(raw_entry)
251
+ boundaries.append(boundary)
252
+ except (KeyError, TypeError, ValueError) as exc:
253
+ _log.warning(
254
+ "load_refactor_boundaries: skipping entry %d: %s",
255
+ i, exc,
256
+ )
257
+
258
+ _log.info(
259
+ "load_refactor_seeds: loaded %d boundaries from %s",
260
+ len(boundaries), boundaries_path,
261
+ )
262
+ return boundaries
263
+
264
+
265
+ # Backward compatibility alias (deprecated, use load_refactor_seeds)
266
+ load_refactor_boundaries = load_refactor_seeds