cctally 1.117.2 → 1.118.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.
- package/CHANGELOG.md +37 -0
- package/README.md +7 -3
- package/bin/_cctally_cache.py +2873 -193
- package/bin/_cctally_completion.py +106 -33
- package/bin/_cctally_core.py +69 -4
- package/bin/_cctally_dashboard.py +188 -13
- package/bin/_cctally_dashboard_conversation.py +5 -1
- package/bin/_cctally_dashboard_envelope.py +50 -19
- package/bin/_cctally_dashboard_sources.py +23 -1
- package/bin/_cctally_db.py +193 -153
- package/bin/_cctally_diagnosis_sources.py +63 -7
- package/bin/_cctally_doctor.py +865 -93
- package/bin/_cctally_five_hour.py +67 -50
- package/bin/_cctally_forecast.py +35 -13
- package/bin/_cctally_journal.py +186 -18
- package/bin/_cctally_milestone_history.py +859 -62
- package/bin/_cctally_oauth_samples.py +286 -15
- package/bin/_cctally_parser.py +2 -2
- package/bin/_cctally_quota.py +104 -12
- package/bin/_cctally_record.py +153 -29
- package/bin/_cctally_rederive.py +608 -68
- package/bin/_cctally_statusline.py +108 -81
- package/bin/_cctally_store.py +179 -38
- package/bin/_cctally_tui.py +892 -181
- package/bin/_cctally_update.py +32 -13
- package/bin/_lib_codex_conversation_query.py +52 -14
- package/bin/_lib_codex_drain_admission.py +224 -6
- package/bin/_lib_codex_metadata.py +39 -0
- package/bin/_lib_conversation_anon.py +15 -8
- package/bin/_lib_conversation_dispatch.py +7 -0
- package/bin/_lib_conversation_query.py +289 -70
- package/bin/_lib_dashboard_sources.py +37 -1
- package/bin/_lib_detector_access_registry.py +497 -26
- package/bin/_lib_doctor.py +85 -20
- package/bin/_lib_doctor_scan_index.py +321 -0
- package/bin/_lib_ingest_frontier.py +20 -1
- package/bin/_lib_oauth_samples.py +23 -7
- package/bin/_lib_pricing.py +146 -16
- package/bin/_lib_quota.py +19 -0
- package/bin/_lib_rederive.py +11 -6
- package/bin/_lib_retained_records.py +516 -0
- package/bin/_lib_snapshot_cache.py +10 -0
- package/bin/_lib_stale_proof.py +272 -43
- package/bin/_lib_stats_content_revision.py +831 -0
- package/bin/_lib_write_io.py +11 -4
- package/bin/cctally +4 -1
- package/dashboard/static/assets/ConversationsView-D4Iv4ku0.js +72 -0
- package/dashboard/static/assets/{DoctorModal-B0DnU9d9.js → DoctorModal-D4QSq6uz.js} +1 -1
- package/dashboard/static/assets/ModalRoot-C9F5dhZi.js +1 -0
- package/dashboard/static/assets/{ProjectsDrillPanel-DSxXQSa-.js → ProjectsDrillPanel-WxAdRDMt.js} +1 -1
- package/dashboard/static/assets/{SourceDetailModal-BleDpQqG.js → SourceDetailModal-NyyEfXmc.js} +1 -1
- package/dashboard/static/assets/{UpdateModal-CMqaAkSK.js → UpdateModal-CFLq9pT1.js} +1 -1
- package/dashboard/static/assets/{index-BjQV-0-D.js → index-BKTWH9JE.js} +2 -2
- package/dashboard/static/assets/{outlineNavigation-CO-VWBm7.js → outlineNavigation-BnGUwCS3.js} +3 -3
- package/dashboard/static/dashboard.html +1 -1
- package/package.json +4 -1
- package/dashboard/static/assets/ConversationsView-oqNsWzWV.js +0 -72
- package/dashboard/static/assets/ModalRoot-CYua2wP_.js +0 -1
|
@@ -639,7 +639,11 @@ def _codex_observation_hold_only(stats, *, executor_owned=False):
|
|
|
639
639
|
return False
|
|
640
640
|
if getattr(stats, "barrier_retry", False) and not executor_owned:
|
|
641
641
|
return False
|
|
642
|
-
|
|
642
|
+
# #1052: every skip the pass saw, its unit phase's included, when the
|
|
643
|
+
# stats object splits them; otherwise its single census dict.
|
|
644
|
+
every_skip = getattr(stats, "all_container_skipped", None)
|
|
645
|
+
skipped = (every_skip() if callable(every_skip)
|
|
646
|
+
else getattr(stats, "container_skipped", {}))
|
|
643
647
|
return (bool(getattr(stats, "container_pending", 0) or any(skipped.values()))
|
|
644
648
|
and set(skipped) <= {
|
|
645
649
|
"decoder-unavailable", "decode-error", "read-error",
|
|
@@ -1274,6 +1274,25 @@ def _sync_failure_envelope(
|
|
|
1274
1274
|
"action": "cctally db repair --db stats --yes",
|
|
1275
1275
|
}
|
|
1276
1276
|
|
|
1277
|
+
# #932 §4.1: an epoch deferral whose admission FAILED has no rebuild
|
|
1278
|
+
# running (no marker, no worker), so "rebuilding" would be false. It is the
|
|
1279
|
+
# existing server-sync error until a later admission succeeds.
|
|
1280
|
+
def field(item, key, default=None):
|
|
1281
|
+
return (item.get(key, default) if isinstance(item, dict)
|
|
1282
|
+
else getattr(item, key, default))
|
|
1283
|
+
|
|
1284
|
+
for item in attributions or ():
|
|
1285
|
+
if (field(item, "database") == "stats"
|
|
1286
|
+
and not bool(field(item, "corruption", False))
|
|
1287
|
+
and bool(field(item, "deferred", False))
|
|
1288
|
+
and field(item, "deferral_outcome") == "failed"):
|
|
1289
|
+
return {
|
|
1290
|
+
"kind": "server_sync",
|
|
1291
|
+
"label": "⚠ server sync error",
|
|
1292
|
+
"detail": "The server could not complete its background sync.",
|
|
1293
|
+
"action": None,
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1277
1296
|
if attributed("stats"):
|
|
1278
1297
|
return {
|
|
1279
1298
|
"kind": "maintenance_active",
|
|
@@ -1676,6 +1695,29 @@ def _header_rate_and_delta(current_rate, current_week_start, trend):
|
|
|
1676
1695
|
return current_rate, None
|
|
1677
1696
|
|
|
1678
1697
|
|
|
1698
|
+
def current_week_freshness(captured, *, now_utc: "dt.datetime",
|
|
1699
|
+
oauth_usage_cfg: "dict | None" = None
|
|
1700
|
+
) -> "dict | None":
|
|
1701
|
+
"""`current_week.freshness` (``{label, captured_at, age_seconds}``) of a
|
|
1702
|
+
confirming-reading instant, or None when there is none. The one
|
|
1703
|
+
derivation the envelope and the source payload's idle refresh share
|
|
1704
|
+
(#1018 twin spec 5.4/5.5)."""
|
|
1705
|
+
if not isinstance(captured, dt.datetime):
|
|
1706
|
+
return None
|
|
1707
|
+
if captured.tzinfo is None:
|
|
1708
|
+
captured = captured.replace(tzinfo=dt.timezone.utc)
|
|
1709
|
+
age_s = max(0.0, (now_utc - captured).total_seconds())
|
|
1710
|
+
_fresh_cfg = (
|
|
1711
|
+
oauth_usage_cfg if oauth_usage_cfg is not None
|
|
1712
|
+
else sys.modules["cctally"]._OAUTH_USAGE_DEFAULTS
|
|
1713
|
+
)
|
|
1714
|
+
return {
|
|
1715
|
+
"label": sys.modules["cctally"]._freshness_label(age_s, _fresh_cfg),
|
|
1716
|
+
"captured_at": _iso_z(captured),
|
|
1717
|
+
"age_seconds": int(age_s),
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
|
|
1679
1721
|
def snapshot_to_envelope(snap: "DataSnapshot", *,
|
|
1680
1722
|
now_utc: "dt.datetime",
|
|
1681
1723
|
monotonic_now: "float | None" = None,
|
|
@@ -1850,25 +1892,14 @@ def snapshot_to_envelope(snap: "DataSnapshot", *,
|
|
|
1850
1892
|
elif tp == 90:
|
|
1851
1893
|
budget_90 = dpd
|
|
1852
1894
|
|
|
1853
|
-
# Freshness envelope for current_week — derived from
|
|
1854
|
-
# cw.
|
|
1855
|
-
# cw is absent or has no
|
|
1856
|
-
#
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
captured = captured.replace(tzinfo=dt.timezone.utc)
|
|
1862
|
-
age_s = max(0.0, (now_utc - captured).total_seconds())
|
|
1863
|
-
_fresh_cfg = (
|
|
1864
|
-
oauth_usage_cfg if oauth_usage_cfg is not None
|
|
1865
|
-
else sys.modules["cctally"]._OAUTH_USAGE_DEFAULTS
|
|
1866
|
-
)
|
|
1867
|
-
cw_freshness = {
|
|
1868
|
-
"label": sys.modules["cctally"]._freshness_label(age_s, _fresh_cfg),
|
|
1869
|
-
"captured_at": _iso_z(captured),
|
|
1870
|
-
"age_seconds": int(age_s),
|
|
1871
|
-
}
|
|
1895
|
+
# Freshness envelope for current_week (spec §3.4) — derived from
|
|
1896
|
+
# cw.latest_weekly_reading_at, the newest genuine reading confirming the
|
|
1897
|
+
# displayed value (#1018 twin spec 5.4). None when cw is absent or has no
|
|
1898
|
+
# resolvable confirmation; the React client renders a placeholder then.
|
|
1899
|
+
# `last_snapshot_age_sec` below keeps the stored row's capture.
|
|
1900
|
+
cw_freshness = current_week_freshness(
|
|
1901
|
+
None if cw is None else getattr(cw, "latest_weekly_reading_at", None),
|
|
1902
|
+
now_utc=now_utc, oauth_usage_cfg=oauth_usage_cfg)
|
|
1872
1903
|
|
|
1873
1904
|
week_lbl: "str | None" = None
|
|
1874
1905
|
reset_at_utc: "dt.datetime | None" = None
|
|
@@ -1490,6 +1490,7 @@ def resolve_dashboard_source_semantics(
|
|
|
1490
1490
|
config: Mapping[str, object] | None,
|
|
1491
1491
|
*,
|
|
1492
1492
|
display_tz_name: str | None,
|
|
1493
|
+
speed: str | None = None,
|
|
1493
1494
|
) -> DashboardSourceSemantics:
|
|
1494
1495
|
"""Resolve dashboard semantics through the shipped CLI kernels.
|
|
1495
1496
|
|
|
@@ -1497,12 +1498,17 @@ def resolve_dashboard_source_semantics(
|
|
|
1497
1498
|
it preserves the CLI's all-$CODEX_HOME fast-service-tier behavior. The
|
|
1498
1499
|
weekly index comes from the same ``get_week_start_name``/``WEEKDAY_MAP``
|
|
1499
1500
|
pair used by the report and budget command surfaces.
|
|
1501
|
+
|
|
1502
|
+
``speed`` (#1050 spec 4.7) is a tier that resolver already returned this
|
|
1503
|
+
tick — the dashboard captures it beside its dispatch read and keys the idle
|
|
1504
|
+
gate on it — so the build uses that one value; ``None`` resolves here.
|
|
1500
1505
|
"""
|
|
1501
1506
|
c = sys.modules["cctally"]
|
|
1502
1507
|
raw_config = dict(config or {})
|
|
1503
1508
|
week_start_name = get_week_start_name(raw_config)
|
|
1504
1509
|
week_start_idx = c.WEEKDAY_MAP[week_start_name]
|
|
1505
|
-
speed
|
|
1510
|
+
if speed is None:
|
|
1511
|
+
speed = c._resolve_codex_speed("auto")
|
|
1506
1512
|
budget_config = c._get_budget_config(raw_config)
|
|
1507
1513
|
quota_alerts = c._get_quota_alerts_config(raw_config)
|
|
1508
1514
|
raw_cache_report = raw_config.get("cache_report")
|
|
@@ -5929,6 +5935,20 @@ def reset_codex_account_scope_cache(*, keep_counters: bool = False) -> None:
|
|
|
5929
5935
|
_CODEX_DERIVED_COHERENCE.clear()
|
|
5930
5936
|
|
|
5931
5937
|
|
|
5938
|
+
def _codex_cycle_index_cost_inputs(context: "DashboardReadContext") -> dict:
|
|
5939
|
+
"""The cost inputs every Codex cycle stamp names (#1050 spec 4.7): this
|
|
5940
|
+
read's cache handle and resolved speed, and — when the build computed it
|
|
5941
|
+
for its own signature — the `codex_stats_digest` that admits the index's
|
|
5942
|
+
process memo."""
|
|
5943
|
+
stats_identity = context.stats_identity
|
|
5944
|
+
return {
|
|
5945
|
+
"cache_conn": context.cache_conn,
|
|
5946
|
+
"speed": context.speed,
|
|
5947
|
+
"stats_digest": (
|
|
5948
|
+
stats_identity[0] if stats_identity is not None else None),
|
|
5949
|
+
}
|
|
5950
|
+
|
|
5951
|
+
|
|
5932
5952
|
def _codex_account_scopes_wire(
|
|
5933
5953
|
context: DashboardReadContext,
|
|
5934
5954
|
*,
|
|
@@ -6060,6 +6080,7 @@ def _codex_account_scopes_wire(
|
|
|
6060
6080
|
sys.modules["cctally"].build_codex_cycle_index(
|
|
6061
6081
|
context.stats_conn, identity=cycle,
|
|
6062
6082
|
now_utc=context.now_utc, account_key=key,
|
|
6083
|
+
**_codex_cycle_index_cost_inputs(context),
|
|
6063
6084
|
)
|
|
6064
6085
|
)
|
|
6065
6086
|
except sqlite3.Error:
|
|
@@ -8704,6 +8725,7 @@ def _build_codex_source_state(
|
|
|
8704
8725
|
cycle_index = tuple(
|
|
8705
8726
|
sys.modules["cctally"].build_codex_cycle_index(
|
|
8706
8727
|
context.stats_conn, identity=cycle, now_utc=context.now_utc,
|
|
8728
|
+
**_codex_cycle_index_cost_inputs(context),
|
|
8707
8729
|
)
|
|
8708
8730
|
)
|
|
8709
8731
|
except sqlite3.Error:
|