|
185 | 185 | </article> |
186 | 186 |
|
187 | 187 | <article class="card worker-health__panel"> |
188 | | - <div class="card-header d-flex align-items-center justify-content-between"> |
189 | | - <div> |
190 | | - <h5 class="mb-0">Health checks</h5> |
191 | | - <small class="text-muted">Operator readiness and compatibility signals.</small> |
192 | | - </div> |
193 | | - |
194 | | - <span class="worker-health__pill worker-health__pill--muted"> |
195 | | - {{ healthChecks.length.toLocaleString() }} checks |
196 | | - </span> |
| 188 | + <div class="card-header"> |
| 189 | + <h5 class="mb-0">Health checks</h5> |
| 190 | + <small class="text-muted"> |
| 191 | + Correctness answers <em>is work being discovered?</em>; acceleration answers <em>is the acceleration layer propagating?</em>. |
| 192 | + </small> |
197 | 193 | </div> |
198 | 194 |
|
199 | | - <div class="card-body card-bg-secondary"> |
200 | | - <div v-if="healthChecks.length > 0" class="worker-health__checks"> |
201 | | - <article v-for="check in healthChecks" :key="check.name" class="worker-health__check"> |
202 | | - <div class="worker-health__check-head"> |
203 | | - <span class="worker-health__pill" :class="statusToneClass(check.status)"> |
204 | | - {{ check.status }} |
205 | | - </span> |
206 | | - <strong>{{ check.name }}</strong> |
| 195 | + <div class="card-body card-bg-secondary worker-health__categories-body"> |
| 196 | + <section |
| 197 | + v-for="category in categorizedChecks" |
| 198 | + :key="category.key" |
| 199 | + class="worker-health__category" |
| 200 | + > |
| 201 | + <header class="worker-health__category-header"> |
| 202 | + <div> |
| 203 | + <span class="worker-health__category-eyebrow">{{ category.eyebrow }}</span> |
| 204 | + <h6 class="worker-health__category-title">{{ category.title }}</h6> |
| 205 | + <p class="worker-health__category-subtitle">{{ category.subtitle }}</p> |
207 | 206 | </div> |
208 | 207 |
|
209 | | - <p class="worker-health__check-copy">{{ check.message }}</p> |
210 | | - </article> |
211 | | - </div> |
212 | | - |
213 | | - <div v-else class="worker-health__empty-state worker-health__empty-state--compact"> |
214 | | - <strong>No health checks reported</strong> |
215 | | - <p class="mb-0 text-muted">The health endpoint returned no explicit checks.</p> |
216 | | - </div> |
| 208 | + <span |
| 209 | + class="worker-health__pill" |
| 210 | + :class="statusToneClass(category.rollupStatus)" |
| 211 | + :title="category.rollupTitle" |
| 212 | + > |
| 213 | + {{ category.rollupStatus.toUpperCase() }} |
| 214 | + </span> |
| 215 | + </header> |
| 216 | + |
| 217 | + <div v-if="category.checks.length > 0" class="worker-health__checks"> |
| 218 | + <article |
| 219 | + v-for="check in category.checks" |
| 220 | + :key="check.name" |
| 221 | + class="worker-health__check" |
| 222 | + > |
| 223 | + <div class="worker-health__check-head"> |
| 224 | + <span class="worker-health__pill" :class="statusToneClass(check.status)"> |
| 225 | + {{ check.status }} |
| 226 | + </span> |
| 227 | + <strong>{{ check.name }}</strong> |
| 228 | + </div> |
| 229 | + |
| 230 | + <p class="worker-health__check-copy">{{ check.message }}</p> |
| 231 | + </article> |
| 232 | + </div> |
| 233 | + |
| 234 | + <div v-else class="worker-health__empty-state worker-health__empty-state--compact"> |
| 235 | + <strong>No {{ category.title.toLowerCase() }} checks reported</strong> |
| 236 | + <p class="mb-0 text-muted">The health endpoint did not return any checks for this category.</p> |
| 237 | + </div> |
| 238 | + </section> |
217 | 239 | </div> |
218 | 240 | </article> |
219 | 241 | </section> |
@@ -277,6 +299,46 @@ export default { |
277 | 299 | return this.healthData?.checks || []; |
278 | 300 | }, |
279 | 301 |
|
| 302 | + categorizedChecks() { |
| 303 | + const definitions = [ |
| 304 | + { |
| 305 | + key: 'correctness', |
| 306 | + eyebrow: 'Durable substrate', |
| 307 | + title: 'Correctness', |
| 308 | + subtitle: 'Answers "is work being discovered?" from durable dispatch state.', |
| 309 | + rollupTitle: 'Rollup of correctness-category checks.', |
| 310 | + }, |
| 311 | + { |
| 312 | + key: 'acceleration', |
| 313 | + eyebrow: 'Optional layer', |
| 314 | + title: 'Acceleration', |
| 315 | + subtitle: 'Answers "is the acceleration layer propagating?". Degraded acceleration never masks correctness.', |
| 316 | + rollupTitle: 'Rollup of acceleration-category checks.', |
| 317 | + }, |
| 318 | + ]; |
| 319 | +
|
| 320 | + const grouped = {correctness: [], acceleration: []}; |
| 321 | +
|
| 322 | + this.healthChecks.forEach((check) => { |
| 323 | + if (!check || typeof check !== 'object') return; |
| 324 | +
|
| 325 | + if (check.name === 'engine_source') { |
| 326 | + return; |
| 327 | + } |
| 328 | +
|
| 329 | + const category = this.categoryForCheck(check); |
| 330 | + grouped[category].push(check); |
| 331 | + }); |
| 332 | +
|
| 333 | + const rollups = this.healthData?.categories || {}; |
| 334 | +
|
| 335 | + return definitions.map((definition) => ({ |
| 336 | + ...definition, |
| 337 | + checks: grouped[definition.key], |
| 338 | + rollupStatus: this.rollupForCategory(definition.key, grouped[definition.key], rollups), |
| 339 | + })); |
| 340 | + }, |
| 341 | +
|
280 | 342 | workersTableClass() { |
281 | 343 | const classes = ['table', 'table-hover', 'mb-0']; |
282 | 344 |
|
@@ -510,6 +572,44 @@ export default { |
510 | 572 | } |
511 | 573 | }, |
512 | 574 |
|
| 575 | + categoryForCheck(check) { |
| 576 | + const declared = typeof check.category === 'string' ? check.category.toLowerCase() : null; |
| 577 | +
|
| 578 | + if (declared === 'correctness' || declared === 'acceleration') { |
| 579 | + return declared; |
| 580 | + } |
| 581 | +
|
| 582 | + // Backwards-compatibility: if an older workflow package version |
| 583 | + // omits the category field, infer a safe default so the UI still |
| 584 | + // renders. Only the wake-acceleration check is known to belong to |
| 585 | + // the acceleration category; every other check is durable |
| 586 | + // correctness-substrate. |
| 587 | + if (check.name === 'long_poll_wake_acceleration') { |
| 588 | + return 'acceleration'; |
| 589 | + } |
| 590 | +
|
| 591 | + return 'correctness'; |
| 592 | + }, |
| 593 | +
|
| 594 | + rollupForCategory(key, checks, rollups) { |
| 595 | + const declared = rollups && rollups[key] && rollups[key].status; |
| 596 | +
|
| 597 | + if (declared === 'ok' || declared === 'warning' || declared === 'error') { |
| 598 | + return declared; |
| 599 | + } |
| 600 | +
|
| 601 | + if (!Array.isArray(checks) || checks.length === 0) { |
| 602 | + return 'ok'; |
| 603 | + } |
| 604 | +
|
| 605 | + const statuses = checks.map((check) => check.status); |
| 606 | +
|
| 607 | + if (statuses.includes('error')) return 'error'; |
| 608 | + if (statuses.includes('warning')) return 'warning'; |
| 609 | +
|
| 610 | + return 'ok'; |
| 611 | + }, |
| 612 | +
|
513 | 613 | statusColor(status) { |
514 | 614 | return { |
515 | 615 | ok: 'text-success', |
@@ -752,6 +852,55 @@ export default { |
752 | 852 | min-height: 22rem; |
753 | 853 | } |
754 | 854 |
|
| 855 | +.worker-health__categories-body { |
| 856 | + display: flex; |
| 857 | + flex-direction: column; |
| 858 | + gap: 1.4rem; |
| 859 | +} |
| 860 | +
|
| 861 | +.worker-health__category { |
| 862 | + display: flex; |
| 863 | + flex-direction: column; |
| 864 | + gap: 0.75rem; |
| 865 | + padding-bottom: 1.1rem; |
| 866 | + border-bottom: 1px solid color-mix(in srgb, var(--wl-text) 8%, transparent); |
| 867 | +} |
| 868 | +
|
| 869 | +.worker-health__category:last-child { |
| 870 | + border-bottom: 0; |
| 871 | + padding-bottom: 0; |
| 872 | +} |
| 873 | +
|
| 874 | +.worker-health__category-header { |
| 875 | + display: flex; |
| 876 | + align-items: flex-start; |
| 877 | + justify-content: space-between; |
| 878 | + gap: 0.75rem; |
| 879 | +} |
| 880 | +
|
| 881 | +.worker-health__category-eyebrow { |
| 882 | + display: block; |
| 883 | + color: var(--wl-text-soft); |
| 884 | + font-family: 'IBM Plex Mono', monospace; |
| 885 | + font-size: 0.7rem; |
| 886 | + letter-spacing: 0.08em; |
| 887 | + text-transform: uppercase; |
| 888 | +} |
| 889 | +
|
| 890 | +.worker-health__category-title { |
| 891 | + margin: 0.25rem 0 0; |
| 892 | + color: var(--wl-text); |
| 893 | + font-size: 1rem; |
| 894 | + font-weight: 600; |
| 895 | +} |
| 896 | +
|
| 897 | +.worker-health__category-subtitle { |
| 898 | + margin: 0.3rem 0 0; |
| 899 | + color: var(--wl-text-muted); |
| 900 | + font-size: 0.88rem; |
| 901 | + line-height: 1.4; |
| 902 | +} |
| 903 | +
|
755 | 904 | .worker-health__checks { |
756 | 905 | display: grid; |
757 | 906 | gap: 0.75rem; |
|
0 commit comments