continuum-toolkit 1.0.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 (72) hide show
  1. cli/__init__.py +12 -0
  2. cli/main.py +415 -0
  3. confidence/__init__.py +13 -0
  4. confidence/calculator.py +308 -0
  5. confidence/models.py +40 -0
  6. context/__init__.py +17 -0
  7. context/models.py +108 -0
  8. context/pruner.py +228 -0
  9. context/selector.py +193 -0
  10. continuum_toolkit-1.0.0.dist-info/METADATA +511 -0
  11. continuum_toolkit-1.0.0.dist-info/RECORD +72 -0
  12. continuum_toolkit-1.0.0.dist-info/WHEEL +5 -0
  13. continuum_toolkit-1.0.0.dist-info/entry_points.txt +2 -0
  14. continuum_toolkit-1.0.0.dist-info/licenses/LICENSE +21 -0
  15. continuum_toolkit-1.0.0.dist-info/top_level.txt +13 -0
  16. contradictions/__init__.py +19 -0
  17. contradictions/detector.py +442 -0
  18. contradictions/models.py +75 -0
  19. core/__init__.py +97 -0
  20. core/enums.py +130 -0
  21. core/evidence.py +117 -0
  22. core/interfaces.py +209 -0
  23. core/schema.py +391 -0
  24. core/serializer.py +84 -0
  25. core/state_models.py +530 -0
  26. daemon/__init__.py +12 -0
  27. daemon/service.py +170 -0
  28. extractors/__init__.py +51 -0
  29. extractors/base.py +117 -0
  30. extractors/config/parsers.py +288 -0
  31. extractors/config/secret_sanitizer.py +91 -0
  32. extractors/config_extractor.py +172 -0
  33. extractors/conversation/analyzers.py +193 -0
  34. extractors/conversation/models.py +148 -0
  35. extractors/conversation_extractor.py +166 -0
  36. extractors/git_extractor.py +305 -0
  37. extractors/parsers/base.py +91 -0
  38. extractors/parsers/comment_parser.py +51 -0
  39. extractors/parsers/js_ts_parser.py +171 -0
  40. extractors/parsers/python_parser.py +180 -0
  41. extractors/verification/runners.py +278 -0
  42. extractors/verification_extractor.py +263 -0
  43. extractors/workspace_extractor.py +221 -0
  44. graph/__init__.py +24 -0
  45. graph/diff.py +109 -0
  46. graph/manager.py +473 -0
  47. graph/models.py +62 -0
  48. graph/propagator.py +194 -0
  49. graph/query.py +86 -0
  50. graph/snapshot.py +85 -0
  51. handoff/__init__.py +28 -0
  52. handoff/adapters/__init__.py +45 -0
  53. handoff/adapters/base.py +90 -0
  54. handoff/adapters/claude_adapter.py +176 -0
  55. handoff/adapters/codex_gpt_adapter.py +151 -0
  56. handoff/adapters/gemini_adapter.py +151 -0
  57. handoff/adapters/local_model_adapter.py +130 -0
  58. handoff/models.py +88 -0
  59. handoff/packager.py +288 -0
  60. pipeline/__init__.py +9 -0
  61. pipeline/orchestrator.py +260 -0
  62. resolution/__init__.py +15 -0
  63. resolution/resolver.py +311 -0
  64. storage/__init__.py +18 -0
  65. storage/hooks.py +125 -0
  66. storage/manager.py +127 -0
  67. storage/models.py +39 -0
  68. storage/recovery.py +98 -0
  69. watcher/__init__.py +17 -0
  70. watcher/detector.py +136 -0
  71. watcher/models.py +62 -0
  72. watcher/updater.py +163 -0
handoff/models.py ADDED
@@ -0,0 +1,88 @@
1
+ """
2
+ Project Continuum - Handoff Models
3
+ ==================================
4
+ Milestone 6 - Phase 14: Universal Handoff Package Generation.
5
+ Encapsulates standard vendor-neutral handoff packages and disk persistence.
6
+ """
7
+
8
+ from dataclasses import dataclass, field, asdict
9
+ from datetime import datetime, timezone
10
+ import json
11
+ import os
12
+ from pathlib import Path
13
+ from typing import Any, Dict, Optional
14
+
15
+
16
+ @dataclass
17
+ class HandoffPackage:
18
+ """
19
+ Standard vendor-neutral Continuum Handoff Package.
20
+ Contains:
21
+ - project_state_json: machine-readable canonical state JSON string
22
+ - project_context_md: high-level verified architectural context Markdown
23
+ - handoff_md: focused continuation document for the next AI agent
24
+ - evidence_files: map of relative filenames to content strings in evidence/
25
+ """
26
+ project_id: str
27
+ package_timestamp: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
28
+ project_state_json: str = ""
29
+ project_context_md: str = ""
30
+ handoff_md: str = ""
31
+ evidence_files: Dict[str, str] = field(default_factory=dict)
32
+ metadata: Dict[str, Any] = field(default_factory=dict)
33
+
34
+ def to_dict(self) -> Dict[str, Any]:
35
+ return {
36
+ "project_id": self.project_id,
37
+ "package_timestamp": self.package_timestamp,
38
+ "project_state_json": self.project_state_json,
39
+ "project_context_md": self.project_context_md,
40
+ "handoff_md": self.handoff_md,
41
+ "evidence_files": self.evidence_files,
42
+ "metadata": self.metadata
43
+ }
44
+
45
+ def save_to_directory(self, output_dir: str) -> Dict[str, str]:
46
+ """
47
+ Atomically saves the handoff package to output_dir with the standard structure:
48
+ - <output_dir>/project-state.json
49
+ - <output_dir>/project-context.md
50
+ - <output_dir>/handoff.md
51
+ - <output_dir>/evidence/<evidence_files>
52
+
53
+ Returns a dictionary mapping logical keys to their written filepaths.
54
+ """
55
+ base_path = Path(output_dir)
56
+ base_path.mkdir(parents=True, exist_ok=True)
57
+ evidence_dir = base_path / "evidence"
58
+ evidence_dir.mkdir(parents=True, exist_ok=True)
59
+
60
+ written_paths: Dict[str, str] = {}
61
+
62
+ # 1. project-state.json
63
+ state_file = base_path / "project-state.json"
64
+ with open(state_file, "w", encoding="utf-8") as f:
65
+ f.write(self.project_state_json)
66
+ written_paths["project-state.json"] = str(state_file.resolve())
67
+
68
+ # 2. project-context.md
69
+ context_file = base_path / "project-context.md"
70
+ with open(context_file, "w", encoding="utf-8") as f:
71
+ f.write(self.project_context_md)
72
+ written_paths["project-context.md"] = str(context_file.resolve())
73
+
74
+ # 3. handoff.md
75
+ handoff_file = base_path / "handoff.md"
76
+ with open(handoff_file, "w", encoding="utf-8") as f:
77
+ f.write(self.handoff_md)
78
+ written_paths["handoff.md"] = str(handoff_file.resolve())
79
+
80
+ # 4. evidence files
81
+ for rel_filename, content in self.evidence_files.items():
82
+ ev_file = evidence_dir / rel_filename
83
+ ev_file.parent.mkdir(parents=True, exist_ok=True)
84
+ with open(ev_file, "w", encoding="utf-8") as f:
85
+ f.write(content)
86
+ written_paths[f"evidence/{rel_filename}"] = str(ev_file.resolve())
87
+
88
+ return written_paths
handoff/packager.py ADDED
@@ -0,0 +1,288 @@
1
+ """
2
+ Project Continuum - Universal Handoff Package Generator
3
+ ========================================================
4
+ Milestone 6 - Phase 14: Universal Handoff Package Generation.
5
+ Generates standard vendor-neutral Continuum Handoff Packages that strictly
6
+ distinguish verified ground truth from conversational claims, report discrepancies,
7
+ blockers, confidence, and actionable next steps.
8
+ """
9
+
10
+ from datetime import datetime, timezone
11
+ import json
12
+ from typing import Any, Dict, List, Optional
13
+
14
+ from core.enums import NodeType, Status
15
+ from core.serializer import CanonicalStateSerializer
16
+ from core.state_models import (
17
+ CanonicalProjectState,
18
+ ContradictionRecord,
19
+ GraphNode,
20
+ ProjectState,
21
+ ConversationalState,
22
+ AgentExecutionState,
23
+ )
24
+ from context.models import TaskContext
25
+ from handoff.models import HandoffPackage
26
+
27
+
28
+ class UniversalHandoffPackager:
29
+ """
30
+ Constructs vendor-neutral Continuum handoff packages containing:
31
+ - project-state.json
32
+ - project-context.md
33
+ - handoff.md
34
+ - evidence/ directory artifacts
35
+ """
36
+
37
+ def __init__(self):
38
+ pass
39
+
40
+ def generate_package(
41
+ self,
42
+ canonical_state: CanonicalProjectState,
43
+ task_context: Optional[TaskContext] = None
44
+ ) -> HandoffPackage:
45
+ """
46
+ Synthesizes the complete handoff package from a CanonicalProjectState and
47
+ optional focused TaskContext.
48
+ """
49
+ # 1. Generate project-state.json (strict canonical schema)
50
+ project_state_json = CanonicalStateSerializer.to_json(canonical_state, indent=2)
51
+
52
+ # 2. Generate project-context.md (high-level verified architectural narrative)
53
+ project_context_md = self._generate_project_context_md(canonical_state)
54
+
55
+ # 3. Generate handoff.md (focused continuation briefing for the next agent)
56
+ handoff_md = self._generate_handoff_md(canonical_state, task_context)
57
+
58
+ # 4. Generate evidence/ directory artifacts
59
+ evidence_files = self._generate_evidence_artifacts(canonical_state)
60
+
61
+ metadata = {
62
+ "schema_version": canonical_state.schema_version,
63
+ "total_nodes": len(canonical_state.graph_nodes),
64
+ "total_edges": len(canonical_state.graph_edges),
65
+ "total_evidence": len(canonical_state.evidence_pool),
66
+ "contradiction_count": len(canonical_state.contradictions),
67
+ "generated_at": datetime.now(timezone.utc).isoformat(),
68
+ }
69
+
70
+ return HandoffPackage(
71
+ project_id=canonical_state.project_id,
72
+ package_timestamp=datetime.now(timezone.utc).isoformat(),
73
+ project_state_json=project_state_json,
74
+ project_context_md=project_context_md,
75
+ handoff_md=handoff_md,
76
+ evidence_files=evidence_files,
77
+ metadata=metadata
78
+ )
79
+
80
+ def _generate_project_context_md(self, state: CanonicalProjectState) -> str:
81
+ """
82
+ Generates project-context.md: High-level architectural briefing of verified reality.
83
+ """
84
+ p_state = state.project_state
85
+ c_state = state.conversational_state
86
+
87
+ lines = [
88
+ f"# Project Continuum — Verified Project Context",
89
+ f"**Project ID:** `{state.project_id}` | **Schema:** `{state.schema_version}`",
90
+ f"**Last Scanned:** `{p_state.last_scanned_at}`",
91
+ "",
92
+ "## 1. Physical Workspace Reality",
93
+ f"- **Root Path:** `{p_state.root_path}`",
94
+ f"- **Detected Languages:** {', '.join(p_state.detected_languages) if p_state.detected_languages else 'None detected'}",
95
+ f"- **Source Files Tracked:** {len(p_state.files)} file(s)",
96
+ f"- **AST Symbols Extracted:** {len(p_state.symbols)} symbol(s)",
97
+ f"- **Build Status:** `[{p_state.build_status.value}]`",
98
+ "",
99
+ "### Git State",
100
+ f"- **Repository:** {'Yes' if p_state.git_state.is_repo else 'No'}",
101
+ f"- **Active Branch:** `{p_state.git_state.branch or 'N/A'}`",
102
+ f"- **Head Commit:** `{p_state.git_state.head_commit or 'N/A'}`",
103
+ f"- **Working Tree Dirty:** {'Yes (Uncommitted Changes)' if p_state.git_state.is_dirty else 'Clean'}",
104
+ f"- **Staged Files:** {len(p_state.git_state.staged_files)}",
105
+ f"- **Unstaged Files:** {len(p_state.git_state.unstaged_files)}",
106
+ f"- **Untracked Files:** {len(p_state.git_state.untracked_files)}",
107
+ "",
108
+ "## 2. Canonical Architecture & Component Inventory",
109
+ ]
110
+
111
+ if state.graph_nodes:
112
+ # Group by NodeType
113
+ nodes_by_type: Dict[str, List[GraphNode]] = {}
114
+ for n in state.graph_nodes.values():
115
+ t = n.node_type.value
116
+ nodes_by_type.setdefault(t, []).append(n)
117
+
118
+ for n_type, n_list in sorted(nodes_by_type.items()):
119
+ lines.append(f"### {n_type.capitalize()}s ({len(n_list)})")
120
+ for n in sorted(n_list, key=lambda x: x.name):
121
+ conf_str = f" | Confidence: {n.confidence_score:.0f}%" if n.confidence_score > 0 else ""
122
+ lines.append(f"- **{n.name}** (`{n.id}`): Status `[{n.status.value}]`{conf_str}")
123
+ lines.append("")
124
+ else:
125
+ lines.append("- *No graph components registered.*")
126
+ lines.append("")
127
+
128
+ lines.extend([
129
+ "## 3. Verified Test & Verification Baseline",
130
+ f"- **Recorded Test Executions:** {len(p_state.test_results)}",
131
+ ])
132
+
133
+ if p_state.test_results:
134
+ passed = [t for t in p_state.test_results if t.status.value == "VERIFIED"]
135
+ failed = [t for t in p_state.test_results if t.status.value != "VERIFIED"]
136
+ lines.append(f"- **Passing Tests:** {len(passed)}")
137
+ lines.append(f"- **Failing Tests:** {len(failed)}")
138
+ if failed:
139
+ lines.append("\n#### ❌ Failing Tests Detail:")
140
+ for ft in failed:
141
+ lines.append(f"- **{ft.name}** (`{ft.suite}`): exit code {ft.exit_code}")
142
+ if ft.error_message:
143
+ lines.append(f" - Error: `{ft.error_message}`")
144
+ lines.append("")
145
+
146
+ lines.extend([
147
+ "## 4. Architectural Decisions & Requirements",
148
+ f"- **User Requirements:** {len(c_state.user_requirements)}",
149
+ f"- **Recorded Decisions:** {len(c_state.architectural_decisions)}",
150
+ ])
151
+
152
+ if c_state.architectural_decisions:
153
+ for d in c_state.architectural_decisions:
154
+ lines.append(f"- **{d.title}**: {d.rationale}")
155
+ if d.constraints:
156
+ for c in d.constraints:
157
+ lines.append(f" - *Constraint*: {c}")
158
+
159
+ lines.append("\n---")
160
+ lines.append("*Generated automatically by Project Continuum Universal Handoff Engine.*")
161
+ return "\n".join(lines)
162
+
163
+ def _generate_handoff_md(
164
+ self,
165
+ state: CanonicalProjectState,
166
+ task_context: Optional[TaskContext] = None
167
+ ) -> str:
168
+ """
169
+ Generates handoff.md: Tactical continuation document explaining exactly
170
+ what the next agent needs to do, distinguishing verified vs unverified claims.
171
+ """
172
+ exec_state = state.agent_execution_state
173
+ c_state = state.conversational_state
174
+ p_state = state.project_state
175
+
176
+ lines = [
177
+ "# Project Continuum — Agent Handoff Briefing",
178
+ f"**Session / Project ID:** `{state.project_id}`",
179
+ f"**Previous Agent Model:** `{exec_state.model_name}` (ID: `{exec_state.agent_id}`)",
180
+ f"**Handoff Generated At:** `{datetime.now(timezone.utc).isoformat()}`",
181
+ "",
182
+ "> ⚠️ **MANDATORY DIRECTIVE FOR RESUMING AGENT:**",
183
+ "> Maintain strict separation between verified physical evidence and conversational claims.",
184
+ "> Never accept unverified agent claims as completed tasks without physical verification.",
185
+ "",
186
+ "## 🎯 1. Tactical In-Flight & Active Tasks",
187
+ ]
188
+
189
+ if exec_state.active_tasks:
190
+ for t in exec_state.active_tasks:
191
+ lines.append(f"- **{t.title}** (`{t.id}`): Status `[{t.status.value}]`")
192
+ if t.target_files:
193
+ lines.append(f" - Target Files: {', '.join(f'`{f}`' for f in t.target_files)}")
194
+ if t.target_symbols:
195
+ lines.append(f" - Target Symbols: {', '.join(f'`{s}`' for s in t.target_symbols)}")
196
+ if t.notes:
197
+ lines.append(f" - Notes: {t.notes}")
198
+ else:
199
+ lines.append("- *No in-flight tasks recorded.*")
200
+
201
+ lines.extend([
202
+ "",
203
+ "## 🚀 2. Recommended Next Action",
204
+ ])
205
+
206
+ if exec_state.next_action:
207
+ na = exec_state.next_action
208
+ lines.append(f"- **Action Type:** `{na.action_type}`")
209
+ lines.append(f"- **Target URI:** `{na.target_uri}`")
210
+ lines.append(f"- **Description:** {na.description}")
211
+ if na.prerequisites:
212
+ lines.append(f"- **Prerequisites:** {', '.join(f'`{p}`' for p in na.prerequisites)}")
213
+ elif exec_state.last_error_encountered:
214
+ lines.append(f"- **Action Required:** Fix last encountered error: `{exec_state.last_error_encountered}`")
215
+ else:
216
+ lines.append("- *Inspect known blockers and continue highest priority in-progress component.*")
217
+
218
+ lines.extend([
219
+ "",
220
+ "## ⚠️ 3. Known Blockers & Contradiction Ledger",
221
+ ])
222
+
223
+ if state.contradictions:
224
+ lines.append(f"**Total Contradictions Detected:** {len(state.contradictions)}")
225
+ for c in state.contradictions:
226
+ res_tag = " [RESOLVED]" if c.resolved else " [ACTIVE BLOCKER]"
227
+ lines.append(f"- 🔴 **[{c.severity}]{res_tag}**: {c.explanation}")
228
+ if c.claim_text:
229
+ lines.append(f" - *Conflicting Claim*: \"{c.claim_text}\"")
230
+ else:
231
+ lines.append("- ✅ *Zero unresolved contradictions detected between claims and physical state.*")
232
+
233
+ lines.extend([
234
+ "",
235
+ "## 💬 4. Unverified Conversational Claims & Unresolved Questions",
236
+ ])
237
+
238
+ if c_state.agent_claims:
239
+ lines.append("### Unverified Agent Claims (Level 5 Evidence):")
240
+ for cl in c_state.agent_claims:
241
+ lines.append(f"- \"{cl.claim_text}\" (Claimed Status: `[{cl.claimed_status.value}]` by `{cl.source_agent}`)")
242
+ else:
243
+ lines.append("- *No unverified agent claims recorded.*")
244
+
245
+ if c_state.unresolved_questions:
246
+ lines.append("\n### Unresolved Questions:")
247
+ for uq in c_state.unresolved_questions:
248
+ block_tag = " **[BLOCKING]**" if uq.blocking else ""
249
+ lines.append(f"- ❓{block_tag} {uq.question} (Context: {uq.context or 'N/A'})")
250
+
251
+ if task_context:
252
+ lines.extend([
253
+ "",
254
+ "## 🔍 5. Focused Task Context",
255
+ task_context.to_markdown()
256
+ ])
257
+
258
+ lines.append("\n---")
259
+ lines.append("*Project Continuum AI Work Continuity Package.*")
260
+ return "\n".join(lines)
261
+
262
+ def _generate_evidence_artifacts(self, state: CanonicalProjectState) -> Dict[str, str]:
263
+ """
264
+ Generates artifacts for the evidence/ directory:
265
+ - evidence/test_results.json
266
+ - evidence/contradictions.json
267
+ - evidence/symbols_manifest.json
268
+ - evidence/evidence_manifest.json
269
+ """
270
+ artifacts: Dict[str, str] = {}
271
+
272
+ # 1. Test Results
273
+ test_data = [t.to_dict() for t in state.project_state.test_results]
274
+ artifacts["test_results.json"] = json.dumps(test_data, indent=2)
275
+
276
+ # 2. Contradictions
277
+ contra_data = [c.to_dict() for c in state.contradictions]
278
+ artifacts["contradictions.json"] = json.dumps(contra_data, indent=2)
279
+
280
+ # 3. Symbols
281
+ sym_data = [s.to_dict() for s in state.project_state.symbols]
282
+ artifacts["symbols_manifest.json"] = json.dumps(sym_data, indent=2)
283
+
284
+ # 4. Evidence Pool Manifest
285
+ ev_data = {k: v.to_dict() for k, v in state.evidence_pool.items()}
286
+ artifacts["evidence_manifest.json"] = json.dumps(ev_data, indent=2)
287
+
288
+ return artifacts
pipeline/__init__.py ADDED
@@ -0,0 +1,9 @@
1
+ """
2
+ Project Continuum - End-to-End Pipeline Package
3
+ ===============================================
4
+ Exposes the ContinuumPipeline and PipelineExecutionSummary.
5
+ """
6
+
7
+ from pipeline.orchestrator import ContinuumPipeline, PipelineExecutionSummary
8
+
9
+ __all__ = ["ContinuumPipeline", "PipelineExecutionSummary"]
@@ -0,0 +1,260 @@
1
+ """
2
+ Project Continuum - End-to-End Orchestrator Pipeline
3
+ =====================================================
4
+ Milestone 8 - Phase 19: End-to-End Integration & Polyglot Validation.
5
+ Connects the complete Continuum pipeline:
6
+ 1. Multi-source evidence harvesting (Workspace, Config, Git, Verification, Conversation).
7
+ 2. Evidence Resolution Engine (arbitration by hierarchy level 1-5).
8
+ 3. Contradiction Detection Engine (detecting mismatches between claims and reality).
9
+ 4. Confidence Calculation Engine (explainable scoring grounded in proof).
10
+ 5. Canonical State Graph / DAG (node/edge modeling, cycle prevention, dependency propagation).
11
+ 6. Task-driven Context Selection & Budget Pruning (minimum sufficient high-signal context).
12
+ 7. Model-Specific Handoff Adapters (Claude, Codex/GPT, Gemini, Local LLM, Universal).
13
+ """
14
+
15
+ from dataclasses import dataclass, field
16
+ from pathlib import Path
17
+ from typing import Any, Dict, List, Optional, Tuple, Union
18
+
19
+ from core.enums import EvidenceLevel, EvidenceType, NodeType, RelationType, Status, TargetModel
20
+ from core.evidence import Evidence
21
+ from core.state_models import (
22
+ AgentClaim,
23
+ AgentExecutionState,
24
+ CanonicalProjectState,
25
+ ContradictionRecord,
26
+ ConversationalState,
27
+ GraphEdge,
28
+ GraphNode,
29
+ ProjectState,
30
+ Requirement,
31
+ TestResult,
32
+ )
33
+ from core.serializer import CanonicalStateSerializer
34
+ from extractors.workspace_extractor import WorkspaceEvidenceExtractor
35
+ from extractors.config_extractor import ConfigEvidenceExtractor
36
+ from extractors.git_extractor import GitEvidenceExtractor
37
+ from extractors.verification_extractor import VerificationEvidenceExtractor
38
+ from extractors.conversation_extractor import ConversationEvidenceExtractor
39
+ from resolution.resolver import EvidenceResolver, ResolutionResult
40
+ from contradictions.detector import ContradictionDetector
41
+ from confidence.calculator import ConfidenceCalculator
42
+ from graph.manager import StateGraphManager
43
+ from context.selector import TaskContextSelector
44
+ from context.pruner import ContextPruner
45
+ from context.models import TaskContext
46
+ from handoff.packager import UniversalHandoffPackager
47
+ from handoff.adapters import get_adapter_for_model
48
+ from handoff.models import HandoffPackage
49
+
50
+
51
+ @dataclass
52
+ class PipelineExecutionSummary:
53
+ """Summary metrics of an end-to-end pipeline execution."""
54
+ project_id: str
55
+ workspace_path: str
56
+ languages_detected: List[str]
57
+ total_files_scanned: int
58
+ total_symbols_extracted: int
59
+ total_evidence_collected: int
60
+ contradictions_detected: int
61
+ project_confidence: float
62
+ graph_nodes_count: int
63
+ graph_edges_count: int
64
+ context_tokens_generated: Optional[int] = None
65
+ handoff_formats_generated: List[str] = field(default_factory=list)
66
+
67
+ def to_dict(self) -> Dict[str, Any]:
68
+ return {
69
+ "project_id": self.project_id,
70
+ "workspace_path": self.workspace_path,
71
+ "languages_detected": self.languages_detected,
72
+ "total_files_scanned": self.total_files_scanned,
73
+ "total_symbols_extracted": self.total_symbols_extracted,
74
+ "total_evidence_collected": self.total_evidence_collected,
75
+ "contradictions_detected": self.contradictions_detected,
76
+ "project_confidence": self.project_confidence,
77
+ "graph_nodes_count": self.graph_nodes_count,
78
+ "graph_edges_count": self.graph_edges_count,
79
+ "context_tokens_generated": self.context_tokens_generated,
80
+ "handoff_formats_generated": self.handoff_formats_generated,
81
+ }
82
+
83
+
84
+ class ContinuumPipeline:
85
+ """
86
+ High-level orchestrator for Project Continuum.
87
+ Executes the complete end-to-end pipeline from physical workspace scanning
88
+ to model-optimized handoff generation.
89
+ """
90
+
91
+ def __init__(
92
+ self,
93
+ workspace_path: Union[str, Path],
94
+ project_id: Optional[str] = None,
95
+ custom_parsers: Optional[List[Any]] = None
96
+ ):
97
+ self.workspace_path = Path(workspace_path).resolve()
98
+ self.project_id = project_id or f"proj_{self.workspace_path.name}"
99
+
100
+ # Initialize subsystem engines
101
+ self.ws_extractor = WorkspaceEvidenceExtractor(custom_parsers=custom_parsers)
102
+ self.config_extractor = ConfigEvidenceExtractor()
103
+ self.git_extractor = GitEvidenceExtractor()
104
+ self.verification_extractor = VerificationEvidenceExtractor()
105
+ self.conversation_extractor = ConversationEvidenceExtractor()
106
+
107
+ self.resolver = EvidenceResolver()
108
+ self.contradiction_detector = ContradictionDetector()
109
+ self.confidence_calculator = ConfidenceCalculator()
110
+ self.context_selector = TaskContextSelector()
111
+ self.context_pruner = ContextPruner()
112
+ self.universal_packager = UniversalHandoffPackager()
113
+
114
+ def run_full_analysis(
115
+ self,
116
+ conversation_input: Optional[Union[str, Path, Dict[str, Any]]] = None,
117
+ explicit_verification_results: Optional[List[TestResult]] = None,
118
+ task_description: Optional[str] = None,
119
+ token_budget: Optional[int] = None,
120
+ target_models: Optional[List[TargetModel]] = None
121
+ ) -> Tuple[CanonicalProjectState, PipelineExecutionSummary, Dict[str, Any]]:
122
+ """
123
+ Executes the complete end-to-end pipeline:
124
+ 1. Workspace scanning & symbol parsing.
125
+ 2. Manifest & config discovery.
126
+ 3. Git tree inspection.
127
+ 4. Test verification & results recording.
128
+ 5. Conversation ingestion (preserving strict 3-state separation).
129
+ 6. Truth resolution across evidence hierarchy.
130
+ 7. Contradiction detection.
131
+ 8. Grounded confidence computation.
132
+ 9. DAG construction & dependency propagation.
133
+ 10. Task-driven context selection & budget pruning.
134
+ 11. Universal & model-specific handoff generation.
135
+ """
136
+ # Initialize Canonical State container
137
+ canonical_state = CanonicalProjectState(
138
+ schema_version="1.0.0",
139
+ project_id=self.project_id,
140
+ project_state=ProjectState(root_path=str(self.workspace_path))
141
+ )
142
+
143
+ # ----------------------------------------------------------------------
144
+ # Step 1: Physical Workspace & Source Code Evidence Extraction
145
+ # ----------------------------------------------------------------------
146
+ self.ws_extractor.populate_project_state(str(self.workspace_path), canonical_state)
147
+
148
+ # ----------------------------------------------------------------------
149
+ # Step 2: Configuration, Environment & Manifest Extraction
150
+ # ----------------------------------------------------------------------
151
+ self.config_extractor.populate_project_state(str(self.workspace_path), canonical_state)
152
+
153
+ # ----------------------------------------------------------------------
154
+ # Step 3: Git History & Delta Analysis
155
+ # ----------------------------------------------------------------------
156
+ self.git_extractor.populate_project_state(str(self.workspace_path), canonical_state)
157
+
158
+ # ----------------------------------------------------------------------
159
+ # Step 4: Verification & Test Execution Recording
160
+ # ----------------------------------------------------------------------
161
+ if explicit_verification_results:
162
+ for tr in explicit_verification_results:
163
+ canonical_state.project_state.test_results.append(tr)
164
+ test_ev = self.verification_extractor.create_evidence(
165
+ evidence_type=EvidenceType.TEST_RUN,
166
+ summary=f"Test Suite: {tr.suite} (Test: {tr.name}, Status: {tr.status.value})",
167
+ raw_payload=tr.to_dict(),
168
+ source_uri=tr.suite,
169
+ locator=f"test:{tr.suite}:{tr.name}"
170
+ )
171
+ canonical_state.add_evidence(test_ev)
172
+
173
+ # ----------------------------------------------------------------------
174
+ # Step 5: Conversation & Agent State Ingestion (Strict 3-State Separation)
175
+ # ----------------------------------------------------------------------
176
+ if conversation_input:
177
+ self.conversation_extractor.ingest_transcript(conversation_input, canonical_state)
178
+
179
+ # ----------------------------------------------------------------------
180
+ # Step 6 & 7: Contradiction Detection & Discrepancy Resolution
181
+ # ----------------------------------------------------------------------
182
+ contradictions = self.contradiction_detector.detect_contradictions(
183
+ project_state=canonical_state.project_state,
184
+ conversational_state=canonical_state.conversational_state,
185
+ evidence_pool=canonical_state.evidence_pool
186
+ )
187
+ canonical_state.contradictions = contradictions
188
+
189
+ # ----------------------------------------------------------------------
190
+ # Step 8 & 9: Canonical State Graph (DAG) Construction
191
+ # ----------------------------------------------------------------------
192
+ graph_manager = StateGraphManager(canonical_state)
193
+ graph_manager.build_from_canonical_state(canonical_state)
194
+
195
+ # ----------------------------------------------------------------------
196
+ # Step 10: Grounded Confidence Calculation
197
+ # ----------------------------------------------------------------------
198
+ proj_confidence, conf_explanation = self.confidence_calculator.calculate_project_confidence(canonical_state)
199
+
200
+ # ----------------------------------------------------------------------
201
+ # Step 11: Task Context Selection & Budget Pruning (Optional)
202
+ # ----------------------------------------------------------------------
203
+ task_ctx: Optional[TaskContext] = None
204
+ pruned_tokens = None
205
+ if task_description:
206
+ task_ctx = self.context_selector.extract_task_context(
207
+ task_description=task_description,
208
+ canonical_state=canonical_state,
209
+ token_budget=token_budget
210
+ )
211
+ if token_budget:
212
+ prune_res = self.context_pruner.prune_to_budget(task_ctx, token_budget)
213
+ pruned_tokens = prune_res.estimated_tokens_after
214
+
215
+ # ----------------------------------------------------------------------
216
+ # Step 12: Model Handoff Generation (Universal & Model-Specific)
217
+ # ----------------------------------------------------------------------
218
+ handoff_results: Dict[str, Any] = {}
219
+ generated_formats: List[str] = []
220
+
221
+ # Universal Handoff Package
222
+ universal_pkg = self.universal_packager.generate_package(canonical_state, task_ctx)
223
+ handoff_results["universal"] = universal_pkg
224
+ generated_formats.append("universal")
225
+
226
+ # Model-Specific Adapters
227
+ models_to_generate = target_models or [
228
+ TargetModel.CLAUDE,
229
+ TargetModel.CODEX_GPT,
230
+ TargetModel.GEMINI,
231
+ TargetModel.LOCAL_LLM
232
+ ]
233
+
234
+ for model in models_to_generate:
235
+ adapter = get_adapter_for_model(model)
236
+ model_handoff = adapter.generate_handoff(canonical_state)
237
+ handoff_results[model.value] = model_handoff
238
+ handoff_results[model.value.lower()] = model_handoff
239
+ if model == TargetModel.CODEX_GPT:
240
+ handoff_results["codex"] = model_handoff
241
+ generated_formats.append(model.value)
242
+
243
+ p_state = canonical_state.project_state
244
+ # Build execution summary
245
+ summary = PipelineExecutionSummary(
246
+ project_id=self.project_id,
247
+ workspace_path=str(self.workspace_path),
248
+ languages_detected=list(set(p_state.detected_languages)),
249
+ total_files_scanned=len(p_state.files),
250
+ total_symbols_extracted=len(p_state.symbols),
251
+ total_evidence_collected=len(canonical_state.evidence_pool),
252
+ contradictions_detected=len(contradictions),
253
+ project_confidence=proj_confidence,
254
+ graph_nodes_count=len(canonical_state.graph_nodes),
255
+ graph_edges_count=len(canonical_state.graph_edges),
256
+ context_tokens_generated=pruned_tokens,
257
+ handoff_formats_generated=generated_formats
258
+ )
259
+
260
+ return canonical_state, summary, handoff_results
resolution/__init__.py ADDED
@@ -0,0 +1,15 @@
1
+ """
2
+ Project Continuum - Evidence Resolution Subsystem Package Initialization
3
+ """
4
+
5
+ from resolution.resolver import (
6
+ EvidenceResolver,
7
+ EvidenceCandidate,
8
+ ResolutionResult,
9
+ )
10
+
11
+ __all__ = [
12
+ "EvidenceResolver",
13
+ "EvidenceCandidate",
14
+ "ResolutionResult",
15
+ ]