cctally 1.71.0 → 1.73.0

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.
@@ -67,6 +67,9 @@ def _init_paths_from_env() -> None:
67
67
  global HOOK_TICK_LOG_DIR, HOOK_TICK_LOG_PATH, HOOK_TICK_LOG_ROTATED_PATH
68
68
  global HOOK_TICK_THROTTLE_PATH, HOOK_TICK_THROTTLE_LOCK_PATH
69
69
  global STATUSLINE_OBSERVE_MARKER_PATH, STATUSLINE_PERSIST_LOCK_PATH
70
+ global STATUSLINE_CANDIDATE_DIR, STATUSLINE_SELECTED_PATH
71
+ global STATUSLINE_TRANSPORT_MARKER_PATH
72
+ global STATUSLINE_AUTHORITATIVE_7D_PATH, STATUSLINE_AUTHORITATIVE_5H_PATH
70
73
  global OAUTH_BACKOFF_MARKER_PATH, OAUTH_BACKOFF_COUNT_PATH
71
74
  global UPDATE_STATE_PATH, UPDATE_SUPPRESS_PATH
72
75
  global UPDATE_LOCK_PATH, UPDATE_LOG_PATH, UPDATE_LOG_ROTATED_PATH
@@ -126,25 +129,17 @@ def _init_paths_from_env() -> None:
126
129
  HOOK_TICK_THROTTLE_PATH = APP_DIR / "hook-tick.last-fetch"
127
130
  HOOK_TICK_THROTTLE_LOCK_PATH = APP_DIR / "hook-tick.last-fetch.lock"
128
131
 
129
- # Statusline usage-persistence markers + lock (spec 2026-07-17
130
- # usage-statusline-fallback). The statusline is the PRIMARY automatic
131
- # writer of weekly/5h usage snapshots; these gate it.
132
- # - STATUSLINE_OBSERVE_MARKER_PATH: liveness marker (mtime-based,
133
- # like HOOK_TICK_THROTTLE_PATH) — touched after every statusline
134
- # persist that fed valid 7d input through cmd_record_usage, INCLUDING
135
- # a dedup no-op. Represents "the statusline is alive and feeding".
136
- # The statusline persist throttle AND the OAuth backfill gate both
137
- # key off this, NOT snapshot age (cmd_record_usage dedups unchanged
138
- # percentages without refreshing captured_at, so snapshot age keeps
139
- # growing while the statusline is actively feeding).
140
- # - STATUSLINE_PERSIST_LOCK_PATH: cross-process flock serializing the
141
- # detached persist feeder so a multi-session render herd yields at
142
- # most one snapshot per throttle window.
143
- # - OAUTH_BACKOFF_MARKER_PATH: shared 429 cooldown. Stores an ABSOLUTE
144
- # epoch deadline in the file CONTENT (never the mtime — future-dating
145
- # an mtime would corrupt HOOK_TICK_THROTTLE_PATH's age reading).
132
+ # Statusline candidate arbitration (#318). The spool and derived selected
133
+ # state are entirely APP_DIR-derived so dev/data-dir redirection remains
134
+ # complete. The observation marker now means selected/authoritative
135
+ # freshness; transport liveness has its own marker.
146
136
  STATUSLINE_OBSERVE_MARKER_PATH = APP_DIR / "statusline-observe.last"
147
137
  STATUSLINE_PERSIST_LOCK_PATH = APP_DIR / "statusline-persist.lock"
138
+ STATUSLINE_CANDIDATE_DIR = APP_DIR / "statusline-candidates"
139
+ STATUSLINE_SELECTED_PATH = APP_DIR / "statusline-selected.json"
140
+ STATUSLINE_TRANSPORT_MARKER_PATH = APP_DIR / "statusline-transport.last"
141
+ STATUSLINE_AUTHORITATIVE_7D_PATH = APP_DIR / "statusline-authoritative-7d.json"
142
+ STATUSLINE_AUTHORITATIVE_5H_PATH = APP_DIR / "statusline-authoritative-5h.json"
148
143
  OAUTH_BACKOFF_MARKER_PATH = APP_DIR / "oauth-backoff.until"
149
144
  # Consecutive-429 counter (text int) driving the headerless exponential
150
145
  # backoff (base * 2**count). Separate from the deadline marker so the
@@ -246,38 +241,23 @@ def _real_prod_data_dir() -> pathlib.Path:
246
241
  # Internal (no config UI — YAGNI, spec §Out of scope); test injection only.
247
242
  # Spec 2026-07-17-usage-statusline-fallback-design.
248
243
  #
249
- # STATUSLINE_PERSIST_THROTTLE_SECONDS: min seconds between statusline
250
- # persist attempts (keyed off STATUSLINE_OBSERVE_MARKER_PATH liveness).
251
- # Retuned 60.0 -> 25.0 for #311: the setup-managed statusLine.refreshInterval
252
- # timer fires the statusline on a 30s cadence, and the throttle MUST be
253
- # strictly LESS than that interval. When interval <= throttle, phase jitter
254
- # produces beat-frequency skips (a tick at 59.9s of marker age is throttled;
255
- # the next persist waits ~120s), so a 60/60 pairing oscillates 60<->120s.
256
- # With interval 30 > throttle 25, every tick whose predecessor's record
257
- # completed promptly (within interval - throttle = 5s) passes the gate.
258
- # CADENCE QUALIFIER: the marker is touched at persist COMPLETION, so a tick
259
- # observes marker age = 30 - d where d is the previous record's duration;
260
- # if d > 5s (the record kernel can run cmd_sync_week JSONL scans) that tick
261
- # throttles and the cycle degrades to skip-one-tick (~60s), self-correcting
262
- # on the next tick. Exact-30s is NOT an invariant (no attempt-start marker
263
- # exists — one would let a hung/failed record claim liveness and suppress
264
- # the OAuth backfill). Still strictly better than the 60/60 beat's 60-120s.
265
244
  # OAUTH_BACKFILL_STALE_SECONDS: the OAuth poll only backfills once the
266
- # observation marker is at least this stale (i.e. the statusline has
267
- # NOT fed recently). Strictly greater than the persist throttle so the
268
- # statusline is the primary writer and OAuth only covers its absence
269
- # (300 > 25 still holds).
245
+ # selected-freshness marker is at least this stale. The 30-second statusline
246
+ # transport tick does not run OAuth.
270
247
  # OAUTH_BACKOFF_BASE_SECONDS / OAUTH_BACKOFF_CAP_SECONDS: the headerless
271
248
  # exponential 429 backoff (base * 2**consecutive_429, capped).
272
- STATUSLINE_PERSIST_THROTTLE_SECONDS = 25.0
249
+ STATUSLINE_CANDIDATE_TTL_SECONDS = 90
250
+ STATUSLINE_CANDIDATE_FUTURE_SKEW_SECONDS = 5
251
+ STATUSLINE_CANDIDATE_DOCUMENT_MAX_BYTES = 4 * 1024
252
+ STATUSLINE_SELECTED_DOCUMENT_MAX_BYTES = 1024 * 1024
253
+ STATUSLINE_TOMBSTONE_DOCUMENT_MAX_BYTES = 1024
273
254
  # STATUSLINE_REFRESH_INTERVAL_DEFAULT (#311): the value `cctally setup`
274
255
  # writes into Claude Code's settings.json `statusLine.refreshInterval` when a
275
256
  # recognized cctally statusLine block lacks one. Claude Code re-runs the
276
257
  # statusline command on this fixed timer "in addition to the event-driven
277
258
  # updates", which keeps the usage-persistence feeder ticking while a parent
278
259
  # session waits on a long subagent (event-driven updates go quiet then). MUST
279
- # exceed STATUSLINE_PERSIST_THROTTLE_SECONDS (30 > 25) see the pairing rule
280
- # above. Add-when-absent only; a user-set value is never mutated.
260
+ # Add-when-absent only; a user-set value is never mutated.
281
261
  STATUSLINE_REFRESH_INTERVAL_DEFAULT = 30
282
262
  OAUTH_BACKFILL_STALE_SECONDS = 300.0
283
263
  OAUTH_BACKOFF_BASE_SECONDS = 60.0