===== stageRollup / selectStage / selectedCategoryObject / renderCenterCategory / renderCenterBucket ===== 480 els.selectedPipelineSteps.innerHTML = '
  • No pipeline contract foundmissing
  • '; 481 return; 482 } 483 484 els.selectedPipelineSteps.innerHTML = seq.map(function (step) { 485 const observed = stepStatuses.find(function (x) { 486 return normStageKey(x.step || x.name) === normStageKey(step); 487 }); 488 const status = observed ? safeUpper(observed.status) : "MISSING"; 489 return [ 490 '
  • ', 491 '' + titleize(step) + '', 492 '' + status + '', 493 '
  • ' 494 ].join(""); 495 }).join(""); 496 } 497 498 499 function selectedPhaseObject() { 500 const phases = (state.hubIndex && Array.isArray(state.hubIndex.phases)) ? state.hubIndex.phases : []; 501 return phases.find(function (p) { 502 return normStageKey(p.id || p.stage_key || "") === normStageKey(state.selectedStage); 503 }) || null; 504 } 505 506 function selectedCategoryObject() { 507 if (!state.selectedCategory) return null; 508 const cats = (state.hubIndex && Array.isArray(state.hubIndex.categories)) ? state.hubIndex.categories : []; 509 return cats.find(function (c) { 510 return String(c.id || "") === String(state.selectedCategory); 511 }) || null; 512 } 513 514 function renderCenterCategory(ph, cat) { 515 if (!els.selectedStageName) return; 516 if (els.selectedStageName) els.selectedStageName.textContent = cat.title || ph.name || "Category"; 517 if (els.selectedStageDesc) els.selectedStageDesc.textContent = cat.sub || "Category view from canonical hub index."; 518 if (els.selectedStageTotal) els.selectedStageTotal.innerHTML = ((cat.docs || []).length) + ' docs
    in category'; 519 if (els.selectedStageDonut) els.selectedStageDonut.innerHTML = donutMarkup(0, "category"); 520 if (els.selectedPipelineSteps) { 521 const docs = Array.isArray(cat.docs) ? cat.docs : []; 522 els.selectedPipelineSteps.innerHTML = docs.length ? docs.map(function (doc) { 523 return '
  • ' + (doc.title || doc.label || doc.id || "item") + '' + (doc.type || "doc") + '
  • '; 524 }).join("") : '
  • No documents registeredMISSING
  • '; 525 } 526 } 527 528 function renderCenterBucket(ph, cat, bucket) { 529 if (els.selectedStageName) els.selectedStageName.textContent = (cat.title || ph.name || "Category") + " / " + titleize(bucket); 530 if (els.selectedStageDesc) els.selectedStageDesc.textContent = "Bucket detail from canonical category documents."; 531 532 const docs = Array.isArray(cat.docs) ? cat.docs : []; 533 const bucketDocs = bucket === "authority_docs" ? docs : []; 534 535 if (els.selectedStageTotal) els.selectedStageTotal.innerHTML = bucketDocs.length + ' docs
    in bucket view'; 536 if (els.selectedStageDonut) els.selectedStageDonut.innerHTML = donutMarkup(0, titleize(bucket)); 537 538 if (els.selectedPipelineSteps) { 539 els.selectedPipelineSteps.innerHTML = bucketDocs.length ? bucketDocs.map(function (doc) { 540 return [ 541 '
  • ', 542 '' + (doc.title || doc.label || doc.id || "item") + '', 543 '' + (doc.type || "doc") + '', 544 '
  • ' 545 ].join(""); 546 }).join("") : '
  • No documents registered in this bucket.MISSING
  • '; 547 } 548 } 549 550 function renderCanonicalSelection() { 551 const ph = selectedPhaseObject(); 552 const cat = selectedCategoryObject(); 553 554 if (!ph) return; 555 556 if (cat && state.selectedBucket) { 557 renderCenterBucket(ph, cat, state.selectedBucket); 558 return; 559 } 560 561 if (cat) { 562 renderCenterCategory(ph, cat); 563 return; 564 } 565 } 566 567 568 function selectStage(stageKey) { 569 state.selectedStage = normStageKey(stageKey); 570 const items = ((state.contentIndex && state.contentIndex.content_index) || []); 571 const navItem = items.find(function (item) { 572 return normStageKey(item.stage_key) === state.selectedStage; 573 }) || null; 574 const rollup = stageRollup(state.selectedStage); 575 const pct = rollup && typeof rollup.progress_pct === "number" ? Math.round(rollup.progress_pct) : 0; 576 const totalSteps = rollup && Array.isArray(rollup.step_statuses) ? rollup.step_statuses.length : 0; 577 578 if (els.heroTitle) els.heroTitle.textContent = navItem ? navItem.label : titleize(state.selectedStage); 579 if (els.heroSubtitle) { 580 els.heroSubtitle.textContent = "Runtime-backed stage view. Contract and runtime data are rendered from panel exports only."; 581 } 582 if (els.stageOrderBadge) { 583 els.stageOrderBadge.textContent = navItem ? ("ORDER " + navItem.deployment_order) : "—"; 584 } 585 if (els.selectedStageName) { 586 els.selectedStageName.textContent = navItem ? navItem.label : titleize(state.selectedStage); 587 } 588 if (els.selectedStageDesc) { 589 els.selectedStageDesc.textContent = "Stage completion is read from runtime_status stage_rollup.progress_pct."; 590 } 591 if (els.selectedStageTotal) { 592 els.selectedStageTotal.innerHTML = totalSteps 593 ? (totalSteps + ' required steps
    in contract') 594 : 'MISSING stage rollup
    in runtime'; 595 } 596 if (els.selectedStageDonut) { 597 els.selectedStageDonut.innerHTML = donutMarkup(pct, "stage completion"); 598 } 599 if (els.selectedRuntimeBadge) { 600 setBadge(els.selectedRuntimeBadge, rollup ? runtimeStatusOf(rollup) : "MISSING", rollup ? runtimeStatusOf(rollup) : "MISSING"); 601 } 602 603 renderSelectedPipeline(state.selectedStage, rollup); 604 renderCanonicalSelection(); 605 606 document.querySelectorAll(".stage-btn").forEach(function (btn) { 607 btn.classList.toggle("active", btn.dataset.stageKey === state.selectedStage); 608 }); 609 } 610 611 function wireButtons() { 612 [ 613 ["Manifest", els.btnOpenManifest, state.manifest], 614 ["Project Progress", els.btnOpenContract, state.projectProgress], 615 ["Host Runtime", els.btnOpenHost, state.hostRuntime], 616 ["Docker Runtime", els.btnOpenDocker, state.dockerRuntime], 617 ["Runtime Status", els.btnOpenRuntime, state.runtimeStatus] 618 ].forEach(function (entry) { 619 const label = entry[0]; 620 const btn = entry[1]; ===== runtime loaders ===== 363: const snapshot = ((state.runtimeStatus && state.runtimeStatus.runtime_snapshot) || []); 376: const snapshot = ((state.runtimeStatus && state.runtimeStatus.runtime_snapshot) || []); 448: const items = ((state.runtimeStatus && state.runtimeStatus.runtime_snapshot) || []); 617: ["Runtime Status", els.btnOpenRuntime, state.runtimeStatus] 636: getJsonOptional("subcategory_pipelines.json"), 640: getJsonOptional("runtime_status.json") 651: state.runtimeStatus = core[8];