cctally 1.59.0 → 1.61.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.
- package/CHANGELOG.md +31 -0
- package/bin/_cctally_cache.py +323 -48
- package/bin/_cctally_core.py +8 -0
- package/bin/_cctally_dashboard.py +913 -143
- package/bin/_cctally_doctor.py +2 -0
- package/bin/_cctally_forecast.py +24 -2
- package/bin/_cctally_parser.py +28 -2
- package/bin/_cctally_tui.py +676 -16
- package/bin/_cctally_update.py +49 -9
- package/bin/_cctally_weekrefs.py +92 -2
- package/bin/_lib_doctor.py +10 -0
- package/bin/_lib_snapshot_cache.py +988 -0
- package/bin/_lib_view_models.py +117 -12
- package/bin/cctally +57 -0
- package/dashboard/static/assets/index-0jzYm75p.css +1 -0
- package/dashboard/static/assets/index-D_Ylyqsf.js +80 -0
- package/dashboard/static/dashboard.html +2 -2
- package/package.json +2 -1
- package/dashboard/static/assets/index-BatfACUX.css +0 -1
- package/dashboard/static/assets/index-VUPDfWul.js +0 -80
package/bin/_cctally_doctor.py
CHANGED
|
@@ -516,6 +516,8 @@ def doctor_gather_state(
|
|
|
516
516
|
dev_mode=_cctally_core.DEV_MODE,
|
|
517
517
|
app_dir=str(_cctally_core.APP_DIR),
|
|
518
518
|
is_dev_checkout=_cctally_core._is_dev_checkout(),
|
|
519
|
+
# Preview channel (CCTALLY_CHANNEL=preview): surfaced in install.mode.
|
|
520
|
+
channel=("preview" if _cctally_core.is_preview_channel() else "prod"),
|
|
519
521
|
# Pricing-freshness check (spec §5.1): trailing-30d coverage gaps.
|
|
520
522
|
pricing_coverage=pricing_coverage,
|
|
521
523
|
# Conversation-sessions rollup consistency (#217 S1 / U9).
|
package/bin/_cctally_forecast.py
CHANGED
|
@@ -327,6 +327,7 @@ def _select_dollars_per_percent(
|
|
|
327
327
|
spent_usd: float,
|
|
328
328
|
*,
|
|
329
329
|
skip_sync: bool = False,
|
|
330
|
+
use_weekref_cost_cache: bool = False,
|
|
330
331
|
) -> tuple[float, str]:
|
|
331
332
|
"""Return (dollars_per_percent, source_label). See spec §1 selection rule.
|
|
332
333
|
|
|
@@ -375,7 +376,26 @@ def _select_dollars_per_percent(
|
|
|
375
376
|
import statistics
|
|
376
377
|
values: list[float] = []
|
|
377
378
|
for ws, we, final_pct in prior:
|
|
378
|
-
|
|
379
|
+
if use_weekref_cost_cache:
|
|
380
|
+
# #269 §4: every `prior` week satisfies `we < now_utc` (an
|
|
381
|
+
# eligibility filter above), so all four are CLOSED and
|
|
382
|
+
# cacheable — this is the SAME immutable per-weekref cost the
|
|
383
|
+
# trend builder caches (B1↔B3 shared key). The `ws=ws, we=we`
|
|
384
|
+
# default-arg capture pins the loop variables (the closure is
|
|
385
|
+
# invoked lazily inside cached_weekref_cost). `skip_sync=True`
|
|
386
|
+
# unconditionally (the dashboard synced once at the top of the
|
|
387
|
+
# rebuild; the flag is only True there).
|
|
388
|
+
_sc = c._load_sibling("_lib_snapshot_cache")
|
|
389
|
+
week_cost = _sc.cached_weekref_cost(
|
|
390
|
+
week_start_at=ws, week_end_at=we, now_utc=now_utc,
|
|
391
|
+
compute=lambda ws=ws, we=we: c._sum_cost_for_range(
|
|
392
|
+
ws, we, mode="auto", skip_sync=True
|
|
393
|
+
),
|
|
394
|
+
)
|
|
395
|
+
else:
|
|
396
|
+
week_cost = c._sum_cost_for_range(
|
|
397
|
+
ws, we, mode="auto", skip_sync=skip_sync
|
|
398
|
+
)
|
|
379
399
|
values.append(week_cost / final_pct)
|
|
380
400
|
return statistics.median(values), "trailing_4wk_median"
|
|
381
401
|
|
|
@@ -422,6 +442,7 @@ def _load_forecast_inputs(
|
|
|
422
442
|
now_utc: dt.datetime,
|
|
423
443
|
*,
|
|
424
444
|
skip_sync: bool = False,
|
|
445
|
+
use_weekref_cost_cache: bool = False,
|
|
425
446
|
) -> ForecastInputs | None:
|
|
426
447
|
"""Gather everything from the DB. Returns None if no current-week snapshot.
|
|
427
448
|
|
|
@@ -466,7 +487,8 @@ def _load_forecast_inputs(
|
|
|
466
487
|
# re-syncs in downstream cost lookups (trailing-4wk-median loop hits
|
|
467
488
|
# _sum_cost_for_range once per historical week).
|
|
468
489
|
dpp, dpp_source = _select_dollars_per_percent(
|
|
469
|
-
conn, now_utc, week_start_at, p_now, spent_usd, skip_sync=True
|
|
490
|
+
conn, now_utc, week_start_at, p_now, spent_usd, skip_sync=True,
|
|
491
|
+
use_weekref_cost_cache=use_weekref_cost_cache,
|
|
470
492
|
)
|
|
471
493
|
confidence, reasons = _assess_forecast_confidence(elapsed_hours, p_now, len(samples))
|
|
472
494
|
target_24h = now_utc - dt.timedelta(hours=24)
|
package/bin/_cctally_parser.py
CHANGED
|
@@ -1523,8 +1523,8 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1523
1523
|
dp.add_argument(
|
|
1524
1524
|
"--port",
|
|
1525
1525
|
type=int,
|
|
1526
|
-
default=
|
|
1527
|
-
help="TCP port to bind (default: 8789).",
|
|
1526
|
+
default=None,
|
|
1527
|
+
help="TCP port to bind (default: 8789; 8790 under the preview channel).",
|
|
1528
1528
|
)
|
|
1529
1529
|
dp.add_argument(
|
|
1530
1530
|
"--host",
|
|
@@ -1960,6 +1960,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1960
1960
|
default="all",
|
|
1961
1961
|
help="Which ingest half to sync/rebuild (default: all).",
|
|
1962
1962
|
)
|
|
1963
|
+
p_cache_sync.add_argument(
|
|
1964
|
+
"--prune-orphans",
|
|
1965
|
+
action="store_true",
|
|
1966
|
+
help="Prune cache rows for source files removed from disk "
|
|
1967
|
+
"(e.g. a deleted git worktree) without a full rebuild.",
|
|
1968
|
+
)
|
|
1963
1969
|
p_cache_sync.set_defaults(func=c.cmd_cache_sync)
|
|
1964
1970
|
|
|
1965
1971
|
# -- daily --
|
|
@@ -2533,6 +2539,26 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2533
2539
|
help=argparse.SUPPRESS) # JSON string fed to mock fetch (tests only)
|
|
2534
2540
|
ht.set_defaults(func=c.cmd_hook_tick)
|
|
2535
2541
|
|
|
2542
|
+
# ---- __preview (internal — maintainer-local preview channel) ----
|
|
2543
|
+
# The preview modules are maintainer-only (excluded from the public
|
|
2544
|
+
# mirror). On a public build `c.cmd_preview` is None — its load in
|
|
2545
|
+
# bin/cctally is wrapped in a tolerant try/except — so skip registering
|
|
2546
|
+
# the hidden subcommand entirely rather than wiring a None handler.
|
|
2547
|
+
if getattr(c, "cmd_preview", None) is not None:
|
|
2548
|
+
pv = sub.add_parser("__preview", help=argparse.SUPPRESS,
|
|
2549
|
+
formatter_class=CLIHelpFormatter,
|
|
2550
|
+
description="Internal: provision/manage the preview-channel data dir.")
|
|
2551
|
+
pv_sub = pv.add_subparsers(dest="action", required=True)
|
|
2552
|
+
pv_ensure = pv_sub.add_parser("ensure", help=argparse.SUPPRESS)
|
|
2553
|
+
pv_ensure.add_argument("--no-refresh", action="store_true")
|
|
2554
|
+
pv_ensure.add_argument("--reseed", action="store_true")
|
|
2555
|
+
pv_ensure.set_defaults(func=c.cmd_preview)
|
|
2556
|
+
pv_clean = pv_sub.add_parser("clean", help=argparse.SUPPRESS)
|
|
2557
|
+
pv_clean.add_argument("--dry-run", action="store_true")
|
|
2558
|
+
pv_clean.set_defaults(func=c.cmd_preview)
|
|
2559
|
+
pv_status = pv_sub.add_parser("status", help=argparse.SUPPRESS)
|
|
2560
|
+
pv_status.set_defaults(func=c.cmd_preview)
|
|
2561
|
+
|
|
2536
2562
|
# ---- update (user-facing self-update subcommand; spec §4) ----
|
|
2537
2563
|
sub_update = sub.add_parser(
|
|
2538
2564
|
"update",
|