Skip to content

Commit e8ae36d

Browse files
Add diagnostics freshness indicators.
Expose diagnostics freshness state on repo summaries and surface it in the list and details UI so operators can distinguish warm diagnostics from placeholder or stale values, with updated worker transition tests and handover notes. Made-with: Cursor
1 parent 51c0360 commit e8ae36d

7 files changed

Lines changed: 50 additions & 2 deletions

File tree

docs/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
- Added async diagnostics batching in `repos/workspace-hub/server/workspace.ts` with a background queue, diagnostics cache TTL, and configurable worker concurrency for full-summary diagnostics refresh.
2323
- Added worker cache-coherency invalidation so refreshed diagnostics propagate to subsequent summary reads.
2424
- Extended `repos/workspace-hub/test/workspace-cache-search.test.ts` with diagnostics warming coverage and confirmed updated local test-suite pass outside sandbox (`14 passed, 0 failed`).
25+
- Added diagnostics freshness state (`fresh`, `warming`, `stale`) to workspace repo summaries and surfaced it in repo list and details UI.
26+
- Updated diagnostics worker coverage to assert `warming -> fresh` transition and reconfirmed local test-suite pass (`14 passed, 0 failed`).
2527

2628
## 2026-04-05
2729

docs/HANDOVER.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,3 +362,28 @@ Verification after diagnostics worker slice:
362362
- `pnpm --dir "repos/workspace-hub" lint`: passed
363363
- `pnpm --dir "repos/workspace-hub" typecheck`: passed
364364
- `pnpm --dir "repos/workspace-hub" test`: passed outside sandbox in local terminal (`14 passed, 0 failed`, duration ~`2864ms`)
365+
366+
### Implementation update (2026-04-07, diagnostics freshness indicator slice)
367+
368+
Completed in `repos/workspace-hub`:
369+
370+
1. Added diagnostics freshness state on repo records.
371+
- `WorkspaceRepo` now includes `diagnosticsFreshness` with values: `fresh`, `warming`, `stale`.
372+
373+
2. Surfaced freshness in UI.
374+
- Added freshness status pills to repo cards in `RepoSnapshot`.
375+
- Added a diagnostics freshness row in `RepoDetails` overview.
376+
377+
3. Defined freshness transitions in summary generation.
378+
- `warming`: first full-summary read before diagnostics cache is warm
379+
- `stale`: expired diagnostics returned while background refresh is queued
380+
- `fresh`: warm diagnostics cache or intentionally skipped diagnostics mode
381+
382+
4. Extended worker test assertions.
383+
- `workspace-cache-search` test now validates `warming -> fresh` transition during async diagnostics warmup.
384+
385+
Verification after diagnostics freshness slice:
386+
387+
- `pnpm --dir "repos/workspace-hub" lint`: passed
388+
- `pnpm --dir "repos/workspace-hub" typecheck`: passed
389+
- `pnpm --dir "repos/workspace-hub" test`: passed (`14 passed, 0 failed`, duration ~`2337ms`)

repos/workspace-hub/server/workspace.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ type WorkspaceSummaryBuildOptions = {
176176

177177
type RepoDiagnostics = {
178178
dependencies: RepoDependencyState
179+
freshness: 'fresh' | 'stale' | 'warming'
179180
git: RepoGitState
180181
health: RepoHealth
181182
}
@@ -1527,12 +1528,13 @@ async function buildRepoRecord(
15271528
}),
15281529
])
15291530

1530-
return { dependencies, git, health }
1531+
return { dependencies, freshness: 'fresh', git, health }
15311532
}
15321533
let diagnostics: RepoDiagnostics
15331534
if (!includeDiagnostics) {
15341535
diagnostics = {
15351536
dependencies: buildUnknownDependencyState(),
1537+
freshness: 'fresh',
15361538
git: buildUnavailableGitState(),
15371539
health: buildUnknownHealth(healthcheckUrl ?? resolvedPreview.previewUrl),
15381540
}
@@ -1541,11 +1543,15 @@ async function buildRepoRecord(
15411543
if (cachedDiagnostics && cachedDiagnostics.expiresAt > Date.now()) {
15421544
diagnostics = cachedDiagnostics.value
15431545
} else if (cachedDiagnostics) {
1544-
diagnostics = cachedDiagnostics.value
1546+
diagnostics = {
1547+
...cachedDiagnostics.value,
1548+
freshness: 'stale',
1549+
}
15451550
enqueueRepoDiagnostics(diagnosticsKey, diagnosticsFactory)
15461551
} else {
15471552
diagnostics = {
15481553
dependencies: buildUnknownDependencyState(),
1554+
freshness: 'warming',
15491555
git: buildUnavailableGitState(),
15501556
health: buildUnknownHealth(healthcheckUrl ?? resolvedPreview.previewUrl),
15511557
}
@@ -1558,6 +1564,7 @@ async function buildRepoRecord(
15581564
buildCommand: effectiveBuildCommand,
15591565
collection: collection ?? 'direct',
15601566
detectedBy: hasManifest ? 'manifest' : 'files',
1567+
diagnosticsFreshness: diagnostics.freshness,
15611568
dependencies: diagnostics.dependencies,
15621569
devCommand: effectiveDevCommand,
15631570
externalUrl,

repos/workspace-hub/src/features/repos/RepoDetails.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,14 @@ function RepoDetailsContent({
669669
{` ${repo.dependencies.reason}`}
670670
</dd>
671671
</div>
672+
<div className="details-row">
673+
<dt>Diagnostics freshness</dt>
674+
<dd>
675+
<span className={`status-pill ${repo.diagnosticsFreshness}`}>
676+
{repo.diagnosticsFreshness}
677+
</span>
678+
</dd>
679+
</div>
672680
<div className="details-row">
673681
<dt>Dev command</dt>
674682
<dd>{repo.devCommand ?? 'Not inferred yet'}</dd>

repos/workspace-hub/src/features/repos/RepoSnapshot.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ function RepoSnapshotCard({ repo, selected }: RepoSnapshotCardProps) {
134134
</span>
135135
<span className="repo-card-diagnostics">
136136
<span className="repo-card-branch">git {formatBranchLabel(repo)}</span>
137+
<span className={`status-pill ${repo.diagnosticsFreshness}`}>
138+
{repo.diagnosticsFreshness}
139+
</span>
137140
<span className={`status-pill ${repo.git.visibility}`}>
138141
{formatGitVisibilityLabel(repo)}
139142
</span>

repos/workspace-hub/src/types/workspace.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ export type WorkspaceRepo = {
229229
buildCommand: string | null
230230
collection: string
231231
detectedBy: 'files' | 'manifest'
232+
diagnosticsFreshness: 'fresh' | 'stale' | 'warming'
232233
dependencies: RepoDependencyState
233234
devCommand: string | null
234235
externalUrl: string | null

repos/workspace-hub/test/workspace-cache-search.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ test('diagnostics mode warms git diagnostics asynchronously via worker', async (
164164
const firstRepo = firstSummary.repos.find((entry) => entry.relativePath.endsWith('repo-git-worker'))
165165
assert.ok(firstRepo)
166166
assert.equal(firstRepo.git.hasGit, false)
167+
assert.equal(firstRepo.diagnosticsFreshness, 'warming')
167168

168169
const maxAttempts = 20
169170
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
@@ -183,6 +184,7 @@ test('diagnostics mode warms git diagnostics asynchronously via worker', async (
183184
assert.ok(refreshedRepo)
184185

185186
if (refreshedRepo.git.hasGit) {
187+
assert.equal(refreshedRepo.diagnosticsFreshness, 'fresh')
186188
assert.match(refreshedRepo.git.summary, /Git status available|No commits yet on/i)
187189
return
188190
}

0 commit comments

Comments
 (0)