cctally 1.7.1 → 1.7.3
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.
- package/CHANGELOG.md +37 -0
- package/bin/_cctally_dashboard.py +256 -10
- package/bin/_cctally_db.py +290 -21
- package/bin/_cctally_record.py +616 -32
- package/bin/_cctally_tui.py +217 -12
- package/bin/_lib_blocks.py +33 -6
- package/bin/_lib_doctor.py +79 -0
- package/bin/_lib_render.py +20 -0
- package/bin/cctally +841 -29
- package/dashboard/static/assets/index-DhCnIFq9.js +18 -0
- package/dashboard/static/assets/index-Dv5Dzag5.css +1 -0
- package/dashboard/static/dashboard.html +2 -2
- package/package.json +1 -1
- package/dashboard/static/assets/index-BgpoazlS.js +0 -18
- package/dashboard/static/assets/index-nJdUaGys.css +0 -1
package/bin/_cctally_record.py
CHANGED
|
@@ -372,6 +372,47 @@ def _normalize_percent(value: "float | int | None") -> "float | None":
|
|
|
372
372
|
return round(float(value), _PERCENT_NORMALIZE_DECIMALS)
|
|
373
373
|
|
|
374
374
|
|
|
375
|
+
def _resolve_active_five_hour_reset_event_id(
|
|
376
|
+
conn: "sqlite3.Connection",
|
|
377
|
+
five_hour_window_key: int,
|
|
378
|
+
) -> int:
|
|
379
|
+
"""Return ``id`` of the most-recent ``five_hour_reset_events`` row for
|
|
380
|
+
``five_hour_window_key``, else 0 (pre-credit / no-event sentinel).
|
|
381
|
+
|
|
382
|
+
Mirrors the weekly active-segment resolution pattern used by
|
|
383
|
+
``maybe_record_milestone`` for ``percent_milestones.reset_event_id``.
|
|
384
|
+
Called once per ``maybe_update_five_hour_block`` invocation and the
|
|
385
|
+
return value is threaded through every read/write site that keys on
|
|
386
|
+
``(five_hour_window_key, percent_threshold)`` so post-credit threshold
|
|
387
|
+
crossings land as a distinct row from any pre-credit one at the same
|
|
388
|
+
threshold. See spec
|
|
389
|
+
docs/superpowers/specs/2026-05-16-5h-in-place-credit-detection.md §3.3.
|
|
390
|
+
|
|
391
|
+
Returns ``0`` when:
|
|
392
|
+
- The window has no ``five_hour_reset_events`` row (most blocks).
|
|
393
|
+
- The table doesn't exist yet (DB predates this feature).
|
|
394
|
+
|
|
395
|
+
Returns the largest ``id`` matching the window otherwise; the
|
|
396
|
+
``ORDER BY id DESC LIMIT 1`` clause is what *defines* "active" in
|
|
397
|
+
the stacked-credit case (spec §2.3 — multiple events across distinct
|
|
398
|
+
10-min slots): pre-credit milestones key on ``seg=0``, milestones
|
|
399
|
+
between credit 1 and credit 2 key on event-1's id, and milestones
|
|
400
|
+
after credit 2 key on event-2's id.
|
|
401
|
+
"""
|
|
402
|
+
try:
|
|
403
|
+
row = conn.execute(
|
|
404
|
+
"SELECT id FROM five_hour_reset_events "
|
|
405
|
+
"WHERE five_hour_window_key = ? "
|
|
406
|
+
"ORDER BY id DESC LIMIT 1",
|
|
407
|
+
(int(five_hour_window_key),),
|
|
408
|
+
).fetchone()
|
|
409
|
+
except sqlite3.DatabaseError:
|
|
410
|
+
return 0
|
|
411
|
+
if row is None:
|
|
412
|
+
return 0
|
|
413
|
+
return int(row["id"])
|
|
414
|
+
|
|
415
|
+
|
|
375
416
|
def maybe_record_milestone(
|
|
376
417
|
saved: dict[str, Any],
|
|
377
418
|
) -> None:
|
|
@@ -398,7 +439,31 @@ def maybe_record_milestone(
|
|
|
398
439
|
|
|
399
440
|
conn = open_db()
|
|
400
441
|
try:
|
|
401
|
-
|
|
442
|
+
# Resolve the active segment for THIS captured moment. The segment
|
|
443
|
+
# is the latest week_reset_events row keyed on week_end_at whose
|
|
444
|
+
# effective_reset_at_utc <= captured_at; 0 = pre-credit / no-event
|
|
445
|
+
# sentinel. ``unixepoch()`` normalizes the comparison across mixed
|
|
446
|
+
# +00:00 / Z offsets (see precedent at bin/cctally:_compute_block_totals
|
|
447
|
+
# cross-reset detection; also project gotcha
|
|
448
|
+
# ``unixepoch_for_cross_offset_compare``).
|
|
449
|
+
captured_at_iso = saved.get("capturedAt") or now_utc_iso()
|
|
450
|
+
reset_event_id = 0
|
|
451
|
+
if week_end_at:
|
|
452
|
+
seg_row = conn.execute(
|
|
453
|
+
"""
|
|
454
|
+
SELECT id FROM week_reset_events
|
|
455
|
+
WHERE new_week_end_at = ?
|
|
456
|
+
AND unixepoch(effective_reset_at_utc) <= unixepoch(?)
|
|
457
|
+
ORDER BY id DESC LIMIT 1
|
|
458
|
+
""",
|
|
459
|
+
(week_end_at, captured_at_iso),
|
|
460
|
+
).fetchone()
|
|
461
|
+
if seg_row is not None:
|
|
462
|
+
reset_event_id = int(seg_row["id"])
|
|
463
|
+
|
|
464
|
+
max_existing = get_max_milestone_for_week(
|
|
465
|
+
conn, week_start_date, reset_event_id=reset_event_id,
|
|
466
|
+
)
|
|
402
467
|
if max_existing is not None and current_floor <= max_existing:
|
|
403
468
|
return
|
|
404
469
|
|
|
@@ -482,7 +547,10 @@ def maybe_record_milestone(
|
|
|
482
547
|
pending_alerts: list[dict[str, Any]] = []
|
|
483
548
|
for pct in range(start_threshold, current_floor + 1):
|
|
484
549
|
if pct == start_threshold and max_existing is not None:
|
|
485
|
-
prev_cost = get_milestone_cost_for_week(
|
|
550
|
+
prev_cost = get_milestone_cost_for_week(
|
|
551
|
+
conn, week_start_date, max_existing,
|
|
552
|
+
reset_event_id=reset_event_id,
|
|
553
|
+
)
|
|
486
554
|
marginal = (cumulative_cost - prev_cost) if prev_cost is not None else None
|
|
487
555
|
else:
|
|
488
556
|
marginal = None
|
|
@@ -499,6 +567,7 @@ def maybe_record_milestone(
|
|
|
499
567
|
cost_snapshot_id=cost_snapshot_id,
|
|
500
568
|
five_hour_percent_at_crossing=five_hour_percent,
|
|
501
569
|
commit=False,
|
|
570
|
+
reset_event_id=reset_event_id,
|
|
502
571
|
)
|
|
503
572
|
# ── Threshold-actions dispatch (set-then-dispatch, spec §3.2) ──
|
|
504
573
|
# Only the genuine-new-crossing winner (rowcount==1) reaches this
|
|
@@ -523,17 +592,22 @@ def maybe_record_milestone(
|
|
|
523
592
|
conn.execute(
|
|
524
593
|
"UPDATE percent_milestones SET alerted_at = ? "
|
|
525
594
|
"WHERE week_start_date = ? AND percent_threshold = ? "
|
|
526
|
-
"AND
|
|
527
|
-
|
|
595
|
+
" AND reset_event_id = ? "
|
|
596
|
+
" AND alerted_at IS NULL",
|
|
597
|
+
(crossed_at, week_start_date, pct, reset_event_id),
|
|
528
598
|
)
|
|
529
599
|
# Cheap re-read for payload context (cumulative_cost_usd
|
|
530
600
|
# reflects the value persisted on insert, immune to any
|
|
531
601
|
# subsequent recompute drift). SELECT inside the open
|
|
532
602
|
# transaction is fine; values reflect post-INSERT state.
|
|
603
|
+
# Filter by reset_event_id so a credited week's
|
|
604
|
+
# alert payload reads the post-credit row, not a
|
|
605
|
+
# stale pre-credit row at the same (week, threshold).
|
|
533
606
|
row = conn.execute(
|
|
534
607
|
"SELECT cumulative_cost_usd FROM percent_milestones "
|
|
535
|
-
"WHERE week_start_date = ? AND percent_threshold = ?"
|
|
536
|
-
|
|
608
|
+
"WHERE week_start_date = ? AND percent_threshold = ? "
|
|
609
|
+
" AND reset_event_id = ?",
|
|
610
|
+
(week_start_date, pct, reset_event_id),
|
|
537
611
|
).fetchone()
|
|
538
612
|
if row is not None:
|
|
539
613
|
cum = float(row["cumulative_cost_usd"])
|
|
@@ -930,7 +1004,23 @@ def maybe_update_five_hour_block(saved: dict[str, Any]) -> None:
|
|
|
930
1004
|
# Snap-up-by-1e-9 per the gotcha: 0.50 * 100 == 49.99...9 in
|
|
931
1005
|
# IEEE-754, so bare math.floor would miss the 50 threshold.
|
|
932
1006
|
current_floor = math.floor(float(five_hour_percent) + 1e-9)
|
|
1007
|
+
|
|
1008
|
+
# Resolve active segment ONCE so every per-site read + write
|
|
1009
|
+
# below sees the same value within this transaction. Spec
|
|
1010
|
+
# §3.3 & §3.4 of
|
|
1011
|
+
# docs/superpowers/specs/2026-05-16-5h-in-place-credit-detection.md:
|
|
1012
|
+
# the active segment is the latest five_hour_reset_events row
|
|
1013
|
+
# for this window_key, else sentinel 0 (pre-credit).
|
|
1014
|
+
active_reset_event_id = _resolve_active_five_hour_reset_event_id(
|
|
1015
|
+
conn, int(five_hour_window_key)
|
|
1016
|
+
)
|
|
1017
|
+
|
|
933
1018
|
if current_floor >= 1:
|
|
1019
|
+
# Site A — MAX(percent_threshold) scoped to active segment.
|
|
1020
|
+
# Without the reset_event_id filter, MAX returns the
|
|
1021
|
+
# pre-credit max and post-credit milestones from 1..max
|
|
1022
|
+
# are silently never emitted.
|
|
1023
|
+
#
|
|
934
1024
|
# Use max(percent_threshold) directly (not prior block's
|
|
935
1025
|
# final_pct) so first-observation already-mid-stream doesn't
|
|
936
1026
|
# synthesize crossings 1..(current_floor - 1) we never had
|
|
@@ -938,8 +1028,8 @@ def maybe_update_five_hour_block(saved: dict[str, Any]) -> None:
|
|
|
938
1028
|
# maybe_record_milestone's max_existing path.
|
|
939
1029
|
row = conn.execute(
|
|
940
1030
|
"SELECT MAX(percent_threshold) AS m FROM five_hour_milestones "
|
|
941
|
-
"WHERE five_hour_window_key = ?",
|
|
942
|
-
(int(five_hour_window_key),),
|
|
1031
|
+
"WHERE five_hour_window_key = ? AND reset_event_id = ?",
|
|
1032
|
+
(int(five_hour_window_key), active_reset_event_id),
|
|
943
1033
|
).fetchone()
|
|
944
1034
|
max_existing = row["m"] if row and row["m"] is not None else None
|
|
945
1035
|
|
|
@@ -952,14 +1042,21 @@ def maybe_update_five_hour_block(saved: dict[str, Any]) -> None:
|
|
|
952
1042
|
# block_id was resolved above (before the children writes) and
|
|
953
1043
|
# is still in scope here.
|
|
954
1044
|
|
|
1045
|
+
# Site B — prior-cost lookup scoped to active segment.
|
|
955
1046
|
# Marginal-cost lookup for the start_threshold milestone
|
|
956
1047
|
# (only when there's a prior milestone in this block).
|
|
1048
|
+
# Without the reset_event_id filter, marginal could be
|
|
1049
|
+
# computed against a pre-credit row whose block_cost is
|
|
1050
|
+
# unrelated to the post-credit segment's totals.
|
|
957
1051
|
prior_cost: float | None = None
|
|
958
1052
|
if max_existing is not None:
|
|
959
1053
|
prev_row = conn.execute(
|
|
960
1054
|
"SELECT block_cost_usd FROM five_hour_milestones "
|
|
961
|
-
"WHERE five_hour_window_key = ?
|
|
962
|
-
|
|
1055
|
+
"WHERE five_hour_window_key = ? "
|
|
1056
|
+
" AND percent_threshold = ? "
|
|
1057
|
+
" AND reset_event_id = ?",
|
|
1058
|
+
(int(five_hour_window_key), int(max_existing),
|
|
1059
|
+
active_reset_event_id),
|
|
963
1060
|
).fetchone()
|
|
964
1061
|
if prev_row is not None:
|
|
965
1062
|
prior_cost = float(prev_row["block_cost_usd"])
|
|
@@ -969,6 +1066,12 @@ def maybe_update_five_hour_block(saved: dict[str, Any]) -> None:
|
|
|
969
1066
|
marginal: float | None = totals["cost_usd"] - prior_cost
|
|
970
1067
|
else:
|
|
971
1068
|
marginal = None
|
|
1069
|
+
# Site C — INSERT stamps the resolved
|
|
1070
|
+
# ``active_reset_event_id`` (0 = pre-credit, else
|
|
1071
|
+
# the latest five_hour_reset_events.id). UNIQUE
|
|
1072
|
+
# is now (window_key, threshold, reset_event_id)
|
|
1073
|
+
# so post-credit threshold crossings re-fire
|
|
1074
|
+
# fresh — not absorbed into the pre-credit row.
|
|
972
1075
|
cur = conn.execute(
|
|
973
1076
|
"""
|
|
974
1077
|
INSERT OR IGNORE INTO five_hour_milestones (
|
|
@@ -983,9 +1086,10 @@ def maybe_update_five_hour_block(saved: dict[str, Any]) -> None:
|
|
|
983
1086
|
block_cache_read_tokens,
|
|
984
1087
|
block_cost_usd,
|
|
985
1088
|
marginal_cost_usd,
|
|
986
|
-
seven_day_pct_at_crossing
|
|
1089
|
+
seven_day_pct_at_crossing,
|
|
1090
|
+
reset_event_id
|
|
987
1091
|
)
|
|
988
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1092
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
989
1093
|
""",
|
|
990
1094
|
(
|
|
991
1095
|
block_id,
|
|
@@ -1000,6 +1104,7 @@ def maybe_update_five_hour_block(saved: dict[str, Any]) -> None:
|
|
|
1000
1104
|
totals["cost_usd"],
|
|
1001
1105
|
marginal,
|
|
1002
1106
|
weekly_percent,
|
|
1107
|
+
active_reset_event_id,
|
|
1003
1108
|
),
|
|
1004
1109
|
)
|
|
1005
1110
|
# ── Threshold-actions dispatch (set-then-dispatch, spec §3.2) ──
|
|
@@ -1028,11 +1133,19 @@ def maybe_update_five_hour_block(saved: dict[str, Any]) -> None:
|
|
|
1028
1133
|
and pct in alerts_cfg["five_hour_thresholds"]
|
|
1029
1134
|
):
|
|
1030
1135
|
crossed_at = now_utc_iso()
|
|
1136
|
+
# Site D — alerted_at UPDATE scoped to the
|
|
1137
|
+
# active segment, so the post-credit row
|
|
1138
|
+
# gets stamped without overwriting an
|
|
1139
|
+
# already-alerted pre-credit row at the
|
|
1140
|
+
# same threshold.
|
|
1031
1141
|
conn.execute(
|
|
1032
1142
|
"UPDATE five_hour_milestones SET alerted_at = ? "
|
|
1033
|
-
"WHERE five_hour_window_key = ?
|
|
1034
|
-
"AND
|
|
1035
|
-
|
|
1143
|
+
"WHERE five_hour_window_key = ? "
|
|
1144
|
+
" AND percent_threshold = ? "
|
|
1145
|
+
" AND reset_event_id = ? "
|
|
1146
|
+
" AND alerted_at IS NULL",
|
|
1147
|
+
(crossed_at, int(five_hour_window_key),
|
|
1148
|
+
int(pct), active_reset_event_id),
|
|
1036
1149
|
)
|
|
1037
1150
|
# Cheap re-reads inside BEGIN are SELECT-only and
|
|
1038
1151
|
# safe; values reflect post-INSERT state. We
|
|
@@ -1040,10 +1153,17 @@ def maybe_update_five_hour_block(saved: dict[str, Any]) -> None:
|
|
|
1040
1153
|
# are in scope) and defer ONLY the Popen-side
|
|
1041
1154
|
# _dispatch_alert_notification to after the outer
|
|
1042
1155
|
# commit.
|
|
1156
|
+
# Site E — alert-payload reread scoped to
|
|
1157
|
+
# the active segment so the dispatch shows
|
|
1158
|
+
# post-credit cost, not the pre-credit
|
|
1159
|
+
# row's stale value at the same threshold.
|
|
1043
1160
|
cost_row = conn.execute(
|
|
1044
1161
|
"SELECT block_cost_usd FROM five_hour_milestones "
|
|
1045
|
-
"WHERE five_hour_window_key = ?
|
|
1046
|
-
|
|
1162
|
+
"WHERE five_hour_window_key = ? "
|
|
1163
|
+
" AND percent_threshold = ? "
|
|
1164
|
+
" AND reset_event_id = ?",
|
|
1165
|
+
(int(five_hour_window_key), int(pct),
|
|
1166
|
+
active_reset_event_id),
|
|
1047
1167
|
).fetchone()
|
|
1048
1168
|
block_row = conn.execute(
|
|
1049
1169
|
"SELECT block_start_at FROM five_hour_blocks "
|
|
@@ -1305,9 +1425,9 @@ def cmd_record_usage(args: argparse.Namespace) -> int:
|
|
|
1305
1425
|
prior["week_end_at"], "record.prior"
|
|
1306
1426
|
)
|
|
1307
1427
|
prior_pct = prior["weekly_percent"]
|
|
1428
|
+
now_utc = dt.datetime.now(dt.timezone.utc)
|
|
1308
1429
|
if prior_end_canon and prior_end_canon != cur_end_canon:
|
|
1309
1430
|
prior_end_dt = parse_iso_datetime(prior_end_canon, "prior.week_end_at")
|
|
1310
|
-
now_utc = dt.datetime.now(dt.timezone.utc)
|
|
1311
1431
|
# Fire only when (a) prior window was still in the FUTURE
|
|
1312
1432
|
# (Anthropic shifted the boundary before natural expiration),
|
|
1313
1433
|
# AND (b) weekly_percent dropped by RESET_PCT_DROP_THRESHOLD
|
|
@@ -1331,32 +1451,429 @@ def cmd_record_usage(args: argparse.Namespace) -> int:
|
|
|
1331
1451
|
effective_iso),
|
|
1332
1452
|
)
|
|
1333
1453
|
conn.commit()
|
|
1454
|
+
elif prior_end_canon and prior_end_canon == cur_end_canon:
|
|
1455
|
+
# In-place credit branch (v1.7.2). When `resets_at` stays
|
|
1456
|
+
# unchanged but `weekly_percent` drops by RESET_PCT_DROP_THRESHOLD
|
|
1457
|
+
# or more, Anthropic has issued a goodwill in-place weekly
|
|
1458
|
+
# credit. Emit one week_reset_events row keyed on the
|
|
1459
|
+
# current end_at (old == new) so the reset-aware clamp
|
|
1460
|
+
# above and the milestone segment writer can pivot to
|
|
1461
|
+
# the post-credit segment. The seed snapshot lands via
|
|
1462
|
+
# the now-reset-aware clamp on this same call.
|
|
1463
|
+
prior_end_dt = parse_iso_datetime(prior_end_canon, "prior.week_end_at")
|
|
1464
|
+
if (
|
|
1465
|
+
prior_end_dt > now_utc
|
|
1466
|
+
and prior_pct is not None
|
|
1467
|
+
and (float(prior_pct) - float(weekly_percent)) >= c._RESET_PCT_DROP_THRESHOLD
|
|
1468
|
+
):
|
|
1469
|
+
# Pre-check (Q5 belt-and-suspenders): suppress duplicate
|
|
1470
|
+
# event rows for the same new_week_end_at across
|
|
1471
|
+
# consecutive ticks. UNIQUE(old, new) at the DDL
|
|
1472
|
+
# also catches the duplicate in the (old == new) case,
|
|
1473
|
+
# but the pre-check avoids a useless write attempt
|
|
1474
|
+
# and keeps the log clean. After the seed lands at
|
|
1475
|
+
# post-credit %, the next tick's `prior_pct` will be
|
|
1476
|
+
# the post-credit value so the drop predicate alone
|
|
1477
|
+
# also suffices — pre-check is belt-and-suspenders.
|
|
1478
|
+
already = conn.execute(
|
|
1479
|
+
"SELECT 1 FROM week_reset_events "
|
|
1480
|
+
"WHERE new_week_end_at = ? LIMIT 1",
|
|
1481
|
+
(cur_end_canon,),
|
|
1482
|
+
).fetchone()
|
|
1483
|
+
effective_dt = _floor_to_hour(now_utc)
|
|
1484
|
+
effective_iso = effective_dt.isoformat(timespec="seconds")
|
|
1485
|
+
if already is None:
|
|
1486
|
+
# Row shape: old=effective_iso, new=cur_end_canon
|
|
1487
|
+
# (distinct values). The previous shape stored
|
|
1488
|
+
# old==new==cur_end_canon, which let BOTH
|
|
1489
|
+
# _apply_reset_events_to_weekrefs maps
|
|
1490
|
+
# (pre_map[old] and post_map[new]) fire on the
|
|
1491
|
+
# SAME WeekRef — pre_map rewrote week_end_at to
|
|
1492
|
+
# effective, post_map rewrote week_start_at to
|
|
1493
|
+
# effective, collapsing the credited week to a
|
|
1494
|
+
# zero-width window in downstream renders. With
|
|
1495
|
+
# old==effective and new==cur_end_canon, only
|
|
1496
|
+
# post_map fires on the credited week (setting
|
|
1497
|
+
# week_start_at = effective, the intended
|
|
1498
|
+
# behavior); pre_map keys on effective_iso and
|
|
1499
|
+
# finds no matching WeekRef in practice. The
|
|
1500
|
+
# UNIQUE(old, new) constraint permits this
|
|
1501
|
+
# row, and the pre-check above keys on
|
|
1502
|
+
# new_week_end_at so dedup still works.
|
|
1503
|
+
conn.execute(
|
|
1504
|
+
"INSERT OR IGNORE INTO week_reset_events "
|
|
1505
|
+
"(detected_at_utc, old_week_end_at, new_week_end_at, "
|
|
1506
|
+
" effective_reset_at_utc) VALUES (?, ?, ?, ?)",
|
|
1507
|
+
(now_utc_iso(), effective_iso, cur_end_canon,
|
|
1508
|
+
effective_iso),
|
|
1509
|
+
)
|
|
1510
|
+
conn.commit()
|
|
1511
|
+
# Pivots fire UNCONDITIONALLY whenever a credit
|
|
1512
|
+
# is detected — they're NOT gated on
|
|
1513
|
+
# ``already is None``. Memory
|
|
1514
|
+
# ``project_dedup_must_not_gate_side_effects.md``:
|
|
1515
|
+
# "Skipping a no-op INSERT must NOT skip
|
|
1516
|
+
# milestones/rollups/alerts; prior run may have
|
|
1517
|
+
# died mid-flight." Crash scenario: tick N
|
|
1518
|
+
# committed the event row, then died before
|
|
1519
|
+
# HWM + DELETE. Tick N+1's pre-check sees
|
|
1520
|
+
# ``already`` non-None (the row IS in the
|
|
1521
|
+
# table) and would skip the pivots, leaving
|
|
1522
|
+
# the system wedged on pre-credit HWM + stale-
|
|
1523
|
+
# replica rows. Pivots are individually
|
|
1524
|
+
# idempotent (file overwrite + DELETE on stable
|
|
1525
|
+
# predicate), so re-running them is safe.
|
|
1526
|
+
# ``effective_iso`` is resolved above; on a
|
|
1527
|
+
# recovery tick it lands on the SAME 10-min
|
|
1528
|
+
# slot as the original (now_utc has drifted
|
|
1529
|
+
# only seconds), so the DELETE predicate's
|
|
1530
|
+
# ``unixepoch(captured_at_utc) >= unixepoch(?)``
|
|
1531
|
+
# still matches every stale-replica row.
|
|
1532
|
+
#
|
|
1533
|
+
# Force-write hwm-7d so the next status-line
|
|
1534
|
+
# render reflects the post-credit value. The
|
|
1535
|
+
# monotonic guard at the normal write site
|
|
1536
|
+
# (below) would refuse to decrease the file;
|
|
1537
|
+
# this write is the credit-only escape hatch.
|
|
1538
|
+
# Lands AFTER the conn.commit() so a concurrent
|
|
1539
|
+
# record-usage reader doesn't see the new HWM
|
|
1540
|
+
# before the event row is durable.
|
|
1541
|
+
try:
|
|
1542
|
+
(c.APP_DIR / "hwm-7d").write_text(
|
|
1543
|
+
f"{week_start_date} {weekly_percent}\n"
|
|
1544
|
+
)
|
|
1545
|
+
except OSError:
|
|
1546
|
+
pass
|
|
1547
|
+
|
|
1548
|
+
# Race-defensive cleanup. Between the moment
|
|
1549
|
+
# Anthropic credited the user (effective_iso)
|
|
1550
|
+
# and this code firing, the EXTERNAL
|
|
1551
|
+
# claude-statusline tool can replay stale
|
|
1552
|
+
# pre-credit `--percent` values (it has its
|
|
1553
|
+
# own in-memory HWM cache and re-runs us once
|
|
1554
|
+
# per status-line tick). Those replays land
|
|
1555
|
+
# captured_at_utc >= effective_iso with
|
|
1556
|
+
# weekly_percent == prior_pct (the pre-credit
|
|
1557
|
+
# value), and they dominate the reset-aware
|
|
1558
|
+
# clamp's MAX over the post-credit segment so
|
|
1559
|
+
# legitimate fresh OAuth values are rejected.
|
|
1560
|
+
# Strict equality (round(.,1)) keeps this
|
|
1561
|
+
# narrow: we only delete rows whose percent
|
|
1562
|
+
# exactly matches the pre-credit value we just
|
|
1563
|
+
# observed — legitimate post-credit climbs
|
|
1564
|
+
# past `prior_pct` (rare, but possible if the
|
|
1565
|
+
# credit is small + activity is heavy) stay.
|
|
1566
|
+
try:
|
|
1567
|
+
conn.execute(
|
|
1568
|
+
"DELETE FROM weekly_usage_snapshots "
|
|
1569
|
+
"WHERE week_start_date = ? "
|
|
1570
|
+
" AND unixepoch(captured_at_utc) >= "
|
|
1571
|
+
" unixepoch(?) "
|
|
1572
|
+
" AND round(weekly_percent, 1) = "
|
|
1573
|
+
" round(?, 1)",
|
|
1574
|
+
(week_start_date, effective_iso,
|
|
1575
|
+
float(prior_pct)),
|
|
1576
|
+
)
|
|
1577
|
+
conn.commit()
|
|
1578
|
+
except sqlite3.DatabaseError as exc:
|
|
1579
|
+
eprint(
|
|
1580
|
+
"[record-usage] post-credit cleanup "
|
|
1581
|
+
f"failed: {exc}"
|
|
1582
|
+
)
|
|
1583
|
+
|
|
1584
|
+
# ── 5h in-place credit detection (parallel to weekly above) ──
|
|
1585
|
+
# Spec §2.2 of
|
|
1586
|
+
# docs/superpowers/specs/2026-05-16-5h-in-place-credit-detection.md.
|
|
1587
|
+
# Slot SECOND so the weekly branch retains control-flow
|
|
1588
|
+
# priority — both branches are independent (they touch
|
|
1589
|
+
# different tables) and the order has no behavioral
|
|
1590
|
+
# interaction. Same outer try/except wraps both so a
|
|
1591
|
+
# 5h-detection failure logs but does not regress the rest
|
|
1592
|
+
# of cmd_record_usage.
|
|
1593
|
+
#
|
|
1594
|
+
# Diverges from weekly in three places:
|
|
1595
|
+
# - Threshold: 5.0pp (constant on cctally module), not 25.0pp.
|
|
1596
|
+
# The 5h envelope is smaller so a 5pp move is
|
|
1597
|
+
# proportionally larger.
|
|
1598
|
+
# - Effective-iso floor: 10-min (matches
|
|
1599
|
+
# ``_canonical_5h_window_key``'s 600s floor), not hour.
|
|
1600
|
+
# Up to ~30 distinct slots per 5h block; same-slot
|
|
1601
|
+
# collisions absorbed by UNIQUE per spec §2.3.
|
|
1602
|
+
# - Pre-check: pair-checks the latest event's
|
|
1603
|
+
# ``(prior_percent, post_percent)`` against this tick's
|
|
1604
|
+
# ``(prior_5h_pct, five_hour_percent)``, not
|
|
1605
|
+
# ``new_week_end_at`` equality. A genuine replay matches
|
|
1606
|
+
# BOTH fields; a NEW credit-with-idle (prior_pct equals
|
|
1607
|
+
# the prior credit's post_pct because the user didn't
|
|
1608
|
+
# move between credits) matches only one field and
|
|
1609
|
+
# correctly proceeds to write a second event row.
|
|
1610
|
+
try:
|
|
1611
|
+
if (
|
|
1612
|
+
five_hour_window_key is not None
|
|
1613
|
+
and five_hour_percent is not None
|
|
1614
|
+
):
|
|
1615
|
+
prior_5h_row = conn.execute(
|
|
1616
|
+
"SELECT five_hour_window_key, five_hour_percent, "
|
|
1617
|
+
" five_hour_resets_at "
|
|
1618
|
+
" FROM weekly_usage_snapshots "
|
|
1619
|
+
" WHERE five_hour_window_key IS NOT NULL "
|
|
1620
|
+
" AND five_hour_percent IS NOT NULL "
|
|
1621
|
+
" ORDER BY captured_at_utc DESC, id DESC LIMIT 1"
|
|
1622
|
+
).fetchone()
|
|
1623
|
+
if (
|
|
1624
|
+
prior_5h_row is not None
|
|
1625
|
+
and int(prior_5h_row["five_hour_window_key"])
|
|
1626
|
+
== int(five_hour_window_key)
|
|
1627
|
+
and prior_5h_row["five_hour_resets_at"] is not None
|
|
1628
|
+
):
|
|
1629
|
+
prior_5h_pct = float(prior_5h_row["five_hour_percent"])
|
|
1630
|
+
prior_5h_resets_dt = parse_iso_datetime(
|
|
1631
|
+
prior_5h_row["five_hour_resets_at"],
|
|
1632
|
+
"prior.five_hour_resets_at",
|
|
1633
|
+
)
|
|
1634
|
+
# ``now_utc`` was bound earlier in this same
|
|
1635
|
+
# outer try block from
|
|
1636
|
+
# ``dt.datetime.now(dt.timezone.utc)``; reuse it
|
|
1637
|
+
# so both branches see the same instant.
|
|
1638
|
+
if (
|
|
1639
|
+
prior_5h_resets_dt > now_utc
|
|
1640
|
+
and (prior_5h_pct - float(five_hour_percent))
|
|
1641
|
+
>= c._FIVE_HOUR_RESET_PCT_DROP_THRESHOLD
|
|
1642
|
+
):
|
|
1643
|
+
# Pair-check dedup pre-check (spec §2.2;
|
|
1644
|
+
# refined by Codex r4 P1 finding). The
|
|
1645
|
+
# round-1 predicate compared only the
|
|
1646
|
+
# latest event's ``post_percent`` against
|
|
1647
|
+
# this tick's ``prior_5h_pct``; that
|
|
1648
|
+
# false-positived on a legitimate 2nd
|
|
1649
|
+
# credit where the user was idle between
|
|
1650
|
+
# credits (Credit 1 lands prior=20/post=5;
|
|
1651
|
+
# user does nothing; Credit 2 arrives with
|
|
1652
|
+
# CLI percent=0 so prior_5h_pct=5 reads
|
|
1653
|
+
# equal to stored post_percent=5 →
|
|
1654
|
+
# silently swallowed). Pair-checking
|
|
1655
|
+
# against BOTH fields disambiguates: a
|
|
1656
|
+
# genuine replay matches BOTH; a new
|
|
1657
|
+
# credit-with-idle matches at most ONE
|
|
1658
|
+
# (the prior side coincides but
|
|
1659
|
+
# post_percent differs).
|
|
1660
|
+
most_recent = conn.execute(
|
|
1661
|
+
"SELECT prior_percent, post_percent "
|
|
1662
|
+
" FROM five_hour_reset_events "
|
|
1663
|
+
" WHERE five_hour_window_key = ? "
|
|
1664
|
+
" ORDER BY id DESC LIMIT 1",
|
|
1665
|
+
(int(five_hour_window_key),),
|
|
1666
|
+
).fetchone()
|
|
1667
|
+
is_dup = (
|
|
1668
|
+
most_recent is not None
|
|
1669
|
+
and round(prior_5h_pct, 1)
|
|
1670
|
+
== round(float(most_recent["prior_percent"]), 1)
|
|
1671
|
+
and round(float(five_hour_percent), 1)
|
|
1672
|
+
== round(float(most_recent["post_percent"]), 1)
|
|
1673
|
+
)
|
|
1674
|
+
# 10-min floor (spec §2.3 — bounded
|
|
1675
|
+
# stacked-credit resolution; one event per
|
|
1676
|
+
# 10-min slot per block). Resolved BEFORE
|
|
1677
|
+
# the ``if not is_dup`` branch so it's in
|
|
1678
|
+
# scope for the pivots below (per memory
|
|
1679
|
+
# ``project_dedup_must_not_gate_side_effects.md``:
|
|
1680
|
+
# the recovery-tick path must still force
|
|
1681
|
+
# HWM + DELETE even when the INSERT is
|
|
1682
|
+
# absorbed by the pre-check or by
|
|
1683
|
+
# UNIQUE — see comment below for the
|
|
1684
|
+
# crash scenario). ``_floor_to_ten_minutes``
|
|
1685
|
+
# is a cctally module attribute; the
|
|
1686
|
+
# ``c.X`` accessor resolves at call time
|
|
1687
|
+
# so test ``monkeypatch.setitem(ns,
|
|
1688
|
+
# "_floor_to_ten_minutes", …)``
|
|
1689
|
+
# propagates.
|
|
1690
|
+
effective_dt = c._floor_to_ten_minutes(now_utc)
|
|
1691
|
+
effective_iso = effective_dt.isoformat(
|
|
1692
|
+
timespec="seconds"
|
|
1693
|
+
)
|
|
1694
|
+
if not is_dup:
|
|
1695
|
+
conn.execute(
|
|
1696
|
+
"INSERT OR IGNORE INTO five_hour_reset_events "
|
|
1697
|
+
"(detected_at_utc, five_hour_window_key, "
|
|
1698
|
+
" prior_percent, post_percent, "
|
|
1699
|
+
" effective_reset_at_utc) "
|
|
1700
|
+
"VALUES (?, ?, ?, ?, ?)",
|
|
1701
|
+
(
|
|
1702
|
+
now_utc_iso(),
|
|
1703
|
+
int(five_hour_window_key),
|
|
1704
|
+
prior_5h_pct,
|
|
1705
|
+
float(five_hour_percent),
|
|
1706
|
+
effective_iso,
|
|
1707
|
+
),
|
|
1708
|
+
)
|
|
1709
|
+
conn.commit()
|
|
1710
|
+
# Pivots fire UNCONDITIONALLY whenever a
|
|
1711
|
+
# credit is detected — NOT gated on
|
|
1712
|
+
# ``not is_dup`` and NOT on
|
|
1713
|
+
# ``rowcount == 1``. Memory
|
|
1714
|
+
# ``project_dedup_must_not_gate_side_effects.md``:
|
|
1715
|
+
# "Skipping a no-op INSERT must NOT skip
|
|
1716
|
+
# milestones/rollups/alerts; prior run may
|
|
1717
|
+
# have died mid-flight." Crash scenario A:
|
|
1718
|
+
# tick N committed the event row, then died
|
|
1719
|
+
# before HWM + DELETE. Tick N+1's
|
|
1720
|
+
# INSERT OR IGNORE returns rowcount == 0
|
|
1721
|
+
# (UNIQUE absorbs) but the system is still
|
|
1722
|
+
# wedged on the pre-credit HWM + stale-
|
|
1723
|
+
# replica rows. Crash scenario B (the
|
|
1724
|
+
# Codex r4 finding): a recovery tick where
|
|
1725
|
+
# ``(prior, post)`` pair-matches the
|
|
1726
|
+
# already-stored event row also takes the
|
|
1727
|
+
# ``is_dup`` branch; without the hoist the
|
|
1728
|
+
# pivots would be skipped and the system
|
|
1729
|
+
# would stay wedged. The pivots are
|
|
1730
|
+
# individually idempotent (file overwrite
|
|
1731
|
+
# + DELETE on a stable predicate), so
|
|
1732
|
+
# re-running them on the recovery tick is
|
|
1733
|
+
# always safe. Mirrors the weekly hoist at
|
|
1734
|
+
# ``_cctally_record.py`` after the
|
|
1735
|
+
# ``if already is None`` block (grep
|
|
1736
|
+
# ``Force-write hwm-7d``).
|
|
1737
|
+
#
|
|
1738
|
+
# Force-write hwm-5h: bypasses the
|
|
1739
|
+
# monotonic guard at the normal hwm-5h
|
|
1740
|
+
# writer below. Lands AFTER
|
|
1741
|
+
# ``conn.commit()`` so a concurrent reader
|
|
1742
|
+
# doesn't see the new HWM before the
|
|
1743
|
+
# event row is durable. File format
|
|
1744
|
+
# matches the canonical writer:
|
|
1745
|
+
# ``<key> <percent>\n``.
|
|
1746
|
+
try:
|
|
1747
|
+
(c.APP_DIR / "hwm-5h").write_text(
|
|
1748
|
+
f"{int(five_hour_window_key)} "
|
|
1749
|
+
f"{float(five_hour_percent)}\n"
|
|
1750
|
+
)
|
|
1751
|
+
except OSError:
|
|
1752
|
+
pass
|
|
1753
|
+
# Stale-replica DELETE (spec §4.3).
|
|
1754
|
+
# Defends against claude-statusline
|
|
1755
|
+
# replaying the pre-credit
|
|
1756
|
+
# ``--five-hour-percent`` value past the
|
|
1757
|
+
# credit moment from its own in-memory
|
|
1758
|
+
# HWM cache. Strict round-1 equality
|
|
1759
|
+
# keeps the scope narrow — only rows
|
|
1760
|
+
# whose five_hour_percent exactly matches
|
|
1761
|
+
# the just-observed pre-credit value are
|
|
1762
|
+
# removed. ``unixepoch()`` on both sides
|
|
1763
|
+
# for offset robustness (Z vs +00:00).
|
|
1764
|
+
try:
|
|
1765
|
+
conn.execute(
|
|
1766
|
+
"DELETE FROM weekly_usage_snapshots "
|
|
1767
|
+
" WHERE five_hour_window_key = ? "
|
|
1768
|
+
" AND unixepoch(captured_at_utc) "
|
|
1769
|
+
" >= unixepoch(?) "
|
|
1770
|
+
" AND round(five_hour_percent, 1) "
|
|
1771
|
+
" = round(?, 1)",
|
|
1772
|
+
(
|
|
1773
|
+
int(five_hour_window_key),
|
|
1774
|
+
effective_iso,
|
|
1775
|
+
prior_5h_pct,
|
|
1776
|
+
),
|
|
1777
|
+
)
|
|
1778
|
+
conn.commit()
|
|
1779
|
+
except sqlite3.DatabaseError as exc:
|
|
1780
|
+
eprint(
|
|
1781
|
+
"[record-usage] 5h post-credit "
|
|
1782
|
+
f"cleanup failed: {exc}"
|
|
1783
|
+
)
|
|
1784
|
+
except (sqlite3.DatabaseError, ValueError, TypeError) as exc:
|
|
1785
|
+
eprint(
|
|
1786
|
+
f"[record-usage] 5h in-place-credit detection "
|
|
1787
|
+
f"failed: {exc}"
|
|
1788
|
+
)
|
|
1334
1789
|
except (sqlite3.DatabaseError, ValueError) as exc:
|
|
1335
1790
|
eprint(f"[record-usage] reset-event detection failed: {exc}")
|
|
1336
1791
|
|
|
1337
|
-
# 7-day usage is monotonically non-decreasing within a billing week
|
|
1338
|
-
#
|
|
1339
|
-
#
|
|
1792
|
+
# 7-day usage is monotonically non-decreasing within a billing week
|
|
1793
|
+
# — UNTIL Anthropic issues an in-place weekly credit. When a
|
|
1794
|
+
# week_reset_events row exists for THIS week_end_at, the MAX query
|
|
1795
|
+
# filters to samples captured at-or-after the segment's
|
|
1796
|
+
# effective_reset_at_utc so a fresh post-credit OAuth value (e.g.
|
|
1797
|
+
# 2%) lands instead of being held back by stale pre-credit history
|
|
1798
|
+
# (e.g. 67%). When no event row exists, COALESCE defaults to
|
|
1799
|
+
# epoch-zero so the filter is a no-op and legacy clamp behavior
|
|
1800
|
+
# is preserved byte-identically.
|
|
1801
|
+
# NB: comparison wrapped with ``unixepoch()`` on BOTH sides.
|
|
1802
|
+
# ``captured_at_utc`` is stored with `Z` suffix, but
|
|
1803
|
+
# ``effective_reset_at_utc`` may have a non-UTC offset on
|
|
1804
|
+
# historical backfill rows written before Bug 3 was fixed
|
|
1805
|
+
# (parse_iso_datetime returned host-local). Lex string compare
|
|
1806
|
+
# on mixed offsets silently mis-orders moments for non-UTC
|
|
1807
|
+
# hosts (CLAUDE.md gotcha: 5h-block cross-reset flag — "all
|
|
1808
|
+
# comparisons go through unixepoch(), NOT lex
|
|
1809
|
+
# BETWEEN/`<`/`>`"). Same rule applies here.
|
|
1340
1810
|
max_row = conn.execute(
|
|
1341
|
-
"
|
|
1342
|
-
(
|
|
1811
|
+
"""
|
|
1812
|
+
SELECT MAX(weekly_percent) AS v
|
|
1813
|
+
FROM weekly_usage_snapshots
|
|
1814
|
+
WHERE week_start_date = ?
|
|
1815
|
+
AND unixepoch(captured_at_utc) >= unixepoch(COALESCE(
|
|
1816
|
+
(SELECT effective_reset_at_utc
|
|
1817
|
+
FROM week_reset_events
|
|
1818
|
+
WHERE new_week_end_at = ?
|
|
1819
|
+
ORDER BY id DESC
|
|
1820
|
+
LIMIT 1),
|
|
1821
|
+
'1970-01-01T00:00:00Z'
|
|
1822
|
+
))
|
|
1823
|
+
""",
|
|
1824
|
+
(week_start_date, week_end_at),
|
|
1343
1825
|
).fetchone()
|
|
1344
1826
|
if max_row and max_row["v"] is not None and round(weekly_percent, 1) < round(float(max_row["v"]), 1):
|
|
1345
1827
|
should_insert = False
|
|
1346
1828
|
else:
|
|
1347
|
-
# 5-hour usage is monotonically non-decreasing within a window
|
|
1348
|
-
#
|
|
1349
|
-
#
|
|
1829
|
+
# 5-hour usage is monotonically non-decreasing within a window
|
|
1830
|
+
# — UNTIL an in-place 5h credit fires. When a
|
|
1831
|
+
# ``five_hour_reset_events`` row exists for THIS
|
|
1832
|
+
# ``five_hour_window_key``, the MAX query filters to samples
|
|
1833
|
+
# captured at-or-after the event's ``effective_reset_at_utc``
|
|
1834
|
+
# so a fresh post-credit OAuth value (e.g. 4%) lands instead
|
|
1835
|
+
# of being re-clamped to the pre-credit max (e.g. 28%). When
|
|
1836
|
+
# no event row exists, ``COALESCE`` defaults to epoch-zero so
|
|
1837
|
+
# the filter is a no-op and legacy clamp behavior is preserved
|
|
1838
|
+
# byte-identically.
|
|
1839
|
+
#
|
|
1840
|
+
# ``unixepoch()`` on BOTH sides for offset robustness — stored
|
|
1841
|
+
# ``captured_at_utc`` carries ``Z`` while
|
|
1842
|
+
# ``effective_reset_at_utc`` carries ``+00:00``. Lex compare
|
|
1843
|
+
# would silently mis-order moments for non-UTC hosts (same
|
|
1844
|
+
# gotcha as the weekly clamp / 5h-block cross-reset flag).
|
|
1845
|
+
#
|
|
1846
|
+
# Joining on ``five_hour_window_key`` (canonical 10-min-floored
|
|
1350
1847
|
# epoch) absorbs Anthropic's seconds-level jitter on
|
|
1351
|
-
# resets_at
|
|
1848
|
+
# ``resets_at``; an ISO-string equality at this site silently
|
|
1352
1849
|
# skipped the clamp every time a jittered fetch landed in
|
|
1353
1850
|
# the same physical 5h window (spec Bug B).
|
|
1851
|
+
#
|
|
1852
|
+
# Spec §4.1 of
|
|
1853
|
+
# docs/superpowers/specs/2026-05-16-5h-in-place-credit-detection.md.
|
|
1354
1854
|
if five_hour_percent is not None and five_hour_window_key is not None:
|
|
1355
1855
|
max_5h_row = conn.execute(
|
|
1356
|
-
"
|
|
1357
|
-
(
|
|
1856
|
+
"""
|
|
1857
|
+
SELECT MAX(five_hour_percent) AS v
|
|
1858
|
+
FROM weekly_usage_snapshots
|
|
1859
|
+
WHERE five_hour_window_key = ?
|
|
1860
|
+
AND unixepoch(captured_at_utc) >= unixepoch(COALESCE(
|
|
1861
|
+
(SELECT effective_reset_at_utc
|
|
1862
|
+
FROM five_hour_reset_events
|
|
1863
|
+
WHERE five_hour_window_key = ?
|
|
1864
|
+
ORDER BY id DESC
|
|
1865
|
+
LIMIT 1),
|
|
1866
|
+
'1970-01-01T00:00:00Z'
|
|
1867
|
+
))
|
|
1868
|
+
""",
|
|
1869
|
+
(int(five_hour_window_key), int(five_hour_window_key)),
|
|
1358
1870
|
).fetchone()
|
|
1359
|
-
if
|
|
1871
|
+
if (
|
|
1872
|
+
max_5h_row
|
|
1873
|
+
and max_5h_row["v"] is not None
|
|
1874
|
+
and round(five_hour_percent, 1)
|
|
1875
|
+
< round(float(max_5h_row["v"]), 1)
|
|
1876
|
+
):
|
|
1360
1877
|
five_hour_percent = float(max_5h_row["v"])
|
|
1361
1878
|
|
|
1362
1879
|
# Dedup vs last snapshot: if BOTH weekly_percent and
|
|
@@ -1426,11 +1943,29 @@ def cmd_record_usage(args: argparse.Namespace) -> int:
|
|
|
1426
1943
|
)
|
|
1427
1944
|
need_milestone_heal = False
|
|
1428
1945
|
if latest_floor >= 1:
|
|
1946
|
+
# v1.7.2: scope the heal probe to the ACTIVE segment.
|
|
1947
|
+
# Without this, a credited week's MAX over the whole
|
|
1948
|
+
# ledger would still read the pre-credit ceiling
|
|
1949
|
+
# (e.g. 67%) and silently suppress the post-credit
|
|
1950
|
+
# ledger's heal even though it has zero rows.
|
|
1951
|
+
captured_at_for_probe = latest_row["captured_at_utc"]
|
|
1952
|
+
week_end_at_for_probe = latest_row["week_end_at"]
|
|
1953
|
+
heal_segment = 0
|
|
1954
|
+
if week_end_at_for_probe and captured_at_for_probe:
|
|
1955
|
+
seg = heal_conn.execute(
|
|
1956
|
+
"SELECT id FROM week_reset_events "
|
|
1957
|
+
"WHERE new_week_end_at = ? "
|
|
1958
|
+
" AND unixepoch(effective_reset_at_utc) <= unixepoch(?) "
|
|
1959
|
+
"ORDER BY id DESC LIMIT 1",
|
|
1960
|
+
(week_end_at_for_probe, captured_at_for_probe),
|
|
1961
|
+
).fetchone()
|
|
1962
|
+
if seg is not None:
|
|
1963
|
+
heal_segment = int(seg["id"])
|
|
1429
1964
|
max_existing = heal_conn.execute(
|
|
1430
1965
|
"SELECT MAX(percent_threshold) AS m "
|
|
1431
1966
|
"FROM percent_milestones "
|
|
1432
|
-
"WHERE week_start_date = ?",
|
|
1433
|
-
(week_start_date,),
|
|
1967
|
+
"WHERE week_start_date = ? AND reset_event_id = ?",
|
|
1968
|
+
(week_start_date, heal_segment),
|
|
1434
1969
|
).fetchone()
|
|
1435
1970
|
if max_existing is None or max_existing["m"] is None:
|
|
1436
1971
|
need_milestone_heal = True
|
|
@@ -1442,6 +1977,16 @@ def cmd_record_usage(args: argparse.Namespace) -> int:
|
|
|
1442
1977
|
# last_observed_at_utc is stale relative to the latest
|
|
1443
1978
|
# snapshot's captured_at_utc (the kill landed between
|
|
1444
1979
|
# insert_usage_snapshot and maybe_update_five_hour_block).
|
|
1980
|
+
#
|
|
1981
|
+
# Round-3: ALSO scope the milestone-coverage half of
|
|
1982
|
+
# this probe by ACTIVE 5h SEGMENT. Without this, a
|
|
1983
|
+
# credited block's MAX over the whole milestone ledger
|
|
1984
|
+
# would still read the pre-credit ceiling (e.g. 28%) and
|
|
1985
|
+
# silently suppress the post-credit ledger's heal even
|
|
1986
|
+
# though it has zero rows. Mirrors weekly Probe 1's
|
|
1987
|
+
# segment-aware fix above. Uses
|
|
1988
|
+
# ``_resolve_active_five_hour_reset_event_id`` to find
|
|
1989
|
+
# the active segment for the latest snapshot's window.
|
|
1445
1990
|
need_5h_heal = False
|
|
1446
1991
|
window_key = latest_row["five_hour_window_key"]
|
|
1447
1992
|
if window_key is not None:
|
|
@@ -1458,6 +2003,45 @@ def cmd_record_usage(args: argparse.Namespace) -> int:
|
|
|
1458
2003
|
< latest_row["captured_at_utc"]
|
|
1459
2004
|
):
|
|
1460
2005
|
need_5h_heal = True
|
|
2006
|
+
else:
|
|
2007
|
+
# Block row exists AND last_observed is fresh
|
|
2008
|
+
# — but the post-credit milestone segment may
|
|
2009
|
+
# still owe rows. Scope MAX(percent_threshold)
|
|
2010
|
+
# by the active reset_event_id segment so
|
|
2011
|
+
# post-credit climbs from threshold 1 trigger
|
|
2012
|
+
# heal even when the pre-credit segment already
|
|
2013
|
+
# crossed higher thresholds. Probe shape mirrors
|
|
2014
|
+
# weekly Probe 1 (lines 1922-1956).
|
|
2015
|
+
five_hour_percent_for_probe = latest_row[
|
|
2016
|
+
"five_hour_percent"
|
|
2017
|
+
]
|
|
2018
|
+
if five_hour_percent_for_probe is not None:
|
|
2019
|
+
latest_5h_floor = math.floor(
|
|
2020
|
+
float(five_hour_percent_for_probe) + 1e-9
|
|
2021
|
+
)
|
|
2022
|
+
if latest_5h_floor >= 1:
|
|
2023
|
+
heal_5h_segment = (
|
|
2024
|
+
_resolve_active_five_hour_reset_event_id(
|
|
2025
|
+
heal_conn, int(window_key)
|
|
2026
|
+
)
|
|
2027
|
+
)
|
|
2028
|
+
max_5h_existing = heal_conn.execute(
|
|
2029
|
+
"SELECT MAX(percent_threshold) AS m "
|
|
2030
|
+
"FROM five_hour_milestones "
|
|
2031
|
+
"WHERE five_hour_window_key = ? "
|
|
2032
|
+
" AND reset_event_id = ?",
|
|
2033
|
+
(int(window_key), heal_5h_segment),
|
|
2034
|
+
).fetchone()
|
|
2035
|
+
if (
|
|
2036
|
+
max_5h_existing is None
|
|
2037
|
+
or max_5h_existing["m"] is None
|
|
2038
|
+
):
|
|
2039
|
+
need_5h_heal = True
|
|
2040
|
+
elif (
|
|
2041
|
+
int(max_5h_existing["m"])
|
|
2042
|
+
< latest_5h_floor
|
|
2043
|
+
):
|
|
2044
|
+
need_5h_heal = True
|
|
1461
2045
|
finally:
|
|
1462
2046
|
heal_conn.close()
|
|
1463
2047
|
|