htmlgraph 0.20.1__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.
Files changed (304) hide show
  1. htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
  2. htmlgraph/.htmlgraph/agents.json +72 -0
  3. htmlgraph/.htmlgraph/htmlgraph.db +0 -0
  4. htmlgraph/__init__.py +51 -1
  5. htmlgraph/__init__.pyi +123 -0
  6. htmlgraph/agent_detection.py +26 -10
  7. htmlgraph/agent_registry.py +2 -1
  8. htmlgraph/analytics/__init__.py +8 -1
  9. htmlgraph/analytics/cli.py +86 -20
  10. htmlgraph/analytics/cost_analyzer.py +391 -0
  11. htmlgraph/analytics/cost_monitor.py +664 -0
  12. htmlgraph/analytics/cost_reporter.py +675 -0
  13. htmlgraph/analytics/cross_session.py +617 -0
  14. htmlgraph/analytics/dependency.py +10 -6
  15. htmlgraph/analytics/pattern_learning.py +771 -0
  16. htmlgraph/analytics/session_graph.py +707 -0
  17. htmlgraph/analytics/strategic/__init__.py +80 -0
  18. htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
  19. htmlgraph/analytics/strategic/pattern_detector.py +876 -0
  20. htmlgraph/analytics/strategic/preference_manager.py +709 -0
  21. htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
  22. htmlgraph/analytics/work_type.py +67 -27
  23. htmlgraph/analytics_index.py +53 -20
  24. htmlgraph/api/__init__.py +3 -0
  25. htmlgraph/api/cost_alerts_websocket.py +416 -0
  26. htmlgraph/api/main.py +2498 -0
  27. htmlgraph/api/static/htmx.min.js +1 -0
  28. htmlgraph/api/static/style-redesign.css +1344 -0
  29. htmlgraph/api/static/style.css +1079 -0
  30. htmlgraph/api/templates/dashboard-redesign.html +1366 -0
  31. htmlgraph/api/templates/dashboard.html +794 -0
  32. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  33. htmlgraph/api/templates/partials/activity-feed.html +1100 -0
  34. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  35. htmlgraph/api/templates/partials/agents.html +317 -0
  36. htmlgraph/api/templates/partials/event-traces.html +373 -0
  37. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  38. htmlgraph/api/templates/partials/features.html +578 -0
  39. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  40. htmlgraph/api/templates/partials/metrics.html +346 -0
  41. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  42. htmlgraph/api/templates/partials/orchestration.html +198 -0
  43. htmlgraph/api/templates/partials/spawners.html +375 -0
  44. htmlgraph/api/templates/partials/work-items.html +613 -0
  45. htmlgraph/api/websocket.py +538 -0
  46. htmlgraph/archive/__init__.py +24 -0
  47. htmlgraph/archive/bloom.py +234 -0
  48. htmlgraph/archive/fts.py +297 -0
  49. htmlgraph/archive/manager.py +583 -0
  50. htmlgraph/archive/search.py +244 -0
  51. htmlgraph/atomic_ops.py +560 -0
  52. htmlgraph/attribute_index.py +2 -1
  53. htmlgraph/bounded_paths.py +539 -0
  54. htmlgraph/builders/base.py +57 -2
  55. htmlgraph/builders/bug.py +19 -3
  56. htmlgraph/builders/chore.py +19 -3
  57. htmlgraph/builders/epic.py +19 -3
  58. htmlgraph/builders/feature.py +27 -3
  59. htmlgraph/builders/insight.py +2 -1
  60. htmlgraph/builders/metric.py +2 -1
  61. htmlgraph/builders/pattern.py +2 -1
  62. htmlgraph/builders/phase.py +19 -3
  63. htmlgraph/builders/spike.py +29 -3
  64. htmlgraph/builders/track.py +42 -1
  65. htmlgraph/cigs/__init__.py +81 -0
  66. htmlgraph/cigs/autonomy.py +385 -0
  67. htmlgraph/cigs/cost.py +475 -0
  68. htmlgraph/cigs/messages_basic.py +472 -0
  69. htmlgraph/cigs/messaging.py +365 -0
  70. htmlgraph/cigs/models.py +771 -0
  71. htmlgraph/cigs/pattern_storage.py +427 -0
  72. htmlgraph/cigs/patterns.py +503 -0
  73. htmlgraph/cigs/posttool_analyzer.py +234 -0
  74. htmlgraph/cigs/reporter.py +818 -0
  75. htmlgraph/cigs/tracker.py +317 -0
  76. htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
  77. htmlgraph/cli/.htmlgraph/agents.json +72 -0
  78. htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
  79. htmlgraph/cli/__init__.py +42 -0
  80. htmlgraph/cli/__main__.py +6 -0
  81. htmlgraph/cli/analytics.py +1424 -0
  82. htmlgraph/cli/base.py +685 -0
  83. htmlgraph/cli/constants.py +206 -0
  84. htmlgraph/cli/core.py +954 -0
  85. htmlgraph/cli/main.py +147 -0
  86. htmlgraph/cli/models.py +475 -0
  87. htmlgraph/cli/templates/__init__.py +1 -0
  88. htmlgraph/cli/templates/cost_dashboard.py +399 -0
  89. htmlgraph/cli/work/__init__.py +239 -0
  90. htmlgraph/cli/work/browse.py +115 -0
  91. htmlgraph/cli/work/features.py +568 -0
  92. htmlgraph/cli/work/orchestration.py +676 -0
  93. htmlgraph/cli/work/report.py +728 -0
  94. htmlgraph/cli/work/sessions.py +466 -0
  95. htmlgraph/cli/work/snapshot.py +559 -0
  96. htmlgraph/cli/work/tracks.py +486 -0
  97. htmlgraph/cli_commands/__init__.py +1 -0
  98. htmlgraph/cli_commands/feature.py +195 -0
  99. htmlgraph/cli_framework.py +115 -0
  100. htmlgraph/collections/__init__.py +2 -0
  101. htmlgraph/collections/base.py +197 -14
  102. htmlgraph/collections/bug.py +2 -1
  103. htmlgraph/collections/chore.py +2 -1
  104. htmlgraph/collections/epic.py +2 -1
  105. htmlgraph/collections/feature.py +2 -1
  106. htmlgraph/collections/insight.py +2 -1
  107. htmlgraph/collections/metric.py +2 -1
  108. htmlgraph/collections/pattern.py +2 -1
  109. htmlgraph/collections/phase.py +2 -1
  110. htmlgraph/collections/session.py +194 -0
  111. htmlgraph/collections/spike.py +13 -2
  112. htmlgraph/collections/task_delegation.py +241 -0
  113. htmlgraph/collections/todo.py +14 -1
  114. htmlgraph/collections/traces.py +487 -0
  115. htmlgraph/config/cost_models.json +56 -0
  116. htmlgraph/config.py +190 -0
  117. htmlgraph/context_analytics.py +2 -1
  118. htmlgraph/converter.py +116 -7
  119. htmlgraph/cost_analysis/__init__.py +5 -0
  120. htmlgraph/cost_analysis/analyzer.py +438 -0
  121. htmlgraph/dashboard.html +2246 -248
  122. htmlgraph/dashboard.html.backup +6592 -0
  123. htmlgraph/dashboard.html.bak +7181 -0
  124. htmlgraph/dashboard.html.bak2 +7231 -0
  125. htmlgraph/dashboard.html.bak3 +7232 -0
  126. htmlgraph/db/__init__.py +38 -0
  127. htmlgraph/db/queries.py +790 -0
  128. htmlgraph/db/schema.py +1788 -0
  129. htmlgraph/decorators.py +317 -0
  130. htmlgraph/dependency_models.py +2 -1
  131. htmlgraph/deploy.py +26 -27
  132. htmlgraph/docs/API_REFERENCE.md +841 -0
  133. htmlgraph/docs/HTTP_API.md +750 -0
  134. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  135. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
  136. htmlgraph/docs/README.md +532 -0
  137. htmlgraph/docs/__init__.py +77 -0
  138. htmlgraph/docs/docs_version.py +55 -0
  139. htmlgraph/docs/metadata.py +93 -0
  140. htmlgraph/docs/migrations.py +232 -0
  141. htmlgraph/docs/template_engine.py +143 -0
  142. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  143. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  144. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  145. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  146. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  147. htmlgraph/docs/version_check.py +163 -0
  148. htmlgraph/edge_index.py +2 -1
  149. htmlgraph/error_handler.py +544 -0
  150. htmlgraph/event_log.py +86 -37
  151. htmlgraph/event_migration.py +2 -1
  152. htmlgraph/file_watcher.py +12 -8
  153. htmlgraph/find_api.py +2 -1
  154. htmlgraph/git_events.py +67 -9
  155. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  156. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  157. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  158. htmlgraph/hooks/__init__.py +8 -0
  159. htmlgraph/hooks/bootstrap.py +169 -0
  160. htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
  161. htmlgraph/hooks/concurrent_sessions.py +208 -0
  162. htmlgraph/hooks/context.py +350 -0
  163. htmlgraph/hooks/drift_handler.py +525 -0
  164. htmlgraph/hooks/event_tracker.py +790 -99
  165. htmlgraph/hooks/git_commands.py +175 -0
  166. htmlgraph/hooks/installer.py +5 -1
  167. htmlgraph/hooks/orchestrator.py +327 -76
  168. htmlgraph/hooks/orchestrator_reflector.py +31 -4
  169. htmlgraph/hooks/post_tool_use_failure.py +32 -7
  170. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  171. htmlgraph/hooks/posttooluse.py +92 -19
  172. htmlgraph/hooks/pretooluse.py +527 -7
  173. htmlgraph/hooks/prompt_analyzer.py +637 -0
  174. htmlgraph/hooks/session_handler.py +668 -0
  175. htmlgraph/hooks/session_summary.py +395 -0
  176. htmlgraph/hooks/state_manager.py +504 -0
  177. htmlgraph/hooks/subagent_detection.py +202 -0
  178. htmlgraph/hooks/subagent_stop.py +369 -0
  179. htmlgraph/hooks/task_enforcer.py +99 -4
  180. htmlgraph/hooks/validator.py +212 -91
  181. htmlgraph/ids.py +2 -1
  182. htmlgraph/learning.py +125 -100
  183. htmlgraph/mcp_server.py +2 -1
  184. htmlgraph/models.py +217 -18
  185. htmlgraph/operations/README.md +62 -0
  186. htmlgraph/operations/__init__.py +79 -0
  187. htmlgraph/operations/analytics.py +339 -0
  188. htmlgraph/operations/bootstrap.py +289 -0
  189. htmlgraph/operations/events.py +244 -0
  190. htmlgraph/operations/fastapi_server.py +231 -0
  191. htmlgraph/operations/hooks.py +350 -0
  192. htmlgraph/operations/initialization.py +597 -0
  193. htmlgraph/operations/initialization.py.backup +228 -0
  194. htmlgraph/operations/server.py +303 -0
  195. htmlgraph/orchestration/__init__.py +58 -0
  196. htmlgraph/orchestration/claude_launcher.py +179 -0
  197. htmlgraph/orchestration/command_builder.py +72 -0
  198. htmlgraph/orchestration/headless_spawner.py +281 -0
  199. htmlgraph/orchestration/live_events.py +377 -0
  200. htmlgraph/orchestration/model_selection.py +327 -0
  201. htmlgraph/orchestration/plugin_manager.py +140 -0
  202. htmlgraph/orchestration/prompts.py +137 -0
  203. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  204. htmlgraph/orchestration/spawners/__init__.py +16 -0
  205. htmlgraph/orchestration/spawners/base.py +194 -0
  206. htmlgraph/orchestration/spawners/claude.py +173 -0
  207. htmlgraph/orchestration/spawners/codex.py +435 -0
  208. htmlgraph/orchestration/spawners/copilot.py +294 -0
  209. htmlgraph/orchestration/spawners/gemini.py +471 -0
  210. htmlgraph/orchestration/subprocess_runner.py +36 -0
  211. htmlgraph/{orchestration.py → orchestration/task_coordination.py} +16 -8
  212. htmlgraph/orchestration.md +563 -0
  213. htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
  214. htmlgraph/orchestrator.py +2 -1
  215. htmlgraph/orchestrator_config.py +357 -0
  216. htmlgraph/orchestrator_mode.py +115 -4
  217. htmlgraph/parallel.py +2 -1
  218. htmlgraph/parser.py +86 -6
  219. htmlgraph/path_query.py +608 -0
  220. htmlgraph/pattern_matcher.py +636 -0
  221. htmlgraph/pydantic_models.py +476 -0
  222. htmlgraph/quality_gates.py +350 -0
  223. htmlgraph/query_builder.py +2 -1
  224. htmlgraph/query_composer.py +509 -0
  225. htmlgraph/reflection.py +443 -0
  226. htmlgraph/refs.py +344 -0
  227. htmlgraph/repo_hash.py +512 -0
  228. htmlgraph/repositories/__init__.py +292 -0
  229. htmlgraph/repositories/analytics_repository.py +455 -0
  230. htmlgraph/repositories/analytics_repository_standard.py +628 -0
  231. htmlgraph/repositories/feature_repository.py +581 -0
  232. htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
  233. htmlgraph/repositories/feature_repository_memory.py +607 -0
  234. htmlgraph/repositories/feature_repository_sqlite.py +858 -0
  235. htmlgraph/repositories/filter_service.py +620 -0
  236. htmlgraph/repositories/filter_service_standard.py +445 -0
  237. htmlgraph/repositories/shared_cache.py +621 -0
  238. htmlgraph/repositories/shared_cache_memory.py +395 -0
  239. htmlgraph/repositories/track_repository.py +552 -0
  240. htmlgraph/repositories/track_repository_htmlfile.py +619 -0
  241. htmlgraph/repositories/track_repository_memory.py +508 -0
  242. htmlgraph/repositories/track_repository_sqlite.py +711 -0
  243. htmlgraph/sdk/__init__.py +398 -0
  244. htmlgraph/sdk/__init__.pyi +14 -0
  245. htmlgraph/sdk/analytics/__init__.py +19 -0
  246. htmlgraph/sdk/analytics/engine.py +155 -0
  247. htmlgraph/sdk/analytics/helpers.py +178 -0
  248. htmlgraph/sdk/analytics/registry.py +109 -0
  249. htmlgraph/sdk/base.py +484 -0
  250. htmlgraph/sdk/constants.py +216 -0
  251. htmlgraph/sdk/core.pyi +308 -0
  252. htmlgraph/sdk/discovery.py +120 -0
  253. htmlgraph/sdk/help/__init__.py +12 -0
  254. htmlgraph/sdk/help/mixin.py +699 -0
  255. htmlgraph/sdk/mixins/__init__.py +15 -0
  256. htmlgraph/sdk/mixins/attribution.py +113 -0
  257. htmlgraph/sdk/mixins/mixin.py +410 -0
  258. htmlgraph/sdk/operations/__init__.py +12 -0
  259. htmlgraph/sdk/operations/mixin.py +427 -0
  260. htmlgraph/sdk/orchestration/__init__.py +17 -0
  261. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  262. htmlgraph/sdk/orchestration/spawner.py +204 -0
  263. htmlgraph/sdk/planning/__init__.py +19 -0
  264. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  265. htmlgraph/sdk/planning/mixin.py +211 -0
  266. htmlgraph/sdk/planning/parallel.py +186 -0
  267. htmlgraph/sdk/planning/queue.py +210 -0
  268. htmlgraph/sdk/planning/recommendations.py +87 -0
  269. htmlgraph/sdk/planning/smart_planning.py +319 -0
  270. htmlgraph/sdk/session/__init__.py +19 -0
  271. htmlgraph/sdk/session/continuity.py +57 -0
  272. htmlgraph/sdk/session/handoff.py +110 -0
  273. htmlgraph/sdk/session/info.py +309 -0
  274. htmlgraph/sdk/session/manager.py +103 -0
  275. htmlgraph/sdk/strategic/__init__.py +26 -0
  276. htmlgraph/sdk/strategic/mixin.py +563 -0
  277. htmlgraph/server.py +295 -107
  278. htmlgraph/session_hooks.py +300 -0
  279. htmlgraph/session_manager.py +285 -3
  280. htmlgraph/session_registry.py +587 -0
  281. htmlgraph/session_state.py +436 -0
  282. htmlgraph/session_warning.py +2 -1
  283. htmlgraph/sessions/__init__.py +23 -0
  284. htmlgraph/sessions/handoff.py +756 -0
  285. htmlgraph/system_prompts.py +450 -0
  286. htmlgraph/templates/orchestration-view.html +350 -0
  287. htmlgraph/track_builder.py +33 -1
  288. htmlgraph/track_manager.py +38 -0
  289. htmlgraph/transcript.py +18 -5
  290. htmlgraph/validation.py +115 -0
  291. htmlgraph/watch.py +2 -1
  292. htmlgraph/work_type_utils.py +2 -1
  293. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2246 -248
  294. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +95 -64
  295. htmlgraph-0.27.5.dist-info/RECORD +337 -0
  296. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
  297. htmlgraph/cli.py +0 -4839
  298. htmlgraph/sdk.py +0 -2359
  299. htmlgraph-0.20.1.dist-info/RECORD +0 -118
  300. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
  301. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  302. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  303. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  304. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,552 @@
1
+ """
2
+ TrackRepository - Abstract interface for Track data access.
3
+
4
+ Unifies all data access patterns for Tracks across HtmlGraph.
5
+ Implementations handle:
6
+ - HTML file storage + SQLite database
7
+ - Lazy loading and caching
8
+ - Query building and filtering
9
+ - Concurrent access safety
10
+ - Event logging and session tracking
11
+
12
+ All implementations MUST pass TrackRepositoryComplianceTests.
13
+ """
14
+
15
+ import builtins
16
+ from abc import ABC, abstractmethod
17
+ from collections.abc import Callable
18
+ from dataclasses import dataclass
19
+ from typing import Any
20
+
21
+
22
+ @dataclass
23
+ class RepositoryQuery:
24
+ """
25
+ Query builder for chaining filters.
26
+
27
+ Supports method chaining:
28
+ repo.where(status='active').where(priority='high').execute()
29
+ """
30
+
31
+ filters: dict[str, Any]
32
+
33
+ def execute(self) -> list[Any]:
34
+ """Execute the query and return results."""
35
+ raise NotImplementedError("Subclass must implement")
36
+
37
+
38
+ class TrackRepositoryError(Exception):
39
+ """Base exception for repository operations."""
40
+
41
+ pass
42
+
43
+
44
+ class TrackNotFoundError(TrackRepositoryError):
45
+ """Raised when a track is not found."""
46
+
47
+ def __init__(self, track_id: str):
48
+ self.track_id = track_id
49
+ super().__init__(f"Track not found: {track_id}")
50
+
51
+
52
+ class TrackValidationError(TrackRepositoryError):
53
+ """Raised when track data fails validation."""
54
+
55
+ pass
56
+
57
+
58
+ class TrackConcurrencyError(TrackRepositoryError):
59
+ """Raised when concurrent modification detected."""
60
+
61
+ pass
62
+
63
+
64
+ class TrackRepository(ABC):
65
+ """
66
+ Abstract interface for Track data access.
67
+
68
+ Unifies access to Tracks stored in HTML files and SQLite database.
69
+
70
+ CONTRACT:
71
+ 1. **Identity Invariant**: get(id) returns same object instance for same track
72
+ 2. **Atomicity**: write operations are atomic (all-or-nothing)
73
+ 3. **Consistency**: cache stays in sync with storage
74
+ 4. **Isolation**: concurrent operations don't corrupt state
75
+ 5. **Error Handling**: all errors preserve full context
76
+
77
+ CACHING BEHAVIOR:
78
+ - Single object instances per track (identity, not just equality)
79
+ - Automatic cache invalidation on writes
80
+ - Optional auto-load on first access
81
+
82
+ PERFORMANCE:
83
+ - get(id): O(1) cached, O(log n) uncached
84
+ - list(): O(n) where n = tracks
85
+ - where(**kwargs): O(n) with early termination
86
+ - batch_get(): O(k) where k = batch size
87
+ - batch_update(): O(k) vectorized
88
+
89
+ THREAD SAFETY:
90
+ - Implementations should be thread-safe
91
+ - Concurrent reads allowed
92
+ - Concurrent writes serialized (via database locks or explicit locking)
93
+ """
94
+
95
+ # ===== READ OPERATIONS =====
96
+
97
+ @abstractmethod
98
+ def get(self, track_id: str) -> Any | None:
99
+ """
100
+ Get single track by ID.
101
+
102
+ Returns same object instance for multiple calls with same ID.
103
+ Implements identity caching (is, not ==).
104
+
105
+ Args:
106
+ track_id: Track ID to retrieve (e.g., "track-001")
107
+
108
+ Returns:
109
+ Track object if found, None if not found
110
+
111
+ Raises:
112
+ ValueError: If track_id is invalid format
113
+
114
+ Performance: O(1) if cached, O(log n) if uncached
115
+
116
+ Examples:
117
+ >>> track = repo.get("track-001")
118
+ >>> track2 = repo.get("track-001")
119
+ >>> assert track is track2 # Identity, not just equality
120
+ >>> assert track is not None
121
+ """
122
+ ...
123
+
124
+ @abstractmethod
125
+ def list(self, filters: dict[str, Any] | None = None) -> list[Any]:
126
+ """
127
+ List all tracks with optional filters.
128
+
129
+ Returns empty list if no matches, never None.
130
+
131
+ Args:
132
+ filters: Optional dict of attribute->value filters.
133
+ Empty/None dict means no filters (returns all).
134
+
135
+ Returns:
136
+ List of Track objects (empty list if no matches)
137
+
138
+ Raises:
139
+ TrackValidationError: If filter keys are invalid
140
+
141
+ Performance: O(n) where n = total tracks
142
+
143
+ Examples:
144
+ >>> all_tracks = repo.list()
145
+ >>> assert isinstance(all_tracks, list)
146
+ >>> active_tracks = repo.list({"status": "active"})
147
+ >>> multiple = repo.list({"status": "active", "priority": "high"})
148
+ """
149
+ ...
150
+
151
+ @abstractmethod
152
+ def where(self, **kwargs: Any) -> RepositoryQuery:
153
+ """
154
+ Build a filtered query with chaining support.
155
+
156
+ Supports method chaining for composable queries:
157
+ repo.where(status='active').where(priority='high').execute()
158
+
159
+ Args:
160
+ **kwargs: Attribute->value filter pairs.
161
+ Common: status, priority, has_spec, has_plan
162
+
163
+ Returns:
164
+ RepositoryQuery object that can be further filtered or executed
165
+
166
+ Raises:
167
+ TrackValidationError: If invalid attribute names
168
+
169
+ Examples:
170
+ >>> query = repo.where(status='active')
171
+ >>> query2 = query.where(priority='high') # Chaining
172
+ >>> results = query2.execute()
173
+ >>> assert all(t.status == 'active' for t in results)
174
+ >>> assert all(t.priority == 'high' for t in results)
175
+ """
176
+ ...
177
+
178
+ @abstractmethod
179
+ def by_status(self, status: str) -> builtins.list[Any]:
180
+ """
181
+ Filter tracks by status.
182
+
183
+ Args:
184
+ status: Status to filter by (e.g., 'planned', 'active', 'completed', 'abandoned')
185
+
186
+ Returns:
187
+ List of matching tracks (empty if no matches)
188
+
189
+ Performance: O(n) with early termination
190
+
191
+ Examples:
192
+ >>> active_tracks = repo.by_status("active")
193
+ >>> completed = repo.by_status("completed")
194
+ """
195
+ ...
196
+
197
+ @abstractmethod
198
+ def by_priority(self, priority: str) -> builtins.list[Any]:
199
+ """
200
+ Filter tracks by priority.
201
+
202
+ Args:
203
+ priority: Priority level (e.g., 'low', 'medium', 'high', 'critical')
204
+
205
+ Returns:
206
+ List of matching tracks
207
+
208
+ Performance: O(n)
209
+
210
+ Examples:
211
+ >>> critical = repo.by_priority("critical")
212
+ >>> important = repo.by_priority("high")
213
+ """
214
+ ...
215
+
216
+ @abstractmethod
217
+ def active_tracks(self) -> builtins.list[Any]:
218
+ """
219
+ Get all tracks currently in progress.
220
+
221
+ Convenience method for status='active' filter.
222
+
223
+ Returns:
224
+ List of active tracks
225
+
226
+ Performance: O(n) with early termination
227
+
228
+ Examples:
229
+ >>> current_work = repo.active_tracks()
230
+ >>> assert all(t.status == 'active' for t in current_work)
231
+ """
232
+ ...
233
+
234
+ @abstractmethod
235
+ def batch_get(self, track_ids: builtins.list[str]) -> builtins.list[Any]:
236
+ """
237
+ Bulk retrieve multiple tracks.
238
+
239
+ More efficient than multiple get() calls (vectorized).
240
+ Returns partial results if some tracks not found.
241
+
242
+ Args:
243
+ track_ids: List of track IDs
244
+
245
+ Returns:
246
+ List of found tracks (in order of input, with None for missing)
247
+ or list of only found tracks (implementation-dependent)
248
+
249
+ Raises:
250
+ ValueError: If track_ids is not a list
251
+
252
+ Performance: O(k) where k = batch size
253
+
254
+ Examples:
255
+ >>> ids = ["track-001", "track-002", "track-003"]
256
+ >>> tracks = repo.batch_get(ids)
257
+ >>> assert len(tracks) <= len(ids)
258
+ """
259
+ ...
260
+
261
+ # ===== WRITE OPERATIONS =====
262
+
263
+ @abstractmethod
264
+ def create(self, title: str, **kwargs: Any) -> Any:
265
+ """
266
+ Create new track.
267
+
268
+ Generates ID if not provided.
269
+ Saves to storage immediately.
270
+
271
+ Args:
272
+ title: Track title (required)
273
+ **kwargs: Additional properties (priority, status, description, etc.)
274
+
275
+ Returns:
276
+ Created Track object (with generated ID)
277
+
278
+ Raises:
279
+ TrackValidationError: If invalid data provided
280
+ TrackRepositoryError: If create fails
281
+
282
+ Performance: O(1) cached write
283
+
284
+ Examples:
285
+ >>> track = repo.create("Planning Phase 1")
286
+ >>> assert track.id is not None
287
+ >>> track2 = repo.create("Feature Development", priority="high", status="active")
288
+ """
289
+ ...
290
+
291
+ @abstractmethod
292
+ def save(self, track: Any) -> Any:
293
+ """
294
+ Save existing track (update or insert).
295
+
296
+ If track.id exists in repo, updates. Otherwise inserts.
297
+
298
+ Args:
299
+ track: Track object to save
300
+
301
+ Returns:
302
+ Saved track (same instance)
303
+
304
+ Raises:
305
+ TrackValidationError: If track is invalid
306
+ TrackConcurrencyError: If track was modified elsewhere
307
+
308
+ Performance: O(1)
309
+
310
+ Examples:
311
+ >>> track = repo.get("track-001")
312
+ >>> track.status = "completed"
313
+ >>> repo.save(track)
314
+ """
315
+ ...
316
+
317
+ @abstractmethod
318
+ def batch_update(
319
+ self, track_ids: builtins.list[str], updates: dict[str, Any]
320
+ ) -> int:
321
+ """
322
+ Vectorized batch update operation.
323
+
324
+ Updates all specified tracks with same values.
325
+ More efficient than individual saves.
326
+
327
+ Args:
328
+ track_ids: List of track IDs to update
329
+ updates: Dict of attribute->value to set
330
+
331
+ Returns:
332
+ Number of tracks successfully updated
333
+
334
+ Raises:
335
+ TrackValidationError: If invalid updates
336
+
337
+ Performance: O(k) vectorized where k = batch size
338
+
339
+ Examples:
340
+ >>> count = repo.batch_update(
341
+ ... ["track-1", "track-2", "track-3"],
342
+ ... {"status": "completed", "priority": "low"}
343
+ ... )
344
+ >>> assert count == 3
345
+ """
346
+ ...
347
+
348
+ @abstractmethod
349
+ def delete(self, track_id: str) -> bool:
350
+ """
351
+ Delete a track by ID.
352
+
353
+ Args:
354
+ track_id: Track ID to delete
355
+
356
+ Returns:
357
+ True if deleted, False if not found
358
+
359
+ Raises:
360
+ TrackValidationError: If track_id invalid
361
+
362
+ Performance: O(1) cache removal, O(log n) storage deletion
363
+
364
+ Examples:
365
+ >>> success = repo.delete("track-001")
366
+ >>> assert success is True or success is False
367
+ """
368
+ ...
369
+
370
+ @abstractmethod
371
+ def batch_delete(self, track_ids: builtins.list[str]) -> int:
372
+ """
373
+ Delete multiple tracks.
374
+
375
+ Args:
376
+ track_ids: List of track IDs to delete
377
+
378
+ Returns:
379
+ Number of tracks successfully deleted
380
+
381
+ Raises:
382
+ ValueError: If track_ids not a list
383
+
384
+ Performance: O(k) where k = batch size
385
+
386
+ Examples:
387
+ >>> count = repo.batch_delete(["track-1", "track-2"])
388
+ >>> assert count == 2
389
+ """
390
+ ...
391
+
392
+ # ===== ADVANCED QUERIES =====
393
+
394
+ @abstractmethod
395
+ def find_by_features(self, feature_ids: builtins.list[str]) -> builtins.list[Any]:
396
+ """
397
+ Find tracks containing any of the specified features.
398
+
399
+ Args:
400
+ feature_ids: List of feature IDs to search for
401
+
402
+ Returns:
403
+ Tracks that contain at least one of these features
404
+
405
+ Raises:
406
+ ValueError: If feature_ids is not a list
407
+
408
+ Performance: O(n) with early termination
409
+
410
+ Examples:
411
+ >>> features = ["feat-001", "feat-002"]
412
+ >>> tracks = repo.find_by_features(features)
413
+ >>> # Returns all tracks that contain feat-001 or feat-002
414
+ """
415
+ ...
416
+
417
+ @abstractmethod
418
+ def with_feature_count(self) -> builtins.list[Any]:
419
+ """
420
+ Get all tracks with feature count calculated.
421
+
422
+ Convenience method for calculating feature counts across all tracks.
423
+
424
+ Returns:
425
+ All tracks with feature_count property set
426
+
427
+ Examples:
428
+ >>> tracks = repo.with_feature_count()
429
+ >>> for t in tracks:
430
+ ... print(f"{t.title}: {len(t.features)} features")
431
+ """
432
+ ...
433
+
434
+ @abstractmethod
435
+ def filter(self, predicate: Callable[[Any], bool]) -> builtins.list[Any]:
436
+ """
437
+ Filter tracks with custom predicate function.
438
+
439
+ For complex queries not covered by standard filters.
440
+
441
+ Args:
442
+ predicate: Function that takes Track and returns True/False
443
+
444
+ Returns:
445
+ Tracks matching predicate
446
+
447
+ Examples:
448
+ >>> recent = repo.filter(
449
+ ... lambda t: (datetime.now() - t.created).days < 7
450
+ ... )
451
+ >>> with_spec_and_plan = repo.filter(
452
+ ... lambda t: t.has_spec and t.has_plan
453
+ ... )
454
+ """
455
+ ...
456
+
457
+ # ===== CACHE/LIFECYCLE MANAGEMENT =====
458
+
459
+ @abstractmethod
460
+ def invalidate_cache(self, track_id: str | None = None) -> None:
461
+ """
462
+ Invalidate cache for single track or all tracks.
463
+
464
+ Forces reload from storage on next access.
465
+ Used when external process modifies storage.
466
+
467
+ Args:
468
+ track_id: Specific track to invalidate, or None for all
469
+
470
+ Examples:
471
+ >>> repo.invalidate_cache("track-001") # Single track
472
+ >>> repo.invalidate_cache() # Clear entire cache
473
+ """
474
+ ...
475
+
476
+ @abstractmethod
477
+ def reload(self) -> None:
478
+ """
479
+ Force reload all tracks from storage.
480
+
481
+ Invalidates all caches and reloads from disk/database.
482
+ Useful for external changes or cache reconciliation.
483
+
484
+ Examples:
485
+ >>> repo.reload() # Force refresh from storage
486
+ """
487
+ ...
488
+
489
+ @property
490
+ @abstractmethod
491
+ def auto_load(self) -> bool:
492
+ """
493
+ Whether auto-loading is enabled.
494
+
495
+ If True, tracks auto-load on first access.
496
+ If False, manual reload() required.
497
+
498
+ Returns:
499
+ True if auto-loading enabled, False otherwise
500
+ """
501
+ ...
502
+
503
+ @auto_load.setter
504
+ @abstractmethod
505
+ def auto_load(self, enabled: bool) -> None:
506
+ """
507
+ Enable/disable auto-loading.
508
+
509
+ Args:
510
+ enabled: True to enable auto-load, False to disable
511
+ """
512
+ ...
513
+
514
+ # ===== UTILITY METHODS =====
515
+
516
+ @abstractmethod
517
+ def count(self, filters: dict[str, Any] | None = None) -> int:
518
+ """
519
+ Count tracks matching filters.
520
+
521
+ Args:
522
+ filters: Optional filters (same as list())
523
+
524
+ Returns:
525
+ Number of matching tracks
526
+
527
+ Performance: O(n) or O(1) if optimized with SQL count
528
+
529
+ Examples:
530
+ >>> total = repo.count()
531
+ >>> active_count = repo.count({"status": "active"})
532
+ """
533
+ ...
534
+
535
+ @abstractmethod
536
+ def exists(self, track_id: str) -> bool:
537
+ """
538
+ Check if track exists without loading it.
539
+
540
+ Args:
541
+ track_id: Track ID to check
542
+
543
+ Returns:
544
+ True if exists, False otherwise
545
+
546
+ Performance: O(1) if optimized
547
+
548
+ Examples:
549
+ >>> if repo.exists("track-001"):
550
+ ... track = repo.get("track-001")
551
+ """
552
+ ...