@trac3er/oh-my-god 2.0.0-beta.2 → 2.1.0-alpha

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 (47) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/OMG-setup.sh +33 -0
  4. package/README.md +43 -0
  5. package/claude_experimental/__init__.py +27 -0
  6. package/claude_experimental/_compat.py +12 -0
  7. package/claude_experimental/_degradation.py +210 -0
  8. package/claude_experimental/_flags.py +35 -0
  9. package/claude_experimental/_lifecycle.py +122 -0
  10. package/claude_experimental/integration/__init__.py +16 -0
  11. package/claude_experimental/integration/_placeholder.py +7 -0
  12. package/claude_experimental/integration/autotuner.py +182 -0
  13. package/claude_experimental/integration/checkpoints.py +327 -0
  14. package/claude_experimental/integration/experiments.py +302 -0
  15. package/claude_experimental/integration/openapi_gen.py +428 -0
  16. package/claude_experimental/integration/streaming.py +131 -0
  17. package/claude_experimental/integration/telemetry.py +287 -0
  18. package/claude_experimental/memory/__init__.py +16 -0
  19. package/claude_experimental/memory/_placeholder.py +7 -0
  20. package/claude_experimental/memory/api.py +434 -0
  21. package/claude_experimental/memory/augmented_generation.py +142 -0
  22. package/claude_experimental/memory/episodic.py +190 -0
  23. package/claude_experimental/memory/failure_learning.py +183 -0
  24. package/claude_experimental/memory/migrate.py +169 -0
  25. package/claude_experimental/memory/procedural.py +212 -0
  26. package/claude_experimental/memory/semantic.py +376 -0
  27. package/claude_experimental/memory/store.py +310 -0
  28. package/claude_experimental/parallel/__init__.py +17 -0
  29. package/claude_experimental/parallel/_placeholder.py +7 -0
  30. package/claude_experimental/parallel/aggregation.py +131 -0
  31. package/claude_experimental/parallel/api.py +244 -0
  32. package/claude_experimental/parallel/executor.py +110 -0
  33. package/claude_experimental/parallel/ralph_bridge.py +164 -0
  34. package/claude_experimental/parallel/sandbox.py +314 -0
  35. package/claude_experimental/parallel/scaling.py +171 -0
  36. package/claude_experimental/parallel/ultraworker.py +285 -0
  37. package/claude_experimental/patterns/__init__.py +16 -0
  38. package/claude_experimental/patterns/_placeholder.py +7 -0
  39. package/claude_experimental/patterns/antipatterns.py +454 -0
  40. package/claude_experimental/patterns/api.py +196 -0
  41. package/claude_experimental/patterns/extractor.py +163 -0
  42. package/claude_experimental/patterns/mining.py +219 -0
  43. package/claude_experimental/patterns/refactoring.py +234 -0
  44. package/hooks/_common.py +3 -1
  45. package/package.json +1 -1
  46. package/runtime/subagent_dispatcher.py +109 -9
  47. package/settings.json +6 -1
@@ -0,0 +1,302 @@
1
+ """ExperimentTracker - A/B experiment tagging framework with variant assignment and metric comparison.
2
+
3
+ Design decisions:
4
+ - Shared SQLite DB with TelemetryCollector (.omg/state/telemetry.db)
5
+ - Connection-per-invocation (hooks are short-lived subprocesses, no pooling)
6
+ - WAL mode for concurrent multi-session access
7
+ - Deterministic variant assignment via hash-based default, random fallback
8
+ - Feature-gated via ADVANCED_INTEGRATION flag
9
+ - Schema versioning from day one
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import hashlib
14
+ import json
15
+ import os
16
+ import random
17
+ import sqlite3
18
+ from datetime import datetime, timezone
19
+ from typing import cast
20
+
21
+ SCHEMA_VERSION = 1
22
+
23
+
24
+ def _default_db_path() -> str:
25
+ """Return default experiments DB path (shared with telemetry)."""
26
+ project_dir = os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
27
+ return os.path.join(project_dir, ".omg", "state", "telemetry.db")
28
+
29
+
30
+ class ExperimentTracker:
31
+ """A/B experiment tagging framework with variant assignment and metric comparison.
32
+
33
+ Supports defining experiments with multiple variants, deterministically assigning
34
+ subjects to variants, and collecting per-variant metrics for comparison.
35
+
36
+ Usage:
37
+ tracker = ExperimentTracker()
38
+ exp_id = tracker.define_experiment("pool_size", ["small", "large"])
39
+ variant = tracker.assign_variant(exp_id, "user_123")
40
+ tracker.tag_metric(exp_id, variant, "latency_ms", 42.5)
41
+ results = tracker.compare(exp_id)
42
+ """
43
+
44
+ def __init__(self, db_path: str | None = None):
45
+ from claude_experimental.integration import _require_enabled
46
+ _require_enabled()
47
+
48
+ self.db_path: str = db_path or _default_db_path()
49
+ self._ensure_dir()
50
+ self._shared_memory_conn: sqlite3.Connection | None = None
51
+ if self.db_path == ":memory:":
52
+ self._shared_memory_conn = sqlite3.connect("file::memory:?cache=shared", uri=True, check_same_thread=False)
53
+ self._shared_memory_conn.row_factory = sqlite3.Row
54
+ self._init_schema(self._shared_memory_conn)
55
+
56
+ def _ensure_dir(self) -> None:
57
+ if self.db_path != ":memory:":
58
+ os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
59
+
60
+ def _connect(self) -> sqlite3.Connection:
61
+ """Open a new connection and initialize the schema if needed."""
62
+ if self.db_path == ":memory:":
63
+ if self._shared_memory_conn is None:
64
+ raise RuntimeError("Shared memory connection not initialized")
65
+ return self._shared_memory_conn
66
+ conn = sqlite3.connect(self.db_path, check_same_thread=False)
67
+ conn.row_factory = sqlite3.Row
68
+ self._init_schema(conn)
69
+ return conn
70
+
71
+ def _init_schema(self, conn: sqlite3.Connection) -> None:
72
+ """Create schema if not exists."""
73
+ _ = conn.executescript("""
74
+ PRAGMA journal_mode=WAL;
75
+ PRAGMA busy_timeout=5000;
76
+
77
+ CREATE TABLE IF NOT EXISTS schema_info (
78
+ key TEXT PRIMARY KEY,
79
+ value TEXT NOT NULL
80
+ );
81
+
82
+ CREATE TABLE IF NOT EXISTS experiments (
83
+ id TEXT PRIMARY KEY,
84
+ name TEXT NOT NULL,
85
+ variants TEXT NOT NULL,
86
+ assignment TEXT NOT NULL,
87
+ created_at TEXT NOT NULL,
88
+ schema_version INTEGER NOT NULL DEFAULT 1
89
+ );
90
+
91
+ CREATE TABLE IF NOT EXISTS experiment_metrics (
92
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
93
+ experiment_id TEXT NOT NULL,
94
+ variant TEXT NOT NULL,
95
+ metric_name TEXT NOT NULL,
96
+ value REAL NOT NULL,
97
+ recorded_at TEXT NOT NULL,
98
+ schema_version INTEGER NOT NULL DEFAULT 1,
99
+ FOREIGN KEY (experiment_id) REFERENCES experiments(id)
100
+ );
101
+
102
+ CREATE INDEX IF NOT EXISTS idx_experiment_metrics_exp_id ON experiment_metrics(experiment_id);
103
+ CREATE INDEX IF NOT EXISTS idx_experiment_metrics_variant ON experiment_metrics(variant);
104
+ CREATE INDEX IF NOT EXISTS idx_experiment_metrics_name ON experiment_metrics(metric_name);
105
+ """)
106
+
107
+ # Set schema version if not present
108
+ row = cast(
109
+ sqlite3.Row | None,
110
+ conn.execute(
111
+ "SELECT value FROM schema_info WHERE key='schema_version'"
112
+ ).fetchone(),
113
+ )
114
+ if row is None:
115
+ _ = conn.execute(
116
+ "INSERT OR REPLACE INTO schema_info (key, value) VALUES ('schema_version', ?)",
117
+ (str(SCHEMA_VERSION),),
118
+ )
119
+ conn.commit()
120
+
121
+ def define_experiment(
122
+ self,
123
+ name: str,
124
+ variants: list[str],
125
+ assignment: str = "random",
126
+ ) -> str:
127
+ """Define a new A/B experiment.
128
+
129
+ Args:
130
+ name: Experiment name (e.g. "pool_size").
131
+ variants: List of variant names (e.g. ["small", "large"]).
132
+ assignment: Assignment strategy - "random" or "hash" (default "random").
133
+
134
+ Returns:
135
+ Experiment ID (UUID-like string).
136
+ """
137
+ from claude_experimental.integration import _require_enabled
138
+ _require_enabled()
139
+
140
+ if not variants or len(variants) < 2:
141
+ raise ValueError("Experiment must have at least 2 variants")
142
+
143
+ if assignment not in ("random", "hash"):
144
+ raise ValueError("Assignment must be 'random' or 'hash'")
145
+
146
+ # Generate experiment ID from name + timestamp
147
+ now = datetime.now(timezone.utc).isoformat()
148
+ exp_id = hashlib.sha256(f"{name}:{now}".encode()).hexdigest()[:16]
149
+
150
+ conn = self._connect()
151
+ try:
152
+ _ = conn.execute(
153
+ "INSERT INTO experiments (id, name, variants, assignment, created_at, schema_version) VALUES (?, ?, ?, ?, ?, ?)",
154
+ (
155
+ exp_id,
156
+ name,
157
+ json.dumps(variants),
158
+ assignment,
159
+ now,
160
+ SCHEMA_VERSION,
161
+ ),
162
+ )
163
+ conn.commit()
164
+ finally:
165
+ if self.db_path != ":memory:":
166
+ conn.close()
167
+
168
+ return exp_id
169
+
170
+ def assign_variant(self, experiment_id: str, subject_id: str) -> str:
171
+ """Assign a subject to a variant in an experiment.
172
+
173
+ Deterministic for hash-based assignment (same subject always gets same variant).
174
+ Random for random-based assignment.
175
+
176
+ Args:
177
+ experiment_id: Experiment ID from define_experiment().
178
+ subject_id: Subject identifier (e.g. user ID, session ID).
179
+
180
+ Returns:
181
+ Assigned variant name.
182
+ """
183
+ from claude_experimental.integration import _require_enabled
184
+ _require_enabled()
185
+
186
+ conn = self._connect()
187
+ try:
188
+ row = cast(
189
+ sqlite3.Row | None,
190
+ conn.execute(
191
+ "SELECT variants, assignment FROM experiments WHERE id = ?",
192
+ (experiment_id,),
193
+ ).fetchone(),
194
+ )
195
+ if row is None:
196
+ raise ValueError(f"Experiment not found: {experiment_id}")
197
+
198
+ variants = json.loads(row["variants"])
199
+ assignment = row["assignment"]
200
+
201
+ if assignment == "hash":
202
+ # Deterministic: hash subject_id to select variant
203
+ hash_val = int(
204
+ hashlib.sha256(f"{experiment_id}:{subject_id}".encode()).hexdigest(),
205
+ 16,
206
+ )
207
+ variant = variants[hash_val % len(variants)]
208
+ else:
209
+ # Random assignment
210
+ variant = random.choice(variants)
211
+
212
+ return variant
213
+ finally:
214
+ if self.db_path != ":memory:":
215
+ conn.close()
216
+
217
+ def tag_metric(
218
+ self,
219
+ experiment_id: str,
220
+ variant: str,
221
+ metric_name: str,
222
+ value: float,
223
+ ) -> None:
224
+ """Record a metric observation for a variant in an experiment.
225
+
226
+ Args:
227
+ experiment_id: Experiment ID from define_experiment().
228
+ variant: Variant name.
229
+ metric_name: Metric name (e.g. "latency_ms").
230
+ value: Numeric value.
231
+ """
232
+ from claude_experimental.integration import _require_enabled
233
+ _require_enabled()
234
+
235
+ now = datetime.now(timezone.utc).isoformat()
236
+ conn = self._connect()
237
+ try:
238
+ _ = conn.execute(
239
+ "INSERT INTO experiment_metrics (experiment_id, variant, metric_name, value, recorded_at, schema_version) VALUES (?, ?, ?, ?, ?, ?)",
240
+ (
241
+ experiment_id,
242
+ variant,
243
+ metric_name,
244
+ value,
245
+ now,
246
+ SCHEMA_VERSION,
247
+ ),
248
+ )
249
+ conn.commit()
250
+ finally:
251
+ if self.db_path != ":memory:":
252
+ conn.close()
253
+
254
+ def compare(self, experiment_id: str) -> dict[str, dict[str, object]]:
255
+ """Compare metrics across variants in an experiment.
256
+
257
+ Args:
258
+ experiment_id: Experiment ID from define_experiment().
259
+
260
+ Returns:
261
+ Dict mapping variant name to summary dict with keys:
262
+ - count: number of observations
263
+ - mean: average value
264
+ - min: minimum value
265
+ - max: maximum value
266
+ """
267
+ from claude_experimental.integration import _require_enabled
268
+ _require_enabled()
269
+
270
+ conn = self._connect()
271
+ try:
272
+ rows = cast(
273
+ list[sqlite3.Row],
274
+ conn.execute(
275
+ """
276
+ SELECT variant,
277
+ COUNT(*) as cnt,
278
+ AVG(value) as avg_val,
279
+ MIN(value) as min_val,
280
+ MAX(value) as max_val
281
+ FROM experiment_metrics
282
+ WHERE experiment_id = ?
283
+ GROUP BY variant
284
+ ORDER BY variant
285
+ """,
286
+ (experiment_id,),
287
+ ).fetchall(),
288
+ )
289
+
290
+ result: dict[str, dict[str, object]] = {}
291
+ for row in rows:
292
+ result[row["variant"]] = {
293
+ "count": row["cnt"],
294
+ "mean": row["avg_val"],
295
+ "min": row["min_val"],
296
+ "max": row["max_val"],
297
+ }
298
+
299
+ return result
300
+ finally:
301
+ if self.db_path != ":memory:":
302
+ conn.close()