fix(web): show provider source evidence on homepage
Some checks failed
CD Pipeline / tests (push) Has started running
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
Code Review / ai-code-review (push) Has been cancelled

This commit is contained in:
Your Name
2026-05-29 11:14:19 +08:00
parent d6d2719e02
commit aeaa77bbe1
3 changed files with 79 additions and 16 deletions

View File

@@ -321,6 +321,10 @@
"title": "CI/CD notifications enter AwoooP Timeline",
"detail": "Gitea main deploys, deploy markers, and post-deploy notifications flow through the AWOOI API and AwoooP Run Timeline."
},
"sourceDossier": {
"title": "Sentry / SigNoz source dossier evidence",
"detail": "Latest sources {sources}; Sentry refs {sentry}, SigNoz refs {signoz}. Provider filters verify this, so the overall sample no longer hides source evidence."
},
"callbackEvidence": {
"title": "Telegram detail / history DB truth chain",
"detail": "{total} callback evidence rows are available for Run detail, history, and snapshot lookup."
@@ -349,7 +353,7 @@
},
"kmGovernance": {
"title": "Stale KM governance",
"detail": "{stale} KM rows are older than {days} days; Hermes drafts, owner review, and writeback remain."
"detail": "{stale}/{total} KM rows are older than {days} days ({ratio}); pending owner reviews {pending}, entries still needed for threshold {remaining}."
},
"callbackBacklogDecay": {
"title": "Callback legacy backlog 24h decay",
@@ -535,6 +539,7 @@
},
"sources": {
"dossierCoverage": "/api/v1/platform/events/dossier/coverage",
"dossierCoverageWithProviders": "/api/v1/platform/events/dossier/coverage + provider=sentry/signoz",
"runsAndCicd": "/api/v1/platform/runs/list + /api/v1/platform/cicd/events",
"aiRouteStatus": "/api/v1/platform/ai-route-status",
"runsAndStatusChain": "/api/v1/platform/runs/list + /api/v1/platform/status-chain",
@@ -545,7 +550,7 @@
},
"signal": {
"metric": "sources {sources} / refs {refs}",
"detail": "missing refs {missing}, duplicates {duplicates}; Alert {alert} / Sentry {sentry} / SigNoz {signoz}"
"detail": "missing refs {missing}, duplicates {duplicates}; Alert {alert} / Sentry(provider) {sentry} / SigNoz(provider) {signoz}"
},
"intake": {
"metric": "Runs {runs} / linked {linked}",

View File

@@ -322,6 +322,10 @@
"title": "CI/CD 通知進 AwoooP 時間線",
"detail": "Gitea main 推版、deploy marker、post-deploy 通知已走 AWOOI API 與 AwoooP 執行時間線。"
},
"sourceDossier": {
"title": "Sentry / SigNoz 來源卷宗證據",
"detail": "最近來源 {sources} 筆Sentry refs {sentry}、SigNoz refs {signoz},用 provider 篩選驗證,不再被整體樣本誤判。"
},
"callbackEvidence": {
"title": "Telegram 詳情 / 歷史 DB 真相鏈",
"detail": "callback evidence 目前 {total} 筆,可從 Runs 反查詳情、歷史與快照。"
@@ -350,7 +354,7 @@
},
"kmGovernance": {
"title": "KM 陳舊資料治理",
"detail": "超過 {days} 天未更新 KM{stale} 筆;需 Hermes 產草稿、owner 審核後回寫。"
"detail": "超過 {days} 天未更新 KM{stale}/{total}{ratio});待 owner 審核 {pending} 筆,距離門檻還需處理 {remaining} 筆。"
},
"callbackBacklogDecay": {
"title": "Callback legacy backlog 24h decay",
@@ -536,6 +540,7 @@
},
"sources": {
"dossierCoverage": "/api/v1/platform/events/dossier/coverage",
"dossierCoverageWithProviders": "/api/v1/platform/events/dossier/coverage + provider=sentry/signoz",
"runsAndCicd": "/api/v1/platform/runs/list + /api/v1/platform/cicd/events",
"aiRouteStatus": "/api/v1/platform/ai-route-status",
"runsAndStatusChain": "/api/v1/platform/runs/list + /api/v1/platform/status-chain",
@@ -546,7 +551,7 @@
},
"signal": {
"metric": "來源 {sources} / refs {refs}",
"detail": "missing refs {missing}duplicates {duplicates}Alert {alert} / Sentry {sentry} / SigNoz {signoz}"
"detail": "missing refs {missing}duplicates {duplicates}Alert {alert} / Sentry(provider) {sentry} / SigNoz(provider) {signoz}"
},
"intake": {
"metric": "Runs {runs} / linked {linked}",

View File

@@ -193,6 +193,8 @@ interface HomepageAutomationBriefSnapshot {
aiRouteStatus?: HomepageAiRouteStatusResponse | null
kmStaleCandidates?: HomepageKmStaleCandidatesResponse | null
dossierCoverage?: HomepageDossierCoverageResponse | null
dossierCoverageSentry?: HomepageDossierCoverageResponse | null
dossierCoverageSignoz?: HomepageDossierCoverageResponse | null
eventRecurrence?: HomepageEventRecurrenceResponse | null
runsList?: HomepageRunsListResponse | null
cicdEvents?: HomepageCicdEventsResponse | null
@@ -774,7 +776,7 @@ export default function Home({ params }: { params: { locale: string } }) {
const controller = new AbortController()
const encodedProjectId = encodeURIComponent('awoooi')
let isCancelled = false
let pendingRequests = 8
let pendingRequests = 10
const finishRequest = () => {
pendingRequests -= 1
if (pendingRequests <= 0 && !isCancelled) {
@@ -829,6 +831,20 @@ export default function Home({ params }: { params: { locale: string } }) {
controller.signal
)
)
loadBriefPart(
'dossierCoverageSentry',
fetchHomepageJson<HomepageDossierCoverageResponse>(
`${API_BASE}/api/v1/platform/events/dossier/coverage?project_id=${encodedProjectId}&provider=sentry&limit=100`,
controller.signal
)
)
loadBriefPart(
'dossierCoverageSignoz',
fetchHomepageJson<HomepageDossierCoverageResponse>(
`${API_BASE}/api/v1/platform/events/dossier/coverage?project_id=${encodedProjectId}&provider=signoz&limit=100`,
controller.signal
)
)
loadBriefPart(
'eventRecurrence',
fetchHomepageJson<HomepageEventRecurrenceResponse>(
@@ -875,6 +891,8 @@ export default function Home({ params }: { params: { locale: string } }) {
const aiRouteStatusLoaded = hasAutomationBriefPart('aiRouteStatus')
const kmStaleCandidatesLoaded = hasAutomationBriefPart('kmStaleCandidates')
const dossierCoverageLoaded = hasAutomationBriefPart('dossierCoverage')
const dossierCoverageSentryLoaded = hasAutomationBriefPart('dossierCoverageSentry')
const dossierCoverageSignozLoaded = hasAutomationBriefPart('dossierCoverageSignoz')
const eventRecurrenceLoaded = hasAutomationBriefPart('eventRecurrence')
const runsListLoaded = hasAutomationBriefPart('runsList')
const cicdEventsLoaded = hasAutomationBriefPart('cicdEvents')
@@ -943,6 +961,12 @@ export default function Home({ params }: { params: { locale: string } }) {
const hasKmStaleCandidates = automationBrief.kmStaleCandidates !== undefined && automationBrief.kmStaleCandidates !== null
const canClaimFullAutoRepair = automationQualityAvailable && Boolean(automationQuality?.production_claim?.can_claim_full_auto_repair)
const dossierCoverageSummary = automationBrief.dossierCoverage?.summary ?? null
const dossierCoverageSentrySummary = automationBrief.dossierCoverageSentry?.summary ?? null
const dossierCoverageSignozSummary = automationBrief.dossierCoverageSignoz?.summary ?? null
const dossierSentryRefs = dossierCoverageSentrySummary?.sentry_ref_total ?? dossierCoverageSummary?.sentry_ref_total
const dossierSignozRefs = dossierCoverageSignozSummary?.signoz_ref_total ?? dossierCoverageSummary?.signoz_ref_total
const dossierProviderRefsLoaded = dossierCoverageSentryLoaded && dossierCoverageSignozLoaded
const dossierProviderRefsLive = (dossierSentryRefs ?? 0) > 0 || (dossierSignozRefs ?? 0) > 0
const recurrenceSummary = automationBrief.eventRecurrence?.summary ?? null
const recentRuns = automationBrief.runsList?.runs ?? []
const latestRun = recentRuns[0]
@@ -999,6 +1023,10 @@ export default function Home({ params }: { params: { locale: string } }) {
const cicdNeedsAttention = cicdItems.filter(item => item.needs_attention).length
const kmOwnerReviewBurndown = automationBrief.kmOwnerReviewBurndown ?? null
const kmBurndownSnapshot = kmOwnerReviewBurndown?.current_snapshot ?? null
const kmStaleDisplayCount = kmBurndownSnapshot?.stale_count ?? kmStaleTotal
const kmTotalDisplayCount = kmBurndownSnapshot?.total_count
const kmEntriesToThreshold = kmOwnerReviewBurndown?.entries_to_threshold
const kmGovernanceLoaded = kmOwnerReviewBurndownLoaded || kmStaleCandidatesLoaded
const staleRatioLabel = typeof kmBurndownSnapshot?.stale_ratio === 'number'
? `${(kmBurndownSnapshot.stale_ratio * 100).toFixed(1)}%`
: kmOwnerReviewBurndownLoaded ? unavailableValue : loadingStatus
@@ -1029,6 +1057,22 @@ export default function Home({ params }: { params: { locale: string } }) {
href: `/${locale}/awooop/runs`,
tone: 'live',
},
{
key: 'sourceDossier',
title: tDashboard('automationDelivery.delivered.sourceDossier.title'),
status: !dossierProviderRefsLoaded
? loadingStatus
: dossierProviderRefsLive
? tDashboard('automationDelivery.status.live')
: tDashboard('automationDelivery.status.watching'),
detail: tDashboard('automationDelivery.delivered.sourceDossier.detail', {
sources: formatAutomationNumber(dossierCoverageSummary?.source_count, dossierCoverageLoaded),
sentry: formatAutomationNumber(dossierSentryRefs, dossierCoverageSentryLoaded || dossierCoverageLoaded),
signoz: formatAutomationNumber(dossierSignozRefs, dossierCoverageSignozLoaded || dossierCoverageLoaded),
}),
href: `/${locale}/alerts`,
tone: dossierProviderRefsLive ? 'live' : dossierProviderRefsLoaded ? 'watching' : 'progress',
},
{
key: 'callbackEvidence',
title: tDashboard('automationDelivery.delivered.callbackEvidence.title'),
@@ -1133,19 +1177,23 @@ export default function Home({ params }: { params: { locale: string } }) {
{
key: 'kmGovernance',
title: tDashboard('automationDelivery.remaining.kmGovernance.title'),
status: !kmStaleCandidatesLoaded
status: !kmGovernanceLoaded
? loadingStatus
: typeof kmStaleTotal === 'number' && kmStaleTotal > 0
: typeof kmStaleDisplayCount === 'number' && kmStaleDisplayCount > 0
? tDashboard('automationDelivery.status.progress')
: hasKmStaleCandidates
? tDashboard('automationDelivery.status.live')
: unavailableStatus,
detail: tDashboard('automationDelivery.remaining.kmGovernance.detail', {
stale: formatAutomationNumber(kmStaleTotal, kmStaleCandidatesLoaded),
days: formatAutomationNumber(kmStaleThreshold, kmStaleCandidatesLoaded),
stale: formatAutomationNumber(kmStaleDisplayCount, kmGovernanceLoaded),
total: formatAutomationNumber(kmTotalDisplayCount, kmOwnerReviewBurndownLoaded),
ratio: staleRatioLabel,
pending: formatAutomationNumber(kmOwnerReviewBurndown?.pending_owner_reviews, kmOwnerReviewBurndownLoaded),
remaining: formatAutomationNumber(kmEntriesToThreshold, kmOwnerReviewBurndownLoaded),
days: formatAutomationNumber(kmStaleThreshold ?? kmBurndownSnapshot?.stale_days, kmGovernanceLoaded),
}),
href: `/${locale}/awooop/work-items?project_id=awoooi`,
tone: typeof kmStaleTotal === 'number' && kmStaleTotal > 0 ? 'progress' : hasKmStaleCandidates ? 'live' : 'watching',
tone: typeof kmStaleDisplayCount === 'number' && kmStaleDisplayCount > 0 ? 'progress' : hasKmStaleCandidates ? 'live' : 'watching',
},
{
key: 'callbackBacklogDecay',
@@ -1243,11 +1291,16 @@ export default function Home({ params }: { params: { locale: string } }) {
missing: formatAutomationNumber(dossierCoverageSummary?.missing_source_refs_total, dossierCoverageLoaded),
duplicates: formatAutomationNumber(dossierCoverageSummary?.duplicate_total, dossierCoverageLoaded),
alert: formatAutomationNumber(dossierCoverageSummary?.alert_ref_total, dossierCoverageLoaded),
sentry: formatAutomationNumber(dossierCoverageSummary?.sentry_ref_total, dossierCoverageLoaded),
signoz: formatAutomationNumber(dossierCoverageSummary?.signoz_ref_total, dossierCoverageLoaded),
sentry: formatAutomationNumber(dossierSentryRefs, dossierCoverageSentryLoaded || dossierCoverageLoaded),
signoz: formatAutomationNumber(dossierSignozRefs, dossierCoverageSignozLoaded || dossierCoverageLoaded),
}),
source: tDashboard('automationDiagrams.workspace.liveEvidence.sources.dossierCoverage'),
updated: formatLiveEvidenceTime(dossierCoverageSummary?.latest_received_at, dossierCoverageLoaded),
source: tDashboard('automationDiagrams.workspace.liveEvidence.sources.dossierCoverageWithProviders'),
updated: formatLiveEvidenceTime(
dossierCoverageSummary?.latest_received_at
?? dossierCoverageSentrySummary?.latest_received_at
?? dossierCoverageSignozSummary?.latest_received_at,
dossierCoverageLoaded || dossierProviderRefsLoaded
),
},
},
{
@@ -1430,13 +1483,13 @@ export default function Home({ params }: { params: { locale: string } }) {
nextAction: tDashboard('automationDiagrams.workspace.inspector.stages.verify.nextAction'),
liveEvidence: {
metric: tDashboard('automationDiagrams.workspace.liveEvidence.verify.metric', {
stale: formatAutomationNumber(kmBurndownSnapshot?.stale_count ?? kmStaleTotal, kmOwnerReviewBurndownLoaded || kmStaleCandidatesLoaded),
stale: formatAutomationNumber(kmStaleDisplayCount, kmGovernanceLoaded),
ratio: staleRatioLabel,
}),
detail: tDashboard('automationDiagrams.workspace.liveEvidence.verify.detail', {
pending: formatAutomationNumber(kmOwnerReviewBurndown?.pending_owner_reviews, kmOwnerReviewBurndownLoaded),
completed: formatAutomationNumber(kmOwnerReviewBurndown?.completed_owner_reviews, kmOwnerReviewBurndownLoaded),
remaining: formatAutomationNumber(kmOwnerReviewBurndown?.entries_to_threshold, kmOwnerReviewBurndownLoaded),
remaining: formatAutomationNumber(kmEntriesToThreshold, kmOwnerReviewBurndownLoaded),
}),
source: tDashboard('automationDiagrams.workspace.liveEvidence.sources.kmBurndown'),
updated: formatLiveEvidenceTime(kmOwnerReviewBurndown?.generated_at, kmOwnerReviewBurndownLoaded),