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.
- codex_flow/__init__.py +28 -0
- codex_flow/__main__.py +9 -0
- codex_flow/cli.py +242 -0
- codex_flow/data/LICENSE +21 -0
- codex_flow/data/README.en.md +303 -0
- codex_flow/data/README.md +305 -0
- codex_flow/data/VERSION +1 -0
- codex_flow/data/apps/chatgpt-mcp/README.md +86 -0
- codex_flow/data/apps/chatgpt-mcp/__init__.py +1 -0
- codex_flow/data/apps/chatgpt-mcp/adapter.py +458 -0
- codex_flow/data/apps/chatgpt-mcp/server.py +358 -0
- codex_flow/data/apps/chatgpt-mcp/widget.html +927 -0
- codex_flow/data/apps/macos-overlay/README.en.md +121 -0
- codex_flow/data/apps/macos-overlay/README.md +123 -0
- codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayRuntimeState.swift +126 -0
- codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayScreenGeometry.swift +82 -0
- codex_flow/data/apps/macos-overlay/Sources/Controllers/OverlayWindowController.swift +1052 -0
- codex_flow/data/apps/macos-overlay/Sources/Localization.swift +197 -0
- codex_flow/data/apps/macos-overlay/Sources/Models/TelemetryData.swift +1557 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/AccountSnapshotService.swift +1101 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/FlowPilotInstanceLock.swift +153 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/IPCServer.swift +298 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/TelemetryQueryEngine.swift +800 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/TelemetryWatcher.swift +135 -0
- codex_flow/data/apps/macos-overlay/Sources/Services/UpdateService.swift +610 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/AccountView.swift +610 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/AnalyticsView.swift +566 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/AutostartView.swift +293 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/BubbleView.swift +317 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/HistoryView.swift +1124 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/HoverRevealText.swift +165 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/InspectorSkillsToolsView.swift +121 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/LogoView.swift +182 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/SleekSwitch.swift +117 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/StrategyModeView.swift +561 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/SummaryView.swift +1273 -0
- codex_flow/data/apps/macos-overlay/Sources/Views/UpdateView.swift +352 -0
- codex_flow/data/apps/macos-overlay/Sources/main.swift +340 -0
- codex_flow/data/apps/macos-overlay/Tests/OverlayScreenGeometryTests.swift +163 -0
- codex_flow/data/apps/macos-overlay/Tests/TelemetryPhase1ContractTests.swift +357 -0
- codex_flow/data/apps/macos-overlay/Tests/TelemetryQueryEngineConcurrencyTests.swift +221 -0
- codex_flow/data/apps/macos-overlay/Tests/TelemetryQuotaSelectionTests.swift +158 -0
- codex_flow/data/apps/macos-overlay/Tests/TelemetryWorkerTokenTests.swift +122 -0
- codex_flow/data/apps/macos-overlay/build.sh +75 -0
- codex_flow/data/benchmark/corpus.json +103 -0
- codex_flow/data/benchmark/manifest.example.json +41 -0
- codex_flow/data/benchmark/manifest.schema.json +137 -0
- codex_flow/data/benchmark/prices/gpt-5.6-2026-08-30.json +5 -0
- codex_flow/data/benchmark/profiles.json +90 -0
- codex_flow/data/benchmark/schema.json +77 -0
- codex_flow/data/benchmark/tasks.json +50 -0
- codex_flow/data/completions/codex-flow.bash +34 -0
- codex_flow/data/completions/codex-flow.zsh +52 -0
- codex_flow/data/glama.json +6 -0
- codex_flow/data/install-release.ps1 +126 -0
- codex_flow/data/install-release.sh +155 -0
- codex_flow/data/install.ps1 +349 -0
- codex_flow/data/install.sh +362 -0
- codex_flow/data/policy/benchmark.toml +49 -0
- codex_flow/data/policy/defaults.toml +70 -0
- codex_flow/data/scripts/analyze-benchmark.py +510 -0
- codex_flow/data/scripts/benchmark-local.py +171 -0
- codex_flow/data/scripts/check-recommendation.py +277 -0
- codex_flow/data/scripts/doctor.py +449 -0
- codex_flow/data/scripts/generate-release-manifest.py +74 -0
- codex_flow/data/scripts/localization.py +192 -0
- codex_flow/data/scripts/manage-hooks.py +448 -0
- codex_flow/data/scripts/manage-instructions.py +389 -0
- codex_flow/data/scripts/manage-shell.py +151 -0
- codex_flow/data/scripts/materialize-corpus.py +193 -0
- codex_flow/data/scripts/menu.py +646 -0
- codex_flow/data/scripts/migrations/0001_update_settings.py +80 -0
- codex_flow/data/scripts/package-release.py +132 -0
- codex_flow/data/scripts/render-benchmark-report.py +292 -0
- codex_flow/data/scripts/run-benchmark.py +829 -0
- codex_flow/data/scripts/strategies/__init__.py +28 -0
- codex_flow/data/scripts/strategies/balanced.py +115 -0
- codex_flow/data/scripts/strategies/base.py +363 -0
- codex_flow/data/scripts/strategies/efficient.py +158 -0
- codex_flow/data/scripts/strategies/lifecycle_runtime.py +590 -0
- codex_flow/data/scripts/strategies/quality.py +209 -0
- codex_flow/data/scripts/strategies/speed.py +108 -0
- codex_flow/data/scripts/strategies/task_budget_runtime.py +644 -0
- codex_flow/data/scripts/strategies/task_phase_runtime.py +341 -0
- codex_flow/data/scripts/strategies/work_unit_runtime.py +421 -0
- codex_flow/data/scripts/strategy_runtime.py +1091 -0
- codex_flow/data/scripts/telemetry.py +400 -0
- codex_flow/data/scripts/telemetry_core/__init__.py +192 -0
- codex_flow/data/scripts/telemetry_core/app_server.py +1192 -0
- codex_flow/data/scripts/telemetry_core/collector.py +1247 -0
- codex_flow/data/scripts/telemetry_core/common.py +421 -0
- codex_flow/data/scripts/telemetry_core/latency.py +593 -0
- codex_flow/data/scripts/telemetry_core/query.py +427 -0
- codex_flow/data/scripts/telemetry_core/quota_ledger.py +598 -0
- codex_flow/data/scripts/telemetry_core/render.py +460 -0
- codex_flow/data/scripts/telemetry_core/repair.py +223 -0
- codex_flow/data/scripts/ui.py +266 -0
- codex_flow/data/scripts/update-homebrew-formula.py +146 -0
- codex_flow/data/scripts/update_runtime_config.py +134 -0
- codex_flow/data/scripts/updater.py +1718 -0
- codex_flow/data/smithery.yaml +18 -0
- codex_flow/data/templates/agents/worker-explorer.toml +24 -0
- codex_flow/data/templates/agents/worker-implementer.toml +49 -0
- codex_flow/data/templates/agents/worker-reviewer.toml +25 -0
- codex_flow/data/templates/flow-pilot-instructions.md +35 -0
- codex_flow/data/templates/skills/flow-pilot/SKILL.md +577 -0
- codex_flow/mcp.py +35 -0
- codex_flow-2.1.13.dist-info/METADATA +342 -0
- codex_flow-2.1.13.dist-info/RECORD +113 -0
- codex_flow-2.1.13.dist-info/WHEEL +5 -0
- codex_flow-2.1.13.dist-info/entry_points.txt +3 -0
- codex_flow-2.1.13.dist-info/licenses/LICENSE +21 -0
- 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}
|