Add publisher abuse signal review dashboard#2927
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Codex review: needs maintainer review before merge. Reviewed July 2, 2026, 11:40 PM ET / 03:40 UTC. Summary Reproducibility: not applicable. This PR adds a new staff moderation workflow rather than fixing a current-main bug. The PR body and inspected screenshots provide real local UI proof, and the body includes loopback Hermit digest output for the sender path. Review metrics: 3 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the Signals workflow after maintainers accept the review-only temporal-signal policy and coordinate the Convex schema plus Hermit receiver/config rollout. Do we have a high-confidence way to reproduce the issue? Not applicable: this PR adds a new staff moderation workflow rather than fixing a current-main bug. The PR body and inspected screenshots provide real local UI proof, and the body includes loopback Hermit digest output for the sender path. Is this the best way to solve the issue? Mostly yes: a staff-gated indexed archive is a maintainable shape if maintainers accept the moderation boundary. The remaining concern is rollout and product acceptance, not a narrow code repair. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against a89bfaf61d1b. Label changesLabel justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
There was a problem hiding this comment.
Pull request overview
This PR adds a durable “publisher abuse Signals” archive and staff review surface, separating temporal anomaly evidence (review-only) from pressure-score nominations (the only input to warning/ban enforcement). It introduces new Convex tables and queries/mutations for signal lifecycle (open/snoozed/dismissed + Hermit digest notifications), updates the management abuse dashboard UI to display Signals with pagination, and updates the moderation spec to reflect the enforcement boundary.
Changes:
- Added
publisherAbuseSignals+publisherAbuseSignalReviewEventstables, pagination APIs, review mutations (snooze/dismiss/reopen), and Hermit digest notification plumbing. - Updated temporal scan + cron to archive review-only temporal signals (while keeping the scheduled temporal scan otherwise dry-run).
- Added a “Signals” tab to the management abuse dashboard with new table UI, counts, skeleton loading states, and client-side search filtering.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/styles.css | Adds styling for Signals status toggles, signals table, skeleton shimmer rows, and link/action affordances. |
| src/routes/management.tsx | Wires Signals tab state, paginated signals query, and signal review mutations into the management abuse view. |
| src/routes/-management/managementShared.ts | Adds shared types for signal entries/status and a new formatPercent helper for ratio display. |
| src/routes/-management/AbusePage.tsx | Implements the Signals tab UI (status filter, table, actions), tab badge/count logic, and skeleton rows. |
| src/routes/-management.test.tsx | Adds UI tests ensuring Signals load is deferred until tab activation and that counts/links/rendering behave. |
| specs/security-moderation.md | Documents the enforcement split and the review-only nature / Hermit notification rules for Signals. |
| convex/schema.ts | Defines new Convex tables + indexes for signals, review events, and notification claim tracking. |
| convex/publisherAbuseDevSeed.ts | Seeds demo signals (including install/download ratio + sustained downloads evidence) and clears them reliably. |
| convex/publisherAbuseDevSeed.test.ts | Extends seed tests to cover signal fixtures and seed-clearing behavior. |
| convex/publisherAbuse.ts | Adds dashboard signal count summary, paginated signal listing, signal review mutations, archival actions, and Hermit digest delivery. |
| convex/publisherAbuse.test.ts | Adds extensive backend tests for signal paging, archival rules, review lifecycle, notification claiming/retry, and dashboard counts. |
| convex/lib/retentionPolicy.ts | Marks signals and signal review events as permanent retention. |
| convex/lib/retentionPolicy.test.ts | Adds coverage asserting signals are documented as durable evidence. |
| convex/lib/publisherAbuseScoring.ts | Adjusts temporal near-conversion thresholds and makes temporal labels review-only (no potential-ban escalation). |
| convex/lib/publisherAbuseScoring.test.ts | Updates scoring tests to match the new review-only boundary and ratio threshold behavior. |
| convex/crons.ts | Updates the temporal cron invocation to explicitly archive dry-run signals. |
| convex/crons.test.ts | Updates cron tests to assert archiveDryRunSignals: true is passed. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <tbody> | ||
| {!loaded ? ( | ||
| {tab === "signals" ? ( | ||
| <div className="pa-signal-status-tabs" role="tablist" aria-label="Signal status"> |
| key={status} | ||
| type="button" | ||
| className={signalStatus === status ? "active" : ""} | ||
| aria-selected={signalStatus === status} |
| target="_blank" | ||
| rel="noreferrer" | ||
| aria-label={`Open skill ${item.signal.skillDisplayName}`} |
| target="_blank" | ||
| rel="noreferrer" | ||
| aria-label={`Open publisher ${item.signal.handleSnapshot}`} |
| kind: "publisher_abuse_signals_changed", | ||
| changedCount: signals.length, | ||
| hasMore, | ||
| dashboardUrl: `${config.siteUrl}/management?view=abuse&tab=signals`, | ||
| topSignals: signals.map((signal) => ({ |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
|
/clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
/clawsweeper re-review |
|
/clawsweeper re-review |
2 similar comments
|
/clawsweeper re-review |
|
/clawsweeper re-review |
Summary
This PR keeps publisher abuse autobanning on the warning-first pressure-score path and moves temporal install/download anomalies into a staff-review Signals workflow. The management abuse view now has a bounded, paginated Signals tab with severity/status filters, compact rows, new-tab skill/publisher links, row detail actions, and skeleton loading states.
Signals can be snoozed, dismissed, or reopened with audit rows. Changed signals can emit one authenticated digest request to the configured Hermit endpoint, but temporal-only signals remain review evidence and do not feed the automatic warning/ban path.
What Changed
potential_ban_candidatenominations remain the only automatic warning/ban input; temporal anomaly evidence is archived as review-only signals.publisherAbuseSignalswith indexed archival, bounded listing/counts, status fields, audit events, retention coverage, and local/dev seed fixtures.open,snoozed, anddismissedsignals, then snooze for 14 days, dismiss, or reopen from the signal detail sheet.openclaw/hermitPR search broken #17 is merged at34b654fcb707abf94b47122fa5674e3442862e8c, adding the/api/clawhub-publisher-abuse/signals/digestreceiver forpublisher_abuse_signals_changed. Production Discord delivery depends on deploying Hermit and matching existing ClawHub-Hermit config; no new token is required when the shared token is already present on both sides.CLAWHUB_HERMIT_TOKENis preferred when configured,CLAWHUB_BAN_APPEALS_TOKENis the accepted fallback, and a dedicatedCLAWHUB_HERMIT_TOKENcan be added later for separation/rotation.dryRun: true, explicitly opts into archiving staff-review signal rows, and only requests Hermit notification for changed completed cron results./management?view=abuse, stable tab counts before the tab is opened, server pagination, severity column, ratio evidence, skeleton rows, and skill/publisher links that open in a new tab.--strictPortso the app fails fast instead of silently moving off the advertised local URL.Workflow
potential_ban_candidatenominations.dryRun: trueand archives review-only signal rows only because the scheduled job explicitly opts in.publisherAbuseSignals; single spike-only evidence is intentionally not archived as a durable signal row.openclaw/hermitPR #17; production delivery depends on Hermit deploy plus shared token/base URL config.CLAWHUB_HERMIT_TOKENis preferred when present; existingCLAWHUB_BAN_APPEALS_TOKENfallback is valid, so this PR does not require minting a new token.open,snoozed, anddismissed.Proof
Behavioral proof:
admired-dodo-615: the app loaded athttp://127.0.0.1:3030,/dev-auth/secretreturned a usable secret, Use Admin signed in as@local-admin, Management unlocked, and Abuse -> Signals showed seeded rowsdemo-temporal-install-ratioanddemo-temporal-download-burst.Signals 2before staff opened the Signals tab, proving the tab count comes from the bounded dashboard query rather than from an already-loaded signal page.notifyPublisherAbuseSignalChangesInternalHandlerwithHERMIT_PUBLISHER_ABUSE_BASE_URLpointed at a one-off127.0.0.1receiver andCLAWHUB_HERMIT_TOKEN=local-hermit-token. The receiver captured exactly onePOST /api/clawhub-publisher-abuse/signals/digestwithAuthorization: Bearer local-hermit-token,kind=publisher_abuse_signals_changed,changedCount=1,dashboardUrl=http://127.0.0.1:3030/management?view=abuse&tab=signals, andtopSignalURLs under127.0.0.1:3030. The handler returned{ ok: true, sent: true, count: 1 }and calledmarkSucceededwith the signal id.Screenshot proof:
Signals 2before staff open the Signals tab, while the other abuse tabs remain populated and not stuck in loading.@local-admin, Potential ban tab active.1440pxwide full-page capture, because the header metrics, tabs, table, and footer prove the whole management route state.@local-admin, Signals tab active.1440pxwide full-page capture, because the changed tab, table header, rows, and count are all visible together.Verification
Reviewer-checkable behavior:
publisherAbuse:listReviewDashboardreturns the bounded signal count used by the tab; in the seeded fixture this renders asSignals 2before the signal page query is active.publisherAbuse:listSignalsPageis skipped until the Signals tab is active, then pages archived signal rows for staff review.publisher-temporal-abuse-scanremainsdryRun: trueand only archives dry-run signals because the cron explicitly passesarchiveDryRunSignals: true.openclaw/hermitPR search broken #17. ClawHub sends toHERMIT_PUBLISHER_ABUSE_BASE_URLwhen set, otherwiseHERMIT_CONTENT_RIGHTS_BASE_URL, otherwisehttps://forms.openclaw.ai; token auth prefersCLAWHUB_HERMIT_TOKENand falls back toCLAWHUB_BAN_APPEALS_TOKEN. Remaining end-to-end Discord delivery proof is deployment/configuration verification.Automated checks run on the current pushed tree:
bunx vitest run convex/publisherAbuse.test.ts --testNamePattern "Hermit|notification|snooz|dismiss|reopen" --reporter verbosepassed: 7 tests passed / 99 skipped.bunx vitest run src/routes/-management.test.tsx --reporter verbosepassed: 26 tests.bunx vitest run scripts/dev-worktree.test.ts --reporter verbosepassed: 18 tests.Earlier branch validation after the backend/signal changes:
bun run test -- convex/crons.test.ts convex/publisherAbuse.test.ts convex/publisherAbuseDevSeed.test.ts src/routes/-management.test.tsx convex/lib/publisherAbuseScoring.test.ts convex/lib/retentionPolicy.test.tspassed: 6 files / 175 tests.bunx tsc --noEmitpassed.bunx convex dev --once --typecheck=disablepassed against dev deploymentadmired-dodo-615.bun run ci:staticpassed.bun run ci:types-buildpassed.bun run ci:unitpassed: 326 files passed / 1 skipped, 4241 tests passed / 1 skipped, coverage threshold passed.Readiness note:
CLAWHUB_HERMIT_TOKENcan be added later for separation/rotation.