htmlgraph 0.9.3__py3-none-any.whl → 0.27.5__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.
- htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/.htmlgraph/agents.json +72 -0
- htmlgraph/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/__init__.py +173 -17
- htmlgraph/__init__.pyi +123 -0
- htmlgraph/agent_detection.py +127 -0
- htmlgraph/agent_registry.py +45 -30
- htmlgraph/agents.py +160 -107
- htmlgraph/analytics/__init__.py +9 -2
- htmlgraph/analytics/cli.py +190 -51
- htmlgraph/analytics/cost_analyzer.py +391 -0
- htmlgraph/analytics/cost_monitor.py +664 -0
- htmlgraph/analytics/cost_reporter.py +675 -0
- htmlgraph/analytics/cross_session.py +617 -0
- htmlgraph/analytics/dependency.py +192 -100
- htmlgraph/analytics/pattern_learning.py +771 -0
- htmlgraph/analytics/session_graph.py +707 -0
- htmlgraph/analytics/strategic/__init__.py +80 -0
- htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
- htmlgraph/analytics/strategic/pattern_detector.py +876 -0
- htmlgraph/analytics/strategic/preference_manager.py +709 -0
- htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
- htmlgraph/analytics/work_type.py +190 -14
- htmlgraph/analytics_index.py +135 -51
- htmlgraph/api/__init__.py +3 -0
- htmlgraph/api/cost_alerts_websocket.py +416 -0
- htmlgraph/api/main.py +2498 -0
- htmlgraph/api/static/htmx.min.js +1 -0
- htmlgraph/api/static/style-redesign.css +1344 -0
- htmlgraph/api/static/style.css +1079 -0
- htmlgraph/api/templates/dashboard-redesign.html +1366 -0
- htmlgraph/api/templates/dashboard.html +794 -0
- htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
- htmlgraph/api/templates/partials/activity-feed.html +1100 -0
- htmlgraph/api/templates/partials/agents-redesign.html +317 -0
- htmlgraph/api/templates/partials/agents.html +317 -0
- htmlgraph/api/templates/partials/event-traces.html +373 -0
- htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
- htmlgraph/api/templates/partials/features.html +578 -0
- htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
- htmlgraph/api/templates/partials/metrics.html +346 -0
- htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
- htmlgraph/api/templates/partials/orchestration.html +198 -0
- htmlgraph/api/templates/partials/spawners.html +375 -0
- htmlgraph/api/templates/partials/work-items.html +613 -0
- htmlgraph/api/websocket.py +538 -0
- htmlgraph/archive/__init__.py +24 -0
- htmlgraph/archive/bloom.py +234 -0
- htmlgraph/archive/fts.py +297 -0
- htmlgraph/archive/manager.py +583 -0
- htmlgraph/archive/search.py +244 -0
- htmlgraph/atomic_ops.py +560 -0
- htmlgraph/attribute_index.py +208 -0
- htmlgraph/bounded_paths.py +539 -0
- htmlgraph/builders/__init__.py +14 -0
- htmlgraph/builders/base.py +118 -29
- htmlgraph/builders/bug.py +150 -0
- htmlgraph/builders/chore.py +119 -0
- htmlgraph/builders/epic.py +150 -0
- htmlgraph/builders/feature.py +31 -6
- htmlgraph/builders/insight.py +195 -0
- htmlgraph/builders/metric.py +217 -0
- htmlgraph/builders/pattern.py +202 -0
- htmlgraph/builders/phase.py +162 -0
- htmlgraph/builders/spike.py +52 -19
- htmlgraph/builders/track.py +148 -72
- htmlgraph/cigs/__init__.py +81 -0
- htmlgraph/cigs/autonomy.py +385 -0
- htmlgraph/cigs/cost.py +475 -0
- htmlgraph/cigs/messages_basic.py +472 -0
- htmlgraph/cigs/messaging.py +365 -0
- htmlgraph/cigs/models.py +771 -0
- htmlgraph/cigs/pattern_storage.py +427 -0
- htmlgraph/cigs/patterns.py +503 -0
- htmlgraph/cigs/posttool_analyzer.py +234 -0
- htmlgraph/cigs/reporter.py +818 -0
- htmlgraph/cigs/tracker.py +317 -0
- htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/cli/.htmlgraph/agents.json +72 -0
- htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/cli/__init__.py +42 -0
- htmlgraph/cli/__main__.py +6 -0
- htmlgraph/cli/analytics.py +1424 -0
- htmlgraph/cli/base.py +685 -0
- htmlgraph/cli/constants.py +206 -0
- htmlgraph/cli/core.py +954 -0
- htmlgraph/cli/main.py +147 -0
- htmlgraph/cli/models.py +475 -0
- htmlgraph/cli/templates/__init__.py +1 -0
- htmlgraph/cli/templates/cost_dashboard.py +399 -0
- htmlgraph/cli/work/__init__.py +239 -0
- htmlgraph/cli/work/browse.py +115 -0
- htmlgraph/cli/work/features.py +568 -0
- htmlgraph/cli/work/orchestration.py +676 -0
- htmlgraph/cli/work/report.py +728 -0
- htmlgraph/cli/work/sessions.py +466 -0
- htmlgraph/cli/work/snapshot.py +559 -0
- htmlgraph/cli/work/tracks.py +486 -0
- htmlgraph/cli_commands/__init__.py +1 -0
- htmlgraph/cli_commands/feature.py +195 -0
- htmlgraph/cli_framework.py +115 -0
- htmlgraph/collections/__init__.py +18 -0
- htmlgraph/collections/base.py +415 -98
- htmlgraph/collections/bug.py +53 -0
- htmlgraph/collections/chore.py +53 -0
- htmlgraph/collections/epic.py +53 -0
- htmlgraph/collections/feature.py +12 -26
- htmlgraph/collections/insight.py +100 -0
- htmlgraph/collections/metric.py +92 -0
- htmlgraph/collections/pattern.py +97 -0
- htmlgraph/collections/phase.py +53 -0
- htmlgraph/collections/session.py +194 -0
- htmlgraph/collections/spike.py +56 -16
- htmlgraph/collections/task_delegation.py +241 -0
- htmlgraph/collections/todo.py +511 -0
- htmlgraph/collections/traces.py +487 -0
- htmlgraph/config/cost_models.json +56 -0
- htmlgraph/config.py +190 -0
- htmlgraph/context_analytics.py +344 -0
- htmlgraph/converter.py +216 -28
- htmlgraph/cost_analysis/__init__.py +5 -0
- htmlgraph/cost_analysis/analyzer.py +438 -0
- htmlgraph/dashboard.html +2406 -307
- htmlgraph/dashboard.html.backup +6592 -0
- htmlgraph/dashboard.html.bak +7181 -0
- htmlgraph/dashboard.html.bak2 +7231 -0
- htmlgraph/dashboard.html.bak3 +7232 -0
- htmlgraph/db/__init__.py +38 -0
- htmlgraph/db/queries.py +790 -0
- htmlgraph/db/schema.py +1788 -0
- htmlgraph/decorators.py +317 -0
- htmlgraph/dependency_models.py +19 -2
- htmlgraph/deploy.py +142 -125
- htmlgraph/deployment_models.py +474 -0
- htmlgraph/docs/API_REFERENCE.md +841 -0
- htmlgraph/docs/HTTP_API.md +750 -0
- htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
- htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
- htmlgraph/docs/README.md +532 -0
- htmlgraph/docs/__init__.py +77 -0
- htmlgraph/docs/docs_version.py +55 -0
- htmlgraph/docs/metadata.py +93 -0
- htmlgraph/docs/migrations.py +232 -0
- htmlgraph/docs/template_engine.py +143 -0
- htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
- htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
- htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
- htmlgraph/docs/templates/base_agents.md.j2 +78 -0
- htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
- htmlgraph/docs/version_check.py +163 -0
- htmlgraph/edge_index.py +182 -27
- htmlgraph/error_handler.py +544 -0
- htmlgraph/event_log.py +100 -52
- htmlgraph/event_migration.py +13 -4
- htmlgraph/exceptions.py +49 -0
- htmlgraph/file_watcher.py +101 -28
- htmlgraph/find_api.py +75 -63
- htmlgraph/git_events.py +145 -63
- htmlgraph/graph.py +1122 -106
- htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/hooks/.htmlgraph/agents.json +72 -0
- htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
- htmlgraph/hooks/__init__.py +45 -0
- htmlgraph/hooks/bootstrap.py +169 -0
- htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
- htmlgraph/hooks/concurrent_sessions.py +208 -0
- htmlgraph/hooks/context.py +350 -0
- htmlgraph/hooks/drift_handler.py +525 -0
- htmlgraph/hooks/event_tracker.py +1314 -0
- htmlgraph/hooks/git_commands.py +175 -0
- htmlgraph/hooks/hooks-config.example.json +12 -0
- htmlgraph/hooks/installer.py +343 -0
- htmlgraph/hooks/orchestrator.py +674 -0
- htmlgraph/hooks/orchestrator_reflector.py +223 -0
- htmlgraph/hooks/post-checkout.sh +28 -0
- htmlgraph/hooks/post-commit.sh +24 -0
- htmlgraph/hooks/post-merge.sh +26 -0
- htmlgraph/hooks/post_tool_use_failure.py +273 -0
- htmlgraph/hooks/post_tool_use_handler.py +257 -0
- htmlgraph/hooks/posttooluse.py +408 -0
- htmlgraph/hooks/pre-commit.sh +94 -0
- htmlgraph/hooks/pre-push.sh +28 -0
- htmlgraph/hooks/pretooluse.py +819 -0
- htmlgraph/hooks/prompt_analyzer.py +637 -0
- htmlgraph/hooks/session_handler.py +668 -0
- htmlgraph/hooks/session_summary.py +395 -0
- htmlgraph/hooks/state_manager.py +504 -0
- htmlgraph/hooks/subagent_detection.py +202 -0
- htmlgraph/hooks/subagent_stop.py +369 -0
- htmlgraph/hooks/task_enforcer.py +255 -0
- htmlgraph/hooks/task_validator.py +177 -0
- htmlgraph/hooks/validator.py +628 -0
- htmlgraph/ids.py +41 -27
- htmlgraph/index.d.ts +286 -0
- htmlgraph/learning.py +767 -0
- htmlgraph/mcp_server.py +69 -23
- htmlgraph/models.py +1586 -87
- htmlgraph/operations/README.md +62 -0
- htmlgraph/operations/__init__.py +79 -0
- htmlgraph/operations/analytics.py +339 -0
- htmlgraph/operations/bootstrap.py +289 -0
- htmlgraph/operations/events.py +244 -0
- htmlgraph/operations/fastapi_server.py +231 -0
- htmlgraph/operations/hooks.py +350 -0
- htmlgraph/operations/initialization.py +597 -0
- htmlgraph/operations/initialization.py.backup +228 -0
- htmlgraph/operations/server.py +303 -0
- htmlgraph/orchestration/__init__.py +58 -0
- htmlgraph/orchestration/claude_launcher.py +179 -0
- htmlgraph/orchestration/command_builder.py +72 -0
- htmlgraph/orchestration/headless_spawner.py +281 -0
- htmlgraph/orchestration/live_events.py +377 -0
- htmlgraph/orchestration/model_selection.py +327 -0
- htmlgraph/orchestration/plugin_manager.py +140 -0
- htmlgraph/orchestration/prompts.py +137 -0
- htmlgraph/orchestration/spawner_event_tracker.py +383 -0
- htmlgraph/orchestration/spawners/__init__.py +16 -0
- htmlgraph/orchestration/spawners/base.py +194 -0
- htmlgraph/orchestration/spawners/claude.py +173 -0
- htmlgraph/orchestration/spawners/codex.py +435 -0
- htmlgraph/orchestration/spawners/copilot.py +294 -0
- htmlgraph/orchestration/spawners/gemini.py +471 -0
- htmlgraph/orchestration/subprocess_runner.py +36 -0
- htmlgraph/orchestration/task_coordination.py +343 -0
- htmlgraph/orchestration.md +563 -0
- htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
- htmlgraph/orchestrator.py +669 -0
- htmlgraph/orchestrator_config.py +357 -0
- htmlgraph/orchestrator_mode.py +328 -0
- htmlgraph/orchestrator_validator.py +133 -0
- htmlgraph/parallel.py +646 -0
- htmlgraph/parser.py +160 -35
- htmlgraph/path_query.py +608 -0
- htmlgraph/pattern_matcher.py +636 -0
- htmlgraph/planning.py +147 -52
- htmlgraph/pydantic_models.py +476 -0
- htmlgraph/quality_gates.py +350 -0
- htmlgraph/query_builder.py +109 -72
- htmlgraph/query_composer.py +509 -0
- htmlgraph/reflection.py +443 -0
- htmlgraph/refs.py +344 -0
- htmlgraph/repo_hash.py +512 -0
- htmlgraph/repositories/__init__.py +292 -0
- htmlgraph/repositories/analytics_repository.py +455 -0
- htmlgraph/repositories/analytics_repository_standard.py +628 -0
- htmlgraph/repositories/feature_repository.py +581 -0
- htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
- htmlgraph/repositories/feature_repository_memory.py +607 -0
- htmlgraph/repositories/feature_repository_sqlite.py +858 -0
- htmlgraph/repositories/filter_service.py +620 -0
- htmlgraph/repositories/filter_service_standard.py +445 -0
- htmlgraph/repositories/shared_cache.py +621 -0
- htmlgraph/repositories/shared_cache_memory.py +395 -0
- htmlgraph/repositories/track_repository.py +552 -0
- htmlgraph/repositories/track_repository_htmlfile.py +619 -0
- htmlgraph/repositories/track_repository_memory.py +508 -0
- htmlgraph/repositories/track_repository_sqlite.py +711 -0
- htmlgraph/routing.py +8 -19
- htmlgraph/scripts/deploy.py +1 -2
- htmlgraph/sdk/__init__.py +398 -0
- htmlgraph/sdk/__init__.pyi +14 -0
- htmlgraph/sdk/analytics/__init__.py +19 -0
- htmlgraph/sdk/analytics/engine.py +155 -0
- htmlgraph/sdk/analytics/helpers.py +178 -0
- htmlgraph/sdk/analytics/registry.py +109 -0
- htmlgraph/sdk/base.py +484 -0
- htmlgraph/sdk/constants.py +216 -0
- htmlgraph/sdk/core.pyi +308 -0
- htmlgraph/sdk/discovery.py +120 -0
- htmlgraph/sdk/help/__init__.py +12 -0
- htmlgraph/sdk/help/mixin.py +699 -0
- htmlgraph/sdk/mixins/__init__.py +15 -0
- htmlgraph/sdk/mixins/attribution.py +113 -0
- htmlgraph/sdk/mixins/mixin.py +410 -0
- htmlgraph/sdk/operations/__init__.py +12 -0
- htmlgraph/sdk/operations/mixin.py +427 -0
- htmlgraph/sdk/orchestration/__init__.py +17 -0
- htmlgraph/sdk/orchestration/coordinator.py +203 -0
- htmlgraph/sdk/orchestration/spawner.py +204 -0
- htmlgraph/sdk/planning/__init__.py +19 -0
- htmlgraph/sdk/planning/bottlenecks.py +93 -0
- htmlgraph/sdk/planning/mixin.py +211 -0
- htmlgraph/sdk/planning/parallel.py +186 -0
- htmlgraph/sdk/planning/queue.py +210 -0
- htmlgraph/sdk/planning/recommendations.py +87 -0
- htmlgraph/sdk/planning/smart_planning.py +319 -0
- htmlgraph/sdk/session/__init__.py +19 -0
- htmlgraph/sdk/session/continuity.py +57 -0
- htmlgraph/sdk/session/handoff.py +110 -0
- htmlgraph/sdk/session/info.py +309 -0
- htmlgraph/sdk/session/manager.py +103 -0
- htmlgraph/sdk/strategic/__init__.py +26 -0
- htmlgraph/sdk/strategic/mixin.py +563 -0
- htmlgraph/server.py +685 -180
- htmlgraph/services/__init__.py +10 -0
- htmlgraph/services/claiming.py +199 -0
- htmlgraph/session_hooks.py +300 -0
- htmlgraph/session_manager.py +1392 -175
- htmlgraph/session_registry.py +587 -0
- htmlgraph/session_state.py +436 -0
- htmlgraph/session_warning.py +201 -0
- htmlgraph/sessions/__init__.py +23 -0
- htmlgraph/sessions/handoff.py +756 -0
- htmlgraph/setup.py +34 -17
- htmlgraph/spike_index.py +143 -0
- htmlgraph/sync_docs.py +12 -15
- htmlgraph/system_prompts.py +450 -0
- htmlgraph/templates/AGENTS.md.template +366 -0
- htmlgraph/templates/CLAUDE.md.template +97 -0
- htmlgraph/templates/GEMINI.md.template +87 -0
- htmlgraph/templates/orchestration-view.html +350 -0
- htmlgraph/track_builder.py +146 -15
- htmlgraph/track_manager.py +69 -21
- htmlgraph/transcript.py +890 -0
- htmlgraph/transcript_analytics.py +699 -0
- htmlgraph/types.py +323 -0
- htmlgraph/validation.py +115 -0
- htmlgraph/watch.py +8 -5
- htmlgraph/work_type_utils.py +3 -2
- {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2406 -307
- htmlgraph-0.27.5.data/data/htmlgraph/templates/AGENTS.md.template +366 -0
- htmlgraph-0.27.5.data/data/htmlgraph/templates/CLAUDE.md.template +97 -0
- htmlgraph-0.27.5.data/data/htmlgraph/templates/GEMINI.md.template +87 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +97 -64
- htmlgraph-0.27.5.dist-info/RECORD +337 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
- htmlgraph/cli.py +0 -2688
- htmlgraph/sdk.py +0 -709
- htmlgraph-0.9.3.dist-info/RECORD +0 -61
- {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AnalyticsRepository - Abstract interface for analytics and work recommendations.
|
|
3
|
+
|
|
4
|
+
Unifies all analytics patterns across HtmlGraph:
|
|
5
|
+
- Work item recommendations and prioritization
|
|
6
|
+
- Dependency analysis and critical path detection
|
|
7
|
+
- Feature/track health metrics
|
|
8
|
+
- Blocked item detection and resolution tracking
|
|
9
|
+
|
|
10
|
+
Implementations handle:
|
|
11
|
+
- Feature and Track repository integration (no direct data access)
|
|
12
|
+
- Multi-criteria recommendation scoring
|
|
13
|
+
- Transitive dependency analysis
|
|
14
|
+
- Centralized metrics caching
|
|
15
|
+
- Concurrent query safety
|
|
16
|
+
|
|
17
|
+
All implementations MUST pass AnalyticsRepositoryComplianceTests.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from abc import ABC, abstractmethod
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class DependencyAnalysis:
|
|
27
|
+
"""
|
|
28
|
+
Complete dependency analysis for a single work item.
|
|
29
|
+
|
|
30
|
+
Contains transitive closure of dependencies, blocking items,
|
|
31
|
+
and critical path information.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
item_id: str
|
|
35
|
+
dependencies: list[str] # All transitive dependencies
|
|
36
|
+
blocking: list[str] # Items blocked by this one
|
|
37
|
+
blocked_by: list[str] # Items blocking this one
|
|
38
|
+
critical_path: bool # Whether on critical path
|
|
39
|
+
blocked_count: int # Count of items blocked by this
|
|
40
|
+
dependency_count: int # Count of dependencies
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def is_blocked(self) -> bool:
|
|
44
|
+
"""True if any dependencies are incomplete."""
|
|
45
|
+
return len(self.blocked_by) > 0
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def is_blocking_others(self) -> bool:
|
|
49
|
+
"""True if any items depend on this one."""
|
|
50
|
+
return len(self.blocking) > 0
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class WorkRecommendation:
|
|
55
|
+
"""
|
|
56
|
+
Recommended work item with priority and reasoning.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
item_id: str
|
|
60
|
+
title: str
|
|
61
|
+
priority_score: float # 0-1 normalized score
|
|
62
|
+
rationale: str # Human-readable explanation
|
|
63
|
+
estimated_impact: float # Expected impact on project (0-1)
|
|
64
|
+
blocking_count: int # How many items it unblocks
|
|
65
|
+
dependency_count: int # How many deps must complete first
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class AnalyticsRepositoryError(Exception):
|
|
69
|
+
"""Base exception for analytics operations."""
|
|
70
|
+
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class AnalysisError(AnalyticsRepositoryError):
|
|
75
|
+
"""Raised when analysis cannot be computed."""
|
|
76
|
+
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class InvalidItemError(AnalyticsRepositoryError):
|
|
81
|
+
"""Raised when item is not found or invalid."""
|
|
82
|
+
|
|
83
|
+
def __init__(self, item_id: str):
|
|
84
|
+
self.item_id = item_id
|
|
85
|
+
super().__init__(f"Invalid or not found: {item_id}")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class AnalyticsRepository(ABC):
|
|
89
|
+
"""
|
|
90
|
+
Abstract interface for work item analytics and recommendations.
|
|
91
|
+
|
|
92
|
+
Uses Feature and Track repositories internally to build unified
|
|
93
|
+
analytics view across all work items. No direct data access.
|
|
94
|
+
|
|
95
|
+
CONTRACT:
|
|
96
|
+
1. **Data Consistency**: All recommendations based on current repo state
|
|
97
|
+
2. **Accuracy**: Dependency analysis correctly computes transitive closure
|
|
98
|
+
3. **Performance**: Heavy computations cached, invalidated on data changes
|
|
99
|
+
4. **Isolation**: Multiple concurrent recommendations don't interfere
|
|
100
|
+
5. **Error Handling**: Analysis failures include full context
|
|
101
|
+
|
|
102
|
+
CACHING BEHAVIOR:
|
|
103
|
+
- Recommendations cached by item_id
|
|
104
|
+
- Dependencies cached and invalidated on feature/track changes
|
|
105
|
+
- Metrics cached with optional TTL
|
|
106
|
+
- Cache statistics available for monitoring
|
|
107
|
+
|
|
108
|
+
PERFORMANCE:
|
|
109
|
+
- recommend_next_work(filters): O(n) with caching
|
|
110
|
+
- analyze_dependencies(item_id): O(n) graph traversal, cached
|
|
111
|
+
- calculate_priority(item_id): O(1) if cached, O(n) if not
|
|
112
|
+
- get_work_items(status): O(n) with early termination
|
|
113
|
+
- get_critical_path(): O(n) computed once per session
|
|
114
|
+
- find_blocked_items(): O(n) with caching
|
|
115
|
+
- find_blocking_items(item_id): O(1) lookup
|
|
116
|
+
|
|
117
|
+
THREAD SAFETY:
|
|
118
|
+
- Implementations should be thread-safe
|
|
119
|
+
- Concurrent reads allowed
|
|
120
|
+
- Concurrent analytics queries serialized if needed
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
# ===== RECOMMENDATION OPERATIONS =====
|
|
124
|
+
|
|
125
|
+
@abstractmethod
|
|
126
|
+
def recommend_next_work(
|
|
127
|
+
self,
|
|
128
|
+
filters: dict[str, Any] | None = None,
|
|
129
|
+
limit: int = 10,
|
|
130
|
+
min_priority: float = 0.0,
|
|
131
|
+
) -> list[WorkRecommendation]:
|
|
132
|
+
"""
|
|
133
|
+
Get prioritized recommendations for next work items.
|
|
134
|
+
|
|
135
|
+
Uses multi-criteria scoring:
|
|
136
|
+
- Item dependencies (prefer unblocking others)
|
|
137
|
+
- Priority level
|
|
138
|
+
- Impact on project timeline
|
|
139
|
+
- Team capacity
|
|
140
|
+
- Business value
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
filters: Optional filters (status, priority, assigned_to, etc.)
|
|
144
|
+
limit: Max recommendations to return (default 10)
|
|
145
|
+
min_priority: Minimum priority score threshold (0-1)
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
List of WorkRecommendation objects sorted by priority
|
|
149
|
+
|
|
150
|
+
Raises:
|
|
151
|
+
AnalysisError: If scoring computation fails
|
|
152
|
+
|
|
153
|
+
Performance: O(n) with caching
|
|
154
|
+
|
|
155
|
+
Examples:
|
|
156
|
+
>>> recs = repo.recommend_next_work(filters={"status": "todo"})
|
|
157
|
+
>>> assert len(recs) <= 10
|
|
158
|
+
>>> assert all(r.priority_score >= 0.0 for r in recs)
|
|
159
|
+
>>> best = recs[0]
|
|
160
|
+
>>> print(f"Do {best.item_id}: {best.rationale}")
|
|
161
|
+
"""
|
|
162
|
+
...
|
|
163
|
+
|
|
164
|
+
@abstractmethod
|
|
165
|
+
def analyze_dependencies(self, item_id: str) -> DependencyAnalysis:
|
|
166
|
+
"""
|
|
167
|
+
Compute complete dependency analysis for a work item.
|
|
168
|
+
|
|
169
|
+
Analyzes:
|
|
170
|
+
- All transitive dependencies (things this must wait for)
|
|
171
|
+
- All blocking items (things waiting on this)
|
|
172
|
+
- Critical path status
|
|
173
|
+
- Blocked/blocking counts
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
item_id: Item to analyze (feature or track)
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
DependencyAnalysis with complete graph information
|
|
180
|
+
|
|
181
|
+
Raises:
|
|
182
|
+
InvalidItemError: If item not found
|
|
183
|
+
AnalysisError: If graph traversal fails
|
|
184
|
+
|
|
185
|
+
Performance: O(n) graph traversal, cached
|
|
186
|
+
|
|
187
|
+
Examples:
|
|
188
|
+
>>> analysis = repo.analyze_dependencies("feat-auth")
|
|
189
|
+
>>> if analysis.is_blocked:
|
|
190
|
+
... print(f"Blocked by: {analysis.blocked_by}")
|
|
191
|
+
>>> print(f"Unblocks {analysis.blocking_count} items")
|
|
192
|
+
>>> if analysis.critical_path:
|
|
193
|
+
... print("On critical path!")
|
|
194
|
+
"""
|
|
195
|
+
...
|
|
196
|
+
|
|
197
|
+
@abstractmethod
|
|
198
|
+
def calculate_priority(self, item_id: str) -> float:
|
|
199
|
+
"""
|
|
200
|
+
Calculate normalized priority score for item.
|
|
201
|
+
|
|
202
|
+
Score 0-1 based on:
|
|
203
|
+
- Item's explicit priority level
|
|
204
|
+
- How many other items depend on it
|
|
205
|
+
- Position on critical path
|
|
206
|
+
- Business value weight
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
item_id: Item to score
|
|
210
|
+
|
|
211
|
+
Returns:
|
|
212
|
+
Priority score 0.0-1.0 (higher = more important)
|
|
213
|
+
|
|
214
|
+
Raises:
|
|
215
|
+
InvalidItemError: If item not found
|
|
216
|
+
AnalysisError: If scoring fails
|
|
217
|
+
|
|
218
|
+
Performance: O(1) if cached, O(n) if not
|
|
219
|
+
|
|
220
|
+
Examples:
|
|
221
|
+
>>> score = repo.calculate_priority("feat-001")
|
|
222
|
+
>>> assert 0.0 <= score <= 1.0
|
|
223
|
+
>>> if score > 0.8:
|
|
224
|
+
... print("This is critical!")
|
|
225
|
+
"""
|
|
226
|
+
...
|
|
227
|
+
|
|
228
|
+
# ===== WORK ITEM QUERIES =====
|
|
229
|
+
|
|
230
|
+
@abstractmethod
|
|
231
|
+
def get_work_items(
|
|
232
|
+
self, status: str | None = None, include_tracks: bool = True
|
|
233
|
+
) -> list[Any]:
|
|
234
|
+
"""
|
|
235
|
+
Get all work items (features and optionally tracks).
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
status: Filter by status (e.g., 'todo', 'in-progress', 'done')
|
|
239
|
+
include_tracks: If True, include both features and tracks
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
List of work item objects (Features or Tracks)
|
|
243
|
+
|
|
244
|
+
Raises:
|
|
245
|
+
ValueError: If status is invalid
|
|
246
|
+
|
|
247
|
+
Performance: O(n) with early termination
|
|
248
|
+
|
|
249
|
+
Examples:
|
|
250
|
+
>>> todo_items = repo.get_work_items(status="todo")
|
|
251
|
+
>>> all_items = repo.get_work_items()
|
|
252
|
+
>>> assert len(all_items) > 0
|
|
253
|
+
"""
|
|
254
|
+
...
|
|
255
|
+
|
|
256
|
+
@abstractmethod
|
|
257
|
+
def find_blocked_items(self) -> list[str]:
|
|
258
|
+
"""
|
|
259
|
+
Find all work items currently blocked by incomplete dependencies.
|
|
260
|
+
|
|
261
|
+
Returns item IDs that cannot proceed until dependencies complete.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
List of blocked item IDs
|
|
265
|
+
|
|
266
|
+
Performance: O(n) with caching
|
|
267
|
+
|
|
268
|
+
Examples:
|
|
269
|
+
>>> blocked = repo.find_blocked_items()
|
|
270
|
+
>>> for item_id in blocked:
|
|
271
|
+
... analysis = repo.analyze_dependencies(item_id)
|
|
272
|
+
... print(f"{item_id} blocked by {analysis.blocked_by}")
|
|
273
|
+
"""
|
|
274
|
+
...
|
|
275
|
+
|
|
276
|
+
@abstractmethod
|
|
277
|
+
def find_blocking_items(self, item_id: str) -> list[str]:
|
|
278
|
+
"""
|
|
279
|
+
Find what items are blocked by the given item.
|
|
280
|
+
|
|
281
|
+
Inverse of dependencies: returns items that depend ON this item.
|
|
282
|
+
|
|
283
|
+
Args:
|
|
284
|
+
item_id: Item to find blockers for
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
List of item IDs blocked by given item
|
|
288
|
+
|
|
289
|
+
Raises:
|
|
290
|
+
InvalidItemError: If item not found
|
|
291
|
+
|
|
292
|
+
Performance: O(1) lookup
|
|
293
|
+
|
|
294
|
+
Examples:
|
|
295
|
+
>>> blocking = repo.find_blocking_items("feat-database")
|
|
296
|
+
>>> print(f"Completing this unblocks {len(blocking)} items")
|
|
297
|
+
"""
|
|
298
|
+
...
|
|
299
|
+
|
|
300
|
+
# ===== CRITICAL PATH ANALYSIS =====
|
|
301
|
+
|
|
302
|
+
@abstractmethod
|
|
303
|
+
def get_critical_path(self) -> list[str]:
|
|
304
|
+
"""
|
|
305
|
+
Get items on the critical path to project completion.
|
|
306
|
+
|
|
307
|
+
Critical path = longest chain of dependent items that determines
|
|
308
|
+
minimum time to complete project.
|
|
309
|
+
|
|
310
|
+
Returns:
|
|
311
|
+
List of item IDs on critical path (in dependency order)
|
|
312
|
+
|
|
313
|
+
Raises:
|
|
314
|
+
AnalysisError: If critical path cannot be computed
|
|
315
|
+
|
|
316
|
+
Performance: O(n) computed once per session
|
|
317
|
+
|
|
318
|
+
Examples:
|
|
319
|
+
>>> path = repo.get_critical_path()
|
|
320
|
+
>>> print(f"Critical path has {len(path)} items")
|
|
321
|
+
>>> for item_id in path:
|
|
322
|
+
... item = repo.get_item(item_id)
|
|
323
|
+
... print(f" {item.title}")
|
|
324
|
+
"""
|
|
325
|
+
...
|
|
326
|
+
|
|
327
|
+
@abstractmethod
|
|
328
|
+
def is_on_critical_path(self, item_id: str) -> bool:
|
|
329
|
+
"""
|
|
330
|
+
Check if item is on critical path.
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
item_id: Item to check
|
|
334
|
+
|
|
335
|
+
Returns:
|
|
336
|
+
True if on critical path, False otherwise
|
|
337
|
+
|
|
338
|
+
Raises:
|
|
339
|
+
InvalidItemError: If item not found
|
|
340
|
+
|
|
341
|
+
Performance: O(1) with cached critical path
|
|
342
|
+
|
|
343
|
+
Examples:
|
|
344
|
+
>>> if repo.is_on_critical_path("feat-auth"):
|
|
345
|
+
... print("This is blocking project completion!")
|
|
346
|
+
"""
|
|
347
|
+
...
|
|
348
|
+
|
|
349
|
+
# ===== METRICS & HEALTH =====
|
|
350
|
+
|
|
351
|
+
@abstractmethod
|
|
352
|
+
def cache_metrics(self) -> dict[str, Any]:
|
|
353
|
+
"""
|
|
354
|
+
Get cache performance metrics.
|
|
355
|
+
|
|
356
|
+
Returns statistics about cache efficiency:
|
|
357
|
+
- Hit count and rate
|
|
358
|
+
- Miss count
|
|
359
|
+
- Eviction count
|
|
360
|
+
- Average load time
|
|
361
|
+
- Memory usage
|
|
362
|
+
|
|
363
|
+
Returns:
|
|
364
|
+
Dict with metrics (keys: hits, misses, rate, memory_kb, etc.)
|
|
365
|
+
|
|
366
|
+
Examples:
|
|
367
|
+
>>> metrics = repo.cache_metrics()
|
|
368
|
+
>>> print(f"Cache hit rate: {metrics['hit_rate']:.1%}")
|
|
369
|
+
>>> print(f"Memory: {metrics['memory_kb']} KB")
|
|
370
|
+
"""
|
|
371
|
+
...
|
|
372
|
+
|
|
373
|
+
@abstractmethod
|
|
374
|
+
def invalidate_analytics_cache(self, item_id: str | None = None) -> None:
|
|
375
|
+
"""
|
|
376
|
+
Invalidate cached analytics for item or all items.
|
|
377
|
+
|
|
378
|
+
Called when underlying data changes:
|
|
379
|
+
- When feature/track status changes
|
|
380
|
+
- When dependencies added/removed
|
|
381
|
+
- When explicit refresh needed
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
item_id: Specific item to invalidate, or None for all
|
|
385
|
+
|
|
386
|
+
Examples:
|
|
387
|
+
>>> repo.invalidate_analytics_cache("feat-001") # Single item
|
|
388
|
+
>>> repo.invalidate_analytics_cache() # Clear all analytics cache
|
|
389
|
+
"""
|
|
390
|
+
...
|
|
391
|
+
|
|
392
|
+
# ===== ADVANCED QUERIES =====
|
|
393
|
+
|
|
394
|
+
@abstractmethod
|
|
395
|
+
def find_dependency_cycles(self) -> list[list[str]]:
|
|
396
|
+
"""
|
|
397
|
+
Find any circular dependencies in the project graph.
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
List of cycles, each cycle is list of item IDs forming loop
|
|
401
|
+
|
|
402
|
+
Returns empty list if no cycles found.
|
|
403
|
+
|
|
404
|
+
Performance: O(n) graph traversal
|
|
405
|
+
|
|
406
|
+
Examples:
|
|
407
|
+
>>> cycles = repo.find_dependency_cycles()
|
|
408
|
+
>>> if cycles:
|
|
409
|
+
... for cycle in cycles:
|
|
410
|
+
... print(f"Cycle detected: {' -> '.join(cycle)}")
|
|
411
|
+
>>> else:
|
|
412
|
+
... print("No circular dependencies!")
|
|
413
|
+
"""
|
|
414
|
+
...
|
|
415
|
+
|
|
416
|
+
@abstractmethod
|
|
417
|
+
def suggest_parallelizable_work(self) -> list[list[str]]:
|
|
418
|
+
"""
|
|
419
|
+
Suggest groups of work that can be done in parallel.
|
|
420
|
+
|
|
421
|
+
Returns:
|
|
422
|
+
List of groups, each group is list of item IDs with no dependencies
|
|
423
|
+
|
|
424
|
+
Useful for team coordination and optimal scheduling.
|
|
425
|
+
|
|
426
|
+
Performance: O(n)
|
|
427
|
+
|
|
428
|
+
Examples:
|
|
429
|
+
>>> groups = repo.suggest_parallelizable_work()
|
|
430
|
+
>>> for i, group in enumerate(groups):
|
|
431
|
+
... print(f"Parallel wave {i+1}: {group}")
|
|
432
|
+
"""
|
|
433
|
+
...
|
|
434
|
+
|
|
435
|
+
@abstractmethod
|
|
436
|
+
def project_completion_estimate(self) -> dict[str, Any]:
|
|
437
|
+
"""
|
|
438
|
+
Estimate project completion time based on current state.
|
|
439
|
+
|
|
440
|
+
Returns:
|
|
441
|
+
Dict with estimates:
|
|
442
|
+
- items_remaining: count of incomplete items
|
|
443
|
+
- critical_path_length: items on critical path
|
|
444
|
+
- estimated_days: days to completion (based on team velocity)
|
|
445
|
+
- blocking_items: count of items blocking others
|
|
446
|
+
- worst_case_days: pessimistic estimate
|
|
447
|
+
|
|
448
|
+
Performance: O(n)
|
|
449
|
+
|
|
450
|
+
Examples:
|
|
451
|
+
>>> estimate = repo.project_completion_estimate()
|
|
452
|
+
>>> print(f"Estimated completion: {estimate['estimated_days']} days")
|
|
453
|
+
>>> print(f"Critical path: {estimate['critical_path_length']} items")
|
|
454
|
+
"""
|
|
455
|
+
...
|