Files
ROMFASTSQL/tools/claude_usage_md.py
Claude Agent a01cac0657 feat(analiza): consum real Claude Code si dimensionarea suplimentului GLM
Plafonul general saptamanal Max 5x se consuma in ~2 zile, urmate de ~5 zile
blocate. Masurat pe 3 masini (Windows, claude-agent, moltbot), 2026-07-29 ->
2026-09-01: 11,15 miliarde tokeni, 435 sesiuni, 64.211 cereri API, dedup pe
message.id + requestId. Deficit +32% (~570 prompturi/saptamana).

Concluzia nu e cea asteptata: bugetele plafonate in dolari (OpenCode Zen $20,
OpenCode Go) se evapora la acest volum -- Go a tinut 1-2 zile in practica.
Planurile Z.AI se contorizeaza in prompturi, nu in dolari, si rezista la un
workload cu 7,1 cereri API per prompt. Z.AI Coding Lite ($18/luna) acopera 70%
din deficit; Pro ($72) il acopera integral.

Verificat empiric ca subagentii nu pot rula pe GLM (in proces, moștenesc auth),
dar sesiunile separate pot: endpoint fals local a primit cererea cu tokenul
alternativ, fara sa atinga OAuth-ul Max. Masurat: ~186MB RSS si 20-60s pornire
per sesiune -- de aici regulile de orchestrare (sarcini mari, max 4 procese,
fan-out in interiorul unei sesiuni GLM).

Ramane neverificat multiplicatorul de credite pentru GLM-5.3-Flash; la 3x in
loc de 1x, Lite pica si decizia se muta pe Pro.

- docs/supliment-glm-zai.md: rezumat de implementare (indexat in CLAUDE.md)
- claude_usage_report.md + CSV-uri: analiza completa si datele brute
- tools/claude_usage_*.py: pipeline de masurare read-only, re-rulabil remote
- tools/claude-glm.sh: wrapper de sesiune GLM (task/resume/shell)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
2026-09-01 11:32:56 +00:00

493 lines
33 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
import json, sys
SP, OUT = sys.argv[1], sys.argv[2]
d = json.load(open(SP + "/_agg.json")); T = d["TOT"]
def tt(x): return x["input"]+x["output"]+x["cache_creation"]+x["cache_read"]
P = {"GLM-5.3":{"in":1.40,"cr":0.26,"out":4.40},
"GLM-5.3-Flash (promo)":{"in":0.075,"cr":0.015,"out":0.25},
"GLM-5.3-Flash (listă)":{"in":0.15,"cr":0.03,"out":0.50},
"Zen Claude Opus 5":{"in":5.0,"cr":0.5,"cw":6.25,"out":25.0},
"Zen Claude Sonnet 5":{"in":2.0,"cr":0.2,"cw":2.50,"out":10.0}}
def cA(t,n):
p=P[n]; cw=p.get("cw",p["in"])
return {"input":t["input"]/1e6*p["in"],"cache_read":t["cache_read"]/1e6*p["cr"],
"cache_write":t["cache_creation"]/1e6*cw,"output":t["output"]/1e6*p["out"]}
def cB(t,n):
p=P[n]; return (t["input"]+t["cache_read"]+t["cache_creation"])/1e6*p["in"]+t["output"]/1e6*p["out"]
def S(t,n): return sum(cA(t,n).values())
N=lambda v: f"{v:,}"
days=d["days"]; nd=d["span"]; ns=d["n_sessions"]
g53,gfp,gfl = S(T,"GLM-5.3"),S(T,"GLM-5.3-Flash (promo)"),S(T,"GLM-5.3-Flash (listă)")
zs = d["zen_self"]
COV={"claude-agent":("2026-08-17","2026-09-01",5,"`~/.claude/projects` (Linux, LXC 171)"),
"moltbot":("2026-08-02","2026-09-01",31,"`/home/moltbot/.claude/projects` (Linux, LXC 110)"),
"LENOVO-AIO-BIRO":("2026-07-29","2026-09-01",29,"`C:\\Users\\<user>\\.claude\\projects` (Windows)")}
L=[];A=L.append
A("# Analiză consum Claude Code — Claude Max 5x vs. OpenCode Zen (GLM-5.3)\n")
A(f"**Generat:** 2026-09-01 · **Perioadă:** {days[0]} → {days[-1]} ({nd} zile) · "
f"**3 mașini · {N(ns)} sesiuni · {tt(T)/1e9:.2f}ial miliarde tokeni**\n".replace("ial",""))
A("## 0. Ce a fost scanat\n")
A("| Mașină | Locație | Fișiere | Înregistrări | Duplicate | Sesiuni | Prima zi | Ultima zi | Zile active |")
A("|---|---|---:|---:|---:|---:|---|---|---:|")
for m in d["meta"]:
mm=m["machine"]; c=COV[mm]
A(f"| `{mm}` | {c[3]} | {N(m['files_scanned'])} | {N(m['assistant_records_with_usage'])} | "
f"{N(m['duplicates_removed'])} | {d['sess_per_machine'][mm]} | {c[0]} | {c[1]} | {c[2]} |")
A("")
A("Windows a fost extras de o sesiune Claude Code rulată manual pe acea mașină, cu **exact același "
"script și aceeași cheie de deduplicare** — altfel cifrele nu s-ar putea aduna. Datele au trecut "
"printr-un pas de tabel (separator TAB, date în format M/D/YYYY); au fost renormalizate la ISO, "
"iar toate cele 218 UUID-uri de sesiune au fost validate. Ceasul din zi s-a pierdut la conversie, "
"dar granularitatea folosită în raport e ziua.\n")
A("### Corecție de premisă\n")
A("Sesiunea care a condus analiza **nu rulează pe Windows** — rulează pe LXC 171 `claude-agent` "
"(`Linux claude-agent 6.8.12-15-pve`). Windows a fost acoperit separat, prin sesiunea deschisă acolo.\n")
A("### Surse de token usage și care e autoritativă\n")
A("| Sursă | Conține | Verdict |")
A("|---|---|---|")
A("| `~/.claude/projects/**/*.jsonl`, câmpul `message.usage` din înregistrările `assistant` | `input_tokens`, `output_tokens`, `cache_creation_input_tokens`, `cache_read_input_tokens`, `thinking_tokens`, `model`, `requestId` | **AUTORITATIVĂ** — valori raportate de API |")
A("| `~/.claude/stats-cache.json` | mesaje/sesiuni/tool-calls pe zi, din 2025-12-31 | secundară — **zero tokeni**; dovadă că istoricul e mai lung decât transcripturile |")
A("| `~/.claude/history.jsonl` | 6.400 de prompturi, din 2025-12-31 | secundară — fără tokeni |")
A("\nLungimea transcriptului nu a fost folosită ca proxy pentru tokeni nicăieri.\n")
A("## 1. Perioada\n")
A(f"- **Început:** {days[0]}\n- **Sfârșit:** {days[-1]}\n- **Zile calendaristice:** {nd}\n"
f"- **Zile cu activitate:** {len(days)}\n- **Zile lipsă:** {', '.join(d['missing']) or 'niciuna'}\n")
A("Acoperirea e inegală: Windows și moltbot acoperă luna întreagă, dar **`claude-agent` are doar "
"5 zile** cu transcripturi păstrate (retenția implicită de 30 de zile plus o recreare a "
"directorului pe 2026-08-30). `stats-cache.json` arată activitate continuă din **2025-12-31**. "
"Consumul istoric real e mai mare decât cel de aici; **nu am extrapolat nimic** — toate cifrele "
"sunt tokeni observați efectiv.\n")
A("## 2. Deduplicare\n")
tr=sum(m["assistant_records_with_usage"] for m in d["meta"])
td=sum(m["duplicates_removed"] for m in d["meta"])
A("Cheie: `message.id` + `requestId`. Aceeași cerere API reapare în mai multe fișiere după "
"`--resume`, fork de sesiune sau compactare.\n")
A(f"- Înregistrări `assistant` cu `usage` întâlnite: **{N(tr)}**")
A(f"- Duplicate eliminate: **{N(td)}** ({td/tr*100:.1f}%)")
A(f"- Cereri API unice numărate: **{N(tr-td)}**")
A(f"- Sesiuni prezente pe mai multe mașini: **{len(d['cross_dupes'])}** (verificat pe toate cele trei perechi)")
A(f"- Linii malformate: **{sum(m['malformed_lines'] for m in d['meta'])}**\n")
A("## 3. Total\n")
A("| Metrică | Valoare |")
A("|---|---:|")
A(f"| Sesiuni | {N(ns)} |")
A(f"| Turn-uri asistent (cereri API) | {N(T['turns'])} |")
A(f"| Input tokens (necache) | {N(T['input'])} |")
A(f"| Output tokens | {N(T['output'])} |")
A(f"| Cache creation (write) | {N(T['cache_creation'])} |")
A(f"| Cache read | {N(T['cache_read'])} |")
A(f"| **TOTAL** | **{N(tt(T))}** |\n")
A(f"Cache read = **{T['cache_read']/tt(T)*100:.1f}%** din volum. Output-ul real e doar "
f"**{T['output']/tt(T)*100:.2f}%**. Asta e semnătura unui workload agentic: contextul se "
"retrimite la fiecare turn, iar tarifarea cache-ului decide costul.\n")
A(f"Medii: **{N(round(tt(T)/ns))}** tokeni/sesiune ({T['turns']/ns:.0f} turn-uri) · "
f"**{N(round(tt(T)/nd))}** tokeni/zi · **{ns/nd:.1f}** sesiuni/zi.\n")
def tbl(title,dic,keyname,sort=None):
A(f"### {title}\n")
A(f"| {keyname} | Sesiuni | Turn-uri | Input | Output | Cache write | Cache read | Total | % |")
A("|---|---:|---:|---:|---:|---:|---:|---:|---:|")
for k,v in (sorted(dic.items(),key=sort) if sort else sorted(dic.items(),key=lambda kv:-tt(kv[1]))):
se=d["sess_per_machine"].get(k,"") if keyname=="Mașină" else ""
A(f"| {k} | {se} | {N(v['turns'])} | {N(v['input'])} | {N(v['output'])} | {N(v['cache_creation'])} | "
f"{N(v['cache_read'])} | {N(tt(v))} | {tt(v)/tt(T)*100:.1f}% |")
A("")
tbl("Breakdown pe calculator", d["by_machine"], "Mașină")
tbl("Breakdown pe model", d["by_model"], "Model")
tbl("Breakdown pe lună", d["by_month"], "Lună", sort=lambda kv:kv[0])
tbl("Breakdown pe zi", d["by_day"], "Zi", sort=lambda kv:kv[0])
A("## 4. Prețuri — verificate 2026-09-01\n")
A("Pagina oficială **OpenCode Zen (`opencode.ai/docs/zen`) nu listează încă GLM-5.3 sau "
"GLM-5.3-Flash.** Cele mai noi GLM de acolo:\n")
A("| Model pe Zen | Input | Output | Cache read | Cache write |")
A("|---|---:|---:|---:|---:|")
for r in [("GLM 5.2","$1.40","$4.40","$0.26","—"),("GLM 5.1","$1.40","$4.40","$0.26","—"),
("GLM 5","$1.00","$3.20","$0.20","—"),("Claude Opus 5","$5.00","$25.00","$0.50","$6.25"),
("Claude Sonnet 5","$2.00","$10.00","$0.20","$2.50"),
("Claude Fable 5","$10.00","$50.00","$1.00","$12.50"),
("Claude Haiku 4.5","$1.00","$5.00","$0.10","$1.25")]:
A("| "+" | ".join(r)+" |")
A("")
A("Pentru GLM-5.3 am folosit **prețurile oficiale Z.AI** (furnizorul modelului). Zen revinde de "
"regulă la același tarif — GLM 5.2 pe Zen e identic cu tariful Z.AI, ceea ce validează proxy-ul.\n")
A("| Model | Input | Cache read | Cache write | Output |")
A("|---|---:|---:|---:|---:|")
A("| **GLM-5.3** | $1.40 | $0.26 | *fără tarif separat* | $4.40 |")
A("| **GLM-5.3-Flash** (promo, până 2026-09-09 24:00 UTC+8) | $0.075 | $0.015 | *fără tarif separat* | $0.25 |")
A("| **GLM-5.3-Flash** (preț de listă) | $0.15 | $0.03 | *fără tarif separat* | $0.50 |\n")
A("Surse: [opencode.ai/docs/zen](https://opencode.ai/docs/zen/) · "
"[docs.z.ai/guides/overview/pricing](https://docs.z.ai/guides/overview/pricing) · "
"[openrouter.ai/z-ai/glm-5.3-flash](https://openrouter.ai/z-ai/glm-5.3-flash)\n")
A("> **Cache write:** niciun model GLM nu are tarif separat de cache creation (spre deosebire de "
"modelele Claude de pe Zen). `cache_creation_input_tokens` se facturează deci la tariful de "
"**input normal**. `cache_read_input_tokens` **nu** a fost tratat ca input normal — are tariful "
"lui redus. Vezi Scenariul B pentru varianta fără cache.\n")
A("## 5. Cost echivalent Zen — Scenariul A (tokeni reali, tarife de cache)\n")
A("| Model | Input | Cache read | Cache write | Output | **TOTAL** |")
A("|---|---:|---:|---:|---:|---:|")
for n in ["GLM-5.3","GLM-5.3-Flash (promo)","GLM-5.3-Flash (listă)"]:
c=cA(T,n)
A(f"| {n} | ${c['input']:.2f} | ${c['cache_read']:.2f} | ${c['cache_write']:.2f} | ${c['output']:.2f} | **${sum(c.values()):.2f}** |")
A("")
A("### Medii\n")
A("| Model | / sesiune | / zi | / lună (30 zile) |")
A("|---|---:|---:|---:|")
for n in ["GLM-5.3","GLM-5.3-Flash (promo)","GLM-5.3-Flash (listă)"]:
s=S(T,n); A(f"| {n} | ${s/ns:.3f} | ${s/nd:.2f} | ${s/nd*30:.2f} |")
A("")
A("## 6. Scenariul B — fără avantajul cache-ului\n")
A("Tot `cache_read` + `cache_creation` facturați ca input normal.\n")
A("| Model | A (cu cache) | B (fără cache) | Factor |")
A("|---|---:|---:|---:|")
for n in ["GLM-5.3","GLM-5.3-Flash (promo)","GLM-5.3-Flash (listă)"]:
a,b=S(T,n),cB(T,n); A(f"| {n} | ${a:.2f} | ${b:.2f} | **{b/a:.1f}×** |")
A("")
A("## 7. Comparație cu Claude Max 5x\n")
A("Nu există conversie oficială Anthropic din quota Max în tokeni, deci nu o inventez. Compar ce "
"ai plătit cu ce ar fi costat exact aceiași tokeni la tarif per-token.\n")
A("| | Claude Max 5x | Zen GLM-5.3 | Zen GLM-5.3-Flash (promo) | Zen GLM-5.3-Flash (listă) |")
A("|---|---|---|---|---|")
A(f"| Cost pentru perioada măsurată | **$100/lună** | ${g53:,.2f} | ${gfp:,.2f} | ${gfl:,.2f} |")
A(f"| Tokeni | {N(tt(T))} | identic | identic | identic |")
A(f"| Sesiuni | {N(ns)} | identic | identic | identic |")
A("| Modele | Opus 5, Sonnet 5, Fable 5, Haiku 4.5 | GLM-5.3 | GLM-5.3-Flash | GLM-5.3-Flash |")
A("")
A("### Cât valorează de fapt abonamentul Max\n")
A(f"Aceiași {N(tt(T))} tokeni, **fiecare model la propriul lui tarif pe Zen** "
"(Opus 5 la preț de Opus 5, Sonnet 5 la preț de Sonnet 5 etc.):\n")
A(f"# **${zs:,.2f}**\n")
A(f"Abonamentul Max 5x de $100 a livrat consum care la tarif per-token ar fi costat **${zs:,.0f}** — "
f"adică Max e de **{zs/100:.0f}× mai ieftin** decât plata la token pentru exact aceleași modele. "
"Asta e cifra cea mai importantă din tot raportul.\n")
A("### Acoperirea celor $20 Zen\n")
A("| Model | Cost pentru consumul observat | % din $20 | De câte ori acoperă $20 consumul |")
A("|---|---:|---:|---:|")
for n in ["GLM-5.3","GLM-5.3-Flash (promo)","GLM-5.3-Flash (listă)"]:
s=S(T,n); A(f"| {n} | ${s:,.2f} | {s/20*100:,.0f}% | **{20/s:.3f}×** |")
A("")
A("Scenariul B, fără cache:\n")
A("| Model | Cost | % din $20 | Acoperire |")
A("|---|---:|---:|---:|")
for n in ["GLM-5.3","GLM-5.3-Flash (promo)","GLM-5.3-Flash (listă)"]:
b=cB(T,n); A(f"| {n} | ${b:,.2f} | {b/20*100:,.0f}% | {20/b:.3f}× |")
A("")
A("### Cât consum încap în $20\n")
A("| Model | Tokeni pentru $20 | % din consumul lunar | Zile la ritmul actual | Sesiuni |")
A("|---|---:|---:|---:|---:|")
for n in ["GLM-5.3","GLM-5.3-Flash (promo)","GLM-5.3-Flash (listă)"]:
s=S(T,n); f=20/s
A(f"| {n} | {N(round(tt(T)*f))} | {f*100:.1f}% | {nd*f:.2f} | {ns*f:.1f} |")
A("")
# ---- Sectiunea abonamentelor Z.AI Coding Plan ----
PROMPTS_LINUX = 245 + 309 # numarate exact (claude-agent + moltbot)
REQ_LINUX = 2143 + 1810
RATIO = REQ_LINUX / PROMPTS_LINUX
REQ_WIN = tt_turns_win = d["by_machine"]["LENOVO-AIO-BIRO"]["turns"]
PROMPTS_WIN = REQ_WIN / RATIO
PROMPTS_TOT = PROMPTS_LINUX + PROMPTS_WIN
WEEKS = nd / 7
PPW = PROMPTS_TOT / WEEKS
PLANS = [("Lite", 18.00, 151.20, 400, 10000),
("Pro", 72.00, 604.80, 2000, 60000),
("Max", 160.00, 1344.00, 8000, 140000)]
son=tt(d["by_model"]["claude-sonnet-5"])/tt(T)*100
op=tt(d["by_model"]["claude-opus-5"])/tt(T)*100
A("## 8. Abonamentele Z.AI GLM Coding Plan\n")
A("Planurile Z.AI nu se facturează pe tokeni, ci pe **prompturi** (turnuri umane) contorizate în "
"credite, cu două limite simultane: una la 5 ore și una săptămânală. Documentația Z.AI notează "
"că *„un prompt poate invoca modelul de 15–20 de ori\"* — deci comparația corectă nu se face pe "
"cererile API, ci pe prompturile tale reale.\n")
A("### Prețuri (verificate 2026-09-01)\n")
A("| Plan | Lunar | Anual | Efectiv/lună anual | Economie | Prompturi / 5h | Prompturi / săpt. | Credite / săpt. |")
A("|---|---:|---:|---:|---:|---:|---:|---:|")
A("| Lite | $18.00 | **$151.20** | $12.60 | 30% | ~80 | ~400 | 10.000 |")
A("| Pro | $72.00 | **$604.80** | $50.40 | 30% | ~400 | ~2.000 | 60.000 |")
A("| Max | $160.00 | **$1.344,00** | $112.00 | 30% | ~1.600 | ~8.000 | 140.000 |")
A("")
A("Toate planurile includ **GLM-5.3 și GLM-5.3-Flash**. Surse: "
"[docs.z.ai/devpack/overview](https://docs.z.ai/devpack/overview) · "
"[aipricing.guru](https://www.aipricing.guru/z-ai-subscription-pricing/)\n")
A("### Câte prompturi dai de fapt\n")
A(f"Am numărat prompturile umane reale (excluzând `tool_result`, care în transcript apar tot ca "
f"mesaje de tip `user`):\n")
A("| Mașină | Prompturi umane | Cereri API | Cereri / prompt |")
A("|---|---:|---:|---:|")
A(f"| `claude-agent` | 245 | 2.143 | 8,75 |")
A(f"| `moltbot` | 309 | 1.810 | 5,86 |")
A(f"| `LENOVO-AIO-BIRO` | **~{PROMPTS_WIN:,.0f}** *(estimat)* | {REQ_WIN:,} | {RATIO:.2f} *(aplicat)* |")
A(f"| **TOTAL** | **~{PROMPTS_TOT:,.0f}** | {T['turns']:,} | {RATIO:.2f} |")
A("")
A(f"> **Estimare marcată:** scriptul rulat pe Windows a raportat doar cererile API, nu și "
f"prompturile umane. Cifra pentru Windows e derivată din raportul măsurat pe cele două mașini "
f"Linux ({RATIO:.2f} cereri API per prompt). E singura extrapolare din tot raportul și e "
f"marcată ca atare. Raportul real pe Windows poate diferi — sesiunile de acolo par mai lungi, "
f"deci numărul de prompturi ar putea fi mai mic (și acoperirea planurilor, mai bună).\n")
A(f"Ritm rezultat: **~{PPW:,.0f} prompturi/săptămână** (~{PROMPTS_TOT/nd:,.0f}/zi) pe {nd} zile.\n")
A("### Acoperire — la multiplicator 1×\n")
A("| Plan | Anual | Efectiv/lună | Prompturi/săpt. | Acoperă din nevoia ta | Verdict |")
A("|---|---:|---:|---:|---:|---|")
for nm,mo,yr,ppw,cr in PLANS:
cov = ppw/PPW*100
v = "**ACOPERĂ**" if cov>=100 else ("aproape" if cov>=70 else "insuficient")
A(f"| {nm} | ${yr:,.2f} | ${yr/12:.2f} | ~{ppw:,} | **{cov:.0f}%** | {v} |")
A("")
A("### Acoperire — dacă GLM-5.3 consumă credite multiplicat\n")
A("Z.AI aplică multiplicatori de credite modelelor mari (documentat 3× în orele de vârf și 2× "
"off-peak pentru GLM-5.2 / GLM-5-Turbo; pentru GLM-5.3 multiplicatorul nu e publicat explicit). "
"Dacă GLM-5.3 se contorizează la fel, acoperirea scade proporțional:\n")
A("| Plan | 1× (Flash / off-peak promo) | 2× (off-peak) | 3× (peak) |")
A("|---|---:|---:|---:|")
for nm,mo,yr,ppw,cr in PLANS:
A(f"| {nm} | {ppw/PPW*100:.0f}% | {ppw/2/PPW*100:.0f}% | {ppw/3/PPW*100:.0f}% |")
A("")
A("### Comparație completă a opțiunilor\n")
A("| Opțiune | Cost efectiv/lună | Acoperă volumul tău? | Observație |")
A("|---|---:|---|---|")
A("| **Claude Max 5x** (actual) | $100.00 | **DA, 100%** | modelele Claude; "
f"${zs:,.0f} valoare la tarif per-token |")
A(f"| OpenCode Zen, GLM-5.3-Flash | ${gfp:,.2f} *(pay-per-token)* | da, dar costă {gfp/100:.1f}× cât Max | fără plafon, dar fără reducere de abonament |")
A(f"| OpenCode Zen, GLM-5.3 | ${g53:,.2f} *(pay-per-token)* | da, dar costă {g53/100:.0f}× cât Max | prohibitiv |")
A("| OpenCode Zen $20 (buget fix) | $20.00 | **NU — 10,5%** | vezi secțiunea 7 |")
A(f"| **Z.AI Coding Lite anual** | **$12.60** | NU — {400/PPW*100:.0f}% la 1× | cel mai ieftin plan cu GLM-5.3 |")
A(f"| **Z.AI Coding Pro anual** | **$50.40** | **DA la 1× ({2000/PPW*100:.0f}%)**, nu la 2–3× | cel mai bun raport dacă multiplicatorul e 1× |")
A(f"| **Z.AI Coding Max anual** | **$112.00** | **DA, cu marjă ({8000/PPW*100:.0f}% la 1×, {8000/3/PPW*100:.0f}% la 3×)** | singurul sigur indiferent de multiplicator |")
A("")
A("### Ce înseamnă asta concret\n")
A(f"**Z.AI Coding Pro anual ($604,80/an = $50,40/lună) e de departe cea mai interesantă opțiune "
f"din tot setul** — la ritmul tău de ~{PPW:,.0f} prompturi/săptămână, cota lui de ~2.000/săptămână "
f"acoperă {2000/PPW*100:.0f}% din volum, la **jumătate din prețul Max 5x**.\n")
A("Dar cu trei rezerve serioase:\n")
A(f"1. **Marja e subțire.** {2000/PPW*100:.0f}% nu e mult peste 100%. O săptămână mai aglomerată "
"decât media te scoate din cotă, și atunci aștepți resetarea.")
A("2. **Multiplicatorul de credite e necunoscut pentru GLM-5.3.** Dacă e 2× sau 3× ca la GLM-5.2, "
f"Pro acoperă doar {2000/2/PPW*100:.0f}%–{2000/3/PPW*100:.0f}% și ai nevoie de Max ($112/lună).")
A("3. **Limita de 5 ore contează separat.** Media ta zilnică încape în cota de 5h a planului Pro "
"(~400), dar zilele de vârf pot să nu încapă. Cotele sunt simultane: săptămânală ȘI la 5 ore.\n")
A("**Diferența de calitate rămâne argumentul decisiv.** Un plan Z.AI îți dă GLM-5.3, nu Opus 5. "
f"La tine {op:.0f}% din volum rulează deja pe Opus 5 — muncă unde ai ales conștient modelul mare.\n")
# ---- Sectiunea 9: scenariul real Opus planifica / Flash executa ----
SON = d["by_model"]["claude-sonnet-5"]; OPU = d["by_model"]["claude-opus-5"]
son_turn_pct = SON["turns"]/T["turns"]*100
opu_turn_pct = OPU["turns"]/T["turns"]*100
PPW_SON = PPW * SON["turns"]/T["turns"]
PPW_OPU = PPW * OPU["turns"]/T["turns"]
son_flash_promo = S(SON,"GLM-5.3-Flash (promo)")
son_flash_list = S(SON,"GLM-5.3-Flash (listă)")
A("## 9. Scenariul real: Opus planifică, GLM-5.3-Flash execută\n")
A("Fluxul vizat înlocuiește **doar treapta de execuție** (azi Sonnet 5) cu GLM-5.3-Flash, "
"păstrând Opus 5 pe Max pentru planificare. Asta nu e o felie arbitrară din volum — e exact "
"împărțirea care se vede deja în date.\n")
A("| Treaptă | Model azi | Tokeni/lună | % volum | Turn-uri | Prompturi/săpt. *(est.)* |")
A("|---|---|---:|---:|---:|---:|")
A(f"| Planificare | Opus 5 | {tt(OPU)/1e9:.2f}B | {tt(OPU)/tt(T)*100:.1f}% | {N(OPU['turns'])} | ~{PPW_OPU:,.0f} |")
A(f"| Execuție | Sonnet 5 | {tt(SON)/1e9:.2f}B | {tt(SON)/tt(T)*100:.1f}% | {N(SON['turns'])} | ~{PPW_SON:,.0f} |")
A(f"| Alte | Fable 5 + Haiku | {(tt(d['by_model']['claude-fable-5'])+tt(d['by_model']['claude-haiku-4-5-20251001']))/1e6:.0f}M | 1.5% | {N(d['by_model']['claude-fable-5']['turns']+d['by_model']['claude-haiku-4-5-20251001']['turns'])} | ~{PPW-PPW_SON-PPW_OPU:,.0f} |")
A("")
A("### Cât costă mutarea treptei de execuție\n")
A("| Variantă | Cost/lună | Observație |")
A("|---|---:|---|")
A(f"| Zen pay-per-token, Flash promo | ${son_flash_promo:,.2f} | tarif promoțional, expiră 2026-09-09 |")
A(f"| Zen pay-per-token, Flash listă | ${son_flash_list:,.2f} | tariful de după |")
A(f"| Z.AI Coding **Lite** anual | $12.60 | cotă ~400 prompturi/săpt. = **{400/PPW_SON*100:.0f}%** din nevoie |")
A(f"| Z.AI Coding **Pro** anual | $50.40 | cotă ~2.000/săpt. = **{2000/PPW_SON*100:.0f}%** din nevoie |")
A(f"| Z.AI Coding **Max** anual | $112.00 | cotă ~8.000/săpt. = {8000/PPW_SON*100:.0f}% |")
A("")
A(f"Treapta de execuție are nevoie de **~{PPW_SON:,.0f} prompturi/săptămână**. "
f"**Lite nu ajunge** ({400/PPW_SON*100:.0f}%). **Pro ajunge cu marjă de {2000/PPW_SON/1:.1f}×** — "
"și, spre deosebire de comparația pe volumul total, aici marja e confortabilă.\n")
A("> **Detaliu în favoarea ta:** multiplicatorul de credite Z.AI (3× peak / 2× off-peak) e "
"documentat pentru modelele mari, nu pentru cele „de rutină\". GLM-5.3-**Flash** e modelul mic, "
f"deci probabil se contorizează la 1×. Dacă e așa, Pro acoperă treapta de execuție cu "
f"{2000/PPW_SON*100:.0f}% și rămâne loc de creștere. Confirmă asta înainte să plătești anual.\n")
A("### Calibrare cu OpenCode Go — datele tale reale\n")
A("OpenCode Go costă **$10/lună** și include limite exprimate în valoare de consum, nu în tokeni:\n")
A("| Limită | Valoare |")
A("|---|---:|")
A("| La 5 ore | $12 de consum |")
A("| Săptămânal | $30 de consum |")
A("| Lunar | $60 de consum |")
A("")
A(f"Abonamentul s-a consumat în 1–2 zile. Asta **confirmă independent** analiza: la volumul tău, "
f"consumul săptămânal echivalent e ${gfp/(nd/7):,.0f} pe GLM-5.3-Flash promo și "
f"${g53/(nd/7):,.0f} pe GLM-5.3 — deci plafonul săptămânal de $30 al lui Go se evaporă în "
f"{30/(g53/(nd/7))*7:.1f} zile pe modelul mare și în {30/(gfp/(nd/7))*7:.1f} zile pe Flash. "
"Un plan plafonat în dolari nu rezistă la acest volum, indiferent de furnizor.\n")
A("**De asta planurile Z.AI sunt altceva:** cota lor e în prompturi, nu în dolari de consum. "
"Un prompt care declanșează 20 de invocări de model costă la fel ca unul care declanșează 2 — "
"iar sesiunile tale au în medie "
f"{RATIO:.1f} cereri API per prompt. Exact tipul de workload pe care tarifarea per-prompt îl "
"avantajează, și pe care cea per-dolar îl penalizează.\n")
# ---- Sectiunea 10: plafonul saptamanal Max 5x ----
import statistics as _st, datetime as _dt, collections as _co
_days={k:tt(v) for k,v in d["by_day"].items()}
_THR=50e6
_blk=[k for k,v in _days.items() if v<_THR]
_act=[v for v in _days.values() if v>=_THR]
_med=_st.median(_act); _deliv=sum(_days.values())/(nd/7); _want=_med*7
_short=_want-_deliv; _shortp=PPW*_short/_deliv
_wk=_co.defaultdict(lambda:[0,[]])
for k in sorted(_days):
_d0=_dt.date.fromisoformat(k); _w=_d0.isocalendar()[:2]
_wk[_w][0]+=_days[k]; _wk[_w][1].append((_d0.strftime("%a")[:2],_days[k]))
A("## 10. Problema reală: plafonul general săptămânal Max 5x\n")
A("Max 5x are **două plafoane săptămânale** — unul general, pe toate modelele, și unul separat "
"pentru Opus. Limita atinsă e cea **generală**, ceea ce înseamnă că un supliment pe GLM-5.3-Flash "
"chiar poate ajuta: fiecare prompt mutat în altă parte eliberează cotă de Max.\n")
A("### Tiparul se vede în date\n")
A("| Săptămână | Total | Profil zilnic (M tokeni, Lu→Du) |")
A("|---|---:|---|")
for _w in sorted(_wk):
_tok,_prof=_wk[_w]
A(f"| {_w[0]}-W{_w[1]:02d} | {_tok/1e9:.2f}B | " + " · ".join(f"{a} **{b/1e6:.0f}**" for a,b in _prof) + " |")
A("")
A("**Săptămâna W33 e semnătura manualului pentru un plafon atins:** 655M luni, 229M marți, apoi "
"40M, 8M, 1M, 1M, 1M. Cota s-a consumat în două zile, urmate de cinci zile moarte. Exact ce "
"descrii. Prin contrast, W32 și W34 au mers 7 zile din 7, la 2,93–3,40B.\n")
A(f"- **Zile efectiv blocate** (sub 50M tokeni): **{len(_blk)} din {len(_days)}** = {len(_blk)/len(_days)*100:.0f}%")
A(f"- **Zi activă mediană:** {_med/1e6:.0f}M tokeni")
A(f"- **Livrat efectiv de Max 5x:** {_deliv/1e9:.2f}B/săptămână")
A(f"- **Cerere dacă ai lucra 7 zile din 7 la ritmul median:** {_want/1e9:.2f}B/săptămână")
A(f"- **Deficit: {_short/1e9:.2f}B/săptămână = +{_short/_deliv*100:.0f}%** ≈ **~{_shortp:,.0f} prompturi/săptămână**\n")
A("> Deficitul e o estimare **conservatoare**: presupune că în zilele blocate ai lucra la ritm "
f"median ({_med/1e6:.0f}M), nu la ritmul zilelor bune (peste 850M). Cererea reală suprimată e "
"probabil mai mare. Nu se poate măsura direct — Claude Code nu persistă evenimentele de limită "
"în transcript, apar doar în stream-ul SDK.\n")
A("### Ce plan acoperă deficitul\n")
A("Nu trebuie mutat tot volumul — doar atât cât să elibereze cota lipsă.\n")
A("| Plan | Lunar | Anual (efectiv/lună) | Cotă/săpt. | Acoperă deficitul de ~%d | Zile blocate rămase |" % round(_shortp))
A("|---|---:|---:|---:|---:|---:|")
for _nm,_mo,_yr,_ppw,_cr in PLANS:
_cov=_ppw/_shortp
_rem=max(0.0, len(_blk)/(nd/7) * (1-min(_cov,1.0)))
A(f"| {_nm} | ${_mo:.2f} | ${_yr/12:.2f} | ~{_ppw:,} | **{_cov*100:.0f}%** | ~{_rem:.1f}/săpt. |")
A("")
A(f"Azi ai ~{len(_blk)/(nd/7):.1f} zile blocate pe săptămână. **Lite ar duce-o la ~"
f"{len(_blk)/(nd/7)*(1-min(400/_shortp,1.0)):.1f}**, **Pro la zero**, cu marjă de "
f"{2000/_shortp:.1f}× pentru creștere.\n")
A("### Verificare din a doua direcție\n")
A(f"Dacă muți **toată** treapta de execuție (Sonnet 5, {SON['turns']/T['turns']*100:.0f}% din "
f"turn-uri, ~{PPW_SON:,.0f} prompturi/săpt.) pe GLM-5.3-Flash, eliberezi "
f"{SON['turns']/T['turns']*100:.0f}% din cota Max — care ar ține atunci de "
f"**{1/(1-SON['turns']/T['turns']):.1f}× mai mult**, adică toată săptămâna în loc de două zile.\n")
A(f"Pentru asta ai nevoie de ~{PPW_SON:,.0f} prompturi/săpt.: **Lite ({400/PPW_SON*100:.0f}%) nu "
f"ajunge, Pro ({2000/PPW_SON*100:.0f}%) ajunge cu marjă.**\n")
A("Cele două calcule dau răspunsuri diferite pentru Lite pentru că măsoară lucruri diferite: "
"primul, cât lipsește ca să nu mai fii blocat; al doilea, cât ar costa mutarea completă a "
"treptei de execuție. **Nu ai nevoie de mutarea completă** — ai nevoie doar de deficit.\n")
A("## 11. Fișiere generate\n")
A("| Fișier | Conținut |")
A("|---|---|")
A("| `claude_usage_report.md` | acest raport |")
A(f"| `claude_usage_sessions.csv` | {N(ns)} rânduri, una per sesiune |")
A("| `claude_usage_summary.csv` | agregate: TOTAL, mașină, model, lună, zi |")
A("| `tools/claude_usage_extract.py` | extractorul read-only (rulabil remote: `ssh host 'python3 -' < script`) |")
A("| `tools/claude_usage_report.py` | agregator + CSV |")
A("| `tools/claude_usage_md.py` | generatorul acestui raport |")
A("")
A("## 12. CONCLUZIE\n")
A("### „Dacă păstrez Claude Max 5x $100 și adaug OpenCode Zen $20, cât coding suplimentar obțin?\"\n")
A(f"**Foarte puțin — aproximativ {nd*(20/gfp):.1f} zile pe lună, în cel mai bun caz.**\n")
A(f"Consumul real pe {nd} zile, pe trei mașini: **{tt(T)/1e9:.2f} miliarde de tokeni**, {N(ns)} sesiuni, "
f"{N(T['turns'])} cereri API. La acest volum, $20 nu sunt un supliment — sunt o rotunjire.\n")
A("| | GLM-5.3 | GLM-5.3-Flash (promo) | GLM-5.3-Flash (listă) |")
A("|---|---:|---:|---:|")
A(f"| Cost pentru volumul tău lunar | ${g53:,.0f} | ${gfp:,.0f} | ${gfl:,.0f} |")
A(f"| Cât din el acoperă $20 | {20/g53*100:.1f}% | **{20/gfp*100:.1f}%** | {20/gfl*100:.1f}% |")
A(f"| Zile de lucru din $20 | {nd*20/g53:.2f} | **{nd*20/gfp:.1f}** | {nd*20/gfl:.1f} |")
A("")
A("### Punct cu punct\n")
A("**1. Ar fi fost $20 Zen suficienți pentru consumul observat?** \n")
A(f"**NU, pe niciun model.**\n")
A(f"- GLM-5.3-Flash (promo): ${gfp:,.2f} — de **{gfp/20:.1f}× peste buget**. Cel mai bun caz posibil.")
A(f"- GLM-5.3-Flash (listă, după 9 sept.): ${gfl:,.2f} — de **{gfl/20:.0f}× peste buget**.")
A(f"- GLM-5.3: ${g53:,.2f} — de **{g53/20:.0f}× peste buget**.")
A(f"- Fără cache (Scenariul B), chiar și Flash promo ajunge la ${cB(T,'GLM-5.3-Flash (promo)'):,.2f} — de {cB(T,'GLM-5.3-Flash (promo)')/20:.0f}× peste.\n")
A("**2. Câte sesiuni/zi înseamnă?** \n")
A(f"Ritmul real: **{ns/nd:.1f} sesiuni/zi**, {tt(T)/nd/1e6:.0f}M tokeni/zi. Cu $20 obții:")
A(f"- GLM-5.3-Flash promo: **{nd*20/gfp:.1f} zile** (~{ns*20/gfp:.0f} sesiuni)")
A(f"- GLM-5.3-Flash listă: **{nd*20/gfl:.1f} zile** (~{ns*20/gfl:.0f} sesiuni)")
A(f"- GLM-5.3: **{nd*20/g53:.2f} zile** (~{ns*20/g53:.0f} sesiuni) — sub o zi\n")
A("**3. Ce model e mai avantajos?** \n")
A(f"**GLM-5.3-Flash**, de **{g53/gfp:.1f}× mai ieftin** decât GLM-5.3. Diferența absolută pe "
f"consumul tău: **${g53-gfp:,.2f}** (${g53:,.2f} vs ${gfp:,.2f}). La preț de listă diferența "
f"rămâne **${g53-gfl:,.2f}**. Compromisul e de calitate — Flash e modelul mic.\n")
A("**4. Diferența de cost GLM-5.3 vs GLM-5.3-Flash** \n")
A(f"| | GLM-5.3 | Flash (promo) | Flash (listă) |")
A("|---|---:|---:|---:|")
A(f"| Total | ${g53:,.2f} | ${gfp:,.2f} | ${gfl:,.2f} |")
A(f"| Pe zi | ${g53/nd:.2f} | ${gfp/nd:.2f} | ${gfl/nd:.2f} |")
A(f"| Pe sesiune | ${g53/ns:.3f} | ${gfp/ns:.3f} | ${gfl/ns:.3f} |")
A(f"| Raport față de GLM-5.3 | 1× | {g53/gfp:.1f}× mai ieftin | {g53/gfl:.1f}× mai ieftin |")
A("")
A("**5. Ce procent din utilizarea Claude poate fi mutat realist pe Zen?** \n")
A(f"Structura reală: **{son:.0f}%** Sonnet 5, **{op:.0f}%** Opus 5, "
f"{tt(d['by_model']['claude-fable-5'])/tt(T)*100:.1f}% Fable 5, restul Haiku.\n")
A("Întrebarea corectă nu mai e „ce procent muți\", ci **„cât încape în $20\"** — și răspunsul e "
f"**{20/gfp*100:.1f}%** din volum, la cel mai ieftin tarif posibil. Chiar dacă ai muta pe Zen "
"absolut tot ce rulează azi pe Sonnet, ai depăși bugetul de câteva ori.\n")
A(f"Cu $20/lună pe GLM-5.3-Flash poți acoperi realist **~{20/gfp*100:.0f}% din volum** — echivalentul "
f"a ~{tt(T)*20/gfp/1e6:.0f}M tokeni. Ținta rezonabilă: **un singur flux automat**, mic și bine "
"delimitat (un bot, un job de noapte, un agent în buclă), nu o felie procentuală din tot ce faci.\n")
A("**6. Dar abonamentele Z.AI?** \n")
A(f"Aici răspunsul e cu totul altul decât la Zen $20. La ~{PPW:,.0f} prompturi/săptămână:\n")
A("| | Efectiv/lună (anual) | Acoperire la 1× | Acoperire la 3× |")
A("|---|---:|---:|---:|")
A(f"| Z.AI Coding **Lite** | $12.60 | {400/PPW*100:.0f}% | {400/3/PPW*100:.0f}% |")
A(f"| Z.AI Coding **Pro** | $50.40 | **{2000/PPW*100:.0f}%** | {2000/3/PPW*100:.0f}% |")
A(f"| Z.AI Coding **Max** | $112.00 | {8000/PPW*100:.0f}% | **{8000/3/PPW*100:.0f}%** |")
A("")
A("**Lite ($12,60/lună) e opțiunea potrivită pentru rolul pe care îl căutai la Zen $20** — cost "
f"similar, dar acoperă {400/PPW*100:.0f}% din volum în loc de {20/gfp*100:.1f}%, adică de "
f"**{(400/PPW)/(20/gfp):.0f}× mai mult** pentru aceiași bani. Modelul de abonament bate plata "
"la token, exact cum o face și Max față de tarifele Zen.\n")
A("### Recomandare\n")
A(f"**Păstrează Max 5x — la ${zs:,.0f} valoare per-token pentru $100 plătiți, e cea mai bună afacere "
"din tot setul de date.** Nu e nimic de optimizat acolo.\n")
A("**Nu lua OpenCode Zen $20.** La volumul tău e o rotunjire (10,5%), iar pentru bani similari "
f"Z.AI Coding Lite anual ($12,60/lună) îți dă de {(400/PPW)/(20/gfp):.0f}× mai mult. Singurul "
"motiv real pentru Zen ar fi accesul la multe modele diferite dintr-un singur cont, nu volumul.\n")
A("**Dacă vrei capacitate suplimentară serioasă**, ordinea corectă e:\n")
A(f"1. **Z.AI Coding Lite anual, $12,60/lună** — ca supliment: preia un flux automat întreg "
f"(tot `moltbot` = {tt(d['by_machine']['moltbot'])/1e6:.0f}M tokeni/lună) și îți lasă Max liber "
"pentru munca grea. Risc mic, cost mic. **Aici aș începe.**")
A(f"2. **Z.AI Coding Pro anual, $50,40/lună** — dacă vrei să muți o felie mare din volum. "
f"Acoperă {2000/PPW*100:.0f}% la 1×, dar doar {2000/3/PPW*100:.0f}% dacă GLM-5.3 se contorizează "
"la 3×. Verifică multiplicatorul înainte, e diferența dintre „ajunge\" și „nu ajunge\".")
A("3. **Z.AI Coding Max anual, $112/lună** — singurul care acoperă volumul indiferent de "
"multiplicator, dar la acel preț compari direct cu un al doilea Max 5x sau cu Max 20x, unde "
"primești Opus 5 în loc de GLM-5.3.\n")
A("**Testul decisiv nu e de preț, e de calitate.** Toate variantele Z.AI îți dau GLM-5.3, nu "
f"Opus 5, iar {op:.0f}% din volumul tău rulează pe Opus 5 pentru că ai ales asta. Ia Lite anual "
"o lună, rutează pe el fluxurile automate, și vezi dacă rezultatul e acceptabil înainte să "
"muți ceva important.\n")
A("**Rolul rămas pentru Zen $20** (dacă îl iei totuși) e restrâns:\n")
A("- **buget de experiment** — să testezi dacă GLM-5.3-Flash e destul de bun pe un flux anume, "
"înainte să iei o decizie mai mare;")
A("- **overflow de urgență** — dacă atingi limita Max într-o zi aglomerată, ai un backup care "
"costă cenți pe oră;")
A(f"- **un singur job automat mic** — de exemplu tot ce rulează pe `moltbot` "
f"({tt(d['by_machine']['moltbot'])/1e6:.0f}M tokeni = ${S(d['by_machine']['moltbot'],'GLM-5.3-Flash (promo)'):.2f}/lună "
f"pe Flash promo, {S(d['by_machine']['moltbot'],'GLM-5.3-Flash (promo)')/20*100:.0f}% din buget).\n")
A("### Rezerve\n")
A(f"1. **`claude-agent` are doar 5 zile din {nd}** cu transcripturi păstrate; consumul lui real e "
f"mai mare decât cei {tt(d['by_machine']['claude-agent'])/1e6:.0f}M măsurați. Nu am extrapolat. "
"Efectul e mic la scara totalului (2,7%), dar direcția e clară: totalul real e mai mare, nu mai mic.")
A("2. **Alte mașini Windows** din tailnet (`marius-hx90g`, `lenovo-aio-h1`, `lg17`, `roa-carapetru2`) "
"nu au fost scanate — erau offline. Dacă rulezi Claude Code și pe ele, totalul crește.")
A(f"3. **Cache hit rate-ul e ipoteza critică:** {T['cache_read']/tt(T)*100:.1f}% din volum e cache read. "
"OpenCode cu GLM nu garantează același comportament de caching ca Claude Code — Scenariul B "
f"(${cB(T,'GLM-5.3-Flash (promo)'):,.0f} în loc de ${gfp:,.0f}) e cazul rău, și nu e improbabil.")
A("4. **Prețul Flash e promoțional** până pe 2026-09-09; se dublează după.")
A("5. **GLM-5.3 nu e listat oficial pe OpenCode Zen** — am folosit tariful Z.AI ca proxy, validat "
"prin faptul că GLM 5.2 are pe Zen exact prețul Z.AI.")
A("6. **Datele Windows au trecut printr-o conversie de tabel** (TAB + date M/D/YYYY). UUID-urile și "
"valorile numerice au fost validate, dar nu am putut verifica independent fișierele sursă.")
open(OUT+"/claude_usage_report.md","w").write("\n".join(L)+"\n")
print("scris")