Skip to content

Commit 7520228

Browse files
committed
merge: dev7 → master — scout_dedup.py (SC-05) + tick leggero Sentinella + fix attribuzione token [RESUME] + Dottore compatta coordinatori + fix nomi tool prompt
2 parents a9ddf8b + 46239db commit 7520228

30 files changed

Lines changed: 561 additions & 43 deletions

.launcher/sentinel-bridge.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,15 @@
146146
# critico. Quando proj rientra nel g-spot, il cooldown si resetta.
147147
SENTINELLA_COOLDOWN_MIN = 15.0
148148

149+
# Tick leggero (2026-06-28): durante un episodio attuabile PROLUNGATO e a
150+
# REGIME INVARIATO (stesso `status`), re-confermare la Sentinella ogni quarto
151+
# è quasi sempre ridondante (l'ordine/throttle è già applicato) — è il caso
152+
# osservato su VPS Ashley (sforo/sottoutilizzo stabile per ore → ~40 wake/g).
153+
# Quando il regime non cambia, posticipiamo la re-conferma fino a questo cap
154+
# di sicurezza (la svegliamo comunque, per ricalibrare, ma molto più di rado).
155+
# Un cambio di `status` (regime) la sveglia SEMPRE, anche prima del cap.
156+
SENTINELLA_RECONFIRM_MIN = 45.0
157+
149158

150159
# ── Config + tmux helpers (libreria per le skill) ───────────────────────
151160

@@ -339,7 +348,7 @@ def _next_tick_sleep_sec(now_dt, override_min=None):
339348
return to_next
340349

341350

342-
def _should_notify_sentinella(on_pace, state, now_ts, is_quarter):
351+
def _should_notify_sentinella(on_pace, state, now_ts, is_quarter, status=None):
343352
"""Decide se SVEGLIARE la Sentinella (gate deterministico, edge-driven).
344353
345354
Lean-comms (2026-06-15): il bridge decide il "silenzio" in codice PRIMA di
@@ -352,16 +361,25 @@ def _should_notify_sentinella(on_pace, state, now_ts, is_quarter):
352361
"HOLD già attivo" ad ogni tick 5min — la causa del coordinator-burn
353362
osservato (la Sentinella ragionava verbosamente per ridire "silenzio").
354363
364+
Tick leggero (2026-06-28): durante un episodio in corso, se il REGIME
365+
(`status`) è INVARIATO rispetto all'ultima notifica, la re-conferma ai
366+
quarti è ridondante (l'ordine è già applicato) → la posticipiamo fino al
367+
cap SENTINELLA_RECONFIRM_MIN. Un cambio di `status` la sveglia subito (al
368+
quarto utile). `status=None` → comportamento legacy (re-conferma al
369+
cooldown), per non sorprendere eventuali chiamatori senza regime.
370+
355371
Il gate orario (fuori finestra → mai svegliare) è applicato a monte dal
356372
chiamante (vedi `_within_working_hours`), non qui.
357373
358374
state è un dict con:
359375
last_sent_ts — timestamp Unix dell'ultima notifica (None se reset)
376+
last_sent_status — `status` (regime) all'ultima notifica (None se reset)
360377
"""
361378
if on_pace:
362379
# Calmo: nessun bisogno di Sentinella. Reset del cooldown così il
363380
# prossimo episodio attuabile è notificato immediatamente.
364381
state["last_sent_ts"] = None
382+
state["last_sent_status"] = None
365383
return False
366384

367385
last_ts = state.get("last_sent_ts")
@@ -372,7 +390,15 @@ def _should_notify_sentinella(on_pace, state, now_ts, is_quarter):
372390
if not is_quarter:
373391
return False
374392
elapsed_min = (now_ts - last_ts) / 60.0
375-
return elapsed_min >= SENTINELLA_COOLDOWN_MIN
393+
if elapsed_min < SENTINELLA_COOLDOWN_MIN:
394+
return False
395+
if status is None:
396+
# Legacy: senza regime, re-conferma appena scaduto il cooldown.
397+
return True
398+
# Tick leggero: regime cambiato → sveglia; regime invariato → aspetta il cap.
399+
if status != state.get("last_sent_status"):
400+
return True
401+
return elapsed_min >= SENTINELLA_RECONFIRM_MIN
376402

377403

378404
def _write_state_file(state, last_tick_at, next_tick_at, tick_interval_min,
@@ -1335,6 +1361,7 @@ def main():
13351361
"tick_phase": "DEFAULT",
13361362
"gspot_consecutive": 0,
13371363
"last_sent_ts": None,
1364+
"last_sent_status": None, # regime all'ultima notifica (tick leggero)
13381365
}
13391366

13401367
while True:
@@ -1482,7 +1509,7 @@ def main():
14821509
effective_on_pace = on_pace and not weekly_binding
14831510
_advance_tick_phase(state, effective_on_pace)
14841511
should_notify = _should_notify_sentinella(
1485-
effective_on_pace, state, now_ts, is_quarter
1512+
effective_on_pace, state, now_ts, is_quarter, status=status
14861513
)
14871514
state["last_status"] = status
14881515

@@ -1635,6 +1662,7 @@ def main():
16351662
f"{weekly_field}{weekly_pace_field}{daily_pace_field}{tools_health_field}{monthly_quota_field} src=bridge."
16361663
)
16371664
state["last_sent_ts"] = now_ts
1665+
state["last_sent_status"] = status # regime notificato (tick leggero)
16381666

16391667
# Recovery se eravamo in failure streak (gate orario: zitto fuori finestra)
16401668
if fail_streak >= FETCH_FAIL_THRESHOLD or capitano_alerted:

agents/_skills/scaling-calc/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ consuma davvero un worker in QUESTO ciclo. Si calibra a gradini.
1515

1616
**2. Osserva ~30 min** per misurare il burn reale. Leggi il burn del worker:
1717
```
18-
python3 /app/shared/skills/rate-budget.py # velocità-target sostenibile (S)
18+
python3 /app/shared/skills/rate_budget.py # velocità-target sostenibile (S)
1919
# burn per-agente: dalla tabella che la Sentinella ti gira, o:
2020
python3 /app/shared/skills/agent-speed-table.py
2121
```

agents/_skills/session-refresh/SKILL.de.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ JOURNAL=/jht_home/logs/doctor-retrospective.jsonl
2424
```bash
2525
tmux list-sessions -F '#{session_name}|#{session_created}'
2626
```
27-
- **Reihenfolge**: Worker-Sitzungen ZUERST (`SCOUT-N · ANALISTA-N · SCORER-N · SCRITTORE-N · CRITICO-S*`), benutzerseitige ZULETZT und mit Sorgfalt (`ASSISTENTE · MENTOR · SENTINELLA · CAPITANO`). Aktualisiere niemals `DOTTORE` / `DOCTOR-WATCHDOG` (dich selbst / den Scheduler).
27+
- **Reihenfolge**: Worker-Sitzungen ZUERST (`SCOUT-N · ANALISTA-N · SCORER-N · SCRITTORE-N · CRITICO-S*`), Koordinatoren ZULETZT und mit Sorgfalt (`ASSISTENTE · MENTOR · SENTINELLA · CAPITANO`). „Mit Sorgfalt" heißt **ihren Zustand gut erfassen und sie kompaktieren — sie NICHT überspringen** (sie sind die Top-Konsumenten; siehe Regeln). Aktualisiere niemals `DOTTORE` / `DOCTOR-WATCHDOG` (dich selbst / den Scheduler).
2828
- **FRESH-Skip**: `age = now - session_created`. Wenn `age < 40 min` → vollständig ÜBERSPRINGEN (es gibt noch nichts zusammenzufassen, und ein Refresh würde eine gerade erst gestartete Sitzung wegwerfen). Logge `action=skipped_fresh`.
2929

3030
## Schritt 2 — pro Sitzung: Erfassung (breit + relevant)
@@ -92,6 +92,8 @@ Setze `resume_msg_sent=True` im Journal-Eintrag. Gehe dann zur nächsten Sitzung
9292

9393
## Regeln
9494
- **Ein Doctor erledigt alle Sitzungen dieser Runde** (Benutzervorgabe: vorerst ein einzelner Doctor). Nutze die dateibasierte Erfassung + grep, damit du nie dein eigenes Kontextfenster sprengst.
95-
- **Niemals** `CAPITANO`/`SENTINELLA` leichtfertig neu erstellen — sie sind die Orchestrierung/der Heartbeat; aktualisiere sie nur, wenn ihr Kontext eindeutig aufgebläht ist, und nach einer Vorwarnung, als letztes in der Reihenfolge.
95+
- **CAPITANO & SENTINELLA sind die TOP-Token-Konsumenten** (ihr Kontext ist fast immer aufgebläht — die Sentinella tickt alle ~15min, der Capitano koordiniert ununterbrochen). Sie sind NICHT ausgenommen: **kompaktiere sie jede Runde** (zuletzt, nach den Workern). **Kompaktieren, nicht zurücksetzen** — der Refresh mit dichter Synthese bewahrt die Kontinuität, ein roher Kill verliert sie.
96+
- **CAPITANO**: er ist der Koordinator mit In-Flight-Zustand (Worker-Zuweisungen, aktive Throttle-Konfiguration, letzte Pacing-Anweisung, ausstehende Entscheidungen). Erfasse im Interview (Step 5) ausdrücklich diesen Koordinationszustand und lege ihn in den seed (Step 7), damit er den Faden nicht verliert. Mach es ZULETZT; wenn er gerade eine live EMERGENZA behandelt (sichtbare Orchestrierung im Pane genau jetzt), lass ihn zuerst stabilisieren, sonst kompaktiere ihn.
97+
- **SENTINELLA**: sie ist **nahezu zustandslos** — ihr Arbeitszustand lebt im bridge/config und in `sentinel-data.jsonl`, nicht in ihrem Chat. Das macht sie zur **sichersten und wertvollsten zum Kompaktieren**: frische sie jede Runde auf, zuletzt, mit einem minimalen seed: `[RESUME] sei la Sentinella; il tuo stato vive nel bridge + sentinel-data.jsonl — riprendi il monitoraggio del pacing dal prossimo tick.` Die alters-basierte Neuerstellung durch den `agent-watchdog` (jenseits von `JHT_SENTINELLA_MAX_CTX_AGE_H`, Default 24h) bleibt nur als **Fallback** für den Fall, dass der Dottore nicht läuft; da du sie jetzt jede Runde kompaktierst, erreicht sie dieses Alter nicht, also gibt es kein Race.
9698
- **Niemals** `tmux new-session` von Hand — immer `start-agent.sh` (siehe `spawn-agent`).
9799
- Logge jede Aktion im Journal (`recreated`/`skipped_parked`/`skipped_fresh`) — das Journal ist der Audit-Trail und wächst jeden Tag.

agents/_skills/session-refresh/SKILL.es.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ JOURNAL=/jht_home/logs/doctor-retrospective.jsonl
2424
```bash
2525
tmux list-sessions -F '#{session_name}|#{session_created}'
2626
```
27-
- **Orden**: las sesiones worker PRIMERO (`SCOUT-N · ANALISTA-N · SCORER-N · SCRITTORE-N · CRITICO-S*`), las orientadas al usuario AL FINAL y con cuidado (`ASSISTENTE · MENTOR · SENTINELLA · CAPITANO`). Nunca refresques `DOTTORE` / `DOCTOR-WATCHDOG` (tú mismo / el planificador).
27+
- **Orden**: las sesiones worker PRIMERO (`SCOUT-N · ANALISTA-N · SCORER-N · SCRITTORE-N · CRITICO-S*`), los coordinadores AL FINAL y con cuidado (`ASSISTENTE · MENTOR · SENTINELLA · CAPITANO`). "Con cuidado" significa **captura bien su estado y compáctalos — NO los saltes** (son los top consumers; ver Reglas). Nunca refresques `DOTTORE` / `DOCTOR-WATCHDOG` (tú mismo / el planificador).
2828
- **Salto de FRESH**: `age = now - session_created`. Si `age < 40 min` → SALTAR por completo (todavía no hay nada que resumir, y refrescar tiraría una sesión que acaba de empezar). Registra `action=skipped_fresh`.
2929

3030
## Paso 2 — por sesión: captura (amplia + saliente)
@@ -92,6 +92,8 @@ Pon `resume_msg_sent=True` en la entrada del diario. Luego pasa a la siguiente s
9292

9393
## Reglas
9494
- **Un solo Doctor hace todas las sesiones en esta ronda** (orden del usuario: un único Doctor por ahora). Usa la captura basada en fichero + grep para no reventar nunca tu propia ventana de contexto.
95-
- **Nunca** recrees `CAPITANO`/`SENTINELLA` a la ligera — son la orquestación/latido; refréscalos solo si su contexto está claramente inflado y tras un aviso previo, los últimos en el orden.
95+
- **CAPITANO y SENTINELLA son los TOP consumers de tokens** (su contexto está casi siempre inflado — la Sentinella tickea cada ~15min, el Capitano coordina continuamente). NO están exentos: **compáctalos cada ronda** (los últimos, después de los workers). **Compacta, no resetees** — el refresh con síntesis densa preserva la continuidad, un kill en seco la pierde.
96+
- **CAPITANO**: es el coordinador con estado in-flight (asignaciones de workers, config de throttle activa, último orden de pacing, decisiones pendientes). En la entrevista (Step 5) captura explícitamente ese estado de coordinación y ponlo en el seed (Step 7) para que no pierda el hilo. Hazlo el ÚLTIMO; si está gestionando una EMERGENZA en vivo (orquestación visible en el pane justo ahora), deja que se estabilice primero, de lo contrario compáctalo.
97+
- **SENTINELLA**: es **near-stateless** — su estado operativo vive en el bridge/config y en `sentinel-data.jsonl`, no en su chat. Esto la hace la **más segura y de mayor valor para compactar**: refréscala cada ronda, la última, con un seed mínimo: `[RESUME] sei la Sentinella; il tuo stato vive nel bridge + sentinel-data.jsonl — riprendi il monitoraggio del pacing dal prossimo tick.` El recreate por edad del `agent-watchdog` (más allá de `JHT_SENTINELLA_MAX_CTX_AGE_H`, default 24h) queda solo como **fallback** para cuando el Dottore no está corriendo; dado que ahora la compactas cada ronda no alcanzará esa edad, así que no hay race.
9698
- **Nunca** hagas `tmux new-session` a mano — siempre `start-agent.sh` (ver `spawn-agent`).
9799
- Registra cada acción en el diario (`recreated`/`skipped_parked`/`skipped_fresh`) — el diario es el rastro de auditoría y crece cada día.

agents/_skills/session-refresh/SKILL.fr.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ JOURNAL=/jht_home/logs/doctor-retrospective.jsonl
2424
```bash
2525
tmux list-sessions -F '#{session_name}|#{session_created}'
2626
```
27-
- **Ordre** : les sessions de travailleurs D'ABORD (`SCOUT-N · ANALISTA-N · SCORER-N · SCRITTORE-N · CRITICO-S*`), celles tournées vers l'utilisateur EN DERNIER et avec précaution (`ASSISTENTE · MENTOR · SENTINELLA · CAPITANO`). Ne rafraîchis jamais `DOTTORE` / `DOCTOR-WATCHDOG` (toi-même / le planificateur).
27+
- **Ordre** : les sessions de travailleurs D'ABORD (`SCOUT-N · ANALISTA-N · SCORER-N · SCRITTORE-N · CRITICO-S*`), les coordinateurs EN DERNIER et avec précaution (`ASSISTENTE · MENTOR · SENTINELLA · CAPITANO`). « Avec précaution » veut dire **capturer bien leur état et les compacter — NE PAS les sauter** (ce sont les top consumers ; voir Règles). Ne rafraîchis jamais `DOTTORE` / `DOCTOR-WATCHDOG` (toi-même / le planificateur).
2828
- **Ignorer si FRESH** : `age = now - session_created`. Si `age < 40 min` → IGNORER entièrement (rien à résumer encore, et rafraîchir gaspillerait une session qui vient tout juste de démarrer). Journaliser `action=skipped_fresh`.
2929

3030
## Étape 2 — par session : capture (large + saillant)
@@ -92,6 +92,8 @@ Mets `resume_msg_sent=True` dans l'entrée du journal. Puis passe à la session
9292

9393
## Règles
9494
- **Un seul Dottore traite toutes les sessions ce tour** (ordre de l'utilisateur : un seul Dottore pour l'instant). Utilise la capture sur fichier + grep pour ne jamais faire exploser ta propre fenêtre de contexte.
95-
- **Ne jamais** recréer `CAPITANO`/`SENTINELLA` à la légère — ce sont l'orchestration/le battement de cœur ; ne les rafraîchis que si leur contexte est manifestement surchargé et après un préavis, en dernier dans l'ordre.
95+
- **CAPITANO et SENTINELLA sont les TOP consumers de token** (leur contexte est presque toujours surchargé — la Sentinella ticke toutes les ~15min, le Capitano coordonne en continu). Ils ne sont PAS exemptés : **compacte-les à chaque tour** (en dernier, après les workers). **Compacte, ne réinitialise pas** — le refresh par synthèse dense préserve la continuité, un kill brut la perd.
96+
- **CAPITANO** : c'est le coordinateur avec un état in-flight (assignations des workers, config de throttle active, dernier ordre de pacing, décisions en attente). Pendant l'entretien (Step 5), capture explicitement cet état de coordination et mets-le dans le seed (Step 7) pour qu'il ne perde pas le fil. Fais-le en DERNIER ; s'il gère une EMERGENZA en direct (orchestration visible dans le pane à l'instant), laisse-le se stabiliser d'abord, sinon compacte-le.
97+
- **SENTINELLA** : elle est **near-stateless** — son état de travail vit dans le bridge/config et dans `sentinel-data.jsonl`, pas dans sa chat. Cela en fait la **plus sûre et la plus rentable à compacter** : rafraîchis-la à chaque tour, en dernier, avec un seed minimal : `[RESUME] sei la Sentinella; il tuo stato vive nel bridge + sentinel-data.jsonl — riprendi il monitoraggio del pacing dal prossimo tick.` Le recreate par âge de l'`agent-watchdog` (au-delà de `JHT_SENTINELLA_MAX_CTX_AGE_H`, défaut 24h) ne reste qu'en **fallback** pour quand le Dottore ne tourne pas ; comme tu la compactes désormais à chaque tour elle n'atteindra pas cet âge, donc aucun race.
9698
- **Ne jamais** faire `tmux new-session` à la main — toujours `start-agent.sh` (voir `spawn-agent`).
9799
- Journalise chaque action dans le journal (`recreated`/`skipped_parked`/`skipped_fresh`) — le journal est la piste d'audit et s'enrichit chaque jour.

agents/_skills/session-refresh/SKILL.hu.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ JOURNAL=/jht_home/logs/doctor-retrospective.jsonl
2424
```bash
2525
tmux list-sessions -F '#{session_name}|#{session_created}'
2626
```
27-
- **Sorrend**: a worker-munkamenetek ELŐSZÖR (`SCOUT-N · ANALISTA-N · SCORER-N · SCRITTORE-N · CRITICO-S*`), a felhasználó felé néző munkamenetek UTOLJÁRA és óvatosan (`ASSISTENTE · MENTOR · SENTINELLA · CAPITANO`). Soha ne frissítsd a `DOTTORE` / `DOCTOR-WATCHDOG` munkamenetet (saját magadat / az ütemezőt).
27+
- **Sorrend**: a worker-munkamenetek ELŐSZÖR (`SCOUT-N · ANALISTA-N · SCORER-N · SCRITTORE-N · CRITICO-S*`), a koordinátorok UTOLJÁRA és óvatosan (`ASSISTENTE · MENTOR · SENTINELLA · CAPITANO`). Az „óvatosan" azt jelenti, hogy **jól fogd be az állapotukat és tömörítsd őket — NE hagyd ki őket** (ők a legnagyobb fogyasztók; lásd a Szabályokat). Soha ne frissítsd a `DOTTORE` / `DOCTOR-WATCHDOG` munkamenetet (saját magadat / az ütemezőt).
2828
- **FRESH kihagyás**: `age = now - session_created`. Ha `age < 40 min` → teljesen KIHAGYNI (még nincs mit összefoglalni, és a frissítés eldobna egy épp elindult munkamenetet). Naplózd: `action=skipped_fresh`.
2929

3030
## Step 2 — munkamenetenként: capture (széles + lényegi)
@@ -92,6 +92,8 @@ sleep 8
9292

9393
## Szabályok
9494
- **Egy Dottore intézi az összes munkamenetet ebben a körben** (felhasználói sorrend: egyelőre egyetlen Dottore). Használd a fájlalapú capture + grep megoldást, hogy soha ne robbantsd fel a saját kontextusablakodat.
95-
- **Soha** ne hozd újra létre könnyelműen a `CAPITANO`/`SENTINELLA` munkameneteket — ezek az orkesztráció/szívverés; csak akkor frissítsd őket, ha a kontextusuk egyértelműen felduzzadt, előzetes figyelmeztetés után, a sorrendben utolsóként.
95+
- **A `CAPITANO` és a `SENTINELLA` a LEGNAGYOBB token-fogyasztók** (a kontextusuk szinte mindig felduzzadt — a Sentinella ~15 percenként tickel, a Capitano folyamatosan koordinál). NEM kivételek: **tömörítsd őket minden körben** (utolsóként, a workerek után). **Tömöríts, ne resetelj** — a sűrű szintézisű frissítés megőrzi a folytonosságot, egy nyers kill elveszíti azt.
96+
- **CAPITANO**: koordinátor in-flight állapottal (worker-beosztások, aktív throttle-konfiguráció, utolsó pacing-utasítás, függőben lévő döntések). Az interjúban (Step 5) explicit módon fogd be ezt a koordinációs állapotot, és tedd a seedbe (Step 7). UTOLSÓKÉNT csináld; ha épp egy élő EMERGENZA-t kezel, előbb hagyd stabilizálódni, egyébként tömörítsd.
97+
- **SENTINELLA**: **majdnem állapotmentes** — az állapota a bridge-ben/configban és a sentinel-data.jsonl-ben él, nem a chatjében. Ezért **a legbiztonságosabb és a legnagyobb értékű tömöríteni**: frissítsd minden körben, utolsóként, minimális seeddel. Az agent-watchdog kor-alapú újra létrehozása (a JHT_SENTINELLA_MAX_CTX_AGE_H, alapból 24h után) csak **fallbackként** marad meg arra az esetre, ha a Dottore nem fut; mivel most minden körben tömöríted, nem éri el azt a kort — nincs versenyhelyzet.
9698
- **Soha** ne `tmux new-session` kézzel — mindig `start-agent.sh` (lásd `spawn-agent`).
9799
- Naplózz minden műveletet a naplóban (`recreated`/`skipped_parked`/`skipped_fresh`) — a napló az audit-nyom, és minden nap bővül.

0 commit comments

Comments
 (0)