feat: perfiles de jitter intercambiables desde Telegram
Cinco perfiles con distinto punto en el compromiso entre variedad visible y
minutos de presencia de mas. Todos dan saldo 0. Se cambian en caliente con
/perfil, con botones, y al cambiar se vuelven a tirar los dados de todos los
dias del horizonte que no se hayan fichado ya.
min/dia madrugon entrada 09:00
discreto 2,8 1,3 2 minutos, moda 75%
natural 4,1 1,8 5 minutos, moda 51% <- por defecto
camuflado 5,5 2,1 4 minutos, moda 43%
disperso 7,9 3,0 6 minutos, moda 29%
sin_madrugar 5,7 1,3 2 minutos, moda 77%
(historico real del usuario: 4 minutos, moda 38%)
La distincion util no es solo el coste total sino DONDE cae. Adelantar la
entrada de la mañana alarga el dia; adelantar la vuelta de comer solo acorta la
comida y se sale a la misma hora. De ahi "sin_madrugar": entrada de la mañana lo
mas pegada posible a las 9 (madrugon 1,26 min/dia, el mas bajo de todos, por
debajo incluso de "discreto") y toda la variedad en la pausa y las salidas.
Para eso los perfiles admiten afinar por tramo con sufijo _w<n>:
entry_median_w0 gana a entry_median para el tramo de la mañana.
tools/perfiles.py mide cada perfil sobre los 226 dias laborables del calendario
real; las cifras de arriba salen de ahi y van guardadas como metadatos para que
/perfil las muestre sin recalcular.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -135,7 +135,8 @@ class Service:
|
||||
logger.info("plan de %s: %s", day, [str(p) for p in plan])
|
||||
return self.store.get_plan(day)
|
||||
|
||||
async def ensure_horizon(self, dias: int = HORIZON_DAYS, force: bool = False) -> None:
|
||||
async def ensure_horizon(self, dias: int = HORIZON_DAYS, force: bool = False,
|
||||
force_all: bool = False) -> None:
|
||||
"""Planifica hoy y los proximos dias, para que la prevision sea exacta."""
|
||||
cal = await asyncio.to_thread(self.executor.calendar)
|
||||
hoy = self.today()
|
||||
@@ -143,7 +144,7 @@ class Service:
|
||||
for i in range(dias):
|
||||
d = hoy + timedelta(days=i)
|
||||
antes = bool(self.store.get_plan(d))
|
||||
await self._plan_un_dia(d, cal, force=force and i == 0)
|
||||
await self._plan_un_dia(d, cal, force=force_all or (force and i == 0))
|
||||
if not antes and self.store.get_plan(d):
|
||||
nuevos += 1
|
||||
self._planned_for = hoy
|
||||
@@ -157,6 +158,13 @@ class Service:
|
||||
await self.ensure_horizon(force=force)
|
||||
return self.store.get_plan(self.today())
|
||||
|
||||
async def cambiar_perfil(self, nombre: str) -> None:
|
||||
"""Cambia el perfil y vuelve a tirar los dados de todo lo que no se ha fichado."""
|
||||
self.store.put("perfil", nombre)
|
||||
self.store.log("perfil", f"cambiado a {nombre}")
|
||||
logger.info("perfil de jitter cambiado a %s", nombre)
|
||||
await self.ensure_horizon(force_all=True)
|
||||
|
||||
async def cancel_pending_today(self, reason: str) -> None:
|
||||
day = self.today()
|
||||
for r in self.store.pending(day):
|
||||
|
||||
Reference in New Issue
Block a user