Skip to content

feat(health): weekly report#264

Draft
MatteoGabriele wants to merge 1 commit into
mainfrom
feat/weekly-health-report
Draft

feat(health): weekly report#264
MatteoGabriele wants to merge 1 commit into
mainfrom
feat/weekly-health-report

Conversation

@MatteoGabriele

@MatteoGabriele MatteoGabriele commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added weekly ecosystem health reporting with classification breakdowns and automation closure rates.
    • Updated dashboards, charts, trends, and lab views to display current-week data.
    • Added date-based chart labels and week-range tooltip summaries.
    • Added fallback notifications using the latest available weekly results.
  • Bug Fixes

    • Improved scan result handling and preservation during daily and weekly processing.
    • Ensured generated scan outputs are included in automated commits.

@netlify

netlify Bot commented Jul 15, 2026

Copy link
Copy Markdown

Deploy Preview for agentscan ready!

Name Link
🔨 Latest commit 9dc9b84
🔍 Latest deploy log https://app.netlify.com/projects/agentscan/deploys/6a572a3b47ded100082ed2cb
😎 Deploy Preview https://deploy-preview-264--agentscan.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR migrates scan output to weekly JSON plus temporary raw results, adds weekly and current-week health APIs, updates health consumers and charts, and revises Discord notifications and workflow staging for the new files.

Changes

Weekly ecosystem health

Layer / File(s) Summary
Weekly data contracts and aggregation
shared/types/ecosystem-health.ts, shared/utils/count-classification-by-date.ts, shared/utils/weekly-aggregator.ts
Defines weekly health records, exports week-boundary helpers, and aggregates classifications and automation closure metrics.
Scan persistence and migration
scripts/scan-users.ts, scripts/migrate-scan-results-to-weekly.ts, data/scan-results-tmp.txt, data/scan-results.json, .github/workflows/scan-users.yml
Stores temporary scan results, rolls complete weeks into JSON, migrates existing data, and stages both generated outputs.
Weekly and current-week health APIs
server/api/health*.get.ts
Reads weekly JSON or temporary raw results and returns counts, trends, dates, scan times, and closure data.
Current-week UI and chart consumers
app/composables/useEcosystemHealthCurrentWeek.ts, app/components/Chart/*, app/components/Health/TrendItemList.vue, app/components/Report/WeeklyClassification.vue, app/pages/lab.vue
Switches current-week views to the new endpoint and updates weekly percentages, closure rates, chart series, and tooltip labels.
Notification input and delivery
scripts/notify-discord.ts
Centralizes webhook sending and uses temporary results with a latest-week fallback.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ScanUsers
  participant WeeklyAggregator
  participant TempResults
  participant WeeklyResults
  participant HealthAPI
  participant HealthUI
  ScanUsers->>TempResults: accumulate scan results
  ScanUsers->>WeeklyAggregator: build weekly entry on Sunday
  WeeklyAggregator->>WeeklyResults: write weekly health record
  HealthUI->>HealthAPI: request health data
  HealthAPI->>WeeklyResults: read weekly records
  WeeklyResults-->>HealthAPI: return weekly data
  HealthAPI-->>HealthUI: return counts, trends, dates, and closure metrics
Loading

Possibly related PRs

Suggested reviewers: graphieros

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the main change: introducing a weekly health report and related weekly data flow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/weekly-health-report

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
scripts/notify-discord.ts (1)

17-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Log the webhook response body on failure.

Discord often returns helpful error details (like invalid format structures or rate-limiting info) in the response body when a request fails. Logging the response text will make debugging much easier when the webhook drops a payload.

♻️ Proposed refactor
   if (!discordRes.ok) {
-    console.error('Discord webhook failed:', discordRes.status)
+    console.error('Discord webhook failed:', discordRes.status, await discordRes.text().catch(() => ''))
     process.exit(1)
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/notify-discord.ts` around lines 17 - 38, Update
sendDiscordNotification so that when discordRes.ok is false, it reads the
webhook response body and includes the response text in the existing
console.error call alongside the status before exiting.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/components/Report/WeeklyClassification.vue`:
- Line 16: Update the data source in WeeklyClassification to use the weekly
health endpoint backed by getClassificationByDateChunks() with rolling disabled,
rather than useEcosystemHealthCurrentWeek(). Preserve the chart’s existing
classification rendering while ensuring it receives complete Monday–Sunday week
data.

In `@scripts/migrate-scan-results-to-weekly.ts`:
- Around line 65-67: Update the fallback in the droppedLeadingDays filter to use
'0000-00-00' instead of '9999-99-99' when completeWeekStarts[0] is absent,
ensuring leftoverDays are preserved as trailing data when no complete weeks
exist.

In `@scripts/scan-users.ts`:
- Around line 279-288: The weekly aggregation around isEndOfWeek must process
every complete week present in tmpResults, not only when the current UTC day is
Sunday. Reuse the detection, extraction, and flushing logic from
migrate-scan-results-to-weekly.ts so missed or delayed runs aggregate older
complete weeks, retain incomplete records, and clear tmpResults only after
successful processing.

In `@server/api/health-current-week.get.ts`:
- Around line 15-20: Update the raw-file handling in the current-week health
endpoint to distinguish a missing scan-results-tmp.txt file from an existing
file with empty content. Preserve the missing-file error, but when the loaded
content is empty, return the endpoint’s normal empty response shape instead of
calling unpack or producing HTTP 500.

---

Nitpick comments:
In `@scripts/notify-discord.ts`:
- Around line 17-38: Update sendDiscordNotification so that when discordRes.ok
is false, it reads the webhook response body and includes the response text in
the existing console.error call alongside the status before exiting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b35d55e8-0b5f-40cd-af45-39c5e4fb1a78

📥 Commits

Reviewing files that changed from the base of the PR and between 1328ceb and 9dc9b84.

📒 Files selected for processing (19)
  • .github/workflows/scan-users.yml
  • app/components/Chart/FeaturedPackageHealthRanking.vue
  • app/components/Chart/GlobalEventsEvolution.vue
  • app/components/Chart/HealthResponseSparklines.vue
  • app/components/Health/TrendItemList.vue
  • app/components/Report/WeeklyClassification.vue
  • app/composables/useEcosystemHealthCurrentWeek.ts
  • app/pages/lab.vue
  • data/scan-results-tmp.txt
  • data/scan-results.json
  • data/scan-results.txt
  • scripts/migrate-scan-results-to-weekly.ts
  • scripts/notify-discord.ts
  • scripts/scan-users.ts
  • server/api/health-current-week.get.ts
  • server/api/health.get.ts
  • shared/types/ecosystem-health.ts
  • shared/utils/count-classification-by-date.ts
  • shared/utils/weekly-aggregator.ts

import('vue-data-ui/style.css')

const { data } = useEcosystemHealth()
const { data } = useEcosystemHealthCurrentWeek()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -A80 -B10 \
  "health-current-week|defineEventHandler|current.?week|weekly" \
  server/api/health-current-week.get.ts \
  server/api/health.get.ts

rg -n -A5 -B5 \
  "useEcosystemHealth(CurrentWeek)?" \
  app/composables

Repository: MatteoGabriele/agentscan

Length of output: 10825


🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline app/components/Report/WeeklyClassification.vue --view expanded || true
printf '\n---\n'
cat -n app/components/Report/WeeklyClassification.vue
printf '\n---\n'
ast-grep outline shared/utils/count-classification-by-date.ts --view expanded || true
printf '\n---\n'
cat -n shared/utils/count-classification-by-date.ts

Repository: MatteoGabriele/agentscan

Length of output: 22952


Keep the weekly report on the weekly health endpoint.

getClassificationByDateChunks() with rolling: false only renders complete Monday–Sunday weeks. useEcosystemHealthCurrentWeek() exposes the current partial week, so this chart stays empty until Sunday and then resets to another partial week.

-const { data } = useEcosystemHealthCurrentWeek()
+const { data } = useEcosystemHealth()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { data } = useEcosystemHealthCurrentWeek()
const { data } = useEcosystemHealth()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/components/Report/WeeklyClassification.vue` at line 16, Update the data
source in WeeklyClassification to use the weekly health endpoint backed by
getClassificationByDateChunks() with rolling disabled, rather than
useEcosystemHealthCurrentWeek(). Preserve the chart’s existing classification
rendering while ensuring it receives complete Monday–Sunday week data.

Comment on lines +65 to +67
const droppedLeadingDays = leftoverDays.filter(
(day) => day < (completeWeekStarts[0] ?? '9999-99-99'),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Safeguard against data loss when no complete weeks exist.

If there are no complete weeks (e.g., less than 7 days of historical data), completeWeekStarts will be empty. completeWeekStarts[0] evaluates to undefined, causing the fallback '9999-99-99' to be used. Because all dates will evaluate as strictly less than '9999-99-99', all data points will be classified as leading days and incorrectly dropped instead of being preserved as trailing days.

Change the fallback to '0000-00-00' to safely retain trailing data when no complete weeks exist.

🛡️ Proposed fix to preserve data
   const droppedLeadingDays = leftoverDays.filter(
-    (day) => day < (completeWeekStarts[0] ?? '9999-99-99'),
+    (day) => day < (completeWeekStarts[0] ?? '0000-00-00'),
   )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const droppedLeadingDays = leftoverDays.filter(
(day) => day < (completeWeekStarts[0] ?? '9999-99-99'),
)
const droppedLeadingDays = leftoverDays.filter(
(day) => day < (completeWeekStarts[0] ?? '0000-00-00'),
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/migrate-scan-results-to-weekly.ts` around lines 65 - 67, Update the
fallback in the droppedLeadingDays filter to use '0000-00-00' instead of
'9999-99-99' when completeWeekStarts[0] is absent, ensuring leftoverDays are
preserved as trailing data when no complete weeks exist.

Comment thread scripts/scan-users.ts
Comment on lines +279 to +288
const isEndOfWeek = new Date(now).getUTCDay() === 0 // Sunday

if (isEndOfWeek) {
const weeklyResults = dryRun ? [] : loadWeeklyResults()
weeklyResults.push(buildWeeklyEntry(tmpResults, now))
saveWeeklyResults(weeklyResults, dryRun)
saveTmpResults([], dryRun)
} else {
saveTmpResults(tmpResults, dryRun)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Potential data loss if a Sunday run is missed or delayed.

If the cron job fails on a Sunday (e.g., due to a GitHub API outage) or is delayed just past midnight UTC into Monday, isEndOfWeek will evaluate to false. The week's data will correctly remain in tmpResults.

However, on the following Sunday, buildWeeklyEntry(tmpResults, now) will only extract records matching that specific new week, completely ignoring the older records. The subsequent saveTmpResults([], dryRun) will then clear the file, permanently deleting the previous week's data without ever aggregating it.

Consider reusing the logic from migrate-scan-results-to-weekly.ts to detect, extract, and flush all complete weeks found within tmpResults regardless of the current execution day, rather than relying strictly on getUTCDay() === 0 and now.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/scan-users.ts` around lines 279 - 288, The weekly aggregation around
isEndOfWeek must process every complete week present in tmpResults, not only
when the current UTC day is Sunday. Reuse the detection, extraction, and
flushing logic from migrate-scan-results-to-weekly.ts so missed or delayed runs
aggregate older complete weeks, retain incomplete records, and clear tmpResults
only after successful processing.

Comment on lines +15 to +20
if (!raw) {
throw new Error('scan-results-tmp.txt not found')
}

const content = Buffer.isBuffer(raw) ? raw.toString('utf-8') : String(raw)
const results: EcosystemHealthItem[] = unpack(content)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Return an empty payload when the temporary results file is empty.

An empty scan-results-tmp.txt is an expected rollover state, but !raw turns it into HTTP 500 and breaks current-week charts. Distinguish a missing file from empty content and return the normal response shape.

Proposed fix
-    if (!raw) {
+    if (raw == null) {
       throw new Error('scan-results-tmp.txt not found')
     }

     const content = Buffer.isBuffer(raw) ? raw.toString('utf-8') : String(raw)
+
+    if (!content.trim()) {
+      return {
+        results: [],
+        categoryProgression: {
+          automation: calcLinearProgression([]),
+          mixed: calcLinearProgression([]),
+          organic: calcLinearProgression([]),
+        },
+        countsByDate: {},
+        dates: [],
+        scanTimes: [],
+      }
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!raw) {
throw new Error('scan-results-tmp.txt not found')
}
const content = Buffer.isBuffer(raw) ? raw.toString('utf-8') : String(raw)
const results: EcosystemHealthItem[] = unpack(content)
if (raw == null) {
throw new Error('scan-results-tmp.txt not found')
}
const content = Buffer.isBuffer(raw) ? raw.toString('utf-8') : String(raw)
if (!content.trim()) {
return {
results: [],
categoryProgression: {
automation: calcLinearProgression([]),
mixed: calcLinearProgression([]),
organic: calcLinearProgression([]),
},
countsByDate: {},
dates: [],
scanTimes: [],
}
}
const results: EcosystemHealthItem[] = unpack(content)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/api/health-current-week.get.ts` around lines 15 - 20, Update the
raw-file handling in the current-week health endpoint to distinguish a missing
scan-results-tmp.txt file from an existing file with empty content. Preserve the
missing-file error, but when the loaded content is empty, return the endpoint’s
normal empty response shape instead of calling unpack or producing HTTP 500.

@MatteoGabriele
MatteoGabriele marked this pull request as draft July 15, 2026 06:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant