cctally 1.115.0 → 1.116.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 +16 -0
- package/bin/_cctally_cache.py +85 -4
- package/bin/_cctally_completion.py +80 -12
- package/bin/_cctally_core.py +106 -9
- package/bin/_cctally_dashboard.py +6 -9
- package/bin/_cctally_dashboard_envelope.py +26 -32
- package/bin/_cctally_db.py +85 -4
- package/bin/_cctally_doctor.py +38 -5
- package/bin/_cctally_five_hour.py +83 -1017
- package/bin/_cctally_journal.py +1307 -180
- package/bin/_cctally_journal_repair.py +9 -7
- package/bin/_cctally_oauth_samples.py +280 -0
- package/bin/_cctally_parser.py +5 -0
- package/bin/_cctally_quarantine.py +14 -4
- package/bin/_cctally_quota.py +70 -8
- package/bin/_cctally_quota_model.py +35 -4
- package/bin/_cctally_record.py +414 -123
- package/bin/_cctally_rederive.py +632 -235
- package/bin/_cctally_refresh.py +29 -0
- package/bin/_cctally_statusline.py +984 -47
- package/bin/_cctally_store.py +972 -58
- package/bin/_cctally_tui.py +62 -7
- package/bin/_cctally_update.py +25 -0
- package/bin/_lib_account_protocol.py +201 -18
- package/bin/_lib_clone_copy.py +46 -11
- package/bin/_lib_dashboard_sources.py +57 -15
- package/bin/_lib_detector_access_registry.py +273 -52
- package/bin/_lib_doctor.py +302 -1
- package/bin/_lib_journal.py +145 -25
- package/bin/_lib_journal_router.py +166 -48
- package/bin/_lib_oauth_samples.py +238 -0
- package/bin/_lib_pricing_check.py +0 -12
- package/bin/_lib_provider_activity.py +770 -0
- package/bin/_lib_quarantine.py +3 -2
- package/bin/_lib_quota_model.py +96 -6
- package/bin/_lib_rebuild_progress.py +146 -0
- package/bin/_lib_record.py +22 -0
- package/bin/_lib_rederive.py +299 -3
- package/bin/_lib_snapshot_cache.py +43 -1
- package/bin/_lib_stale_proof.py +708 -0
- package/bin/_lib_statusline_candidates.py +65 -5
- package/bin/_lib_worker_launches.py +315 -0
- package/bin/cctally +6 -11
- package/dashboard/static/assets/{ConversationsView-Bc8LCOAZ.js → ConversationsView-Dflb_myA.js} +1 -1
- package/dashboard/static/assets/DoctorModal-DFX5CfIs.js +1 -0
- package/dashboard/static/assets/{ModalRoot-DLPgyAM_.js → ModalRoot-HlxoagIa.js} +1 -1
- package/dashboard/static/assets/{ProjectsDrillPanel-z53a4v4M.js → ProjectsDrillPanel-C3PJy1xx.js} +1 -1
- package/dashboard/static/assets/{SourceDetailModal-Bw0T8W-W.js → SourceDetailModal-BczsWKhD.js} +1 -1
- package/dashboard/static/assets/{UpdateModal-D5AKx4Yw.js → UpdateModal-Os-Lo5cs.js} +1 -1
- package/dashboard/static/assets/{index-BXDOzSng.js → index-CYZ3NLqF.js} +3 -3
- package/dashboard/static/assets/{outlineNavigation-JObY7cUY.js → outlineNavigation-k-zIif6W.js} +1 -1
- package/dashboard/static/dashboard.html +1 -1
- package/package.json +7 -2
- package/bin/_lib_merge_gate.py +0 -452
- package/dashboard/static/assets/DoctorModal-D--qVBwe.js +0 -1
package/bin/_cctally_refresh.py
CHANGED
|
@@ -72,6 +72,7 @@ from _cctally_core import (
|
|
|
72
72
|
now_utc_iso,
|
|
73
73
|
_iso_to_epoch,
|
|
74
74
|
_format_short_duration,
|
|
75
|
+
_command_as_of,
|
|
75
76
|
)
|
|
76
77
|
|
|
77
78
|
|
|
@@ -645,6 +646,8 @@ def _refresh_usage_inproc_locked(
|
|
|
645
646
|
|
|
646
647
|
``binding`` was captured together with ``token`` before the fetch. The
|
|
647
648
|
response is revalidated against it before ANY mutation (spec 4.6)."""
|
|
649
|
+
# #797/#823/#840 spec 4.3 D8: `q`, taken immediately before the request.
|
|
650
|
+
request_started = _oauth_request_started_now(c)
|
|
648
651
|
try:
|
|
649
652
|
api = c._fetch_oauth_usage(token=token, timeout_seconds=timeout_seconds)
|
|
650
653
|
except RefreshUsageRateLimitError as exc:
|
|
@@ -730,6 +733,9 @@ def _refresh_usage_inproc_locked(
|
|
|
730
733
|
# This is the OAuth feeder — label the row "api" (spec §5). Without
|
|
731
734
|
# this, cmd_record_usage would fall back to its "statusline" default.
|
|
732
735
|
source="api",
|
|
736
|
+
# #797/#823/#840 spec 4.3 D8: this response's own request-start
|
|
737
|
+
# instant, carried with it and its captured binding to publication.
|
|
738
|
+
oauth_request_started_at=request_started,
|
|
733
739
|
)
|
|
734
740
|
authoritative = c._authoritative_record_usage(
|
|
735
741
|
record_args,
|
|
@@ -974,6 +980,24 @@ def _revalidate_selected_credential(c, binding) -> bool:
|
|
|
974
980
|
return current is not None and bool(token) and current == binding
|
|
975
981
|
|
|
976
982
|
|
|
983
|
+
def _oauth_request_started_now(c) -> str:
|
|
984
|
+
"""#797/#823/#840 spec 4.3 D8: the request-start instant `q` of an OAuth
|
|
985
|
+
fetch — the wall clock immediately before `_fetch_oauth_usage` is called,
|
|
986
|
+
at full clock precision, as the raw key `oauth_request_started_at` records
|
|
987
|
+
it. The provider sampled the response at or after it (assumption A-Q).
|
|
988
|
+
|
|
989
|
+
It reads the same clock as the observation's capture stamp
|
|
990
|
+
(`record_usage_bound`): the wall clock, or the harness's pinned
|
|
991
|
+
`CCTALLY_AS_OF` under `CCTALLY_TEST_PIN_CAPTURE`, so `q` never follows the
|
|
992
|
+
capture of its own response."""
|
|
993
|
+
import _lib_oauth_samples
|
|
994
|
+
if os.environ.get("CCTALLY_TEST_PIN_CAPTURE"):
|
|
995
|
+
instant = _command_as_of()
|
|
996
|
+
else:
|
|
997
|
+
instant = dt.datetime.now(dt.timezone.utc)
|
|
998
|
+
return _lib_oauth_samples.format_request_started(instant)
|
|
999
|
+
|
|
1000
|
+
|
|
977
1001
|
def _hook_tick_oauth_skip_status(c, *, throttle_seconds: float, binding) -> str | None:
|
|
978
1002
|
"""Return the automatic-refresh suppression reason under selected lock.
|
|
979
1003
|
Repair need and selected freshness are the captured account's own."""
|
|
@@ -1080,6 +1104,10 @@ def _hook_tick_oauth_refresh(
|
|
|
1080
1104
|
if skipped is not None:
|
|
1081
1105
|
return skipped, None
|
|
1082
1106
|
|
|
1107
|
+
# #797/#823/#840 spec 4.3 D8: `q`, taken immediately before the request.
|
|
1108
|
+
# It travels only with this response: a failure or a discard below drops
|
|
1109
|
+
# both together.
|
|
1110
|
+
request_started = _oauth_request_started_now(c)
|
|
1083
1111
|
try:
|
|
1084
1112
|
api = c._fetch_oauth_usage(token=token, timeout_seconds=timeout_seconds)
|
|
1085
1113
|
except RefreshUsageRateLimitError as exc:
|
|
@@ -1105,6 +1133,7 @@ def _hook_tick_oauth_refresh(
|
|
|
1105
1133
|
if parsed is None:
|
|
1106
1134
|
return "err(parse)", None
|
|
1107
1135
|
record_args, axes, parts = parsed
|
|
1136
|
+
record_args.oauth_request_started_at = request_started
|
|
1108
1137
|
|
|
1109
1138
|
# #583 S2: the nudge remains deferred until after the publication lock is
|
|
1110
1139
|
# released. The sink contract is now enforced by the authority kernel, so
|