codex-flow 2.1.13__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 (113) hide show
  1. codex_flow/__init__.py +28 -0
  2. codex_flow/__main__.py +9 -0
  3. codex_flow/cli.py +242 -0
  4. codex_flow/data/LICENSE +21 -0
  5. codex_flow/data/README.en.md +303 -0
  6. codex_flow/data/README.md +305 -0
  7. codex_flow/data/VERSION +1 -0
  8. codex_flow/data/apps/chatgpt-mcp/README.md +86 -0
  9. codex_flow/data/apps/chatgpt-mcp/__init__.py +1 -0
  10. codex_flow/data/apps/chatgpt-mcp/adapter.py +458 -0
  11. codex_flow/data/apps/chatgpt-mcp/server.py +358 -0
  12. codex_flow/data/apps/chatgpt-mcp/widget.html +927 -0
  13. codex_flow/data/apps/macos-overlay/README.en.md +121 -0
  14. codex_flow/data/apps/macos-overlay/README.md +123 -0
  15. codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayRuntimeState.swift +126 -0
  16. codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayScreenGeometry.swift +82 -0
  17. codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayWindowController.swift +1052 -0
  18. codex_flow/data/apps/macos-overlay/Sources/Localization.swift +197 -0
  19. codex_flow/data/apps/macos-overlay/Sources/Models/TelemetryData.swift +1557 -0
  20. codex_flow/data/apps/macos-overlay/Sources/Services/AccountSnapshotService.swift +1101 -0
  21. codex_flow/data/apps/macos-overlay/Sources/Services/FlowPilotInstanceLock.swift +153 -0
  22. codex_flow/data/apps/macos-overlay/Sources/Services/IPCServer.swift +298 -0
  23. codex_flow/data/apps/macos-overlay/Sources/Services/TelemetryQueryEngine.swift +800 -0
  24. codex_flow/data/apps/macos-overlay/Sources/Services/TelemetryWatcher.swift +135 -0
  25. codex_flow/data/apps/macos-overlay/Sources/Services/UpdateService.swift +610 -0
  26. codex_flow/data/apps/macos-overlay/Sources/Views/AccountView.swift +610 -0
  27. codex_flow/data/apps/macos-overlay/Sources/Views/AnalyticsView.swift +566 -0
  28. codex_flow/data/apps/macos-overlay/Sources/Views/AutostartView.swift +293 -0
  29. codex_flow/data/apps/macos-overlay/Sources/Views/BubbleView.swift +317 -0
  30. codex_flow/data/apps/macos-overlay/Sources/Views/HistoryView.swift +1124 -0
  31. codex_flow/data/apps/macos-overlay/Sources/Views/HoverRevealText.swift +165 -0
  32. codex_flow/data/apps/macos-overlay/Sources/Views/InspectorSkillsToolsView.swift +121 -0
  33. codex_flow/data/apps/macos-overlay/Sources/Views/LogoView.swift +182 -0
  34. codex_flow/data/apps/macos-overlay/Sources/Views/SleekSwitch.swift +117 -0
  35. codex_flow/data/apps/macos-overlay/Sources/Views/StrategyModeView.swift +561 -0
  36. codex_flow/data/apps/macos-overlay/Sources/Views/SummaryView.swift +1273 -0
  37. codex_flow/data/apps/macos-overlay/Sources/Views/UpdateView.swift +352 -0
  38. codex_flow/data/apps/macos-overlay/Sources/main.swift +340 -0
  39. codex_flow/data/apps/macos-overlay/Tests/OverlayScreenGeometryTests.swift +163 -0
  40. codex_flow/data/apps/macos-overlay/Tests/TelemetryPhase1ContractTests.swift +357 -0
  41. codex_flow/data/apps/macos-overlay/Tests/TelemetryQueryEngineConcurrencyTests.swift +221 -0
  42. codex_flow/data/apps/macos-overlay/Tests/TelemetryQuotaSelectionTests.swift +158 -0
  43. codex_flow/data/apps/macos-overlay/Tests/TelemetryWorkerTokenTests.swift +122 -0
  44. codex_flow/data/apps/macos-overlay/build.sh +75 -0
  45. codex_flow/data/benchmark/corpus.json +103 -0
  46. codex_flow/data/benchmark/manifest.example.json +41 -0
  47. codex_flow/data/benchmark/manifest.schema.json +137 -0
  48. codex_flow/data/benchmark/prices/gpt-5.6-2026-08-30.json +5 -0
  49. codex_flow/data/benchmark/profiles.json +90 -0
  50. codex_flow/data/benchmark/schema.json +77 -0
  51. codex_flow/data/benchmark/tasks.json +50 -0
  52. codex_flow/data/completions/codex-flow.bash +34 -0
  53. codex_flow/data/completions/codex-flow.zsh +52 -0
  54. codex_flow/data/glama.json +6 -0
  55. codex_flow/data/install-release.ps1 +126 -0
  56. codex_flow/data/install-release.sh +155 -0
  57. codex_flow/data/install.ps1 +349 -0
  58. codex_flow/data/install.sh +362 -0
  59. codex_flow/data/policy/benchmark.toml +49 -0
  60. codex_flow/data/policy/defaults.toml +70 -0
  61. codex_flow/data/scripts/analyze-benchmark.py +510 -0
  62. codex_flow/data/scripts/benchmark-local.py +171 -0
  63. codex_flow/data/scripts/check-recommendation.py +277 -0
  64. codex_flow/data/scripts/doctor.py +449 -0
  65. codex_flow/data/scripts/generate-release-manifest.py +74 -0
  66. codex_flow/data/scripts/localization.py +192 -0
  67. codex_flow/data/scripts/manage-hooks.py +448 -0
  68. codex_flow/data/scripts/manage-instructions.py +389 -0
  69. codex_flow/data/scripts/manage-shell.py +151 -0
  70. codex_flow/data/scripts/materialize-corpus.py +193 -0
  71. codex_flow/data/scripts/menu.py +646 -0
  72. codex_flow/data/scripts/migrations/0001_update_settings.py +80 -0
  73. codex_flow/data/scripts/package-release.py +132 -0
  74. codex_flow/data/scripts/render-benchmark-report.py +292 -0
  75. codex_flow/data/scripts/run-benchmark.py +829 -0
  76. codex_flow/data/scripts/strategies/__init__.py +28 -0
  77. codex_flow/data/scripts/strategies/balanced.py +115 -0
  78. codex_flow/data/scripts/strategies/base.py +363 -0
  79. codex_flow/data/scripts/strategies/efficient.py +158 -0
  80. codex_flow/data/scripts/strategies/lifecycle_runtime.py +590 -0
  81. codex_flow/data/scripts/strategies/quality.py +209 -0
  82. codex_flow/data/scripts/strategies/speed.py +108 -0
  83. codex_flow/data/scripts/strategies/task_budget_runtime.py +644 -0
  84. codex_flow/data/scripts/strategies/task_phase_runtime.py +341 -0
  85. codex_flow/data/scripts/strategies/work_unit_runtime.py +421 -0
  86. codex_flow/data/scripts/strategy_runtime.py +1091 -0
  87. codex_flow/data/scripts/telemetry.py +400 -0
  88. codex_flow/data/scripts/telemetry_core/__init__.py +192 -0
  89. codex_flow/data/scripts/telemetry_core/app_server.py +1192 -0
  90. codex_flow/data/scripts/telemetry_core/collector.py +1247 -0
  91. codex_flow/data/scripts/telemetry_core/common.py +421 -0
  92. codex_flow/data/scripts/telemetry_core/latency.py +593 -0
  93. codex_flow/data/scripts/telemetry_core/query.py +427 -0
  94. codex_flow/data/scripts/telemetry_core/quota_ledger.py +598 -0
  95. codex_flow/data/scripts/telemetry_core/render.py +460 -0
  96. codex_flow/data/scripts/telemetry_core/repair.py +223 -0
  97. codex_flow/data/scripts/ui.py +266 -0
  98. codex_flow/data/scripts/update-homebrew-formula.py +146 -0
  99. codex_flow/data/scripts/update_runtime_config.py +134 -0
  100. codex_flow/data/scripts/updater.py +1718 -0
  101. codex_flow/data/smithery.yaml +18 -0
  102. codex_flow/data/templates/agents/worker-explorer.toml +24 -0
  103. codex_flow/data/templates/agents/worker-implementer.toml +49 -0
  104. codex_flow/data/templates/agents/worker-reviewer.toml +25 -0
  105. codex_flow/data/templates/flow-pilot-instructions.md +35 -0
  106. codex_flow/data/templates/skills/flow-pilot/SKILL.md +577 -0
  107. codex_flow/mcp.py +35 -0
  108. codex_flow-2.1.13.dist-info/METADATA +342 -0
  109. codex_flow-2.1.13.dist-info/RECORD +113 -0
  110. codex_flow-2.1.13.dist-info/WHEEL +5 -0
  111. codex_flow-2.1.13.dist-info/entry_points.txt +3 -0
  112. codex_flow-2.1.13.dist-info/licenses/LICENSE +21 -0
  113. codex_flow-2.1.13.dist-info/top_level.txt +1 -0
@@ -0,0 +1,598 @@
1
+ """Deterministic weekly quota ledger engine using SQLite with WAL mode.
2
+
3
+ Maintains an immutable observation timeline, transaction-safe segment lifecycle,
4
+ late-arrival replacement transactions, and anti-regression derived cache exports.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ import sqlite3
11
+ import time
12
+ import uuid
13
+ from datetime import datetime
14
+ from pathlib import Path
15
+ from typing import Any
16
+
17
+ from .common import (
18
+ CODEX_HOME,
19
+ STATE_ROOT,
20
+ atomic_json,
21
+ now_ms,
22
+ read_json_object,
23
+ state_lock,
24
+ )
25
+
26
+ WEEKLY_WINDOW_MINS = 10080
27
+ QUOTA_LEDGER_DB = STATE_ROOT / "quota_ledger.db"
28
+ QUOTA_SUMMARY_FILE = STATE_ROOT / "quota_summary.json"
29
+ QUOTA_LOCK_KEY = "quota_ledger"
30
+
31
+
32
+ def get_db(db_path: Path = QUOTA_LEDGER_DB) -> sqlite3.Connection:
33
+ """Open or create the SQLite ledger database with WAL mode and foreign keys enabled."""
34
+ db_path.parent.mkdir(parents=True, exist_ok=True)
35
+ conn = sqlite3.connect(str(db_path), timeout=10.0)
36
+ conn.row_factory = sqlite3.Row
37
+ conn.execute("PRAGMA journal_mode = WAL;")
38
+ conn.execute("PRAGMA foreign_keys = ON;")
39
+ conn.execute("PRAGMA busy_timeout = 5000;")
40
+ init_db(conn)
41
+ return conn
42
+
43
+
44
+ def init_db(conn: sqlite3.Connection) -> None:
45
+ """Initialize SQLite schema if not already present."""
46
+ with conn:
47
+ conn.execute(
48
+ """
49
+ CREATE TABLE IF NOT EXISTS quota_observations (
50
+ observation_id TEXT PRIMARY KEY,
51
+ account_id TEXT NOT NULL,
52
+ bucket_id TEXT NOT NULL,
53
+ window_duration_mins INTEGER NOT NULL CHECK (window_duration_mins = 10080),
54
+ resets_at_ms INTEGER,
55
+ baseline_generation INTEGER NOT NULL DEFAULT 0,
56
+ cycle_id TEXT NOT NULL,
57
+ sampled_at_ms INTEGER NOT NULL,
58
+ used_percent REAL NOT NULL CHECK (used_percent >= 0.0 AND used_percent <= 100.0),
59
+ sample_source TEXT NOT NULL,
60
+ run_id TEXT,
61
+ is_valid BOOLEAN NOT NULL DEFAULT 1,
62
+ anomaly_status TEXT NOT NULL DEFAULT 'normal',
63
+ created_at_ms INTEGER NOT NULL
64
+ );
65
+ """
66
+ )
67
+ conn.execute(
68
+ """
69
+ CREATE INDEX IF NOT EXISTS idx_obs_cycle_time
70
+ ON quota_observations(cycle_id, sampled_at_ms);
71
+ """
72
+ )
73
+ conn.execute(
74
+ """
75
+ CREATE TABLE IF NOT EXISTS quota_segments (
76
+ segment_id TEXT PRIMARY KEY,
77
+ cycle_id TEXT NOT NULL,
78
+ start_obs_id TEXT NOT NULL REFERENCES quota_observations(observation_id),
79
+ end_obs_id TEXT NOT NULL REFERENCES quota_observations(observation_id),
80
+ start_time_ms INTEGER NOT NULL,
81
+ end_time_ms INTEGER NOT NULL CHECK (end_time_ms >= start_time_ms),
82
+ delta_pp REAL NOT NULL,
83
+ status TEXT NOT NULL CHECK (status IN ('active', 'revoked', 'pending_investigation')),
84
+ attribution_status TEXT NOT NULL CHECK (attribution_status IN ('fully_attributed', 'partially_attributed', 'unattributed', 'waiting_weights')),
85
+ unattributed_pp REAL NOT NULL DEFAULT 0.0 CHECK (unattributed_pp >= 0.0),
86
+ reason_code TEXT,
87
+ has_cross_midnight BOOLEAN NOT NULL DEFAULT 0,
88
+ created_revision INTEGER NOT NULL,
89
+ revoked_revision INTEGER
90
+ );
91
+ """
92
+ )
93
+ conn.execute(
94
+ """
95
+ CREATE INDEX IF NOT EXISTS idx_seg_cycle_active
96
+ ON quota_segments(cycle_id, status, start_time_ms);
97
+ """
98
+ )
99
+ conn.execute(
100
+ """
101
+ CREATE TABLE IF NOT EXISTS quota_allocations (
102
+ allocation_id TEXT PRIMARY KEY,
103
+ segment_id TEXT NOT NULL REFERENCES quota_segments(segment_id),
104
+ run_id TEXT NOT NULL,
105
+ session_id TEXT NOT NULL,
106
+ allocated_pp REAL NOT NULL CHECK (allocated_pp >= 0.0),
107
+ token_weight INTEGER NOT NULL CHECK (token_weight >= 0),
108
+ weight_share REAL NOT NULL CHECK (weight_share >= 0.0 AND weight_share <= 1.0),
109
+ attribution_method TEXT NOT NULL,
110
+ assumption TEXT,
111
+ status TEXT NOT NULL CHECK (status IN ('active', 'revoked')),
112
+ revision INTEGER NOT NULL
113
+ );
114
+ """
115
+ )
116
+ conn.execute(
117
+ """
118
+ CREATE INDEX IF NOT EXISTS idx_alloc_run
119
+ ON quota_allocations(run_id, status);
120
+ """
121
+ )
122
+ conn.execute(
123
+ """
124
+ CREATE INDEX IF NOT EXISTS idx_alloc_session
125
+ ON quota_allocations(session_id, status);
126
+ """
127
+ )
128
+ conn.execute(
129
+ """
130
+ CREATE TABLE IF NOT EXISTS quota_ledger_metadata (
131
+ id INTEGER PRIMARY KEY CHECK (id = 1),
132
+ current_revision INTEGER NOT NULL,
133
+ last_rebuilt_at_ms INTEGER NOT NULL
134
+ );
135
+ """
136
+ )
137
+ cur = conn.execute("SELECT id FROM quota_ledger_metadata WHERE id = 1;")
138
+ if cur.fetchone() is None:
139
+ conn.execute(
140
+ """
141
+ INSERT INTO quota_ledger_metadata (id, current_revision, last_rebuilt_at_ms)
142
+ VALUES (1, 1, ?);
143
+ """,
144
+ (now_ms(),),
145
+ )
146
+
147
+
148
+ def resolve_account_id(account_id: str | None = None) -> str | None:
149
+ """Resolve stable account identifier from argument or auth.json.
150
+
151
+ Prevents concurrent tasks from falling into isolated cycles when account_id
152
+ is omitted in telemetry events. Returns None if unauthenticated (never falls back
153
+ to installation_id).
154
+ """
155
+ if account_id and str(account_id).strip():
156
+ return str(account_id).strip()
157
+ try:
158
+ auth_file = CODEX_HOME / "auth.json"
159
+ if auth_file.is_file():
160
+ data = json.loads(auth_file.read_text(encoding="utf-8"))
161
+ if isinstance(data, dict):
162
+ tokens = data.get("tokens")
163
+ if isinstance(tokens, dict) and tokens.get("account_id"):
164
+ return str(tokens["account_id"]).strip()
165
+ if data.get("account_id"):
166
+ return str(data["account_id"]).strip()
167
+ except Exception:
168
+ pass
169
+ return None
170
+
171
+
172
+ def compute_cycle_id(
173
+ account_id: str | None,
174
+ bucket_id: str | None,
175
+ window_duration_mins: int,
176
+ resets_at_ms: int | None,
177
+ baseline_generation: int = 0,
178
+ isolated_key: str | None = None,
179
+ ) -> str:
180
+ """Construct deterministic cycle identifier.
181
+
182
+ Missing identity is NEVER lumped into a single shared 'unknown' account;
183
+ it receives an isolated namespace to prevent cross-account contamination.
184
+ """
185
+ acc = (account_id or "").strip()
186
+ bkt = (bucket_id or "primary").strip()
187
+ if not acc:
188
+ acc = f"isolated_{isolated_key}" if isolated_key else "isolated_anonymous"
189
+ reset_part = resets_at_ms if resets_at_ms is not None else 0
190
+ return f"{acc}:{bkt}:{window_duration_mins}:{reset_part}:{baseline_generation}"
191
+
192
+
193
+ def record_observation(
194
+ conn: sqlite3.Connection,
195
+ account_id: str | None,
196
+ bucket_id: str | None,
197
+ used_percent: float,
198
+ sampled_at_ms: int,
199
+ sample_source: str,
200
+ window_duration_mins: int = WEEKLY_WINDOW_MINS,
201
+ resets_at_ms: int | None = None,
202
+ baseline_generation: int = 0,
203
+ run_id: str | None = None,
204
+ ) -> dict[str, Any]:
205
+ """Insert immutable sample evidence and reconcile its cycle in one transaction.
206
+
207
+ Validity is derived from sample time, never arrival order: a value below the
208
+ last accepted watermark is pending until the watermark recovers. The interval
209
+ spanning that recovery remains pending; subsequent clean intervals can settle.
210
+ """
211
+ if window_duration_mins != WEEKLY_WINDOW_MINS:
212
+ return {
213
+ "status": "ignored_non_weekly",
214
+ "reason": f"Only window_duration_mins={WEEKLY_WINDOW_MINS} is tracked",
215
+ }
216
+ if not (0.0 <= used_percent <= 100.0):
217
+ return {"status": "rejected_out_of_range", "used_percent": used_percent}
218
+
219
+ resolved_account = resolve_account_id(account_id)
220
+ cycle_id = compute_cycle_id(
221
+ resolved_account, bucket_id, window_duration_mins, resets_at_ms,
222
+ baseline_generation, isolated_key=run_id,
223
+ )
224
+ with conn:
225
+ if not conn.in_transaction:
226
+ conn.execute("BEGIN IMMEDIATE;")
227
+ existing = conn.execute(
228
+ """SELECT observation_id, used_percent, anomaly_status
229
+ FROM quota_observations WHERE cycle_id = ? AND sampled_at_ms = ?;""",
230
+ (cycle_id, sampled_at_ms),
231
+ ).fetchone()
232
+ if existing is not None:
233
+ return {
234
+ "status": "idempotent_duplicate",
235
+ "observation_id": existing["observation_id"],
236
+ "used_percent": existing["used_percent"],
237
+ "anomaly_status": existing["anomaly_status"],
238
+ }
239
+
240
+ obs_id = str(uuid.uuid4())
241
+ created_at = now_ms()
242
+ conn.execute(
243
+ """INSERT INTO quota_observations (
244
+ observation_id, account_id, bucket_id, window_duration_mins,
245
+ resets_at_ms, baseline_generation, cycle_id, sampled_at_ms,
246
+ used_percent, sample_source, run_id, created_at_ms
247
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);""",
248
+ (obs_id, resolved_account or "isolated", bucket_id or "primary",
249
+ window_duration_mins, resets_at_ms, baseline_generation, cycle_id,
250
+ sampled_at_ms, used_percent, sample_source, run_id, created_at),
251
+ )
252
+ revision = conn.execute(
253
+ "SELECT current_revision FROM quota_ledger_metadata WHERE id = 1;"
254
+ ).fetchone()[0] + 1
255
+ created, revoked, invalid = _reconcile_cycle(conn, cycle_id, revision)
256
+ conn.execute(
257
+ """UPDATE quota_ledger_metadata
258
+ SET current_revision = ?, last_rebuilt_at_ms = ? WHERE id = 1;""",
259
+ (revision, created_at),
260
+ )
261
+
262
+ result = {
263
+ "status": "anomaly_detected" if obs_id in invalid else "success",
264
+ "observation_id": obs_id,
265
+ "cycle_id": cycle_id,
266
+ "segments_created": created,
267
+ "segments_revoked": revoked,
268
+ }
269
+ if obs_id in invalid:
270
+ result["anomaly_status"] = "pending_investigation"
271
+ result["reason"] = "Watermark below the preceding accepted sample"
272
+ return result
273
+
274
+
275
+ def _reconcile_cycle(
276
+ conn: sqlite3.Connection, cycle_id: str, revision: int,
277
+ ) -> tuple[list[str], list[str], set[str]]:
278
+ """Derive the canonical timeline from raw evidence, retaining unchanged edges.
279
+
280
+ The caller owns the write transaction. Observation payloads are immutable;
281
+ only their derived validity flags can change when earlier evidence arrives.
282
+ Removed/changed edges invalidate allocations in the same revision. Unchanged
283
+ edges keep their IDs and allocations, including healthy edges after a gap.
284
+ """
285
+ observations = conn.execute(
286
+ """SELECT observation_id, sampled_at_ms, used_percent, is_valid, anomaly_status
287
+ FROM quota_observations WHERE cycle_id = ? ORDER BY sampled_at_ms;""",
288
+ (cycle_id,),
289
+ ).fetchall()
290
+ desired = {}
291
+ invalid = set()
292
+ previous = None
293
+ crosses_anomaly = False
294
+ for obs in observations:
295
+ is_valid = previous is None or obs["used_percent"] >= previous["used_percent"]
296
+ anomaly_status = "normal" if is_valid else "pending_investigation"
297
+ if obs["is_valid"] != int(is_valid) or obs["anomaly_status"] != anomaly_status:
298
+ conn.execute(
299
+ """UPDATE quota_observations SET is_valid = ?, anomaly_status = ?
300
+ WHERE observation_id = ?;""",
301
+ (int(is_valid), anomaly_status, obs["observation_id"]),
302
+ )
303
+ if not is_valid:
304
+ invalid.add(obs["observation_id"])
305
+ crosses_anomaly = True
306
+ continue
307
+ if previous is not None:
308
+ key = (previous["observation_id"], obs["observation_id"])
309
+ status = "pending_investigation" if crosses_anomaly else "active"
310
+ desired[key] = (previous, obs, status)
311
+ previous = obs
312
+ crosses_anomaly = False
313
+
314
+ current = conn.execute(
315
+ """SELECT * FROM quota_segments
316
+ WHERE cycle_id = ? AND status != 'revoked' ORDER BY start_time_ms;""",
317
+ (cycle_id,),
318
+ ).fetchall()
319
+ created, revoked = [], []
320
+ for segment in current:
321
+ sid = segment["segment_id"]
322
+ key = (segment["start_obs_id"], segment["end_obs_id"])
323
+ target = desired.pop(key, None)
324
+ if target is None:
325
+ conn.execute(
326
+ """UPDATE quota_segments SET status = 'revoked', revoked_revision = ?
327
+ WHERE segment_id = ?;""", (revision, sid),
328
+ )
329
+ revoked.append(sid)
330
+ elif segment["status"] == target[2]:
331
+ continue
332
+ else:
333
+ status = target[2]
334
+ reason = "blocked_by_anomaly" if status == "pending_investigation" else "waiting_attribution"
335
+ conn.execute(
336
+ """UPDATE quota_segments SET status = ?, reason_code = ?,
337
+ attribution_status = 'waiting_weights', unattributed_pp = delta_pp
338
+ WHERE segment_id = ?;""", (status, reason, sid),
339
+ )
340
+ conn.execute(
341
+ "UPDATE quota_allocations SET status = 'revoked' WHERE segment_id = ?;",
342
+ (sid,),
343
+ )
344
+
345
+ for start, end, status in desired.values():
346
+ sid = str(uuid.uuid4())
347
+ delta = end["used_percent"] - start["used_percent"]
348
+ reason = "blocked_by_anomaly" if status == "pending_investigation" else "waiting_attribution"
349
+ conn.execute(
350
+ """INSERT INTO quota_segments (
351
+ segment_id, cycle_id, start_obs_id, end_obs_id,
352
+ start_time_ms, end_time_ms, delta_pp, status,
353
+ attribution_status, unattributed_pp, reason_code,
354
+ has_cross_midnight, created_revision
355
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'waiting_weights', ?, ?, ?, ?);""",
356
+ (sid, cycle_id, start["observation_id"], end["observation_id"],
357
+ start["sampled_at_ms"], end["sampled_at_ms"], delta, status, delta,
358
+ reason, _crosses_midnight(start["sampled_at_ms"], end["sampled_at_ms"]), revision),
359
+ )
360
+ created.append(sid)
361
+ return created, revoked, invalid
362
+
363
+
364
+ def _crosses_midnight(start_ms: int, end_ms: int) -> bool:
365
+ """Determine if interval crosses local calendar midnight."""
366
+ d1 = datetime.fromtimestamp(start_ms / 1000.0)
367
+ d2 = datetime.fromtimestamp(end_ms / 1000.0)
368
+ return d1.date() != d2.date()
369
+
370
+
371
+ def export_quota_summary(
372
+ conn: sqlite3.Connection,
373
+ output_path: Path = QUOTA_SUMMARY_FILE,
374
+ ) -> dict[str, Any]:
375
+ """Export derived quota summary JSON protected by single-writer lock and anti-regression guard."""
376
+ with state_lock(QUOTA_LOCK_KEY) as acquired:
377
+ if not acquired:
378
+ return {"status": "lock_failed"}
379
+
380
+ # Read state inside a single SQLite transaction with snapshot isolation
381
+ with conn:
382
+ if not getattr(conn, "in_transaction", False):
383
+ try:
384
+ conn.execute("BEGIN;")
385
+ except sqlite3.OperationalError:
386
+ pass
387
+
388
+ meta = conn.execute(
389
+ "SELECT current_revision, last_rebuilt_at_ms FROM quota_ledger_metadata WHERE id = 1;"
390
+ ).fetchone()
391
+ current_rev = meta["current_revision"] if meta else 1
392
+
393
+ # Check existing cache to strictly prohibit revision regression
394
+ existing_cache = read_json_object(output_path)
395
+ if existing_cache and isinstance(existing_cache.get("revision"), int):
396
+ if existing_cache["revision"] > current_rev:
397
+ return {
398
+ "status": "skipped_anti_regression",
399
+ "existing_revision": existing_cache["revision"],
400
+ "current_db_revision": current_rev,
401
+ }
402
+
403
+ # Query all distinct cycles in observations
404
+ cycle_ids_rows = conn.execute(
405
+ """
406
+ SELECT DISTINCT cycle_id FROM quota_observations
407
+ ORDER BY cycle_id ASC;
408
+ """
409
+ ).fetchall()
410
+
411
+ cycle_summaries = []
412
+ for c_row in cycle_ids_rows:
413
+ cid = c_row["cycle_id"]
414
+ seg_stats = conn.execute(
415
+ """
416
+ SELECT MIN(start_time_ms) as min_start,
417
+ MAX(end_time_ms) as max_end,
418
+ SUM(delta_pp) as total_observed,
419
+ SUM(unattributed_pp) as total_unattributed
420
+ FROM quota_segments
421
+ WHERE cycle_id = ? AND status = 'active';
422
+ """,
423
+ (cid,),
424
+ ).fetchone()
425
+
426
+ base_obs = conn.execute(
427
+ """
428
+ SELECT used_percent
429
+ FROM quota_observations
430
+ WHERE cycle_id = ? AND is_valid = 1
431
+ ORDER BY sampled_at_ms ASC
432
+ LIMIT 1;
433
+ """,
434
+ (cid,),
435
+ ).fetchone()
436
+ base_val = base_obs["used_percent"] if base_obs else 0.0
437
+
438
+ cm_row = conn.execute(
439
+ """
440
+ SELECT SUM(delta_pp) as cross_midnight_total
441
+ FROM quota_segments
442
+ WHERE cycle_id = ? AND status = 'active' AND has_cross_midnight = 1;
443
+ """,
444
+ (cid,),
445
+ ).fetchone()
446
+ cm_val = cm_row["cross_midnight_total"] if cm_row and cm_row["cross_midnight_total"] else 0.0
447
+
448
+ gap_obs = conn.execute(
449
+ """
450
+ SELECT observation_id, sampled_at_ms, used_percent, anomaly_status
451
+ FROM quota_observations
452
+ WHERE cycle_id = ? AND anomaly_status != 'normal'
453
+ ORDER BY sampled_at_ms ASC;
454
+ """,
455
+ (cid,),
456
+ ).fetchall()
457
+ gap_segs = conn.execute(
458
+ """
459
+ SELECT segment_id, start_time_ms, end_time_ms, delta_pp, reason_code
460
+ FROM quota_segments
461
+ WHERE cycle_id = ? AND status = 'pending_investigation'
462
+ ORDER BY start_time_ms ASC;
463
+ """,
464
+ (cid,),
465
+ ).fetchall()
466
+ gaps = []
467
+ for o in gap_obs:
468
+ gaps.append({
469
+ "observation_id": o["observation_id"],
470
+ "start_time_ms": o["sampled_at_ms"],
471
+ "end_time_ms": o["sampled_at_ms"],
472
+ "used_percent": o["used_percent"],
473
+ "status": o["anomaly_status"],
474
+ "reason": "anomaly_detected",
475
+ })
476
+ for s in gap_segs:
477
+ gaps.append({
478
+ "segment_id": s["segment_id"],
479
+ "start_time_ms": s["start_time_ms"],
480
+ "end_time_ms": s["end_time_ms"],
481
+ "delta_pp": s["delta_pp"],
482
+ "status": "pending_investigation",
483
+ "reason": s["reason_code"] or "blocked_by_anomaly",
484
+ })
485
+
486
+ tot_obs = seg_stats["total_observed"] if seg_stats and seg_stats["total_observed"] else 0.0
487
+ tot_unattr = seg_stats["total_unattributed"] if seg_stats and seg_stats["total_unattributed"] else 0.0
488
+
489
+ cycle_summaries.append(
490
+ {
491
+ "cycle_id": cid,
492
+ "baseline_used_percent": round(base_val, 2),
493
+ "total_observed_pp": round(tot_obs, 2),
494
+ "total_allocated_pp": round(tot_obs - tot_unattr, 2),
495
+ "total_unattributed_pp": round(tot_unattr, 2),
496
+ "coverage_start_ms": seg_stats["min_start"] if seg_stats else None,
497
+ "coverage_end_ms": seg_stats["max_end"] if seg_stats else None,
498
+ "gaps": gaps,
499
+ "cross_midnight_pending_pp": round(cm_val, 2),
500
+ }
501
+ )
502
+
503
+ # Daily usage aggregation based on active segments of canonical (non-isolated) cycles
504
+ # Retain account and bucket dimensions
505
+ segments = conn.execute(
506
+ """
507
+ SELECT s.start_time_ms, s.end_time_ms, s.delta_pp, s.unattributed_pp, s.has_cross_midnight,
508
+ o.account_id, o.bucket_id
509
+ FROM quota_segments s
510
+ JOIN quota_observations o ON s.start_obs_id = o.observation_id
511
+ WHERE s.status = 'active' AND s.cycle_id NOT LIKE 'isolated_%'
512
+ ORDER BY s.start_time_ms ASC;
513
+ """
514
+ ).fetchall()
515
+
516
+ daily_map: dict[tuple[str, str, str], dict[str, Any]] = {}
517
+ for seg in segments:
518
+ acc = seg["account_id"]
519
+ bkt = seg["bucket_id"]
520
+ if seg["has_cross_midnight"]:
521
+ d_start = datetime.fromtimestamp(seg["start_time_ms"] / 1000.0).strftime("%Y-%m-%d")
522
+ d_end = datetime.fromtimestamp(seg["end_time_ms"] / 1000.0).strftime("%Y-%m-%d")
523
+ for d_str in (d_start, d_end):
524
+ key = (acc, bkt, d_str)
525
+ if key not in daily_map:
526
+ daily_map[key] = {
527
+ "account_id": acc,
528
+ "bucket_id": bkt,
529
+ "date": d_str,
530
+ "observed_delta_pp": 0.0,
531
+ "unattributed_pp": 0.0,
532
+ "cross_midnight_pending_pp": 0.0,
533
+ "coverage_status": "has_cross_midnight_pending",
534
+ }
535
+ daily_map[key]["cross_midnight_pending_pp"] += seg["delta_pp"]
536
+ daily_map[key]["coverage_status"] = "has_cross_midnight_pending"
537
+ else:
538
+ dt = datetime.fromtimestamp(seg["start_time_ms"] / 1000.0)
539
+ date_str = dt.strftime("%Y-%m-%d")
540
+ key = (acc, bkt, date_str)
541
+ if key not in daily_map:
542
+ daily_map[key] = {
543
+ "account_id": acc,
544
+ "bucket_id": bkt,
545
+ "date": date_str,
546
+ "observed_delta_pp": 0.0,
547
+ "unattributed_pp": 0.0,
548
+ "cross_midnight_pending_pp": 0.0,
549
+ "coverage_status": "partial_day_observed",
550
+ }
551
+ daily_map[key]["observed_delta_pp"] += seg["delta_pp"]
552
+ daily_map[key]["unattributed_pp"] += seg["unattributed_pp"]
553
+
554
+ daily_list = [
555
+ {
556
+ "account_id": d["account_id"],
557
+ "bucket_id": d["bucket_id"],
558
+ "date": d["date"],
559
+ "observed_delta_pp": round(d["observed_delta_pp"], 1),
560
+ "unattributed_pp": round(d["unattributed_pp"], 1),
561
+ "cross_midnight_pending_pp": round(d["cross_midnight_pending_pp"], 1),
562
+ "coverage_status": d["coverage_status"],
563
+ }
564
+ for d in sorted(daily_map.values(), key=lambda x: (x["account_id"], x["date"]))
565
+ ]
566
+
567
+ # Query session allocations
568
+ session_rows = conn.execute(
569
+ """
570
+ SELECT session_id,
571
+ SUM(allocated_pp) as total_allocated,
572
+ attribution_method
573
+ FROM quota_allocations
574
+ WHERE status = 'active'
575
+ GROUP BY session_id;
576
+ """
577
+ ).fetchall()
578
+
579
+ session_allocations = {}
580
+ for s in session_rows:
581
+ session_allocations[s["session_id"]] = {
582
+ "allocated_pp": round(s["total_allocated"], 1),
583
+ "attribution_status": "fully_attributed",
584
+ "method": s["attribution_method"],
585
+ }
586
+
587
+ payload = {
588
+ "revision": current_rev,
589
+ "exported_at_ms": now_ms(),
590
+ "timezone": time.tzname[0],
591
+ "active_account_id": resolve_account_id(),
592
+ "cycle_summaries": cycle_summaries,
593
+ "daily_usage": daily_list,
594
+ "session_allocations": session_allocations,
595
+ }
596
+
597
+ atomic_json(output_path, payload)
598
+ return {"status": "success", "revision": current_rev}