forma-arch 0.10.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -191,7 +191,7 @@ var STRINGS={
191
191
  printExport:"PRINT / EXPORT", exportSvg:"Export SVG", exportPng:"Export PNG", exportLayout:"Export layout JSON", print:"Print",
192
192
  legDone:"DONE (proven)", legDecl:"DONE (declared)", legProg:"IN PROGRESS", legNext:"NEXT", legPlan:"PLAN ONLY", legProb:"PROBLEM",
193
193
  legUnk:"UNKNOWN (no curated state)", stUnk:"?",
194
- detDecl:"Declared in", detCover:"Coverage", coverWhole:"the document names this module itself",
194
+ detDecl:"Declared in", detCover:"Coverage", detRoll:"Rolled up from", rollPart:"mean of the {n} of {t} parts inside that anyone ruled on", coverWhole:"the document names this module itself",
195
195
  coverPart:"{n} of {t} units named by the document",
196
196
  legHint:"— animated arrow = active flow · dashed = to build",
197
197
  crumbRoot:"Context", crumbLevel:"C4", lvlContext:"CONTEXT",
@@ -213,7 +213,7 @@ var STRINGS={
213
213
  printExport:"STAMPA / ESPORTA", exportSvg:"Esporta SVG", exportPng:"Esporta PNG", exportLayout:"Esporta layout JSON", print:"Stampa",
214
214
  legDone:"FATTO (provato)", legDecl:"FATTO (dichiarato)", legProg:"IN CORSO", legNext:"PROSSIMO", legPlan:"SOLO PROGETTO", legProb:"PROBLEMA",
215
215
  legUnk:"IGNOTO (stato non curato)", stUnk:"?",
216
- detDecl:"Dichiarato in", detCover:"Copertura", coverWhole:"il documento nomina il modulo stesso",
216
+ detDecl:"Dichiarato in", detCover:"Copertura", detRoll:"Somma dal basso", rollPart:"media delle {n} parti su {t} qui dentro su cui qualcuno si e pronunciato", coverWhole:"il documento nomina il modulo stesso",
217
217
  coverPart:"{n} unità su {t} nominate dal documento",
218
218
  legHint:"— freccia animata = flusso attivo · tratteggio = da costruire",
219
219
  crumbRoot:"Contesto", crumbLevel:"C4", lvlContext:"CONTESTO",
@@ -260,6 +260,30 @@ var STMAP={done:"done","in-progress":"prog",next:"next",planned:"plan",problem:"
260
260
  // would contribute ONE unknown instead of nine, so 25/53 would print as 25/45 and the coverage
261
261
  // would read better than it is — which is the number this whole function exists to keep honest.
262
262
  // One consequence, deliberate: on a grouped level the dots count units (53), not boxes (6).
263
+ // What a box that GROUPS others can honestly say about itself. Nobody ruled on a domain — `gen`
264
+ // refuses to derive a verdict, everywhere, on purpose — so its badge read `?` while the 22 packages
265
+ // inside it carried 14 verdicts. Four of six domains showed `?` on the one screen a stakeholder is
266
+ // shown, and the board looked less finished than the repo was.
267
+ // The way out is not to invent a verdict but to report a FACT: the mean of the descendants somebody
268
+ // did rule on, and how many that was. `100%` alone would be the invented green this tool exists to
269
+ // kill — 14 of 14 ruled done says nothing about the other 8 — so the coverage is not optional
270
+ // decoration, it is half the claim. Same shape as the level tally and the docmap coverage.
271
+ // Returns null when the box has its own verdict (it speaks for itself) or when nothing below it
272
+ // was ruled (there is no fact to report).
273
+ function rollStatus(node,kidsOf){
274
+ if(node.completion!=null||node.statusWord)return null;
275
+ var lv=[],q=[node],n,k,i,guard=0;
276
+ while(q.length&&guard++<4096){n=q.pop();k=kidsOf(n.id);if(k.length){for(i=0;i<k.length;i++)q.push(k[i]);}else if(n!==node)lv.push(n);}
277
+ if(!lv.length)return null;
278
+ var sum=0,nc=0,rank={problem:5,next:4,"in-progress":3,planned:2,unknown:1.5,done:1},best=0,key="unknown",s2;
279
+ for(i=0;i<lv.length;i++){
280
+ if(lv[i].completion!=null){sum+=(+lv[i].completion||0);nc++;}
281
+ s2=lv[i].status2||(lv[i].status==="planned"?"planned":"unknown");
282
+ if((rank[s2]||0)>best){best=rank[s2]||0;key=s2;}
283
+ }
284
+ if(!nc)return null;
285
+ return {status2:key,mean:Math.round(sum/nc),ruled:nc,total:lv.length};
286
+ }
263
287
  function tallyOf(kids,kidsOf){
264
288
  var cnt={},tot=0,sum=0,nc=0,st3,i,j,k,q,lv,use,n;
265
289
  for(i=0;i<kids.length;i++){
@@ -447,7 +471,10 @@ function draw(animate){
447
471
  }
448
472
  for(var j=0;j<kids.length;j++){
449
473
  var n=kids[j],p=pos[n.id];
450
- var st=STMAP[n.status2]||(n.status==="planned"?"plan":"unk");
474
+ // A grouping box borrows its children's colour and badge — see rollStatus. The MODEL keeps saying
475
+ // `unknown` for it; this is the viewer reporting what is underneath, not gen inventing a verdict.
476
+ var roll=(n.__catalog||mode==="target")?null:rollStatus(n,childrenOf);
477
+ var st=STMAP[(roll?roll.status2:n.status2)]||(n.status==="planned"?"plan":"unk");
451
478
  var pulse=(st==="next"||st==="prog")&&mode!=="target"&&!n.__catalog;
452
479
  var isCat=!!n.__catalog,dr=!isCat&&hasKids(n.id),cls="nd s-"+st+(dr?" drill":"")+(isCat?" cat":"")+(pulse?" pulse":"");
453
480
  var desc=isCat?(n.count+" "+STR.rosterCount):(mode==="target"?(n.target||n.func||""):(n.current||n.func||""));
@@ -456,7 +483,9 @@ function draw(animate){
456
483
  // breathe. The measured fallback text is the generator's honest last resort, not a lie — it just
457
484
  // does not belong on screen when it says nothing the header has not already said.
458
485
  if(!isCat&&echoesName(desc,n.name))desc="";
459
- var badge=isCat?String(n.count):(mode==="target"?STR.detTarget:(n.statusWord||(n.completion!=null?n.completion+"%":STR.stUnk)));
486
+ // The coverage rides WITH the mean, never without it: `100%` on a domain where 14 of 22 packages
487
+ // were ruled is the invented green, and this is the badge a stakeholder reads first.
488
+ var badge=isCat?String(n.count):(mode==="target"?STR.detTarget:(n.statusWord||(n.completion!=null?n.completion+"%":(roll?roll.mean+"% "+roll.ruled+"/"+roll.total:STR.stUnk))));
460
489
  // the title runs until the badge, so reserve the badge's actual width (9px text ≈ 5.4px/char)
461
490
  // instead of a flat 70px — a fixed reserve clipped names that had all the room they needed
462
491
  var tmax=Math.floor((p.w-34-String(badge).length*5.4)/6.7),tt=n.name;
@@ -597,6 +626,8 @@ function showDetail(n){
597
626
  // declared done" and "this module is done" are not the same sentence when the module holds 22
598
627
  // files and the document names 3 of them.
599
628
  +(showSrc?'<div class="row"><span class="lbl">'+esc((n.verify&&n.verify.derived)?STR.detDecl:STR.detSrc)+'</span><span class="src">'+esc(src)+'</span></div>':'')
629
+ // A badge the viewer rolled up must say so, or it reads as a verdict somebody wrote about the box.
630
+ +((function(){var r=rollStatus(n,childrenOf);return r?'<div class="row"><span class="lbl">'+esc(STR.detRoll)+'</span><span class="now">'+esc(STR.rollPart.replace("{n}",r.ruled).replace("{t}",r.total))+'</span></div>':'';})())
600
631
  +(coverText(n)?'<div class="row"><span class="lbl">'+esc(STR.detCover)+'</span><span class="now">'+esc(coverText(n))+'</span></div>':'')
601
632
  +((n.issues&&n.issues.length)?'<div class="row"><span class="lbl">'+esc(STR.detIssue)+'</span><span class="now">'+esc(n.issues.join(", "))+'</span></div>':'');
602
633
  $("detail").style.display="block";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forma-arch",
3
- "version": "0.10.0",
3
+ "version": "0.10.1",
4
4
  "description": "Forma — present your architecture instead of slides. An interactive, stack-agnostic C4 explorer (context → container → component → leaf) generated from your code and kept true to it by a deterministic drift check.",
5
5
  "keywords": [
6
6
  "architecture",