diff --git a/harbor/logbook.py b/harbor/logbook.py index 33beba1..5c7f4b3 100644 --- a/harbor/logbook.py +++ b/harbor/logbook.py @@ -84,7 +84,13 @@ def set_stats(project, stats, history_point=True): _write(project, "stats.json", stats) if history_point: history = _read(project, "history.json", []) + cats = stats.get("by_category") or {} + total = stats.get("functions") or 0 + undone_game = max(0, (cats.get("game") or {}).get("functions", 0) + - ((stats.get("by_status") or {}).get("decompiled") or {}).get("functions", 0)) + handled = total - (cats.get("unsorted") or {}).get("functions", 0) - undone_game history.append({"at": stats["updated_at"], "classified": stats.get("classified_percent", 0), + "done": round(100 * handled / total, 2) if total else 0, "decompiled": stats.get("game_bytes_decompiled_percent", 0), "weighted": stats.get("weighted_percent", 0), "verified": stats.get("game_bytes_verified_percent", 0)}) diff --git a/harbor/web/app.html b/harbor/web/app.html index e2443e7..c4400ee 100644 --- a/harbor/web/app.html +++ b/harbor/web/app.html @@ -690,7 +690,7 @@ button.chip:hover { color: var(--accent-ink); background: var(--accent-soft); }

Trend

-
classifiedgame code decompiledweighted progress
+
classifiedgame code decompileddone (functions handled)
@@ -1136,8 +1136,11 @@ async function renderLogbook(){try{LB=await get('api/logbook')}catch(e){put('lbS const s=LB.stats||{},cat=k=>(s.by_category||{})[k]||{functions:0,bytes:0}; const cur=LB.milestones.find(m=>/progress/i.test(m.state||''));el('lbMilestone').textContent=cur?'Milestone '+cur.code+' · '+cur.title:'Milestones'; const au=LB.auto||{};put('lbStamp',(s.updated_at?'Statistics updated '+esc(central(s.updated_at))+'
main at '+esc(s.commit||'–')+'':'No statistics yet')+(au.last_refresh?'
Keeps itself current: last checked '+esc(central(au.last_refresh))+(au.last_error?' · '+esc(String(au.last_error).slice(0,120))+'':''):'')); - put('lbFigs',[[fmt(s.functions),'functions in the original executable',fmt(s.bytes)+' bytes of code'],[pct(s.classified_percent),'classified (category known)',fmt(cat('unsorted').functions)+' still unsorted'], - [pct(s.weighted_percent),'weighted progress','documented 20 · decompiled 40 · reimplemented 75 · verified 100'],[pct(s.game_bytes_decompiled_percent),'of game code decompiled to readable C','Rust: '+pct(s.game_bytes_reimplemented_percent)+' reimplemented']] + const total=s.functions||0,game=cat('game').functions,done=(s.by_status&&s.by_status.decompiled||{}).functions||0,uns=cat('unsorted').functions; + const handled=total-uns-Math.max(0,game-done); + put('lbFigs',[[pct(total?100*handled/total:0)+' done',fmt(handled)+' of '+fmt(total)+' functions handled','game code decompiled, everything else identified'], + [fmt(done)+' of '+fmt(game),'game functions decompiled to readable C',fmt(game-done)+' to go'], + [fmt(uns),'functions not sorted yet','each one is either game code (to decompile) or engine/library code (to name)']] .map(([v,l,n])=>'
'+esc(v)+'
'+esc(l)+'
'+esc(n)+'
').join('')); put('lbLegend',LB_CATS.map(([k,n])=>''+esc(n)+'').join('')+'decompiled share under each column'); drawLbMap();renderLbWhere(s);renderLbTrend(LB.history);renderLbMilestones(LB.milestones); @@ -1162,7 +1165,7 @@ function drawLbMap(){const m=LB&&LB.map,c=el('lbMap');if(!c||!m||!c.clientWidth) function renderLbTrend(points){const svg=el('lbTrend');if(!points.length){svg.innerHTML='';el('lbTrendNote').textContent='The trend starts with the second report.';return} const n=points.length,x=i=>n===1?150:i*300/(n-1),y=v=>104-Math.min(100,v||0)/100*96,path=k=>points.map((p,i)=>(i?'L':'M')+x(i).toFixed(1)+','+y(p[k]).toFixed(1)).join(' '); svg.innerHTML=[0,25,50,75,100].map(v=>'').join('') - +[['classified','--lb-game'],['decompiled','--lb-platform'],['weighted','--lb-done']].map(([k,c])=>'').join(''); + +[['classified','--lb-game'],['decompiled','--lb-platform'],['done','--lb-done']].map(([k,c])=>{const pts=points.map((p,i)=>[i,p[k]]).filter(q=>q[1]!=null);return pts.length?'':''}).join(''); el('lbTrendNote').textContent=n+' reports since '+new Date(points[0].at).toLocaleDateString()+'. Scale 0–100%.'} function renderLbMilestones(list){let last='';put('lbMilestones',list.length?list.map(m=>{const head=m.phase&&m.phase!==last?'
'+esc(m.phase)+'
':'';last=m.phase||last; const items=m.items||[],done=items.filter(i=>i.done).length,li=items.map(i=>'
  • '+esc(i.text)+'
  • ').join(''),open=/progress/i.test(m.state||'');