mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-11 00:27:01 +01:00
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JThjboXTeZ3yJPBzxMx5wS
57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
"""Active time: the sum of gaps between consecutive records, ignoring idle gaps.
|
|
|
|
A gap longer than :data:`IDLE_GAP` contributes **zero** (not the cap): it means
|
|
nobody and nothing was working. Storing each file as maximal runs of records
|
|
spaced at most ``IDLE_GAP`` apart is lossless for that rule -- the active time
|
|
of several files' merged timeline equals the measure of the union of their runs
|
|
with gaps of up to ``IDLE_GAP`` between runs bridged. That is what lets a main
|
|
session and the subagents it spawned, ingested in different runs, combine
|
|
exactly afterwards.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Iterable
|
|
|
|
IDLE_GAP = 300.0
|
|
Span = tuple[float, float]
|
|
|
|
|
|
def intervals(stamps: Iterable[float], gap: float = IDLE_GAP) -> list[Span]:
|
|
"""Collapse sorted-or-not timestamps into maximal runs."""
|
|
out: list[Span] = []
|
|
for stamp in sorted(stamps):
|
|
if out and stamp - out[-1][1] <= gap:
|
|
out[-1] = (out[-1][0], stamp)
|
|
else:
|
|
out.append((stamp, stamp))
|
|
return out
|
|
|
|
|
|
def measure(
|
|
spans: Iterable[Span],
|
|
low: float = float("-inf"),
|
|
high: float = float("inf"),
|
|
gap: float = IDLE_GAP,
|
|
) -> float:
|
|
"""Active seconds of the union of runs, clipped to ``[low, high)``."""
|
|
merged = intervals_union(spans, gap)
|
|
total = 0.0
|
|
for start, end in merged:
|
|
total += max(0.0, min(end, high) - max(start, low))
|
|
return total
|
|
|
|
|
|
def intervals_union(spans: Iterable[Span], gap: float = IDLE_GAP) -> list[Span]:
|
|
"""Union of runs, bridging gaps no longer than ``gap``."""
|
|
out: list[Span] = []
|
|
for start, end in sorted(spans):
|
|
if out and start - out[-1][1] <= gap:
|
|
out[-1] = (out[-1][0], max(out[-1][1], end))
|
|
else:
|
|
out.append((start, end))
|
|
return out
|