cctally 1.79.0 → 1.79.1

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.
@@ -11,8 +11,8 @@ This module is the IMPURE counterpart to the pure kernel
11
11
  ``_lib_milestone_history.py``. Honest imports are restricted to pure
12
12
  siblings (``_cctally_core`` kernel + ``_lib_*`` pure kernels, none of which
13
13
  back-import ``cctally``); every impure cctally-namespace symbol
14
- (``get_recent_weeks`` / ``get_milestones_for_week`` /
15
- ``_tui_build_five_hour_milestones`` / ``load_config``) is reached via the
14
+ (``get_recent_weeks`` / ``_tui_build_five_hour_milestones`` / ``load_config``)
15
+ is reached via the
16
16
  call-time ``_cctally()`` accessor so test monkeypatches through the
17
17
  ``cctally`` namespace are preserved.
18
18
 
@@ -24,8 +24,11 @@ host-local offset while boundaries are canonical UTC).
24
24
  """
25
25
  from __future__ import annotations
26
26
 
27
+ import datetime as dt
28
+ import json
27
29
  import sqlite3
28
30
  import sys
31
+ from dataclasses import replace
29
32
 
30
33
  from _cctally_core import make_week_ref, parse_iso_datetime
31
34
  from _cctally_quota import codex_quota_breakdown
@@ -34,9 +37,6 @@ from _lib_display_tz import _resolve_display_tz_obj, format_display_dt
34
37
  from _lib_json_envelope import _iso_z
35
38
  from _lib_quota import QuotaWindowIdentity
36
39
 
37
- import datetime as dt
38
- import json
39
-
40
40
  import _lib_milestone_history as _mh
41
41
 
42
42
  UTC = dt.timezone.utc
@@ -115,7 +115,7 @@ def _navigable_claude_refs(conn: sqlite3.Connection) -> list:
115
115
 
116
116
  Navigable set = weeks with ≥1 ``weekly_usage_snapshots`` row ∪ weeks with
117
117
  ≥1 ``percent_milestones`` row (cost-only weeks excluded). Same-key credit
118
- segments are coalesced to one outer-boundary ref; a defensive
118
+ reset-defined segment remains independently navigable; a defensive
119
119
  milestone-only week absent from ``get_recent_weeks`` is synthesized from
120
120
  its milestone rows' stored boundaries.
121
121
  """
@@ -137,14 +137,104 @@ def _navigable_claude_refs(conn: sqlite3.Connection) -> list:
137
137
  navigable = usage_keys | milestone_keys
138
138
 
139
139
  refs = [r for r in refs if r.key in navigable]
140
- refs = _mh.coalesce_week_refs(refs)
141
-
142
140
  present = {r.key for r in refs}
143
141
  for k in sorted(milestone_keys - present, reverse=True):
144
142
  ref = _synthesize_milestone_only_ref(conn, k)
145
143
  if ref is not None:
146
144
  refs.append(ref)
147
- return refs
145
+ return _derive_claude_reset_cycles(conn, refs)
146
+
147
+
148
+ def _parse_optional_iso(value):
149
+ if not value:
150
+ return None
151
+ try:
152
+ return parse_iso_datetime(value, "milestone_cycle.boundary")
153
+ except (TypeError, ValueError):
154
+ return None
155
+
156
+
157
+ def _claude_storage_boundaries(conn: sqlite3.Connection, key: str):
158
+ """Return the outer retained boundary for one storage date bucket."""
159
+ rows = conn.execute(
160
+ "SELECT week_start_at, week_end_at FROM weekly_usage_snapshots "
161
+ "WHERE week_start_date=? AND week_start_at IS NOT NULL "
162
+ "AND week_end_at IS NOT NULL "
163
+ "UNION ALL "
164
+ "SELECT week_start_at, week_end_at FROM percent_milestones "
165
+ "WHERE week_start_date=? AND week_start_at IS NOT NULL "
166
+ "AND week_end_at IS NOT NULL",
167
+ (key, key),
168
+ ).fetchall()
169
+ pairs = [
170
+ (start, end)
171
+ for row in rows
172
+ if (start := _parse_optional_iso(row[0])) is not None
173
+ and (end := _parse_optional_iso(row[1])) is not None
174
+ and end > start
175
+ ]
176
+ if not pairs:
177
+ return None
178
+ return min(start for start, _end in pairs), max(end for _start, end in pairs)
179
+
180
+
181
+ def _linked_reset_events(conn: sqlite3.Connection, key: str) -> list:
182
+ """Reset rows linked to any retained boundary in a storage bucket."""
183
+ return conn.execute(
184
+ "SELECT DISTINCT e.id, e.effective_reset_at_utc "
185
+ "FROM week_reset_events e "
186
+ "WHERE EXISTS ("
187
+ " SELECT 1 FROM weekly_usage_snapshots s "
188
+ " WHERE s.week_start_date=? AND ("
189
+ " unixepoch(s.week_end_at)=unixepoch(e.old_week_end_at) OR "
190
+ " unixepoch(s.week_end_at)=unixepoch(e.new_week_end_at)"
191
+ " )"
192
+ ") OR EXISTS ("
193
+ " SELECT 1 FROM percent_milestones m "
194
+ " WHERE m.week_start_date=? AND ("
195
+ " unixepoch(m.week_end_at)=unixepoch(e.old_week_end_at) OR "
196
+ " unixepoch(m.week_end_at)=unixepoch(e.new_week_end_at)"
197
+ " )"
198
+ ") "
199
+ "ORDER BY unixepoch(e.effective_reset_at_utc), e.id",
200
+ (key, key),
201
+ ).fetchall()
202
+
203
+
204
+ def _derive_claude_reset_cycles(conn: sqlite3.Connection, refs: list) -> list:
205
+ """Expand storage buckets into provider reset-defined cycles.
206
+
207
+ ``get_recent_weeks`` can split an in-place credit, but an early re-anchor
208
+ whose old and new boundaries both remain under one ``week_start_date``
209
+ only exposes the pre-reset half. The retained snapshot boundary set plus
210
+ ``week_reset_events`` is the authoritative reset ledger for both shapes.
211
+ """
212
+ out: list = []
213
+ by_key: dict = {}
214
+ for ref in refs:
215
+ by_key.setdefault(ref.key, ref)
216
+ for key, template in by_key.items():
217
+ outer = _claude_storage_boundaries(conn, key)
218
+ if outer is None:
219
+ out.append(template)
220
+ continue
221
+ start, end = outer
222
+ cuts = []
223
+ for event in _linked_reset_events(conn, key):
224
+ effective = _parse_optional_iso(event["effective_reset_at_utc"])
225
+ if effective is not None and start < effective < end:
226
+ cuts.append(effective)
227
+ boundaries = [start, *sorted(set(cuts)), end]
228
+ cycles = []
229
+ for cycle_start, cycle_end in zip(boundaries, boundaries[1:]):
230
+ cycles.append(replace(
231
+ template,
232
+ week_start_at=cycle_start.isoformat(timespec="seconds"),
233
+ week_end_at=cycle_end.isoformat(timespec="seconds"),
234
+ week_end=(cycle_end - dt.timedelta(seconds=1)).date(),
235
+ ))
236
+ out.extend(reversed(cycles))
237
+ return _cctally()._apply_overlap_clamp_to_weekrefs(out)
148
238
 
149
239
 
150
240
  def _synthesize_milestone_only_ref(conn: sqlite3.Connection, key: str):
@@ -181,31 +271,65 @@ def _current_claude_week_key(conn: sqlite3.Connection) -> "str | None":
181
271
  return row[0] if row is not None else None
182
272
 
183
273
 
184
- def _index_entry(conn, ref, current_key, tz) -> dict:
185
- counts = conn.execute(
186
- "SELECT COUNT(*), COUNT(DISTINCT reset_event_id), MAX(captured_at_utc) "
187
- "FROM percent_milestones WHERE week_start_date = ?",
188
- (ref.key,),
189
- ).fetchone()
190
- milestone_count = int(counts[0] or 0)
191
- segment_count = int(counts[1] or 0)
192
- max_captured = counts[2]
274
+ def _claude_cycle_key(ref) -> str:
275
+ return dashboard_resource_key(
276
+ "milestone_cycle", "claude", ref.key,
277
+ ref.week_start_at or "", ref.week_end_at or "",
278
+ )
279
+
280
+
281
+ def _claude_cycle_rows(conn: sqlite3.Connection, ref) -> list:
282
+ cohort_id = 0
283
+ if ref.week_start_at:
284
+ row = conn.execute(
285
+ "SELECT e.id FROM week_reset_events e "
286
+ "WHERE unixepoch(e.effective_reset_at_utc)=unixepoch(?) "
287
+ "AND (EXISTS ("
288
+ " SELECT 1 FROM weekly_usage_snapshots s "
289
+ " WHERE s.week_start_date=? AND ("
290
+ " unixepoch(s.week_end_at)=unixepoch(e.old_week_end_at) OR "
291
+ " unixepoch(s.week_end_at)=unixepoch(e.new_week_end_at)"
292
+ " )"
293
+ ") OR EXISTS ("
294
+ " SELECT 1 FROM percent_milestones m "
295
+ " WHERE m.week_start_date=? AND ("
296
+ " unixepoch(m.week_end_at)=unixepoch(e.old_week_end_at) OR "
297
+ " unixepoch(m.week_end_at)=unixepoch(e.new_week_end_at)"
298
+ " )"
299
+ ")) ORDER BY e.id DESC LIMIT 1",
300
+ (ref.week_start_at, ref.key, ref.key),
301
+ ).fetchone()
302
+ if row is not None:
303
+ cohort_id = int(row[0])
304
+ return conn.execute(
305
+ "SELECT * FROM percent_milestones WHERE week_start_date=? "
306
+ "AND reset_event_id=? "
307
+ "ORDER BY unixepoch(captured_at_utc) ASC, percent_threshold ASC",
308
+ (ref.key, cohort_id),
309
+ ).fetchall()
310
+
193
311
 
312
+ def _index_entry(conn, ref, current_cycle_key, tz) -> dict:
313
+ rows = _claude_cycle_rows(conn, ref)
314
+ milestone_count = len(rows)
315
+ segment_count = 1 if rows else 0
316
+ max_captured = max((r["captured_at_utc"] for r in rows), default=None)
194
317
  start_z = _to_iso_z(ref.week_start_at)
195
318
  end_z = _to_iso_z(ref.week_end_at)
196
319
  block_count = _count_blocks(conn, start_z, end_z)
320
+ key = _claude_cycle_key(ref)
197
321
 
198
322
  return {
199
- "key": ref.key,
323
+ "key": key,
200
324
  "start_at_utc": start_z,
201
325
  "end_at_utc": end_z,
202
326
  "label": _week_label(ref, tz),
203
- "is_current": ref.key == current_key,
327
+ "is_current": key == current_cycle_key,
204
328
  "milestone_count": milestone_count,
205
329
  "block_count": block_count,
206
330
  "segment_count": segment_count,
207
331
  "detail_stamp": _mh.compute_detail_stamp(
208
- ref.key, milestone_count, block_count, segment_count, max_captured
332
+ key, milestone_count, block_count, segment_count, max_captured
209
333
  ),
210
334
  }
211
335
 
@@ -213,16 +337,21 @@ def _index_entry(conn, ref, current_key, tz) -> dict:
213
337
  def build_claude_week_index(conn: sqlite3.Connection) -> list:
214
338
  """Newest-first navigable Claude week index (spec §1a, §3).
215
339
 
216
- One entry per navigable week; credit-split weeks collapse to a single
217
- entry (segment structure lives in the detail payload). ``detail_stamp``
218
- is a content digest that moves when the week's underlying rows change so
219
- the client cache revalidates.
340
+ One entry per effective reset-defined cycle. Multiple cycles may share one
341
+ storage ``week_start_date`` but always have distinct opaque keys.
220
342
  """
221
343
  refs = _navigable_claude_refs(conn)
222
344
  current_key = _current_claude_week_key(conn)
345
+ current_refs = [r for r in refs if r.key == current_key]
346
+ current_ref = max(
347
+ current_refs,
348
+ key=lambda r: r.week_start_at or "",
349
+ default=None,
350
+ )
351
+ current_cycle_key = _claude_cycle_key(current_ref) if current_ref else None
223
352
  tz = _resolve_display_tz()
224
- entries = [_index_entry(conn, ref, current_key, tz) for ref in refs]
225
- entries.sort(key=lambda e: e["key"], reverse=True)
353
+ entries = [_index_entry(conn, ref, current_cycle_key, tz) for ref in refs]
354
+ entries.sort(key=lambda e: e["start_at_utc"] or "", reverse=True)
226
355
  return entries
227
356
 
228
357
 
@@ -244,58 +373,6 @@ def _shape_weekly_milestone(row) -> dict:
244
373
  }
245
374
 
246
375
 
247
- def _build_segments(rows) -> list:
248
- """Group milestone rows into segments (by ``reset_event_id``), ordered
249
- chronologically by each segment's first ``captured_at_utc``; rows within a
250
- segment ascend by capture time then threshold (spec §1b)."""
251
- groups: dict = {}
252
- for r in rows:
253
- seg = int(r["reset_event_id"] or 0)
254
- groups.setdefault(seg, []).append(r)
255
- ordered: list = []
256
- for seg, seg_rows in groups.items():
257
- seg_rows.sort(key=lambda r: (r["captured_at_utc"], int(r["percent_threshold"])))
258
- first_cap = seg_rows[0]["captured_at_utc"]
259
- ordered.append(
260
- (first_cap, seg, [_shape_weekly_milestone(r) for r in seg_rows])
261
- )
262
- ordered.sort(key=lambda t: (t[0], t[1]))
263
- return [{"reset_event_id": seg, "milestones": ms} for (_c, seg, ms) in ordered]
264
-
265
-
266
- def _build_dividers(conn: sqlite3.Connection, segments: list) -> list:
267
- """Credit dividers between consecutive segments (spec §1b, Q4).
268
-
269
- A divider is emitted for each later segment whose ``reset_event_id``
270
- resolves to an in-place-credit ``week_reset_events`` row
271
- (``old_week_end_at == effective_reset_at_utc``). It carries the effective
272
- time + prior percent (``observed_pre_credit_pct``); no post/delta value is
273
- recorded for weekly credits.
274
- """
275
- dividers: list = []
276
- for later in segments[1:]:
277
- seg_id = later["reset_event_id"]
278
- if not seg_id:
279
- continue
280
- ev = conn.execute(
281
- "SELECT effective_reset_at_utc, observed_pre_credit_pct, old_week_end_at "
282
- "FROM week_reset_events WHERE id = ?",
283
- (seg_id,),
284
- ).fetchone()
285
- if ev is None:
286
- continue
287
- if ev["old_week_end_at"] != ev["effective_reset_at_utc"]:
288
- continue # not an in-place credit → no divider
289
- prior = ev["observed_pre_credit_pct"]
290
- dividers.append(
291
- {
292
- "effective_at_utc": _to_iso_z(ev["effective_reset_at_utc"]),
293
- "prior_percent": None if prior is None else float(prior),
294
- }
295
- )
296
- return dividers
297
-
298
-
299
376
  def _load_block_credits(conn: sqlite3.Connection, window_key: int) -> list:
300
377
  """5h in-place credit rows for a block, ascending by effective time —
301
378
  same wire shape as the envelope's ``five_hour_block.credits``."""
@@ -354,30 +431,21 @@ def _build_blocks(conn: sqlite3.Connection, start_iso, end_iso) -> list:
354
431
  return out
355
432
 
356
433
 
357
- def build_claude_week_detail(
358
- conn: sqlite3.Connection, week_start_date: str
359
- ) -> "dict | None":
360
- """Complete payload for one Claude week (spec §1b). ``None`` for an
361
- unknown/non-navigable key.
362
-
363
- Segments carry ALL ``reset_event_id`` cohorts (both pre- and post-credit)
364
- ordered chronologically; ``dividers`` sit between consecutive segments;
365
- ``blocks`` are the intersecting 5h blocks (dual-membership straddlers
366
- included). Boundary/label/``is_current``/``detail_stamp`` are taken from
367
- the index entry so the detail and index agree exactly.
368
- """
369
- c = _cctally()
370
- entry = None
371
- for e in build_claude_week_index(conn):
372
- if e["key"] == week_start_date:
373
- entry = e
374
- break
375
- if entry is None:
434
+ def build_claude_week_detail(conn: sqlite3.Connection, key: str) -> "dict | None":
435
+ """Complete payload for one reset-defined Claude cycle."""
436
+ refs = _navigable_claude_refs(conn)
437
+ ref = next((candidate for candidate in refs if _claude_cycle_key(candidate) == key), None)
438
+ if ref is None:
376
439
  return None
377
-
378
- rows = c.get_milestones_for_week(conn, week_start_date)
379
- segments = _build_segments(rows)
380
- dividers = _build_dividers(conn, segments)
440
+ entry = next(e for e in build_claude_week_index(conn) if e["key"] == key)
441
+ rows = _claude_cycle_rows(conn, ref)
442
+ segment_key = dashboard_resource_key(
443
+ "milestone_segment", "claude", ref.key,
444
+ ref.week_start_at or "", ref.week_end_at or "",
445
+ )
446
+ segments = ([{"key": segment_key,
447
+ "milestones": [_shape_weekly_milestone(r) for r in rows]}]
448
+ if rows else [])
381
449
  blocks = _build_blocks(conn, entry["start_at_utc"], entry["end_at_utc"])
382
450
 
383
451
  return {
@@ -389,7 +457,7 @@ def build_claude_week_detail(
389
457
  "is_current": entry["is_current"],
390
458
  "detail_stamp": entry["detail_stamp"],
391
459
  "segments": segments,
392
- "dividers": dividers,
460
+ "dividers": [],
393
461
  "blocks": blocks,
394
462
  }
395
463
 
@@ -400,9 +468,9 @@ def build_claude_week_detail(
400
468
  # (quota_window_blocks, stats.db) — explicitly NOT the bounded public quota
401
469
  # read model (35-day / 1000-observation / 250-row caps). Boundaries are the
402
470
  # effective clipped, non-overlapping periods: a provider early re-anchor
403
- # ends the prior cycle at min(raw reset, next nominal start). Cycle keys
404
- # embed the full native identity tuple so two identities sharing a
405
- # resets_at get distinct keys and resolve exactly.
471
+ # ends the prior cycle at min(raw reset, next nominal start). One full native
472
+ # identity is selected per physical reset; the opaque cycle key retains that
473
+ # identity so detail resolves the exact selected ledger.
406
474
  #
407
475
  # `_codex_weekly_periods` (bin/_cctally_dashboard_sources.py) computes the
408
476
  # same clip formula but collapses across roots (losing the per-identity key)
@@ -490,6 +558,10 @@ class _CodexCycle:
490
558
  def key_parts(self) -> tuple:
491
559
  return (self.root, self.limit, self.slot, self.window, self.reset_iso)
492
560
 
561
+ @property
562
+ def identity_parts(self) -> tuple:
563
+ return (self.root, self.limit, self.slot, self.window)
564
+
493
565
  @property
494
566
  def key(self) -> str:
495
567
  return dashboard_resource_key("milestone_cycle", "codex", *self.key_parts)
@@ -499,9 +571,62 @@ class _CodexCycle:
499
571
  return dashboard_resource_key("block", "codex", *self.key_parts)
500
572
 
501
573
 
502
- def _load_codex_cycles(stats_conn, root_keys, *, include_orphaned=False) -> list:
503
- """Non-model-scoped 7-day (window_minutes=10080) cycles for the identity
504
- roots, effective-clipped per identity. Unbounded (no 35-day / row cap)."""
574
+ def _identity_matches_cycle(identity, cyc) -> bool:
575
+ return (
576
+ identity is not None
577
+ and getattr(identity, "source_root_key", None) == cyc.root
578
+ and getattr(identity, "logical_limit_key", None) == cyc.limit
579
+ and getattr(identity, "observed_slot", None) == cyc.slot
580
+ and getattr(identity, "window_minutes", None) == cyc.window
581
+ )
582
+
583
+
584
+ def _choose_physical_cycle(candidates: list, *, preferred_identity=None) -> _CodexCycle:
585
+ preferred = [c for c in candidates if _identity_matches_cycle(preferred_identity, c)]
586
+ pool = preferred or candidates
587
+ return max(
588
+ pool,
589
+ key=lambda c: (
590
+ -1.0 if c.current_percent is None else c.current_percent,
591
+ c.reset,
592
+ c.identity_parts,
593
+ ),
594
+ )
595
+
596
+
597
+ def _canonical_identity_cycles(cycles: list) -> list:
598
+ """Jitter-collapse rows within each full native identity."""
599
+ groups: dict = {}
600
+ for cyc in cycles:
601
+ groups.setdefault(cyc.identity_parts, []).append(cyc)
602
+ return [
603
+ _canonicalize_codex_cluster(cluster)
604
+ for members in groups.values()
605
+ for cluster in _mh.cluster_by_reset_jitter(
606
+ members, reset_key=lambda c: c.reset.timestamp()
607
+ )
608
+ ]
609
+
610
+
611
+ def _select_physical_cycles(cycles: list, *, preferred_identity=None) -> list:
612
+ """Select one full identity per physical reset boundary, then clip globally."""
613
+ identity_cycles = _canonical_identity_cycles(cycles)
614
+ selected = [
615
+ _choose_physical_cycle(cluster, preferred_identity=preferred_identity)
616
+ for cluster in _mh.cluster_by_reset_jitter(
617
+ identity_cycles, reset_key=lambda c: c.reset.timestamp()
618
+ )
619
+ ]
620
+ selected.sort(key=lambda c: (c.start, c.reset, c.identity_parts))
621
+ for index, cyc in enumerate(selected):
622
+ next_start = selected[index + 1].start if index + 1 < len(selected) else None
623
+ cyc.end = min(cyc.reset, next_start) if next_start is not None else cyc.reset
624
+ return [c for c in selected if c.end > c.start]
625
+
626
+
627
+ def _load_codex_cycles(stats_conn, root_keys, *, include_orphaned=False,
628
+ preferred_identity=None) -> list:
629
+ """Unbounded reset-defined 7-day cycles, one selected identity per boundary."""
505
630
  roots = tuple(sorted({r for r in root_keys if isinstance(r, str) and r}))
506
631
  if not roots:
507
632
  return []
@@ -528,34 +653,9 @@ def _load_codex_cycles(stats_conn, root_keys, *, include_orphaned=False) -> list
528
653
  continue
529
654
  cycles.append(cyc)
530
655
 
531
- # Canonicalize per identity (root, limit, slot): jitter-cluster the raw
532
- # observations so one physical weekly reset — surfacing as several rows
533
- # whose ``resets_at`` differ by seconds — becomes ONE cycle instead of a
534
- # fan of degenerate 1-second spans (ui-qa P2). Genuine early re-anchors
535
- # (hours apart) stay distinct (see ``cluster_by_reset_jitter``).
536
- groups: dict = {}
537
- for cyc in cycles:
538
- groups.setdefault((cyc.root, cyc.limit, cyc.slot), []).append(cyc)
539
- clustered: list = []
540
- for members in groups.values():
541
- for cluster in _mh.cluster_by_reset_jitter(
542
- members, reset_key=lambda c: c.reset.timestamp()
543
- ):
544
- clustered.append(_canonicalize_codex_cluster(cluster))
545
-
546
- # Effective clip per identity: end each canonical cycle at the NEXT
547
- # canonical cycle's start (min with its own reset), non-overlapping.
548
- cgroups: dict = {}
549
- for cyc in clustered:
550
- cgroups.setdefault((cyc.root, cyc.limit, cyc.slot), []).append(cyc)
551
- for members in cgroups.values():
552
- members.sort(key=lambda c: c.start)
553
- for i, cyc in enumerate(members):
554
- nxt = members[i + 1].start if i + 1 < len(members) else None
555
- cyc.end = min(cyc.reset, nxt) if nxt is not None else cyc.reset
556
- clustered = [c for c in clustered if c.end > c.start]
557
- clustered.sort(key=lambda c: c.reset, reverse=True)
558
- return clustered
656
+ selected = _select_physical_cycles(cycles, preferred_identity=preferred_identity)
657
+ selected.sort(key=lambda c: c.start, reverse=True)
658
+ return selected
559
659
 
560
660
 
561
661
  def _canonicalize_codex_cluster(members: list) -> "_CodexCycle":
@@ -596,12 +696,12 @@ def _codex_is_current(cyc, identity, now_utc) -> bool:
596
696
 
597
697
 
598
698
  def _codex_milestone_count(stats_conn, cyc) -> tuple[int, str | None]:
599
- """Milestone count + max captured-at over the cluster's union — every
600
- jittered member reset contributes (rows split across sibling resets)."""
699
+ """Unique threshold count + max captured-at for one selected identity."""
601
700
  resets = cyc.member_reset_isos
602
701
  placeholders = ",".join("unixepoch(?)" for _ in resets)
603
702
  row = stats_conn.execute(
604
- "SELECT COUNT(*), MAX(captured_at_utc) FROM quota_percent_milestones "
703
+ "SELECT COUNT(DISTINCT percent_threshold), MAX(captured_at_utc) "
704
+ "FROM quota_percent_milestones "
605
705
  "WHERE source='codex' AND source_root_key=? AND logical_limit_key=? "
606
706
  " AND observed_slot=? AND window_minutes=? "
607
707
  f" AND unixepoch(resets_at_utc) IN ({placeholders}) AND orphaned_at IS NULL",
@@ -611,8 +711,7 @@ def _codex_milestone_count(stats_conn, cyc) -> tuple[int, str | None]:
611
711
 
612
712
 
613
713
  def _codex_five_hour_rows(stats_conn, cyc, *, include_orphaned=False) -> list:
614
- """Retained 5h (window_minutes=300) blocks for this cycle's identity
615
- (root + observed_slot + limit_id) intersecting [start, end)."""
714
+ """Every retained 5h block on the selected root intersecting [start, end)."""
616
715
  orphan_clause = "" if include_orphaned else "AND orphaned_at IS NULL "
617
716
  return stats_conn.execute(
618
717
  "SELECT source_root_key, logical_limit_key, observed_slot, "
@@ -621,12 +720,12 @@ def _codex_five_hour_rows(stats_conn, cyc, *, include_orphaned=False) -> list:
621
720
  "FROM quota_window_blocks "
622
721
  "WHERE source='codex' AND window_minutes=300 "
623
722
  f"{orphan_clause}"
624
- "AND source_root_key=? AND observed_slot=? AND limit_id IS ? "
723
+ "AND source_root_key=? "
625
724
  "AND unixepoch(nominal_start_at_utc) < unixepoch(?) "
626
725
  "AND unixepoch(resets_at_utc) > unixepoch(?) "
627
726
  "ORDER BY unixepoch(nominal_start_at_utc) ASC",
628
- (cyc.root, cyc.slot, cyc.limit_id,
629
- cyc.end.astimezone(UTC).isoformat(), cyc.start.astimezone(UTC).isoformat()),
727
+ (cyc.root, cyc.end.astimezone(UTC).isoformat(),
728
+ cyc.start.astimezone(UTC).isoformat()),
630
729
  ).fetchall()
631
730
 
632
731
 
@@ -645,10 +744,11 @@ def _codex_five_hour_clusters(stats_conn, cyc, *, include_orphaned=False) -> lis
645
744
  if block.start is None or block.reset is None:
646
745
  continue
647
746
  blocks.append(block)
747
+ identity_clusters = _canonical_identity_cycles(blocks)
648
748
  clusters = [
649
- _canonicalize_codex_cluster(members)
749
+ _choose_physical_cycle(members)
650
750
  for members in _mh.cluster_by_reset_jitter(
651
- blocks, reset_key=lambda b: b.reset.timestamp()
751
+ identity_clusters, reset_key=lambda b: b.reset.timestamp()
652
752
  )
653
753
  ]
654
754
  clusters.sort(key=lambda b: b.start)
@@ -686,11 +786,14 @@ def _codex_cycle_label(cyc, tz) -> str:
686
786
 
687
787
  def build_codex_cycle_index(stats_conn, *, identity, now_utc) -> list:
688
788
  """Newest-first Codex cycle index over the durable projection (spec §1c,
689
- §3). Enumerates cycles of the hero-selected identity's roots with no depth
690
- cap; one entry per (root, limit, slot, reset) cycle."""
789
+ §3). Enumerates the hero root's reset-defined ledger with no depth cap;
790
+ one selected full native identity per physical reset."""
691
791
  now = now_utc.astimezone(UTC) if now_utc.tzinfo else now_utc.replace(tzinfo=UTC)
692
792
  tz = _resolve_display_tz()
693
- cycles = _load_codex_cycles(stats_conn, getattr(identity, "source_root_keys", ()))
793
+ cycles = _load_codex_cycles(
794
+ stats_conn, getattr(identity, "source_root_keys", ()),
795
+ preferred_identity=getattr(identity, "quota_identity", None),
796
+ )
694
797
  return [_codex_cycle_entry(stats_conn, c, identity, now, tz) for c in cycles]
695
798
 
696
799
 
@@ -753,8 +856,19 @@ def _union_cluster_milestones(cluster, block_key, speed, cache_conn, stats_conn)
753
856
  _shape_codex_milestone(r, key_parts=member.key_parts, block_key=block_key)
754
857
  for r in breakdown
755
858
  )
756
- shaped.sort(key=lambda m: (m["captured_at"] or "", m["percent"]))
757
- return shaped
859
+ # One physical quota ledger has one crossing per integer threshold. Jitter
860
+ # siblings can contribute missing evidence, but never duplicate a row.
861
+ by_percent: dict[int, dict] = {}
862
+ for row in shaped:
863
+ percent = int(row["percent"])
864
+ prior = by_percent.get(percent)
865
+ if prior is None or (row["captured_at"] or "", row["key"]) < (
866
+ prior["captured_at"] or "", prior["key"]
867
+ ):
868
+ by_percent[percent] = row
869
+ return sorted(
870
+ by_percent.values(), key=lambda m: (m["captured_at"] or "", m["percent"])
871
+ )
758
872
 
759
873
 
760
874
  def _codex_cycle_blocks(stats_conn, cache_conn, cyc, speed) -> "list | None":
@@ -801,7 +915,8 @@ def build_codex_cycle_detail(
801
915
  tz = _resolve_display_tz()
802
916
  try:
803
917
  cycles = _load_codex_cycles(
804
- stats_conn, getattr(identity, "source_root_keys", ())
918
+ stats_conn, getattr(identity, "source_root_keys", ()),
919
+ preferred_identity=getattr(identity, "quota_identity", None),
805
920
  )
806
921
  except sqlite3.Error:
807
922
  return (None, "projection_incoherent")
@@ -813,6 +928,7 @@ def build_codex_cycle_detail(
813
928
  orphaned = _load_codex_cycles(
814
929
  stats_conn, getattr(identity, "source_root_keys", ()),
815
930
  include_orphaned=True,
931
+ preferred_identity=getattr(identity, "quota_identity", None),
816
932
  )
817
933
  except sqlite3.Error:
818
934
  return (None, "projection_incoherent")
@@ -839,7 +955,12 @@ def build_codex_cycle_detail(
839
955
  "label": entry["label"],
840
956
  "is_current": entry["is_current"],
841
957
  "detail_stamp": entry["detail_stamp"],
842
- "segments": [{"reset_event_id": 0, "milestones": milestones}],
958
+ "segments": [{
959
+ "key": dashboard_resource_key(
960
+ "milestone_segment", "codex", *match.key_parts
961
+ ),
962
+ "milestones": milestones,
963
+ }],
843
964
  "dividers": [],
844
965
  "blocks": blocks,
845
966
  }