feat: add clawsweeper dashboard renderer

This commit is contained in:
Peter Steinberger 2026-05-01 07:12:55 +01:00
parent 179a0376bc
commit 6bffc1b29e
No known key found for this signature in database
11 changed files with 1007 additions and 0 deletions

58
.github/workflows/dashboard.yml vendored Normal file
View File

@ -0,0 +1,58 @@
name: dashboard
on:
workflow_dispatch:
repository_dispatch:
types: [clawsweeper_dashboard_refresh]
schedule:
- cron: "*/15 * * * *"
permissions:
contents: write
concurrency:
group: clawsweeper-dashboard
cancel-in-progress: true
jobs:
render:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
path: dashboard
fetch-depth: 0
- uses: actions/checkout@v6
with:
repository: openclaw/clawsweeper
path: clawsweeper
filter: blob:none
fetch-depth: 1
- uses: actions/setup-node@v5
with:
node-version: 24
- name: Enable pnpm
run: corepack enable
- name: Render dashboard
working-directory: dashboard
run: |
pnpm install --frozen-lockfile
pnpm run check
pnpm run render -- --source ../clawsweeper
- name: Commit dashboard
working-directory: dashboard
run: |
if [ -z "$(git status --porcelain -- README.md)" ]; then
echo "Dashboard unchanged."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add README.md
git commit -m "chore: update dashboard"
git push

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules/
.DS_Store

249
README.md Normal file
View File

@ -0,0 +1,249 @@
# ClawSweeper Dashboard
Generated dashboard for [openclaw/clawsweeper](https://github.com/openclaw/clawsweeper).
## Sweep Dashboard
Last source update: May 1, 2026, 06:11 UTC
### Fleet
| Metric | Count |
| --- | ---: |
| Covered repositories | 3 |
| Open review records | 7651 |
| Archived closed records | 15505 |
| Fresh reviews, 7d | 7606 |
| Proposed closes awaiting apply | 6 |
| Work candidates awaiting promotion | 2413 |
| Failed or stale reviews | 21 |
### Current Runs
| Repository | State | Updated | Run |
| --- | --- | --- | --- |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | Idle | unknown | _none_ |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | Idle | unknown | _none_ |
| [openclaw/clawsweeper](https://github.com/openclaw/clawsweeper) | Idle | unknown | _none_ |
### Repositories
| Repository | Open records | Archived | Fresh | Proposed closes | Work candidates | Failed/stale | Last review | Last close |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | --- | --- |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | 6722 | 15479 | 6677 | 6 | 2367 | 9 | May 1, 2026, 06:11 UTC | May 1, 2026, 06:05 UTC |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | 924 | 26 | 924 | 0 | 45 | 12 | Apr 29, 2026, 22:22 UTC | Apr 29, 2026, 17:17 UTC |
| [openclaw/clawsweeper](https://github.com/openclaw/clawsweeper) | 5 | 0 | 5 | 0 | 1 | 0 | May 1, 2026, 02:03 UTC | unknown |
### Work Candidates
| Repository | Item | Title | Priority | Reviewed | Report |
| --- | --- | --- | --- | --- | --- |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75183](https://github.com/openclaw/openclaw/pull/75183) | fix: simplify bundled runtime dependency repair | high | May 1, 2026, 06:08 UTC | [records/openclaw-openclaw/items/75183.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75183.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#72025](https://github.com/openclaw/openclaw/pull/72025) | fix(signal): enable inbound status reactions | high | May 1, 2026, 06:08 UTC | [records/openclaw-openclaw/items/72025.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/72025.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#72677](https://github.com/openclaw/openclaw/pull/72677) | fix(cron): warn on main heartbeat handoff ghost runs | high | May 1, 2026, 06:05 UTC | [records/openclaw-openclaw/items/72677.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/72677.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#74377](https://github.com/openclaw/openclaw/issues/74377) | [Bug]: tools array empty at Anthropic provider despite 17 tools computed in attempt.ts (Telegram channel) | high | May 1, 2026, 06:04 UTC | [records/openclaw-openclaw/items/74377.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/74377.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#73243](https://github.com/openclaw/openclaw/pull/73243) | fix(diagnostics): abort stuck sessions | high | May 1, 2026, 06:04 UTC | [records/openclaw-openclaw/items/73243.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/73243.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75155](https://github.com/openclaw/openclaw/issues/75155) | Talk Mode: user voice transcripts don't render in WebChat/Control UI thread | high | May 1, 2026, 06:04 UTC | [records/openclaw-openclaw/items/75155.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75155.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75206](https://github.com/openclaw/openclaw/issues/75206) | Auto-update leaves stale chunk reference: conversation-runtime imports missing inbound.runtime-*.js → Teleg... | high | May 1, 2026, 06:04 UTC | [records/openclaw-openclaw/items/75206.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75206.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75153](https://github.com/openclaw/openclaw/issues/75153) | [Feature]: expose channels.start / stop / restart via CLI so a wedged channel can recover without container... | high | May 1, 2026, 06:04 UTC | [records/openclaw-openclaw/items/75153.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75153.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75456](https://github.com/openclaw/openclaw/issues/75456) | security audit --json can hang while staging plugin runtime deps and scanning backup extension dirs | high | May 1, 2026, 06:03 UTC | [records/openclaw-openclaw/items/75456.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75456.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75171](https://github.com/openclaw/openclaw/issues/75171) | [Bug]: TypeError: (0, _pluginSdk.createReplyPrefixContext) is not a function after update | high | May 1, 2026, 06:03 UTC | [records/openclaw-openclaw/items/75171.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75171.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75131](https://github.com/openclaw/openclaw/issues/75131) | [Bug]: delivery-queue: send-retry creates fresh UUIDs (not idempotent); recovery should fail-permanent on T... | high | May 1, 2026, 06:03 UTC | [records/openclaw-openclaw/items/75131.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75131.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75151](https://github.com/openclaw/openclaw/issues/75151) | [Bug]: Context overflow reset can map sessionFile to nonexistent transcript, orphaning real session history | high | May 1, 2026, 06:03 UTC | [records/openclaw-openclaw/items/75151.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75151.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75180](https://github.com/openclaw/openclaw/pull/75180) | fix(reply): delivery-aware media tracking in block reply pipeline (#75156) | high | May 1, 2026, 06:00 UTC | [records/openclaw-openclaw/items/75180.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75180.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75452](https://github.com/openclaw/openclaw/issues/75452) | Heartbeat per-turn model override persists after turn completes (2026.4.29) | high | May 1, 2026, 05:57 UTC | [records/openclaw-openclaw/items/75452.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75452.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75425](https://github.com/openclaw/openclaw/pull/75425) | fix(media): fall back to qrcode/lib subpath when bare specifier fails to resolve | high | May 1, 2026, 05:57 UTC | [records/openclaw-openclaw/items/75425.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75425.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#71324](https://github.com/openclaw/openclaw/pull/71324) | fix(webchat): hide legacy runtime transcript wrappers | high | May 1, 2026, 05:56 UTC | [records/openclaw-openclaw/items/71324.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/71324.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#58683](https://github.com/openclaw/openclaw/pull/58683) | feat(heartbeat): add time-of-day schedule for variable intervals | high | May 1, 2026, 05:56 UTC | [records/openclaw-openclaw/items/58683.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/58683.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#58650](https://github.com/openclaw/openclaw/pull/58650) | fix(reply-runtime): preserve final answer in /reasoning on with block replies | high | May 1, 2026, 05:56 UTC | [records/openclaw-openclaw/items/58650.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/58650.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#58608](https://github.com/openclaw/openclaw/issues/58608) | Session corruption from orphaned tool_result blocks survives restart (overload/timeout interruption) | high | May 1, 2026, 05:55 UTC | [records/openclaw-openclaw/items/58608.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/58608.md) |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75447](https://github.com/openclaw/openclaw/issues/75447) | [Bug]: openclaw update installls old whatsapp extension - update should not install extensions that are old... | high | May 1, 2026, 05:49 UTC | [records/openclaw-openclaw/items/75447.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/items/75447.md) |
### Recently Closed
| Repository | Item | Title | Reason | Closed | Report |
| --- | --- | --- | --- | --- | --- |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1434](https://github.com/openclaw/clawhub/issues/1434) | Sonarbay-skill incorrectly flaged. | closed externally after review | Apr 29, 2026, 17:17 UTC | [records/openclaw-clawhub/closed/1434.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1434.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1376](https://github.com/openclaw/clawhub/issues/1376) | False positive: openclaw-workspace-sync flagged as suspicious | closed externally after review | Apr 29, 2026, 17:06 UTC | [records/openclaw-clawhub/closed/1376.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1376.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1812](https://github.com/openclaw/clawhub/issues/1812) | Skill be flagged as suspicious and being marked hidden | closed externally after review | Apr 29, 2026, 13:48 UTC | [records/openclaw-clawhub/closed/1812.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1812.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1861](https://github.com/openclaw/clawhub/pull/1861) | feat: add owner rescan security surfaces | closed externally after review | Apr 28, 2026, 23:32 UTC | [records/openclaw-clawhub/closed/1861.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1861.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1870](https://github.com/openclaw/clawhub/pull/1870) | fix: hide admin CLI help from non-admins | none | Apr 28, 2026, 23:24 UTC | [records/openclaw-clawhub/closed/1870.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1870.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1869](https://github.com/openclaw/clawhub/pull/1869) | [codex] Use GitHub App auth for publish gate lookups | closed externally after review | Apr 28, 2026, 22:18 UTC | [records/openclaw-clawhub/closed/1869.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1869.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1841](https://github.com/openclaw/clawhub/pull/1841) | fix: calibrate VT Code Insight moderation | closed externally after review | Apr 28, 2026, 08:18 UTC | [records/openclaw-clawhub/closed/1841.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1841.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1830](https://github.com/openclaw/clawhub/issues/1830) | False positive: skill-factory incorrectly flagged as suspicious | closed externally after review | Apr 28, 2026, 08:18 UTC | [records/openclaw-clawhub/closed/1830.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1830.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1517](https://github.com/openclaw/clawhub/issues/1517) | [Appeal] Skill Wrongly Flagged: abu-shotai/ai-video-remix | closed externally after review | Apr 28, 2026, 07:43 UTC | [records/openclaw-clawhub/closed/1517.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1517.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#125](https://github.com/openclaw/clawhub/issues/125) | New Provider Plugin: ClawRouter — 30+ models, smart routing, x402 payments | closed externally after review | Apr 28, 2026, 06:41 UTC | [records/openclaw-clawhub/closed/125.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/125.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1699](https://github.com/openclaw/clawhub/issues/1699) | Plugin search returns 500, and plugin catalog breaks after page 2 | closed externally after review | Apr 28, 2026, 05:46 UTC | [records/openclaw-clawhub/closed/1699.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1699.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1736](https://github.com/openclaw/clawhub/pull/1736) | Align hover stats with denormalized counters and fix seed digest stat drift | implemented_on_main | Apr 28, 2026, 05:18 UTC | [records/openclaw-clawhub/closed/1736.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1736.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1324](https://github.com/openclaw/clawhub/pull/1324) | feat: add --dry-run flag to package publish command | implemented_on_main | Apr 28, 2026, 05:18 UTC | [records/openclaw-clawhub/closed/1324.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1324.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1240](https://github.com/openclaw/clawhub/pull/1240) | fix: use esbuild minification for safari builds | implemented_on_main | Apr 28, 2026, 05:18 UTC | [records/openclaw-clawhub/closed/1240.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1240.md) |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | [#1842](https://github.com/openclaw/clawhub/pull/1842) | fix: constrain plugin catalog queries | closed externally after review | Apr 28, 2026, 05:05 UTC | [records/openclaw-clawhub/closed/1842.md](https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-clawhub/closed/1842.md) |
<details>
<summary>Recently Reviewed</summary>
| Repository | Item | Title | Outcome | Status | Reviewed |
| --- | --- | --- | --- | --- | --- |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75448](https://github.com/openclaw/openclaw/pull/75448) | feat(ui): replace textarea with CodeMirror 6 JSON editor in raw config view | keep_open / kept_open | complete | May 1, 2026, 06:11 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75183](https://github.com/openclaw/openclaw/pull/75183) | fix: simplify bundled runtime dependency repair | keep_open / kept_open | complete | May 1, 2026, 06:08 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#72025](https://github.com/openclaw/openclaw/pull/72025) | fix(signal): enable inbound status reactions | keep_open / kept_open | complete | May 1, 2026, 06:08 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75459](https://github.com/openclaw/openclaw/pull/75459) | fix: voice-call CLI gateway delegation path actionable regressions | keep_open / kept_open | complete | May 1, 2026, 06:08 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75454](https://github.com/openclaw/openclaw/issues/75454) | 1M context window not applied for github-copilot/claude-opus-4.x-1m models (capped at 272k) | keep_open / kept_open | complete | May 1, 2026, 06:06 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75423](https://github.com/openclaw/openclaw/pull/75423) | fix(gateway): refresh stale channel health cache | keep_open / kept_open | complete | May 1, 2026, 06:06 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75327](https://github.com/openclaw/openclaw/pull/75327) | fix: deliver group/channel replies automatically when bot is @mentioned | keep_open / kept_open | complete | May 1, 2026, 06:06 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75419](https://github.com/openclaw/openclaw/issues/75419) | [Bug]: [2026.4.29] openclaw cannot accept for any input | keep_open / kept_open | complete | May 1, 2026, 06:05 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#72677](https://github.com/openclaw/openclaw/pull/72677) | fix(cron): warn on main heartbeat handoff ghost runs | keep_open / kept_open | complete | May 1, 2026, 06:05 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#74377](https://github.com/openclaw/openclaw/issues/74377) | [Bug]: tools array empty at Anthropic provider despite 17 tools computed in attempt.ts (Telegram channel) | keep_open / kept_open | complete | May 1, 2026, 06:04 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75406](https://github.com/openclaw/openclaw/issues/75406) | v2026.4.29 - synchronous WASM tokenizer init blocks event loop 20-79s on first LLM call (system-prompt / ru... | keep_open / kept_open | complete | May 1, 2026, 06:04 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#73320](https://github.com/openclaw/openclaw/pull/73320) | Limit internal task completion payloads | keep_open / kept_open | complete | May 1, 2026, 06:04 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#58482](https://github.com/openclaw/openclaw/pull/58482) | fix(memory-host): add AbortSignal support to batch polling (OpenAI, Voyage, Gemini) | keep_open / kept_open | complete | May 1, 2026, 06:04 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75279](https://github.com/openclaw/openclaw/issues/75279) | [Performance]: 3-7 minute agent response latency on Windows — 66 plugins loaded, 49 disabled, 48 skills mis... | keep_open / kept_open | complete | May 1, 2026, 06:04 UTC |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | [#75298](https://github.com/openclaw/openclaw/issues/75298) | Webhook plugin re-registers repeatedly whenever event loop saturates (dreaming, cron catchup, Control UI po... | keep_open / kept_open | complete | May 1, 2026, 06:04 UTC |
</details>
### Audit Health
| Repository | Status | Last audit | Missing eligible | Stale records | Protected proposed | Scan complete |
| --- | --- | --- | ---: | ---: | ---: | --- |
| [openclaw/openclaw](https://github.com/openclaw/openclaw) | _unknown_ | unknown | 0 | 0 | 0 | unknown |
| [openclaw/clawhub](https://github.com/openclaw/clawhub) | _unknown_ | unknown | 0 | 0 | 0 | unknown |
| [openclaw/clawsweeper](https://github.com/openclaw/clawsweeper) | _unknown_ | unknown | 0 | 0 | 0 | unknown |
## Repair Dashboard
Last source update: May 1, 2026, 06:03 UTC
State: Failed clusters need inspection
| Metric | Count | Rate |
| --- | ---: | ---: |
| Latest clusters reviewed | 362 | 100% |
| Run attempts archived | 631 | audit |
| Latest successful clusters | 332 | 91.7% |
| Latest failed clusters | 7 | 1.9% |
| Latest cancelled clusters | 2 | 0.6% |
| Needs-human clusters | 42 | 11.6% |
| Fix actions failed | 26 | 11.8% |
| Fix actions blocked | 56 | 25.5% |
| Completed close actions | 30 | 5.2% |
| Completed merge actions | 23 | 4.0% |
| Blocked mutation attempts | 269 | 46.2% |
| Skipped mutation attempts | 260 | 44.7% |
### Clusters Needing Inspection
| Cluster | State | Reason | Report | Run |
| --- | --- | --- | --- | --- |
| [clawsweeper-commit-openclaw-openclaw-464e57360262](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-464e57360262.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-464e57360262](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-464e57360262.md) | [25204309027](https://github.com/openclaw/clawsweeper/actions/runs/25204309027) |
| [clawsweeper-commit-openclaw-openclaw-e8f9c3e6dedc](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-e8f9c3e6dedc.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-e8f9c3e6dedc](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-e8f9c3e6dedc.md) | [25204170897](https://github.com/openclaw/clawsweeper/actions/runs/25204170897) |
| [clawsweeper-commit-openclaw-openclaw-214b3d333676](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-214b3d333676.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-214b3d333676](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-214b3d333676.md) | [25203815918](https://github.com/openclaw/clawsweeper/actions/runs/25203815918) |
| [clawsweeper-commit-openclaw-openclaw-76930da7ebc7](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-76930da7ebc7.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-76930da7ebc7](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-76930da7ebc7.md) | [25203495459](https://github.com/openclaw/clawsweeper/actions/runs/25203495459) |
| [automerge-openclaw-openclaw-75382](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75382.md) | merge_canonical blocked | job does not allow merge | [automerge-openclaw-openclaw-75382](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75382.md) | [25202542275](https://github.com/openclaw/clawsweeper/actions/runs/25202542275) |
| [clawsweeper-commit-openclaw-openclaw-5d1ba08e3c97](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-5d1ba08e3c97.md) | execute_fix blocked | fix artifact is too broad for autonomous execution; split into narrower jobs or explicitly set CLAWSWEEPER_ALLOW_BROAD_FIX_ARTIFACTS=1 | [clawsweeper-commit-openclaw-openclaw-5d1ba08e3c97](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-5d1ba08e3c97.md) | [25202885744](https://github.com/openclaw/clawsweeper/actions/runs/25202885744) |
| [automerge-openclaw-openclaw-75363](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75363.md) | fix failed | Codex /review did not pass after 2 attempt(s): No security-sensitive issue found in the diff. The artifacts unrelated `.agents` files are absent,... | [automerge-openclaw-openclaw-75363](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75363.md) | [25202543309](https://github.com/openclaw/clawsweeper/actions/runs/25202543309) |
| [clawsweeper-commit-openclaw-openclaw-8989ceee50ab](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-8989ceee50ab.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-8989ceee50ab](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-8989ceee50ab.md) | [25202541355](https://github.com/openclaw/clawsweeper/actions/runs/25202541355) |
| [automerge-openclaw-openclaw-74506](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74506.md) | merge_canonical blocked | job does not allow merge | [automerge-openclaw-openclaw-74506](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74506.md) | [25202544672](https://github.com/openclaw/clawsweeper/actions/runs/25202544672) |
| [clawsweeper-commit-openclaw-openclaw-3e67ee63b4e0](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-3e67ee63b4e0.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-3e67ee63b4e0](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-3e67ee63b4e0.md) | [25200994696](https://github.com/openclaw/clawsweeper/actions/runs/25200994696) |
| [clawsweeper-commit-openclaw-openclaw-45b86450795d](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-45b86450795d.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-45b86450795d](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-45b86450795d.md) | [25200785766](https://github.com/openclaw/clawsweeper/actions/runs/25200785766) |
| [clawsweeper-commit-openclaw-openclaw-60bdb96f2c4c](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-60bdb96f2c4c.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-60bdb96f2c4c](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-60bdb96f2c4c.md) | [25200786346](https://github.com/openclaw/clawsweeper/actions/runs/25200786346) |
| [clawsweeper-commit-openclaw-openclaw-354084b1b320](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-354084b1b320.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-354084b1b320](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-354084b1b320.md) | [25200785151](https://github.com/openclaw/clawsweeper/actions/runs/25200785151) |
| [clawsweeper-commit-openclaw-openclaw-e0fe02fb0970](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-e0fe02fb0970.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-e0fe02fb0970](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-e0fe02fb0970.md) | [25200786950](https://github.com/openclaw/clawsweeper/actions/runs/25200786950) |
| [clawsweeper-commit-openclaw-openclaw-df0ee092f017](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-df0ee092f017.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-df0ee092f017](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-df0ee092f017.md) | [25200373309](https://github.com/openclaw/clawsweeper/actions/runs/25200373309) |
| [automerge-openclaw-openclaw-75326](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75326.md) | merge_canonical blocked | job does not allow merge | [automerge-openclaw-openclaw-75326](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75326.md) | [25198747424](https://github.com/openclaw/clawsweeper/actions/runs/25198747424) |
| [clawsweeper-commit-openclaw-openclaw-b277ae3f4c40](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-b277ae3f4c40.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-b277ae3f4c40](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-b277ae3f4c40.md) | [25198053576](https://github.com/openclaw/clawsweeper/actions/runs/25198053576) |
| [clawsweeper-commit-openclaw-openclaw-a102f4dede6a](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-a102f4dede6a.md) | execute_fix blocked | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests [check:changed] src/agents/agent-command.ts: core production... | [clawsweeper-commit-openclaw-openclaw-a102f4dede6a](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-a102f4dede6a.md) | [25197023690](https://github.com/openclaw/clawsweeper/actions/runs/25197023690) |
| [automerge-openclaw-openclaw-75302](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75302.md) | merge_canonical blocked | job does not allow merge | [automerge-openclaw-openclaw-75302](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75302.md) | [25196881228](https://github.com/openclaw/clawsweeper/actions/runs/25196881228) |
| [clawsweeper-commit-openclaw-openclaw-52bf20b07d6e](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-52bf20b07d6e.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-52bf20b07d6e](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-52bf20b07d6e.md) | [25195746048](https://github.com/openclaw/clawsweeper/actions/runs/25195746048) |
| [clawsweeper-commit-openclaw-openclaw-ef799fd57a77](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-ef799fd57a77.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-ef799fd57a77](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-ef799fd57a77.md) | [25195271001](https://github.com/openclaw/clawsweeper/actions/runs/25195271001) |
| [clawsweeper-commit-openclaw-openclaw-af5a1fbddb14](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-af5a1fbddb14.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-af5a1fbddb14](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-af5a1fbddb14.md) | [25192772436](https://github.com/openclaw/clawsweeper/actions/runs/25192772436) |
| [automerge-openclaw-openclaw-74716](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74716.md) | fix failed | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests, extensions, extensionTests, apps, docs [check:changed] exten... | [automerge-openclaw-openclaw-74716](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74716.md) | [25192389369](https://github.com/openclaw/clawsweeper/actions/runs/25192389369) |
| [clawsweeper-commit-openclaw-openclaw-1d74ecd71f0f](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-1d74ecd71f0f.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-1d74ecd71f0f](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-1d74ecd71f0f.md) | [25191267120](https://github.com/openclaw/clawsweeper/actions/runs/25191267120) |
| [clawsweeper-commit-openclaw-openclaw-027ea5f08bd9](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-027ea5f08bd9.md) | execute_fix blocked | Codex /review did not pass after 2 attempt(s): Merge is blocked by one incomplete repair. The branch is narrow and `pnpm check:changed` plus `git d... | [clawsweeper-commit-openclaw-openclaw-027ea5f08bd9](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-027ea5f08bd9.md) | [25187047448](https://github.com/openclaw/clawsweeper/actions/runs/25187047448) |
| [automerge-openclaw-openclaw-75209](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75209.md) | merge_canonical blocked | job does not allow merge | [automerge-openclaw-openclaw-75209](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75209.md) | [25186718052](https://github.com/openclaw/clawsweeper/actions/runs/25186718052) |
| [clawsweeper-commit-openclaw-openclaw-581fbea1d653](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-581fbea1d653.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-581fbea1d653](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-581fbea1d653.md) | [25183870132](https://github.com/openclaw/clawsweeper/actions/runs/25183870132) |
| [clawsweeper-commit-openclaw-openclaw-54e6e3d7daf5](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-54e6e3d7daf5.md) | merge_canonical blocked | job does not allow merge | [clawsweeper-commit-openclaw-openclaw-54e6e3d7daf5](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-54e6e3d7daf5.md) | [25183184702](https://github.com/openclaw/clawsweeper/actions/runs/25183184702) |
| [automerge-openclaw-openclaw-74472](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74472.md) | merge_canonical blocked | job does not allow merge | [automerge-openclaw-openclaw-74472](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74472.md) | [25182390249](https://github.com/openclaw/clawsweeper/actions/runs/25182390249) |
| [clawsweeper-commit-openclaw-openclaw-82ca6ecdde80](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-82ca6ecdde80.md) | execute_fix blocked | fix artifact is too broad for autonomous execution; split into narrower jobs or explicitly set CLAWSWEEPER_ALLOW_BROAD_FIX_ARTIFACTS=1 | [clawsweeper-commit-openclaw-openclaw-82ca6ecdde80](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-82ca6ecdde80.md) | [25176627885](https://github.com/openclaw/clawsweeper/actions/runs/25176627885) |
### Fix Failure Queue
| Cluster | Status | Target | Branch/PR | Reason | Run |
| --- | --- | --- | --- | --- | --- |
| [clawsweeper-commit-openclaw-openclaw-5d1ba08e3c97](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-5d1ba08e3c97.md) | blocked | | | fix artifact is too broad for autonomous execution; split into narrower jobs or explicitly set CLAWSWEEPER_ALLOW_BROAD_FIX_ARTIFACTS=1 | [25202885744](https://github.com/openclaw/clawsweeper/actions/runs/25202885744) |
| [automerge-openclaw-openclaw-75363](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75363.md) | failed | | | Codex /review did not pass after 2 attempt(s): No security-sensitive issue found in the diff. The artifacts unrelated `.agents` files are absent,... | [25202543309](https://github.com/openclaw/clawsweeper/actions/runs/25202543309) |
| [automerge-openclaw-openclaw-75363](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-75363.md) | blocked | | | Codex /review did not pass after 2 attempt(s): No security-sensitive issue found in the diff. The artifacts unrelated `.agents` files are absent,... | [25202543309](https://github.com/openclaw/clawsweeper/actions/runs/25202543309) |
| [clawsweeper-commit-openclaw-openclaw-a102f4dede6a](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-a102f4dede6a.md) | blocked | | | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests [check:changed] src/agents/agent-command.ts: core production... | [25197023690](https://github.com/openclaw/clawsweeper/actions/runs/25197023690) |
| [automerge-openclaw-openclaw-74716](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74716.md) | failed | | | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests, extensions, extensionTests, apps, docs [check:changed] exten... | [25192389369](https://github.com/openclaw/clawsweeper/actions/runs/25192389369) |
| [automerge-openclaw-openclaw-74716](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74716.md) | blocked | | | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests, extensions, extensionTests, apps, docs [check:changed] exten... | [25192389369](https://github.com/openclaw/clawsweeper/actions/runs/25192389369) |
| [clawsweeper-commit-openclaw-openclaw-027ea5f08bd9](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-027ea5f08bd9.md) | blocked | | | Codex /review did not pass after 2 attempt(s): Merge is blocked by one incomplete repair. The branch is narrow and `pnpm check:changed` plus `git d... | [25187047448](https://github.com/openclaw/clawsweeper/actions/runs/25187047448) |
| [clawsweeper-commit-openclaw-openclaw-82ca6ecdde80](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-82ca6ecdde80.md) | blocked | | | fix artifact is too broad for autonomous execution; split into narrower jobs or explicitly set CLAWSWEEPER_ALLOW_BROAD_FIX_ARTIFACTS=1 | [25176627885](https://github.com/openclaw/clawsweeper/actions/runs/25176627885) |
| [clawsweeper-commit-openclaw-openclaw-ac599c9e539f](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-ac599c9e539f.md) | blocked | | | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests [check:changed] src/plugins/bundled-runtime-deps-selection.ts... | [25171874076](https://github.com/openclaw/clawsweeper/actions/runs/25171874076) |
| [clawsweeper-commit-openclaw-openclaw-3c9437ae547a](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-3c9437ae547a.md) | blocked | | | fix artifact is too broad for autonomous execution; split into narrower jobs or explicitly set CLAWSWEEPER_ALLOW_BROAD_FIX_ARTIFACTS=1 | [25149929229](https://github.com/openclaw/clawsweeper/actions/runs/25149929229) |
| [clawsweeper-commit-openclaw-openclaw-0142c791232e](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-0142c791232e.md) | blocked | | | fix artifact is too broad for autonomous execution; split into narrower jobs or explicitly set CLAWSWEEPER_ALLOW_BROAD_FIX_ARTIFACTS=1 | [25147836943](https://github.com/openclaw/clawsweeper/actions/runs/25147836943) |
| [clawsweeper-commit-openclaw-openclaw-d7396d4ffa2f](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-d7396d4ffa2f.md) | blocked | | | fix artifact is too broad for autonomous execution; split into narrower jobs or explicitly set CLAWSWEEPER_ALLOW_BROAD_FIX_ARTIFACTS=1 | [25147023250](https://github.com/openclaw/clawsweeper/actions/runs/25147023250) |
| [automerge-openclaw-openclaw-74638](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74638.md) | failed | | | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests, docs [check:changed] src/config/config.schema-regressions.te... | [25146762143](https://github.com/openclaw/clawsweeper/actions/runs/25146762143) |
| [automerge-openclaw-openclaw-74638](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74638.md) | blocked | | | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests, docs [check:changed] src/config/config.schema-regressions.te... | [25146762143](https://github.com/openclaw/clawsweeper/actions/runs/25146762143) |
| [clawsweeper-commit-openclaw-openclaw-25d2e9bdace3](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-25d2e9bdace3.md) | blocked | | | validation command failed (pnpm check:changed): [check:changed] lanes=apps [check:changed] apps/macos/Sources/OpenClaw/GatewayLaunchAgentManager.sw... | [25145494152](https://github.com/openclaw/clawsweeper/actions/runs/25145494152) |
| [clawsweeper-commit-openclaw-openclaw-58153d38af57](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-58153d38af57.md) | blocked | | | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests, extensions, extensionTests [check:changed] extensions/codex/... | [25143847817](https://github.com/openclaw/clawsweeper/actions/runs/25143847817) |
| [clawsweeper-commit-openclaw-openclaw-0b59964ec945](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-0b59964ec945.md) | blocked | | | Codex /review failed: structured output was not written to replacement-codex-review-1.json; stdout={"type":"thread.started","thread_id":"019ddbc8-0... | [25140762037](https://github.com/openclaw/clawsweeper/actions/runs/25140762037) |
| [automerge-openclaw-openclaw-74528](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74528.md) | blocked | | | Codex /review failed: structured output was not written to replacement-codex-review-1.json; stdout={"type":"thread.started","thread_id":"019ddba8-1... | [25139586999](https://github.com/openclaw/clawsweeper/actions/runs/25139586999) |
| [clawsweeper-commit-openclaw-openclaw-db6951088a19](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-db6951088a19.md) | blocked | | | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests, extensions, extensionTests [check:changed] extensions/telegr... | [25128072554](https://github.com/openclaw/clawsweeper/actions/runs/25128072554) |
| [clawsweeper-commit-openclaw-openclaw-6a4c866b6a8b](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-6a4c866b6a8b.md) | blocked | | | fix artifact is too broad for autonomous execution; split into narrower jobs or explicitly set CLAWSWEEPER_REPAIR_ALLOW_BROAD_FIX_ARTIFACTS=1 | [25094690632](https://github.com/openclaw/clawsweeper/actions/runs/25094690632) |
| [ghcrawl-166004-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-166004-agentic-merge.md) | blocked | | | Codex /review did not pass after 2 attempt(s): Cannot perform the review without inspecting the repository diff and validation state. | [25087637821](https://github.com/openclaw/clawsweeper/actions/runs/25087637821) |
| [ghcrawl-156717-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156717-autonomous-smoke.md) | blocked | | | validation command failed (pnpm check:changed): [check:changed] lanes=core, coreTests, docs [check:changed] ui/src/styles/chat/layout.css: core pro... | [25085937628](https://github.com/openclaw/clawsweeper/actions/runs/25085937628) |
| [ghcrawl-156593-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156593-autonomous-smoke.md) | failed | | | To https://github.com/LiaoyuanNing/openclaw.git ! [remote rejected] HEAD -> fix/feishu-p2p-thread-reply (refusing to allow a GitHub App to create o... | [25084314903](https://github.com/openclaw/clawsweeper/actions/runs/25084314903) |
| [ghcrawl-156593-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156593-autonomous-smoke.md) | blocked | | | Codex /review did not pass after 2 attempt(s): Blocked. The diff is narrow and has no visible secret, dependency, workflow, install, or security-se... | [25084314903](https://github.com/openclaw/clawsweeper/actions/runs/25084314903) |
| [ghcrawl-156627-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156627-autonomous-smoke.md) | blocked | | | fix artifact is too broad for autonomous execution; split into narrower jobs or explicitly set CLAWSWEEPER_REPAIR_ALLOW_BROAD_FIX_ARTIFACTS=1 | [25070489790](https://github.com/openclaw/clawsweeper/actions/runs/25070489790) |
### Top Blocked Reasons
| Reason | Latest count | Example cluster |
| --- | ---: | --- |
| job does not allow merge | 90 | [clawsweeper-commit-openclaw-openclaw-464e57360262](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/clawsweeper-commit-openclaw-openclaw-464e57360262.md) |
| action status is blocked | 89 | [ghcrawl-156636-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156636-autonomous-smoke.md) |
| close requires ClawSweeper Repair fix PR opened/pushed or merge executed first | 13 | [ghcrawl-156593-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156593-autonomous-smoke.md) |
| merge requires CLAWSWEEPER_REPAIR_ALLOW_MERGE=1; labeled for human review | 10 | [ghcrawl-156679-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156679-autonomous-smoke.md) |
| merge state status is UNSTABLE | 10 | [ghcrawl-156647-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156647-autonomous-smoke.md) |
| target changed since worker review | 9 | [ghcrawl-156624-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156624-autonomous-smoke.md) |
| mergeable state is CONFLICTING | 5 | [ghcrawl-156651-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156651-autonomous-smoke.md) |
| target is not listed in job candidates | 4 | [ghcrawl-156682-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156682-autonomous-smoke.md) |
| Fix-first policy blocks superseded closeout until #49430 is repaired and merged. | 2 | [ghcrawl-156585-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156585-autonomous-smoke.md) |
| Clearly superseded by the canonical PR path, but closure is blocked until the canonical fix lands. | 2 | [ghcrawl-156879-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156879-autonomous-smoke.md) |
| require_fix_before_close blocks superseded PR closeout until the canonical fix path is landed or opened as a concrete fix PR. | 2 | [ghcrawl-156789-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156789-autonomous-smoke.md) |
| canonical is not listed in job refs | 2 | [ghcrawl-156658-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156658-autonomous-smoke.md) |
| maintainer issue comment blocks low-signal auto-close | 2 | [low-signal-pr-sweep-20260425T2346-01](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/low-signal-pr-sweep-20260425t2346-01.md) |
| Blocked on the canonical fix path landing; job policy does not allow unmerged fix closeout. | 1 | [automerge-openclaw-openclaw-74666](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74666.md) |
| Superseded closeout is clear, but closure is blocked by this job's policy and requires human approval. | 1 | [automerge-openclaw-openclaw-74134](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/automerge-openclaw-openclaw-74134.md) |
### Latest Repair Closures
| Target | Action | Title | Closed | Cluster | Report | Run |
| --- | --- | --- | --- | --- | --- | --- |
| [#59439](#59439) | close_superseded | | Apr 28, 2026, 05:25 UTC | [ghcrawl-207050-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-207050-agentic-merge.md) | [ghcrawl-207050-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-207050-agentic-merge.md) | [25035228706](https://github.com/openclaw/clawsweeper/actions/runs/25035228706) |
| [#48388](#48388) | close_fixed_by_candidate | | Apr 28, 2026, 05:23 UTC | [ghcrawl-199239-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-199239-agentic-merge.md) | [ghcrawl-199239-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-199239-agentic-merge.md) | [25035231796](https://github.com/openclaw/clawsweeper/actions/runs/25035231796) |
| [#50435](#50435) | close_superseded | | Apr 28, 2026, 05:23 UTC | [ghcrawl-199239-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-199239-agentic-merge.md) | [ghcrawl-199239-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-199239-agentic-merge.md) | [25035231796](https://github.com/openclaw/clawsweeper/actions/runs/25035231796) |
| [#59409](#59409) | close_fixed_by_candidate | | Apr 28, 2026, 05:23 UTC | [ghcrawl-199239-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-199239-agentic-merge.md) | [ghcrawl-199239-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-199239-agentic-merge.md) | [25035231796](https://github.com/openclaw/clawsweeper/actions/runs/25035231796) |
| [#59431](#59431) | close_superseded | | Apr 28, 2026, 05:23 UTC | [ghcrawl-199239-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-199239-agentic-merge.md) | [ghcrawl-199239-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-199239-agentic-merge.md) | [25035231796](https://github.com/openclaw/clawsweeper/actions/runs/25035231796) |
| [#61016](#61016) | close_superseded | | Apr 28, 2026, 05:00 UTC | [ghcrawl-156640-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156640-autonomous-smoke.md) | [ghcrawl-156640-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156640-autonomous-smoke.md) | [25034019917](https://github.com/openclaw/clawsweeper/actions/runs/25034019917) |
| [#49957](#49957) | close_duplicate | | Apr 28, 2026, 04:59 UTC | [ghcrawl-156664-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156664-autonomous-smoke.md) | [ghcrawl-156664-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156664-autonomous-smoke.md) | [25033552424](https://github.com/openclaw/clawsweeper/actions/runs/25033552424) |
| [#49961](#49961) | close_superseded | | Apr 28, 2026, 04:59 UTC | [ghcrawl-156664-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156664-autonomous-smoke.md) | [ghcrawl-156664-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-156664-autonomous-smoke.md) | [25033552424](https://github.com/openclaw/clawsweeper/actions/runs/25033552424) |
| [#54429](#54429) | close_duplicate | | Apr 26, 2026, 03:04 UTC | [ghcrawl-166002-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-166002-agentic-merge.md) | [ghcrawl-166002-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-166002-agentic-merge.md) | [24946559138](https://github.com/openclaw/clawsweeper-repair/actions/runs/24946559138) |
| [#41992](#41992) | close_duplicate | | Apr 26, 2026, 03:04 UTC | [ghcrawl-165992-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-165992-agentic-merge.md) | [ghcrawl-165992-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-165992-agentic-merge.md) | [24946558493](https://github.com/openclaw/clawsweeper-repair/actions/runs/24946558493) |
| [#43242](#43242) | close_duplicate | | Apr 26, 2026, 03:04 UTC | [ghcrawl-165992-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-165992-agentic-merge.md) | [ghcrawl-165992-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-165992-agentic-merge.md) | [24946558493](https://github.com/openclaw/clawsweeper-repair/actions/runs/24946558493) |
| [#56298](#56298) | close_duplicate | | Apr 26, 2026, 03:04 UTC | [ghcrawl-165992-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-165992-agentic-merge.md) | [ghcrawl-165992-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-165992-agentic-merge.md) | [24946558493](https://github.com/openclaw/clawsweeper-repair/actions/runs/24946558493) |
| [#63094](#63094) | close_duplicate | | Apr 26, 2026, 03:04 UTC | [ghcrawl-165992-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-165992-agentic-merge.md) | [ghcrawl-165992-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-165992-agentic-merge.md) | [24946558493](https://github.com/openclaw/clawsweeper-repair/actions/runs/24946558493) |
| [#67622](#67622) | close_duplicate | | Apr 26, 2026, 03:04 UTC | [ghcrawl-165992-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-165992-agentic-merge.md) | [ghcrawl-165992-agentic-merge](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-165992-agentic-merge.md) | [24946558493](https://github.com/openclaw/clawsweeper-repair/actions/runs/24946558493) |
| [#67029](#67029) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143819-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143819-autonomous-smoke.md) | [ghcrawl-143819-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143819-autonomous-smoke.md) | [24939011554](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939011554) |
| [#69886](#69886) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143819-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143819-autonomous-smoke.md) | [ghcrawl-143819-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143819-autonomous-smoke.md) | [24939011554](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939011554) |
| [#70353](#70353) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143819-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143819-autonomous-smoke.md) | [ghcrawl-143819-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143819-autonomous-smoke.md) | [24939011554](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939011554) |
| [#70395](#70395) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143819-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143819-autonomous-smoke.md) | [ghcrawl-143819-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143819-autonomous-smoke.md) | [24939011554](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939011554) |
| [#71133](#71133) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143819-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143819-autonomous-smoke.md) | [ghcrawl-143819-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143819-autonomous-smoke.md) | [24939011554](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939011554) |
| [#70180](#70180) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143816-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143816-autonomous-smoke.md) | [ghcrawl-143816-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143816-autonomous-smoke.md) | [24939009401](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939009401) |
| [#65832](#65832) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143816-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143816-autonomous-smoke.md) | [ghcrawl-143816-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143816-autonomous-smoke.md) | [24939009401](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939009401) |
| [#66758](#66758) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143816-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143816-autonomous-smoke.md) | [ghcrawl-143816-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143816-autonomous-smoke.md) | [24939009401](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939009401) |
| [#67406](#67406) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143816-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143816-autonomous-smoke.md) | [ghcrawl-143816-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143816-autonomous-smoke.md) | [24939009401](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939009401) |
| [#50541](#50541) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143815-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143815-autonomous-smoke.md) | [ghcrawl-143815-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143815-autonomous-smoke.md) | [24939008778](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939008778) |
| [#50691](#50691) | close_duplicate | | Apr 26, 2026, 01:36 UTC | [ghcrawl-143815-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143815-autonomous-smoke.md) | [ghcrawl-143815-autonomous-smoke](https://github.com/openclaw/clawsweeper/blob/main/results/openclaw/ghcrawl-143815-autonomous-smoke.md) | [24939008778](https://github.com/openclaw/clawsweeper-repair/actions/runs/24939008778) |

15
package.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "@openclaw/clawsweeper-dashboard",
"version": "0.1.0",
"private": true,
"license": "MIT",
"type": "module",
"scripts": {
"render": "node scripts/render.mjs",
"check": "node --check scripts/*.mjs && node --test test/*.test.mjs"
},
"engines": {
"node": ">=24"
},
"packageManager": "pnpm@10.33.2"
}

9
pnpm-lock.yaml generated Normal file
View File

@ -0,0 +1,9 @@
lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.: {}

44
scripts/markdown.mjs Normal file
View File

@ -0,0 +1,44 @@
export function tableCell(value) {
return String(value ?? "").replaceAll("|", "\\|").replace(/\s+/g, " ").trim();
}
export function link(label, url) {
return `[${tableCell(label)}](${url})`;
}
export function githubPath(path) {
return String(path)
.split("/")
.map((segment) => encodeURIComponent(segment))
.join("/");
}
export function formatTimestamp(value) {
if (!value) return "unknown";
const date = new Date(value);
if (Number.isNaN(date.getTime())) return String(value);
return new Intl.DateTimeFormat("en-US", {
month: "short",
day: "numeric",
year: "numeric",
hour: "2-digit",
minute: "2-digit",
hour12: false,
timeZone: "UTC",
timeZoneName: "short",
}).format(date);
}
export function percent(value, total) {
return total > 0 ? `${((value / total) * 100).toFixed(1)}%` : "0.0%";
}
export function truncate(value, max = 110) {
const text = tableCell(value);
if (text.length <= max) return text;
return `${text.slice(0, Math.max(0, max - 3)).trimEnd()}...`;
}
export function rowsOrNone(rows, columns) {
return rows.length ? rows.join("\n") : `| _None_ |${" |".repeat(columns - 1)}`;
}

40
scripts/render.mjs Normal file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env node
import path from "node:path";
import { renderRepairDashboard } from "./repair-dashboard.mjs";
import { writeText } from "./source.mjs";
import { renderSweepDashboard } from "./sweep-dashboard.mjs";
const args = parseArgs(process.argv.slice(2));
const sourceRoot = path.resolve(args.source ?? process.env.CLAWSWEEPER_SOURCE ?? "../clawsweeper");
const output = path.resolve(args.output ?? "README.md");
const body = `# ClawSweeper Dashboard
Generated dashboard for [` +
`openclaw/clawsweeper](https://github.com/openclaw/clawsweeper).
${renderSweepDashboard(sourceRoot)}
${renderRepairDashboard(sourceRoot)}
`;
writeText(output, body);
console.log(JSON.stringify({ output, source: sourceRoot }));
function parseArgs(argv) {
const parsed = {};
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index];
if (arg === "--") continue;
if (arg === "--source") parsed.source = requiredValue(argv, ++index, arg);
else if (arg === "--output") parsed.output = requiredValue(argv, ++index, arg);
else throw new Error(`Unknown argument: ${arg}`);
}
return parsed;
}
function requiredValue(argv, index, flag) {
const value = argv[index];
if (!value || value.startsWith("--")) throw new Error(`${flag} requires a value`);
return value;
}

View File

@ -0,0 +1,216 @@
import path from "node:path";
import { formatTimestamp, link, percent, rowsOrNone, tableCell, truncate } from "./markdown.mjs";
import { jsonFiles, newestTimestamp, readJson } from "./source.mjs";
const REPORT_REPO = "https://github.com/openclaw/clawsweeper";
const CLOSE_ACTIONS = new Set([
"close",
"close_duplicate",
"close_superseded",
"close_fixed_by_candidate",
"close_low_signal",
"post_merge_close",
]);
const MERGE_ACTIONS = new Set(["merge_candidate", "merge_canonical"]);
export function renderRepairDashboard(root) {
const records = jsonFiles(path.join(root, "results", "runs"))
.map((file) => readJson(file))
.filter(Boolean);
const archivedRaw = readJson(path.join(root, "results", "archived-clusters.json"), []);
const archived = new Set(
Array.isArray(archivedRaw)
? archivedRaw
: (archivedRaw.archived_clusters ?? []).map((record) => record.cluster_id),
);
const latest = latestByCluster(records).filter((record) => !archived.has(record.cluster_id));
const allApplyRows = records.flatMap((record) =>
(record.apply_actions ?? []).map((action) => ({ record, action })),
);
const latestApplyRows = latest.flatMap((record) =>
(record.apply_actions ?? []).map((action) => ({ record, action })),
);
const latestFixRows = latest.flatMap((record) =>
(record.fix_actions ?? []).map((action) => ({ record, action })),
);
const mutationRows = allApplyRows.filter((row) =>
["executed", "blocked", "skipped"].includes(String(row.action.status ?? "")),
);
const closedRows = allApplyRows
.filter((row) => row.action.status === "executed" && CLOSE_ACTIONS.has(String(row.action.action)))
.sort(newestActionFirst);
const mergedRows = allApplyRows.filter(
(row) => row.action.status === "executed" && MERGE_ACTIONS.has(String(row.action.action)),
);
const blockedRows = latestApplyRows.filter((row) =>
["blocked", "skipped"].includes(String(row.action.status ?? "")),
);
const failedFixRows = latestFixRows.filter((row) =>
["blocked", "failed"].includes(String(row.action.status ?? "")),
);
const inspectionRows = inspectionQueue(latest, failedFixRows, blockedRows);
const totals = {
latest: latest.length,
runs: records.length,
success: latest.filter((record) => record.workflow_conclusion === "success").length,
failure: latest.filter((record) => record.workflow_conclusion === "failure").length,
cancelled: latest.filter((record) => record.workflow_conclusion === "cancelled").length,
needsHuman: latest.filter((record) => (record.needs_human ?? []).length > 0).length,
closed: closedRows.length,
merged: mergedRows.length,
blocked: allApplyRows.filter((row) => row.action.status === "blocked").length,
skipped: allApplyRows.filter((row) => row.action.status === "skipped").length,
fixFailed: latestFixRows.filter((row) => row.action.status === "failed").length,
fixBlocked: latestFixRows.filter((row) => row.action.status === "blocked").length,
mutationAttempts: mutationRows.length,
};
const lastSourceUpdate = newestTimestamp(...records.map((record) => record.published_at));
return `## Repair Dashboard
Last source update: ${formatTimestamp(lastSourceUpdate)}
State: ${repairState(totals, inspectionRows)}
| Metric | Count | Rate |
| --- | ---: | ---: |
| Latest clusters reviewed | ${totals.latest} | 100% |
| Run attempts archived | ${totals.runs} | audit |
| Latest successful clusters | ${totals.success} | ${percent(totals.success, totals.latest)} |
| Latest failed clusters | ${totals.failure} | ${percent(totals.failure, totals.latest)} |
| Latest cancelled clusters | ${totals.cancelled} | ${percent(totals.cancelled, totals.latest)} |
| Needs-human clusters | ${totals.needsHuman} | ${percent(totals.needsHuman, totals.latest)} |
| Fix actions failed | ${totals.fixFailed} | ${percent(totals.fixFailed, latestFixRows.length)} |
| Fix actions blocked | ${totals.fixBlocked} | ${percent(totals.fixBlocked, latestFixRows.length)} |
| Completed close actions | ${totals.closed} | ${percent(totals.closed, totals.mutationAttempts)} |
| Completed merge actions | ${totals.merged} | ${percent(totals.merged, totals.mutationAttempts)} |
| Blocked mutation attempts | ${totals.blocked} | ${percent(totals.blocked, totals.mutationAttempts)} |
| Skipped mutation attempts | ${totals.skipped} | ${percent(totals.skipped, totals.mutationAttempts)} |
### Clusters Needing Inspection
| Cluster | State | Reason | Report | Run |
| --- | --- | --- | --- | --- |
${rowsOrNone(inspectionRows.slice(0, 30).map(inspectionRow), 5)}
### Fix Failure Queue
| Cluster | Status | Target | Branch/PR | Reason | Run |
| --- | --- | --- | --- | --- | --- |
${rowsOrNone(failedFixRows.slice(0, 25).map(fixRow), 6)}
### Top Blocked Reasons
| Reason | Latest count | Example cluster |
| --- | ---: | --- |
${rowsOrNone(blockedReasonRows(blockedRows), 3)}
### Latest Repair Closures
| Target | Action | Title | Closed | Cluster | Report | Run |
| --- | --- | --- | --- | --- | --- | --- |
${rowsOrNone(closedRows.slice(0, 25).map(closeRow), 7)}
`;
}
function latestByCluster(records) {
const byCluster = new Map();
for (const record of records) {
const key = String(record.cluster_id ?? "");
const previous = byCluster.get(key);
if (!previous || Date.parse(record.published_at ?? "") > Date.parse(previous.published_at ?? "")) {
byCluster.set(key, record);
}
}
return [...byCluster.values()].sort(
(a, b) => Date.parse(b.published_at ?? "") - Date.parse(a.published_at ?? ""),
);
}
function repairState(totals, inspectionRows) {
if (totals.failure > 0) return "Failed clusters need inspection";
if (totals.fixFailed + totals.fixBlocked > 0) return "Fix execution needs repair";
if (inspectionRows.length > 0) return "Inspection needed";
return "Clean";
}
function inspectionQueue(latest, failedFixRows, blockedRows) {
const rows = [];
const seen = new Set();
for (const row of [...failedFixRows, ...blockedRows]) {
const key = String(row.record.cluster_id ?? "");
if (seen.has(key)) continue;
seen.add(key);
rows.push({
record: row.record,
state: row.action.status === "failed" ? "fix failed" : `${row.action.action ?? "action"} ${row.action.status}`,
reason: row.action.reason ?? row.record.summary ?? "",
});
}
for (const record of latest) {
const key = String(record.cluster_id ?? "");
if (seen.has(key) || (record.needs_human ?? []).length === 0) continue;
seen.add(key);
rows.push({
record,
state: "needs human",
reason: (record.needs_human ?? []).join("; "),
});
}
return rows.sort(
(a, b) => Date.parse(b.record.published_at ?? "") - Date.parse(a.record.published_at ?? ""),
);
}
function blockedReasonRows(rows) {
const byReason = new Map();
for (const row of rows) {
const reason = truncate(row.action.reason ?? "unspecified", 140);
const current = byReason.get(reason) ?? { count: 0, row };
current.count += 1;
byReason.set(reason, current);
}
return [...byReason.entries()]
.sort((a, b) => b[1].count - a[1].count)
.slice(0, 15)
.map(([reason, value]) => `| ${reason} | ${value.count} | ${clusterLink(value.row.record)} |`);
}
function newestActionFirst(left, right) {
const leftTime = Date.parse(left.action.closed_at ?? left.action.merged_at ?? left.record.published_at ?? "");
const rightTime = Date.parse(right.action.closed_at ?? right.action.merged_at ?? right.record.published_at ?? "");
return rightTime - leftTime;
}
function clusterLink(record) {
const owner = String(record.repo ?? "unknown/unknown").split("/")[0] || "unknown";
const cluster = String(record.cluster_id ?? "");
const slug = cluster.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
return link(cluster || "unknown", `${REPORT_REPO}/blob/main/results/${owner}/${slug}.md`);
}
function runLink(record) {
return record.run_url ? link(record.run_id ?? "run", record.run_url) : "_none_";
}
function targetLink(action) {
const target = String(action.target ?? "");
const match = target.match(/^https:\/\/github\.com\/([^/]+\/[^/]+)\/(issues|pull)\/(\d+)/);
if (match) return link(`#${match[3]}`, target);
return target ? link(target, target) : "";
}
function inspectionRow(row) {
return `| ${clusterLink(row.record)} | ${tableCell(row.state)} | ${truncate(row.reason, 150)} | ${clusterLink(row.record)} | ${runLink(row.record)} |`;
}
function fixRow(row) {
const action = row.action;
return `| ${clusterLink(row.record)} | ${tableCell(action.status)} | ${targetLink(action)} | ${tableCell(action.branch ?? action.pr ?? "")} | ${truncate(action.reason, 150)} | ${runLink(row.record)} |`;
}
function closeRow(row) {
const action = row.action;
return `| ${targetLink(action)} | ${tableCell(action.action)} | ${truncate(action.title ?? "")} | ${formatTimestamp(action.closed_at ?? action.merged_at ?? row.record.published_at)} | ${clusterLink(row.record)} | ${clusterLink(row.record)} | ${runLink(row.record)} |`;
}

91
scripts/source.mjs Normal file
View File

@ -0,0 +1,91 @@
import fs from "node:fs";
import path from "node:path";
export const PROFILES = [
{
slug: "openclaw-openclaw",
displayName: "OpenClaw",
repo: "openclaw/openclaw",
},
{
slug: "openclaw-clawhub",
displayName: "ClawHub",
repo: "openclaw/clawhub",
},
{
slug: "openclaw-clawsweeper",
displayName: "ClawSweeper",
repo: "openclaw/clawsweeper",
},
];
export function profileForSlug(slug) {
return PROFILES.find((profile) => profile.slug === slug);
}
export function readText(file) {
return fs.existsSync(file) ? fs.readFileSync(file, "utf8") : "";
}
export function readJson(file, fallback = null) {
if (!fs.existsSync(file)) return fallback;
return JSON.parse(fs.readFileSync(file, "utf8"));
}
export function writeText(file, text) {
fs.mkdirSync(path.dirname(file), { recursive: true });
fs.writeFileSync(file, text, "utf8");
}
export function markdownFiles(dir) {
if (!fs.existsSync(dir)) return [];
return fs
.readdirSync(dir)
.filter((name) => name.endsWith(".md"))
.sort()
.map((name) => path.join(dir, name));
}
export function jsonFiles(dir) {
if (!fs.existsSync(dir)) return [];
return fs
.readdirSync(dir)
.filter((name) => name.endsWith(".json"))
.sort()
.map((name) => path.join(dir, name));
}
export function parseFrontMatter(markdown) {
const match = markdown.match(/^---\n([\s\S]*?)\n---/);
const body = {};
if (!match?.[1]) return body;
for (const line of match[1].split(/\r?\n/)) {
const pair = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
if (!pair) continue;
body[pair[1]] = parseFrontMatterScalar(pair[2]);
}
return body;
}
function parseFrontMatterScalar(value) {
const trimmed = String(value ?? "").trim();
if (!trimmed) return "";
try {
return JSON.parse(trimmed);
} catch {
return trimmed.replace(/^"|"$/g, "");
}
}
export function relativePath(root, file) {
return path.relative(root, file).split(path.sep).join("/");
}
export function numberFromFile(file) {
const match = path.basename(file).match(/(\d+)\.md$/);
return match ? Number(match[1]) : 0;
}
export function newestTimestamp(...values) {
return values.filter(Boolean).sort((a, b) => Date.parse(b) - Date.parse(a))[0] ?? "";
}

273
scripts/sweep-dashboard.mjs Normal file
View File

@ -0,0 +1,273 @@
import path from "node:path";
import { formatTimestamp, link, percent, rowsOrNone, tableCell, truncate } from "./markdown.mjs";
import {
PROFILES,
markdownFiles,
newestTimestamp,
numberFromFile,
parseFrontMatter,
profileForSlug,
readJson,
readText,
relativePath,
} from "./source.mjs";
const FRESH_DAYS = 7;
const DAY_MS = 24 * 60 * 60 * 1000;
const REPORT_REPO = "https://github.com/openclaw/clawsweeper";
export function renderSweepDashboard(root) {
const snapshots = PROFILES.map((profile) => sweepSnapshot(root, profile));
const totals = snapshots.reduce(
(acc, snapshot) => {
acc.openRecords += snapshot.openRecords;
acc.closedRecords += snapshot.closedRecords;
acc.fresh += snapshot.fresh;
acc.proposedClose += snapshot.proposedClose;
acc.workCandidates += snapshot.workCandidates;
acc.failedOrStale += snapshot.failedOrStale;
return acc;
},
{
openRecords: 0,
closedRecords: 0,
fresh: 0,
proposedClose: 0,
workCandidates: 0,
failedOrStale: 0,
},
);
const recent = snapshots
.flatMap((snapshot) => snapshot.recent)
.sort((a, b) => Date.parse(b.reviewedAt ?? "") - Date.parse(a.reviewedAt ?? ""))
.slice(0, 15);
const closed = snapshots
.flatMap((snapshot) => snapshot.closed)
.sort((a, b) => Date.parse(b.closedAt ?? "") - Date.parse(a.closedAt ?? ""))
.slice(0, 15);
const work = snapshots
.flatMap((snapshot) => snapshot.work)
.sort(
(a, b) =>
priorityScore(b.workPriority) - priorityScore(a.workPriority) ||
Date.parse(b.reviewedAt ?? "") - Date.parse(a.reviewedAt ?? ""),
)
.slice(0, 20);
const lastSourceUpdate = newestTimestamp(
...snapshots.flatMap((snapshot) => [
snapshot.status?.updated_at,
snapshot.audit?.generatedAt,
snapshot.lastReviewAt,
snapshot.lastCloseAt,
]),
);
return `## Sweep Dashboard
Last source update: ${formatTimestamp(lastSourceUpdate)}
### Fleet
| Metric | Count |
| --- | ---: |
| Covered repositories | ${snapshots.length} |
| Open review records | ${totals.openRecords} |
| Archived closed records | ${totals.closedRecords} |
| Fresh reviews, ${FRESH_DAYS}d | ${totals.fresh} |
| Proposed closes awaiting apply | ${totals.proposedClose} |
| Work candidates awaiting promotion | ${totals.workCandidates} |
| Failed or stale reviews | ${totals.failedOrStale} |
### Current Runs
| Repository | State | Updated | Run |
| --- | --- | --- | --- |
${rowsOrNone(snapshots.map(statusRow), 4)}
### Repositories
| Repository | Open records | Archived | Fresh | Proposed closes | Work candidates | Failed/stale | Last review | Last close |
| --- | ---: | ---: | ---: | ---: | ---: | ---: | --- | --- |
${rowsOrNone(snapshots.map(repositoryRow), 9)}
### Work Candidates
| Repository | Item | Title | Priority | Reviewed | Report |
| --- | --- | --- | --- | --- | --- |
${rowsOrNone(work.map(workRow), 6)}
### Recently Closed
| Repository | Item | Title | Reason | Closed | Report |
| --- | --- | --- | --- | --- | --- |
${rowsOrNone(closed.map(closedRow), 6)}
<details>
<summary>Recently Reviewed</summary>
| Repository | Item | Title | Outcome | Status | Reviewed |
| --- | --- | --- | --- | --- | --- |
${rowsOrNone(recent.map(recentRow), 6)}
</details>
### Audit Health
| Repository | Status | Last audit | Missing eligible | Stale records | Protected proposed | Scan complete |
| --- | --- | --- | ---: | ---: | ---: | --- |
${rowsOrNone(snapshots.map(auditRow), 7)}
`;
}
function sweepSnapshot(root, profile) {
const itemsDir = path.join(root, "records", profile.slug, "items");
const closedDir = path.join(root, "records", profile.slug, "closed");
const status = readJson(path.join(root, "results", "sweep-status", `${profile.slug}.json`), {
state: "Idle",
detail: "No workflow status has been published yet.",
updated_at: "",
run_url: null,
});
const audit = readJson(path.join(root, "results", "audit", `${profile.slug}.json`), null);
const items = markdownFiles(itemsDir).map((file) => recordFromFile(root, file, profile, false));
const closedItems = markdownFiles(closedDir).map((file) =>
recordFromFile(root, file, profile, true),
);
const fresh = items.filter(isFresh).length;
const proposedClose = items.filter(
(item) => isFresh(item) && item.decision === "close" && item.action === "proposed_close",
).length;
const work = items.filter(
(item) =>
isFresh(item) &&
item.workCandidate === "queue_fix_pr" &&
item.workStatus === "candidate",
);
return {
profile,
status,
audit,
openRecords: items.length,
closedRecords: closedItems.length,
fresh,
proposedClose,
workCandidates: work.length,
failedOrStale: items.filter(
(item) => item.reviewStatus === "failed" || item.reviewStatus.startsWith("stale_"),
).length,
lastReviewAt: newestTimestamp(...items.map((item) => item.reviewedAt)),
lastCloseAt: newestTimestamp(...closedItems.map((item) => item.closedAt)),
recent: items
.filter((item) => item.reviewedAt)
.sort((a, b) => Date.parse(b.reviewedAt) - Date.parse(a.reviewedAt))
.slice(0, 15),
closed: closedItems.filter((item) => item.closedAt).slice(0, 15),
work,
};
}
function recordFromFile(root, file, fallbackProfile, archived) {
const frontMatter = parseFrontMatter(readText(file));
const profile = profileForSlug(path.basename(path.dirname(path.dirname(file)))) ?? fallbackProfile;
const repo = String(frontMatter.repository ?? profile.repo);
const kind = String(frontMatter.type ?? "issue");
const action = String(frontMatter.action_taken ?? "unknown");
const currentState = String(frontMatter.current_state ?? "");
return {
profile,
repo,
number: numberFromFile(file),
kind,
title: String(frontMatter.title ?? ""),
reviewedAt: String(frontMatter.reviewed_at ?? ""),
decision: String(frontMatter.decision ?? "unknown"),
action,
reviewStatus: String(frontMatter.review_status ?? ""),
workCandidate: String(frontMatter.work_candidate ?? "none"),
workPriority: String(frontMatter.work_priority ?? "low"),
workStatus: String(frontMatter.work_status ?? "none"),
closeReason: closeReason(frontMatter, action, currentState),
closedAt: dashboardClosedAt(frontMatter, action, currentState),
reportPath: relativePath(root, file),
archived,
};
}
function isFresh(item) {
const reviewedAt = Date.parse(item.reviewedAt);
return Number.isFinite(reviewedAt) && Date.now() - reviewedAt < FRESH_DAYS * DAY_MS;
}
function dashboardClosedAt(frontMatter, action, currentState) {
if (frontMatter.applied_at) return String(frontMatter.applied_at);
if (frontMatter.current_item_closed_at) return String(frontMatter.current_item_closed_at);
if (currentState === "closed") return String(frontMatter.reconciled_at ?? "");
if (action === "skipped_already_closed") return String(frontMatter.apply_checked_at ?? "");
return "";
}
function closeReason(frontMatter, action, currentState) {
if (action === "closed") return String(frontMatter.close_reason ?? "closed");
if (action === "skipped_already_closed") return "already closed before apply";
if (currentState === "closed") return "closed externally after review";
return String(frontMatter.close_reason ?? "");
}
function priorityScore(priority) {
if (priority === "high") return 3;
if (priority === "medium") return 2;
if (priority === "low") return 1;
return 0;
}
function repoLink(repo) {
return link(repo, `https://github.com/${repo}`);
}
function itemLink(item) {
const segment = item.kind === "pull_request" ? "pull" : "issues";
return link(`#${item.number}`, `https://github.com/${item.repo}/${segment}/${item.number}`);
}
function reportLink(item) {
return link(item.reportPath, `${REPORT_REPO}/blob/main/${item.reportPath}`);
}
function statusRow(snapshot) {
const status = snapshot.status ?? {};
const run = status.run_url ? link("run", status.run_url) : "_none_";
return `| ${repoLink(snapshot.profile.repo)} | ${tableCell(status.state ?? "Idle")} | ${formatTimestamp(status.updated_at)} | ${run} |`;
}
function repositoryRow(snapshot) {
return `| ${repoLink(snapshot.profile.repo)} | ${snapshot.openRecords} | ${snapshot.closedRecords} | ${snapshot.fresh} | ${snapshot.proposedClose} | ${snapshot.workCandidates} | ${snapshot.failedOrStale} | ${formatTimestamp(snapshot.lastReviewAt)} | ${formatTimestamp(snapshot.lastCloseAt)} |`;
}
function workRow(item) {
return `| ${repoLink(item.repo)} | ${itemLink(item)} | ${truncate(item.title)} | ${item.workPriority} | ${formatTimestamp(item.reviewedAt)} | ${reportLink(item)} |`;
}
function closedRow(item) {
return `| ${repoLink(item.repo)} | ${itemLink(item)} | ${truncate(item.title)} | ${tableCell(item.closeReason)} | ${formatTimestamp(item.closedAt)} | ${reportLink(item)} |`;
}
function recentRow(item) {
return `| ${repoLink(item.repo)} | ${itemLink(item)} | ${truncate(item.title)} | ${item.decision} / ${item.action} | ${item.reviewStatus} | ${formatTimestamp(item.reviewedAt)} |`;
}
function auditRow(snapshot) {
const audit = snapshot.audit;
if (!audit) return `| ${repoLink(snapshot.profile.repo)} | _unknown_ | unknown | 0 | 0 | 0 | unknown |`;
const counts = audit.counts ?? {};
return `| ${repoLink(snapshot.profile.repo)} | ${tableCell(auditStatus(audit))} | ${formatTimestamp(audit.generatedAt)} | ${counts.missingEligibleOpen ?? 0} | ${counts.staleItemRecords ?? 0} | ${counts.protectedProposed ?? 0} | ${audit.scan?.complete ? "yes" : "no"} |`;
}
function auditStatus(audit) {
const counts = audit.counts ?? {};
if (!audit.scan?.complete) return "scan incomplete";
if ((counts.protectedProposed ?? 0) > 0) return "protected proposed closes";
if ((counts.duplicateRecords ?? 0) > 0) return "duplicate records";
if ((counts.openArchived ?? 0) > 0) return "open archived records";
if ((counts.missingEligibleOpen ?? 0) > 0) return "missing records";
return "clean";
}

10
test/render.test.mjs Normal file
View File

@ -0,0 +1,10 @@
import assert from "node:assert/strict";
import test from "node:test";
import { formatTimestamp, percent, tableCell } from "../scripts/markdown.mjs";
test("markdown helpers keep dashboard tables stable", () => {
assert.equal(tableCell("a | b\nc"), "a \\| b c");
assert.equal(percent(1, 4), "25.0%");
assert.equal(percent(1, 0), "0.0%");
assert.match(formatTimestamp("2026-05-01T05:37:00.000Z"), /May 1, 2026/);
});