skillpool 4.3.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 (90) hide show
  1. skillpool/__init__.py +74 -0
  2. skillpool/__main__.py +6 -0
  3. skillpool/adapters/__init__.py +8 -0
  4. skillpool/adapters/base.py +41 -0
  5. skillpool/adapters/claude_adapter.py +36 -0
  6. skillpool/adapters/codex_adapter.py +92 -0
  7. skillpool/adapters/hermes_adapter.py +38 -0
  8. skillpool/audit/__init__.py +651 -0
  9. skillpool/bridge/__init__.py +16 -0
  10. skillpool/bridge/freeze_detector.py +134 -0
  11. skillpool/bridge/maintenance.py +119 -0
  12. skillpool/bridge/wal_manager.py +136 -0
  13. skillpool/clawmem_client.py +176 -0
  14. skillpool/cli.py +700 -0
  15. skillpool/combiner/__init__.py +31 -0
  16. skillpool/combiner/lifecycle.py +453 -0
  17. skillpool/combiner/models.py +99 -0
  18. skillpool/config.py +34 -0
  19. skillpool/cost/__init__.py +111 -0
  20. skillpool/cost/audit_hash.py +51 -0
  21. skillpool/cost/budget_tracker.py +66 -0
  22. skillpool/cost/dashboard.py +189 -0
  23. skillpool/cost/models.py +129 -0
  24. skillpool/cost/token_governor.py +264 -0
  25. skillpool/cost/trace_ceiling.py +38 -0
  26. skillpool/csdf.py +126 -0
  27. skillpool/evolver/__init__.py +978 -0
  28. skillpool/gain/__init__.py +285 -0
  29. skillpool/gate.py +282 -0
  30. skillpool/gate_policy/__init__.py +31 -0
  31. skillpool/gate_policy/incremental.py +157 -0
  32. skillpool/gate_policy/parser.py +258 -0
  33. skillpool/gate_policy/state_machine.py +432 -0
  34. skillpool/graph/__init__.py +14 -0
  35. skillpool/graph/ppr.py +279 -0
  36. skillpool/health/__init__.py +73 -0
  37. skillpool/health/check.py +85 -0
  38. skillpool/health/degradation.py +90 -0
  39. skillpool/health/models.py +43 -0
  40. skillpool/hooks/__init__.py +4 -0
  41. skillpool/hooks/security_scanner.py +288 -0
  42. skillpool/lifecycle.py +150 -0
  43. skillpool/materializer/__init__.py +124 -0
  44. skillpool/materializer/budget_cropper.py +178 -0
  45. skillpool/materializer/csdf_loader.py +114 -0
  46. skillpool/materializer/lazy_loader.py +265 -0
  47. skillpool/materializer/lifecycle_filter.py +93 -0
  48. skillpool/materializer/mapper.py +178 -0
  49. skillpool/materializer/models.py +66 -0
  50. skillpool/mcp_server.py +2005 -0
  51. skillpool/monitor/__init__.py +576 -0
  52. skillpool/monitor/bug_collector.py +392 -0
  53. skillpool/monitor/defect_classifier.py +218 -0
  54. skillpool/monitor/self_healing.py +530 -0
  55. skillpool/monitor/telemetry_bridge.py +197 -0
  56. skillpool/paradigm/__init__.py +312 -0
  57. skillpool/paradigm/override.py +285 -0
  58. skillpool/profile.py +94 -0
  59. skillpool/quality.py +254 -0
  60. skillpool/registry/__init__.py +509 -0
  61. skillpool/registry/models.py +98 -0
  62. skillpool/resolver/__init__.py +320 -0
  63. skillpool/resolver/cache.py +103 -0
  64. skillpool/resolver/circuit_breaker.py +103 -0
  65. skillpool/resolver/conflict_detector.py +111 -0
  66. skillpool/resolver/health_filter.py +38 -0
  67. skillpool/resolver/models.py +154 -0
  68. skillpool/resolver/rate_limiter.py +48 -0
  69. skillpool/resolver/skill_graph.py +183 -0
  70. skillpool/review/__init__.py +242 -0
  71. skillpool/review/async_queue.py +96 -0
  72. skillpool/review/checkpoint_runner.py +345 -0
  73. skillpool/review/models.py +164 -0
  74. skillpool/review/suspect_marker.py +39 -0
  75. skillpool/review/veto_evaluator.py +94 -0
  76. skillpool/router/__init__.py +481 -0
  77. skillpool/schemas.py +119 -0
  78. skillpool/synergy/__init__.py +240 -0
  79. skillpool/synergy/detector.py +5 -0
  80. skillpool/telemetry.py +126 -0
  81. skillpool/utils/__init__.py +21 -0
  82. skillpool/utils/changelog.py +218 -0
  83. skillpool/utils/logger.py +273 -0
  84. skillpool/utils/runtime_audit.py +163 -0
  85. skillpool/utils/time_utils.py +13 -0
  86. skillpool-4.3.0.dist-info/METADATA +21 -0
  87. skillpool-4.3.0.dist-info/RECORD +90 -0
  88. skillpool-4.3.0.dist-info/WHEEL +5 -0
  89. skillpool-4.3.0.dist-info/entry_points.txt +3 -0
  90. skillpool-4.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,197 @@
1
+ """Telemetry Bridge — Metric emission, evaluation, and alerting.
2
+
3
+ V4.1 module. Bridges runtime metrics to observability backends.
4
+ Architecture constraint:
5
+ - TelemetryBridge is observation only, no control
6
+ - MUST NOT publish versions or replace Audit
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ __all__ = ["TelemetryBridge"]
12
+
13
+ from collections.abc import Callable
14
+ from datetime import UTC, datetime
15
+
16
+
17
+ class TelemetryBridge:
18
+ """Runtime telemetry emission, five-dimension evaluation, and alerting.
19
+
20
+ Responsibilities:
21
+ 1. Collect and emit Metric objects
22
+ 2. Evaluate metric sets against five-dimension model
23
+ 3. Generate alerts from evaluation results
24
+ 4. Provide metric snapshots for external consumers
25
+ """
26
+
27
+ def __init__(self, sink: Callable | None = None) -> None:
28
+ """Initialize TelemetryBridge.
29
+
30
+ Args:
31
+ sink: Optional callable that receives each emitted Metric.
32
+ Signature: sink(metric) -> None
33
+ """
34
+ self._sink = sink
35
+ self._metrics: list[dict] = []
36
+ self._alerts: list[dict] = []
37
+
38
+ def emit(self, metric) -> None:
39
+ """Emit a metric to the bridge.
40
+
41
+ Stores the metric internally and forwards to the sink if configured.
42
+
43
+ Args:
44
+ metric: A Metric object (from skillpool.monitor).
45
+ """
46
+ entry = {
47
+ "timestamp": datetime.now(UTC).isoformat(),
48
+ "metric": metric,
49
+ }
50
+ self._metrics.append(entry)
51
+
52
+ if self._sink is not None:
53
+ from contextlib import suppress
54
+
55
+ with suppress(Exception):
56
+ self._sink(metric)
57
+
58
+ def evaluate(self, metrics: list) -> dict:
59
+ """Evaluate a set of metrics against the five-dimension model.
60
+
61
+ Dimensions:
62
+ 1. Correctness — accuracy of outputs
63
+ 2. Efficiency — resource utilization
64
+ 3. Robustness — error handling and resilience
65
+ 4. Usability — developer experience
66
+ 5. Security — vulnerability resistance
67
+
68
+ Args:
69
+ metrics: List of Metric objects to evaluate.
70
+
71
+ Returns:
72
+ FiveDimensionEvaluation-compatible dict with scores per dimension.
73
+ """
74
+ scores = {
75
+ "correctness": 1.0,
76
+ "efficiency": 1.0,
77
+ "robustness": 1.0,
78
+ "usability": 1.0,
79
+ "security": 1.0,
80
+ }
81
+
82
+ if not metrics:
83
+ return {
84
+ "dimensions": scores,
85
+ "overall": 1.0,
86
+ "level": "basic",
87
+ "evaluated_at": datetime.now(UTC).isoformat(),
88
+ }
89
+
90
+ error_count = 0
91
+ latency_sum = 0.0
92
+ latency_count = 0
93
+ success_count = 0
94
+ total_count = len(metrics)
95
+
96
+ for m in metrics:
97
+ if isinstance(m, dict):
98
+ mtype = m.get("metric_type", "")
99
+ value = m.get("value", 0)
100
+ else:
101
+ mtype = getattr(m, "metric_type", "")
102
+ value = getattr(m, "value", 0)
103
+
104
+ mtype_str = str(mtype).lower()
105
+
106
+ if "error" in mtype_str or "fail" in mtype_str:
107
+ error_count += 1
108
+ elif "latency" in mtype_str or "duration" in mtype_str:
109
+ latency_sum += float(value)
110
+ latency_count += 1
111
+ elif "success" in mtype_str:
112
+ success_count += 1
113
+
114
+ if total_count > 0:
115
+ scores["correctness"] = round(min(5.0, 1.0 + 4.0 * (success_count / total_count)), 2)
116
+ scores["robustness"] = round(min(5.0, max(1.0, 5.0 - error_count * 0.5)), 2)
117
+
118
+ if latency_count > 0:
119
+ avg_latency = latency_sum / latency_count
120
+ scores["efficiency"] = round(min(5.0, max(1.0, 5.0 - avg_latency / 1000)), 2)
121
+
122
+ overall = round(sum(scores.values()) / len(scores), 2)
123
+
124
+ if overall >= 4.0:
125
+ level = "excellent"
126
+ elif overall >= 3.0:
127
+ level = "good"
128
+ elif overall >= 2.0:
129
+ level = "acceptable"
130
+ else:
131
+ level = "basic"
132
+
133
+ return {
134
+ "dimensions": scores,
135
+ "overall": overall,
136
+ "level": level,
137
+ "evaluated_at": datetime.now(UTC).isoformat(),
138
+ }
139
+
140
+ def check_alerts(self, evaluation: dict) -> list:
141
+ """Generate alerts from evaluation results.
142
+
143
+ Args:
144
+ evaluation: FiveDimensionEvaluation dict from evaluate().
145
+
146
+ Returns:
147
+ List of Alert dicts with severity and message.
148
+ """
149
+ alerts = []
150
+ dimensions = evaluation.get("dimensions", {})
151
+ overall = evaluation.get("overall", 1.0)
152
+
153
+ if overall < 2.0:
154
+ alerts.append(
155
+ {
156
+ "severity": "critical",
157
+ "message": f"Overall evaluation critically low: {overall}",
158
+ "dimension": "overall",
159
+ }
160
+ )
161
+
162
+ for dim_name, score in dimensions.items():
163
+ if score < 2.0:
164
+ alerts.append(
165
+ {
166
+ "severity": "warning",
167
+ "message": f"Dimension '{dim_name}' below threshold: {score}",
168
+ "dimension": dim_name,
169
+ }
170
+ )
171
+ elif score < 3.0:
172
+ alerts.append(
173
+ {
174
+ "severity": "info",
175
+ "message": f"Dimension '{dim_name}' needs attention: {score}",
176
+ "dimension": dim_name,
177
+ }
178
+ )
179
+
180
+ self._alerts.extend(alerts)
181
+ return alerts
182
+
183
+ def snapshot(self) -> dict:
184
+ """Return a snapshot of all collected metrics and alerts.
185
+
186
+ Returns:
187
+ Dict with 'metrics', 'alerts', and 'counts' keys.
188
+ """
189
+ return {
190
+ "metrics": list(self._metrics),
191
+ "alerts": list(self._alerts),
192
+ "counts": {
193
+ "metrics": len(self._metrics),
194
+ "alerts": len(self._alerts),
195
+ },
196
+ "snapshot_at": datetime.now(UTC).isoformat(),
197
+ }
@@ -0,0 +1,312 @@
1
+ """
2
+ ParadigmRegistry — 4D 范式 Skill 注册 + 查询。
3
+
4
+ 4 个 4D 范式:
5
+ - DocsDD: 文档驱动开发(需求→规格→验收)
6
+ - SDD: 规格驱动设计(接口→架构→评审)
7
+ - BDD: 行为驱动开发(场景→测试→实现)
8
+ - TDD: 测试驱动开发(红→绿→重构)
9
+
10
+ 每个范式注册为 CSDF 文档,ParadigmRegistry 负责存储和查询。
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from dataclasses import dataclass
16
+ from enum import StrEnum
17
+ from pathlib import Path
18
+ from typing import Optional
19
+
20
+ import yaml
21
+
22
+
23
+ class Paradigm(StrEnum):
24
+ DOCS_DD = "docsdd"
25
+ SDD = "sdd"
26
+ BDD = "bdd"
27
+ TDD = "tdd"
28
+
29
+
30
+ # 4 个范式的 CSDF 定义
31
+ PARADigm_CSDFS: dict[Paradigm, dict] = {
32
+ Paradigm.DOCS_DD: {
33
+ "id": "paradigm-docsdd",
34
+ "name": "DocsDD — 文档驱动开发",
35
+ "version": "1.0.0",
36
+ "dimension": "D11",
37
+ "paradigm": "docsdd",
38
+ "weight": 0.2,
39
+ "description": "文档先行:需求文档 → 规格文档 → 验收标准",
40
+ "checklist": [
41
+ {"item": "需求文档完整", "priority": "high"},
42
+ {"item": "规格文档对齐需求", "priority": "high"},
43
+ {"item": "验收标准可量化", "priority": "medium"},
44
+ ],
45
+ "required_agent_capabilities": {"file_system"},
46
+ "min_trust_level": 1,
47
+ "lifecycle_state": "ACTIVE",
48
+ "input_schema": {
49
+ "type": "object",
50
+ "properties": {
51
+ "requirements": {"type": "string", "description": "需求描述"},
52
+ "scope": {"type": "string", "description": "范围定义"},
53
+ },
54
+ },
55
+ "output_schema": {
56
+ "required": {"doc": "文档路径", "acceptance": "验收标准"},
57
+ },
58
+ },
59
+ Paradigm.SDD: {
60
+ "id": "paradigm-sdd",
61
+ "name": "SDD — 规格驱动设计",
62
+ "version": "1.0.0",
63
+ "dimension": "D11",
64
+ "paradigm": "sdd",
65
+ "weight": 0.2,
66
+ "description": "规格先行:接口定义 → 架构设计 → 同行评审",
67
+ "checklist": [
68
+ {"item": "接口定义明确", "priority": "high"},
69
+ {"item": "架构图更新", "priority": "high"},
70
+ {"item": "同行评审通过", "priority": "medium"},
71
+ ],
72
+ "required_agent_capabilities": {"file_system", "python"},
73
+ "min_trust_level": 2,
74
+ "lifecycle_state": "ACTIVE",
75
+ "input_schema": {
76
+ "type": "object",
77
+ "properties": {
78
+ "spec": {"type": "string", "description": "规格文档路径"},
79
+ "interfaces": {"type": "array", "description": "接口列表"},
80
+ },
81
+ },
82
+ "output_schema": {
83
+ "required": {"design_doc": "设计文档", "interfaces": "接口定义"},
84
+ },
85
+ },
86
+ Paradigm.BDD: {
87
+ "id": "paradigm-bdd",
88
+ "name": "BDD — 行为驱动开发",
89
+ "version": "1.0.0",
90
+ "dimension": "D7",
91
+ "paradigm": "bdd",
92
+ "weight": 0.3,
93
+ "description": "行为先行:场景定义 → 测试用例 → 实现",
94
+ "checklist": [
95
+ {"item": "场景覆盖完整", "priority": "high"},
96
+ {"item": "测试用例可执行", "priority": "high"},
97
+ {"item": "Given-When-Then 格式", "priority": "medium"},
98
+ ],
99
+ "required_agent_capabilities": {"bash", "file_system", "python"},
100
+ "min_trust_level": 2,
101
+ "lifecycle_state": "ACTIVE",
102
+ "input_schema": {
103
+ "type": "object",
104
+ "properties": {
105
+ "scenarios": {"type": "array", "description": "BDD 场景列表"},
106
+ "feature": {"type": "string", "description": "Feature 名称"},
107
+ },
108
+ },
109
+ "output_schema": {
110
+ "required": {"test_file": "测试文件路径", "coverage": "覆盖率"},
111
+ },
112
+ },
113
+ Paradigm.TDD: {
114
+ "id": "paradigm-tdd",
115
+ "name": "TDD — 测试驱动开发",
116
+ "version": "1.0.0",
117
+ "dimension": "D7",
118
+ "paradigm": "tdd",
119
+ "weight": 0.3,
120
+ "description": "测试先行:红(写失败测试)→ 绿(最小实现)→ 重构",
121
+ "checklist": [
122
+ {"item": "测试先于实现", "priority": "high"},
123
+ {"item": "红→绿→重构循环", "priority": "high"},
124
+ {"item": "覆盖率 ≥ 90%", "priority": "medium"},
125
+ ],
126
+ "required_agent_capabilities": {"bash", "file_system", "python"},
127
+ "min_trust_level": 2,
128
+ "lifecycle_state": "ACTIVE",
129
+ "input_schema": {
130
+ "type": "object",
131
+ "properties": {
132
+ "test_spec": {"type": "string", "description": "测试规格"},
133
+ "target": {"type": "string", "description": "目标模块"},
134
+ },
135
+ },
136
+ "output_schema": {
137
+ "required": {"test_file": "测试文件", "impl_file": "实现文件"},
138
+ },
139
+ },
140
+ }
141
+
142
+
143
+ @dataclass
144
+ class ParadigmEntry:
145
+ """注册表中的一条范式记录。"""
146
+
147
+ paradigm: Paradigm
148
+ csdf: dict
149
+ registered_at: str = ""
150
+ gate_file: Optional[str] = None
151
+
152
+
153
+ class OverrideLevel(StrEnum):
154
+ """Emergency override severity levels."""
155
+
156
+ WARN = "WARN"
157
+ DEGRADE = "DEGRADE"
158
+ QUARANTINE = "QUARANTINE"
159
+ KILL = "KILL"
160
+
161
+
162
+ @dataclass
163
+ class EmergencyOverride:
164
+ """An emergency override applied to a paradigm or skill."""
165
+
166
+ level: OverrideLevel
167
+ target: str # paradigm name or skill_id
168
+ reason: str
169
+ applied_at: str = ""
170
+ revoked: bool = False
171
+
172
+
173
+ class ParadigmRegistry:
174
+ """4D 范式注册表 — 存储、查询、校验。
175
+
176
+ Usage:
177
+ registry = ParadigmRegistry()
178
+ registry.register_defaults()
179
+ entry = registry.get(Paradigm.TDD)
180
+ all_entries = registry.list_all()
181
+ """
182
+
183
+ def __init__(self, persist_dir: Optional[Path] = None):
184
+ self._entries: dict[Paradigm, ParadigmEntry] = {}
185
+ self.persist_dir = persist_dir
186
+ self._overrides: list[EmergencyOverride] = []
187
+
188
+ def register(self, paradigm: Paradigm, csdf: dict) -> ParadigmEntry:
189
+ """注册一个范式 CSDF。"""
190
+ from datetime import datetime, timezone
191
+
192
+ entry = ParadigmEntry(
193
+ paradigm=paradigm,
194
+ csdf=csdf,
195
+ registered_at=datetime.now(timezone.utc).isoformat(),
196
+ )
197
+ self._entries[paradigm] = entry
198
+ if self.persist_dir:
199
+ self._save_to_disk(entry)
200
+ return entry
201
+
202
+ def register_defaults(self) -> None:
203
+ """注册 4 个默认 4D 范式。"""
204
+ for p, csdf in PARADigm_CSDFS.items():
205
+ self.register(p, csdf)
206
+
207
+ def get(self, paradigm: Paradigm) -> Optional[ParadigmEntry]:
208
+ """查询指定范式。"""
209
+ return self._entries.get(paradigm)
210
+
211
+ def get_by_name(self, name: str) -> Optional[ParadigmEntry]:
212
+ """按名称查询范式(大小写不敏感)。"""
213
+ name_lower = name.lower()
214
+ for p, entry in self._entries.items():
215
+ if p.value == name_lower or name_lower in entry.csdf.get("name", "").lower():
216
+ return entry
217
+ return None
218
+
219
+ def list_all(self) -> list[ParadigmEntry]:
220
+ """列出所有已注册范式。"""
221
+ return list(self._entries.values())
222
+
223
+ def unregister(self, paradigm: Paradigm) -> bool:
224
+ """注销一个范式。"""
225
+ if paradigm in self._entries:
226
+ del self._entries[paradigm]
227
+ return True
228
+ return False
229
+
230
+ def validate(self, paradigm: Paradigm) -> list[str]:
231
+ """校验范式 CSDF 完整性,返回错误列表。"""
232
+ entry = self._entries.get(paradigm)
233
+ if not entry:
234
+ return [f"paradigm {paradigm} not registered"]
235
+
236
+ errors = []
237
+ csdf = entry.csdf
238
+ required_fields = ["id", "name", "version", "dimension", "paradigm", "checklist"]
239
+ for f in required_fields:
240
+ if f not in csdf or not csdf[f]:
241
+ errors.append(f"missing or empty field: {f}")
242
+
243
+ checklist = csdf.get("checklist", [])
244
+ if checklist:
245
+ for i, item in enumerate(checklist):
246
+ if not item.get("item") and not item.get("description"):
247
+ errors.append(f"checklist[{i}] missing item/description")
248
+ if not item.get("priority") and not item.get("severity"):
249
+ errors.append(f"checklist[{i}] missing priority/severity")
250
+
251
+ return errors
252
+
253
+ def apply_override(self, level: OverrideLevel, target: str, reason: str) -> EmergencyOverride:
254
+ """Apply an emergency override to a paradigm or skill.
255
+
256
+ WARN: Log warning, continue operation.
257
+ DEGRADE: Reduce functionality (e.g., skip non-critical checks).
258
+ QUARANTINE: Isolate the target from active processing.
259
+ KILL: Immediately stop all operations for the target.
260
+ """
261
+ from datetime import datetime, timezone
262
+
263
+ override = EmergencyOverride(
264
+ level=level,
265
+ target=target,
266
+ reason=reason,
267
+ applied_at=datetime.now(timezone.utc).isoformat(),
268
+ )
269
+ self._overrides.append(override)
270
+
271
+ # For QUARANTINE/KILL, unregister the paradigm if it matches
272
+ if level in (OverrideLevel.QUARANTINE, OverrideLevel.KILL):
273
+ for p in list(self._entries.keys()):
274
+ if p.value == target.lower():
275
+ self._entries[p].csdf["lifecycle_state"] = (
276
+ "QUARANTINED" if level == OverrideLevel.QUARANTINE else "KILLED"
277
+ )
278
+
279
+ return override
280
+
281
+ def revoke_override(self, target: str) -> bool:
282
+ """Revoke the most recent active override for a target."""
283
+ for override in reversed(self._overrides):
284
+ if override.target == target and not override.revoked:
285
+ override.revoked = True
286
+ # Restore lifecycle state if paradigm exists
287
+ for p, entry in self._entries.items():
288
+ if p.value == target.lower() and entry.csdf.get("lifecycle_state") in ("QUARANTINED", "KILLED"):
289
+ entry.csdf["lifecycle_state"] = "ACTIVE"
290
+ return True
291
+ return False
292
+
293
+ def get_active_overrides(self) -> list[EmergencyOverride]:
294
+ """Get all active (non-revoked) overrides."""
295
+ return [o for o in self._overrides if not o.revoked]
296
+
297
+ def get_override_level(self, target: str) -> Optional[OverrideLevel]:
298
+ """Get the highest active override level for a target."""
299
+ active = [o for o in self._overrides if o.target == target and not o.revoked]
300
+ if not active:
301
+ return None
302
+ # Priority: KILL > QUARANTINE > DEGRADE > WARN
303
+ priority = {OverrideLevel.KILL: 4, OverrideLevel.QUARANTINE: 3, OverrideLevel.DEGRADE: 2, OverrideLevel.WARN: 1}
304
+ return max(active, key=lambda o: priority[o.level]).level
305
+
306
+ def _save_to_disk(self, entry: ParadigmEntry) -> None:
307
+ """持久化到 YAML 文件。"""
308
+ if not self.persist_dir:
309
+ return
310
+ self.persist_dir.mkdir(parents=True, exist_ok=True)
311
+ path = self.persist_dir / f"{entry.paradigm.value}.yaml"
312
+ path.write_text(yaml.dump(entry.csdf, default_flow_style=False, allow_unicode=True))