cctally 1.7.2 → 1.7.4

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.
@@ -192,28 +192,23 @@ def _cctally():
192
192
  return sys.modules["cctally"]
193
193
 
194
194
 
195
+ # === Honest imports from extracted homes ===================================
196
+ # Spec 2026-05-17-cctally-core-kernel-extraction.md §3.3.
197
+ from _cctally_core import eprint, _now_utc
198
+ from _cctally_config import save_config
199
+
200
+
195
201
  # === Module-level back-ref shims for helpers that STAY in bin/cctally ======
196
202
  # Each shim resolves ``sys.modules['cctally'].X`` at CALL TIME (not bind
197
203
  # time), so monkeypatches on cctally's namespace propagate into the moved
198
- # code unchanged. Mirrors the precedent established in
199
- # ``bin/_cctally_record.py`` (34 shims), ``bin/_cctally_cache.py``
200
- # (4 shims), and ``bin/_cctally_db.py`` (4 shims).
201
- def eprint(*args, **kwargs):
202
- return sys.modules["cctally"].eprint(*args, **kwargs)
203
-
204
-
205
- def _now_utc(*args, **kwargs):
206
- return sys.modules["cctally"]._now_utc(*args, **kwargs)
207
-
208
-
204
+ # code unchanged. `load_config` STAYS as a shim even though its natural
205
+ # home is _cctally_config — tests monkeypatch it via `ns["load_config"]`
206
+ # (16 sites, audited 2026-05-17); direct import would silently bypass.
207
+ # See spec §3.5 (carve-out) and §3.7 (stays-on-shim allowlist).
209
208
  def load_config(*args, **kwargs):
210
209
  return sys.modules["cctally"].load_config(*args, **kwargs)
211
210
 
212
211
 
213
- def save_config(*args, **kwargs):
214
- return sys.modules["cctally"].save_config(*args, **kwargs)
215
-
216
-
217
212
  def _release_read_latest_release_version(*args, **kwargs):
218
213
  return sys.modules["cctally"]._release_read_latest_release_version(
219
214
  *args, **kwargs
@@ -2114,7 +2109,7 @@ def _should_show_update_banner(
2114
2109
  return False
2115
2110
  if not config.get("update", {}).get("check", {}).get("enabled", True):
2116
2111
  return False
2117
- available, _ = c._compute_effective_update_available(state, suppress, c._now_utc())
2112
+ available, _ = c._compute_effective_update_available(state, suppress, _now_utc())
2118
2113
  return available
2119
2114
 
2120
2115
 
@@ -79,6 +79,13 @@ _lib_subscription_weeks = _load_lib("_lib_subscription_weeks")
79
79
  SubWeek = _lib_subscription_weeks.SubWeek
80
80
 
81
81
 
82
+ # === Honest imports from extracted homes ===================================
83
+ # Spec 2026-05-17-cctally-core-kernel-extraction.md §3.3: kernel symbols
84
+ # import from _cctally_core. `CODEX_SESSIONS_DIR` (path constant) and
85
+ # `_decode_escaped_cwd` (out-of-scope) stay on the _cctally() accessor.
86
+ from _cctally_core import parse_iso_datetime
87
+
88
+
82
89
  @dataclass
83
90
  class BucketUsage:
84
91
  """Aggregated usage for one time bucket.
@@ -247,7 +254,6 @@ def _aggregate_weekly(
247
254
  # candidate week in O(log W) per entry rather than the linear
248
255
  # scan that previously ran ~130k x ~54 = 7M comparisons.
249
256
  import bisect
250
- parse_iso_datetime = _cctally().parse_iso_datetime
251
257
  parsed_bounds: list[tuple[dt.datetime, dt.datetime, str]] = []
252
258
  for w in weeks:
253
259
  start_dt = parse_iso_datetime(w.start_ts, "week.start_ts")
@@ -116,11 +116,25 @@ _resolve_tz = _lib_display_tz._resolve_tz
116
116
  format_display_dt = _lib_display_tz.format_display_dt
117
117
 
118
118
 
119
- # Module-level back-ref shims. Each shim resolves
120
- # ``sys.modules['cctally'].X`` at CALL TIME (not bind time), so
121
- # monkeypatches on cctally's namespace propagate into the moved code
122
- # unchanged. Mirrors the precedent established in
123
- # ``bin/_lib_render.py`` / ``bin/_cctally_record.py``.
119
+ # === Honest imports from extracted homes ===================================
120
+ # Spec 2026-05-17-cctally-core-kernel-extraction.md §3.3: kernel symbols
121
+ # (Z-leaf + Z-mid) import from _cctally_core. The legacy shim functions
122
+ # for these names are deleted.
123
+ from _cctally_core import (
124
+ open_db,
125
+ _command_as_of,
126
+ _canonicalize_optional_iso,
127
+ parse_iso_datetime,
128
+ )
129
+
130
+
131
+ # === Module-level back-ref shims for helpers that STAY in bin/cctally ======
132
+ # Each shim resolves ``sys.modules['cctally'].X`` at CALL TIME (not bind
133
+ # time), so monkeypatches on cctally's namespace propagate into the moved
134
+ # code unchanged. `get_claude_session_entries` STAYS as a shim even though
135
+ # its natural home is _cctally_cache — tests monkeypatch it via ``ns["X"]``
136
+ # (audited 2026-05-17); a direct import would silently bypass the patches.
137
+ # See spec §3.5 (carve-out) and §3.7 (stays-on-shim allowlist).
124
138
  def get_claude_session_entries(*args, **kwargs):
125
139
  return sys.modules["cctally"].get_claude_session_entries(*args, **kwargs)
126
140
 
@@ -129,10 +143,6 @@ def _resolve_project_key(*args, **kwargs):
129
143
  return sys.modules["cctally"]._resolve_project_key(*args, **kwargs)
130
144
 
131
145
 
132
- def open_db(*args, **kwargs):
133
- return sys.modules["cctally"].open_db(*args, **kwargs)
134
-
135
-
136
146
  def _iso_z(*args, **kwargs):
137
147
  return sys.modules["cctally"]._iso_z(*args, **kwargs)
138
148
 
@@ -145,18 +155,6 @@ def _style_ansi(*args, **kwargs):
145
155
  return sys.modules["cctally"]._style_ansi(*args, **kwargs)
146
156
 
147
157
 
148
- def _command_as_of(*args, **kwargs):
149
- return sys.modules["cctally"]._command_as_of(*args, **kwargs)
150
-
151
-
152
- def _canonicalize_optional_iso(*args, **kwargs):
153
- return sys.modules["cctally"]._canonicalize_optional_iso(*args, **kwargs)
154
-
155
-
156
- def parse_iso_datetime(*args, **kwargs):
157
- return sys.modules["cctally"].parse_iso_datetime(*args, **kwargs)
158
-
159
-
160
158
  # Private eprint shim per spec §5.3 (pure layer does not back-import
161
159
  # cctally for ubiquitous helpers; eprint isn't actually called by the
162
160
  # moved code, but kept here as the canonical pure-layer pattern so
@@ -2671,6 +2671,12 @@ def _five_hour_blocks_to_json(
2671
2671
  "sevenDayPctAtBlockEnd": p_end,
2672
2672
  "sevenDayPctDeltaPp": delta,
2673
2673
  "crossedSevenDayReset": crossed,
2674
+ # Spec §5.1 — in-place credit events for this 5h block, in
2675
+ # ascending effective_reset_at order. Empty list when the
2676
+ # block carries no credit detections. Source: ``__credits``
2677
+ # side-channel attached by ``cmd_five_hour_blocks`` via
2678
+ # ``credits_by_window``.
2679
+ "credits": d.get("__credits") or [],
2674
2680
  }
2675
2681
  if breakdown_axis == "model":
2676
2682
  out["modelBreakdowns"] = [
@@ -2752,6 +2758,20 @@ def _render_five_hour_blocks_table(
2752
2758
  formatted_start = _format_block_start(d["block_start_at"], args._resolved_tz)
2753
2759
  if crossed:
2754
2760
  formatted_start = f"⚡ {formatted_start}"
2761
+ # Spec §5.1 — credit chip suffix. When the block carries one or
2762
+ # more in-place credit events (5h credit detection v1.7.x;
2763
+ # __credits side-channel set by ``cmd_five_hour_blocks``), append
2764
+ # a ⚡-prefixed chip listing the per-credit delta-pp. Multiple
2765
+ # credits in the same block concatenate (e.g.
2766
+ # `⚡ credited -20pp, -8pp`). The chip text sits AFTER the
2767
+ # block-start cell's existing crossed-reset glyph so the two
2768
+ # signals visually disambiguate by position (crossed-reset
2769
+ # prefix vs. credit suffix). Both use ⚡ — different semantics,
2770
+ # different positions.
2771
+ credits = d.get("__credits") or []
2772
+ if credits:
2773
+ deltas = ", ".join(f"{c['deltaPp']:+.0f}pp" for c in credits)
2774
+ formatted_start = f"{formatted_start} ⚡ credited {deltas}"
2755
2775
  rows.append([
2756
2776
  formatted_start,
2757
2777
  "ACTIVE" if d["__is_active"] else "closed",
@@ -73,6 +73,18 @@ _resolve_tz = _lib_display_tz._resolve_tz
73
73
  _local_tz_name = _lib_display_tz._local_tz_name
74
74
 
75
75
 
76
+ # === Honest imports from extracted homes ===================================
77
+ # Spec 2026-05-17-cctally-core-kernel-extraction.md §3.3: kernel symbols
78
+ # import from _cctally_core. `load_config` stays on the _cctally()
79
+ # accessor per spec §3.5 monkeypatch carve-out (tests reach it via
80
+ # ``ns["load_config"]``).
81
+ from _cctally_core import (
82
+ parse_iso_datetime,
83
+ get_week_start_name,
84
+ WEEKDAY_MAP,
85
+ )
86
+
87
+
76
88
  @dataclass(frozen=True)
77
89
  class SubWeek:
78
90
  """One subscription-week bounded interval.
@@ -142,7 +154,6 @@ def _clamp_end_ats_to_next_start(
142
154
  `pairs` must be sorted by start_at ascending. None values are
143
155
  passed through unchanged and never participate in clamping.
144
156
  """
145
- parse_iso_datetime = _cctally().parse_iso_datetime
146
157
  n = len(pairs)
147
158
  if n < 2:
148
159
  return [p[1] for p in pairs]
@@ -182,7 +193,6 @@ def _apply_overlap_clamp_to_subweeks(weeks: list[SubWeek]) -> list[SubWeek]:
182
193
  Input must be sorted by start_ts ascending (invariant of
183
194
  _compute_subscription_weeks in all three branches).
184
195
  """
185
- parse_iso_datetime = _cctally().parse_iso_datetime
186
196
  if len(weeks) < 2:
187
197
  return weeks
188
198
  pairs: list[tuple[str | None, str | None]] = [(w.start_ts, w.end_ts) for w in weeks]
@@ -217,7 +227,6 @@ def _apply_reset_events_to_subweeks(
217
227
  raw snapshot strings that may be written in non-UTC offsets while
218
228
  `week_reset_events.{old,new}_week_end_at` are canonicalized UTC.
219
229
  """
220
- parse_iso_datetime = _cctally().parse_iso_datetime
221
230
  rows = conn.execute(
222
231
  "SELECT old_week_end_at, new_week_end_at, effective_reset_at_utc "
223
232
  "FROM week_reset_events"
@@ -289,9 +298,6 @@ def _compute_subscription_weeks(
289
298
  dates that miss actual snapshot boundaries for middle weeks. Using
290
299
  snapshot rows directly for weeks they cover avoids that drift.
291
300
  """
292
- cctally = _cctally()
293
- parse_iso_datetime = cctally.parse_iso_datetime
294
-
295
301
  # Case A: snapshots exist.
296
302
  snap_rows = conn.execute(
297
303
  "SELECT "
@@ -460,9 +466,11 @@ def _compute_subscription_weeks(
460
466
  return _apply_overlap_clamp_to_subweeks(weeks)
461
467
 
462
468
  # Case B: no snapshots — config-based calendar-week fallback.
463
- config = cctally.load_config()
464
- week_start_name = cctally.get_week_start_name(config)
465
- week_start_idx = cctally.WEEKDAY_MAP[week_start_name]
469
+ # `load_config` stays on the _cctally() accessor per spec §3.5
470
+ # monkeypatch carve-out — tests reach it via ``ns["load_config"]``.
471
+ config = _cctally().load_config()
472
+ week_start_name = get_week_start_name(config)
473
+ week_start_idx = WEEKDAY_MAP[week_start_name]
466
474
  # internal fallback: host-local intentional
467
475
  local_start_date = range_start.astimezone().date()
468
476
  diff = (local_start_date.weekday() - week_start_idx) % 7