Conversation
A score multiplier only re-sorts upstreams; it doesn't gate them. With group:fallback removed, Chainstack (paid) received hedge and transient failover traffic whenever Nodeful was merely slow or throttled, not only when unhealthy/unsupported as the README claims. Tag each Chainstack upstream tier:fallback so eRPC's default selection policy (auto-attached on the tag) holds it out of rotation until no primary survives. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…board Token usage dashboard
…-activity Remove canceled proposals from the activity
eRPC config v2
- footer links now read About / Docs / Terms of Service / Give Feedback: About keeps the GitBook link, Docs points to https://docs.anticapture.com - API keys page gets a "See our Docs" button next to Create key - whitelabel sign-in skips the one-button login modal and triggers the SIWE flow directly; the dialog only surfaces for signing progress or errors, and dismissing the wallet picker cancels sign-in cleanly
Issue tracker
Design review feedback: the row options menu held a single action and its ellipsis trigger was too small to notice. The menu is gone; each active key row now shows a tooltip-labeled destructive trash button that opens the same delete confirmation modal.
…-siwe feat(dashboard): docs links and direct whitelabel SIWE sign-in
Reduce indexer costs
chore: version packages
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Wrong neverVoted for canceled-only
- Added hasEverVoted to distinguish delegates with no votes from those whose only votes are on canceled proposals, returning neverVoted: false for the latter.
Or push these changes by commenting:
@cursor push 4d0a29734f
Preview (4d0a29734f)
diff --git a/apps/api/src/repositories/proposals-activity/index.ts b/apps/api/src/repositories/proposals-activity/index.ts
--- a/apps/api/src/repositories/proposals-activity/index.ts
+++ b/apps/api/src/repositories/proposals-activity/index.ts
@@ -47,6 +47,15 @@
export class DrizzleProposalsActivityRepository {
constructor(private readonly db: Drizzle) {}
+ async hasEverVoted(address: Address): Promise<boolean> {
+ const [vote] = await this.db
+ .select({ timestamp: votesOnchain.timestamp })
+ .from(votesOnchain)
+ .where(eq(votesOnchain.voterAccountId, address))
+ .limit(1);
+ return !!vote;
+ }
+
async getFirstVoteTimestamp(address: Address): Promise<number | null> {
// Only consider votes on non-canceled proposals so activityStart matches
// the activity scope (canceled proposals are excluded from the metrics).
diff --git a/apps/api/src/repositories/proposals-activity/index.unit.test.ts b/apps/api/src/repositories/proposals-activity/index.unit.test.ts
--- a/apps/api/src/repositories/proposals-activity/index.unit.test.ts
+++ b/apps/api/src/repositories/proposals-activity/index.unit.test.ts
@@ -76,6 +76,32 @@
await db.delete(proposalsOnchain);
});
+ describe("hasEverVoted", () => {
+ it("returns false when no votes exist for the address", async () => {
+ const result = await repository.hasEverVoted(VOTER);
+ expect(result).toBe(false);
+ });
+
+ it("returns true when votes exist only on canceled proposals", async () => {
+ await db.insert(proposalsOnchain).values(
+ createProposal({
+ id: "canceled",
+ txHash: "0xtx1",
+ status: "CANCELED",
+ }),
+ );
+ await db.insert(votesOnchain).values(
+ createVote({
+ txHash: "0xvote1",
+ proposalId: "canceled",
+ }),
+ );
+
+ const result = await repository.hasEverVoted(VOTER);
+ expect(result).toBe(true);
+ });
+ });
+
describe("getFirstVoteTimestamp", () => {
it("returns null when no votes exist for the address", async () => {
const result = await repository.getFirstVoteTimestamp(VOTER);
diff --git a/apps/api/src/services/proposals-activity/index.ts b/apps/api/src/services/proposals-activity/index.ts
--- a/apps/api/src/services/proposals-activity/index.ts
+++ b/apps/api/src/services/proposals-activity/index.ts
@@ -65,6 +65,8 @@
}
export interface ProposalsActivityRepository {
+ hasEverVoted(address: Address): Promise<boolean>;
+
getFirstVoteTimestamp(address: Address): Promise<number | null>;
getProposals(
@@ -116,7 +118,8 @@
await this.repository.getFirstVoteTimestamp(address);
if (!firstVoteTimestamp) {
- return this.createEmptyActivity(address, true);
+ const hasEverVoted = await this.repository.hasEverVoted(address);
+ return this.createEmptyActivity(address, !hasEverVoted);
}
// Get voting period for the DAO from blockchain
diff --git a/apps/api/src/services/proposals-activity/index.unit.test.ts b/apps/api/src/services/proposals-activity/index.unit.test.ts
--- a/apps/api/src/services/proposals-activity/index.unit.test.ts
+++ b/apps/api/src/services/proposals-activity/index.unit.test.ts
@@ -20,6 +20,7 @@
function createStubRepo(): ProposalsActivityRepository & {
lastActivityStart: number | null;
+ hasEverVotedValue: boolean;
firstVoteTs: number | null;
proposals: DbProposal[];
votes: DbVote[];
@@ -27,11 +28,13 @@
} {
const stub = {
lastActivityStart: null as number | null,
+ hasEverVotedValue: false,
firstVoteTs: null as number | null,
proposals: [] as DbProposal[],
votes: [] as DbVote[],
paginationResult: { proposals: [] as DbProposalWithVote[], totalCount: 0 },
+ hasEverVoted: async (_address: Address) => stub.hasEverVotedValue,
getFirstVoteTimestamp: async (_address: Address) => stub.firstVoteTs,
getProposals: async (
_daoId: DaoIdEnum,
@@ -147,6 +150,24 @@
});
});
+ it("should return empty activity with neverVoted false when votes are only on canceled proposals", async () => {
+ repo.hasEverVotedValue = true;
+ repo.firstVoteTs = null;
+
+ const result = await service.getProposalsActivity(defaultRequest);
+
+ expect(result).toEqual({
+ address: VOTER_ADDRESS,
+ totalProposals: 0,
+ votedProposals: 0,
+ neverVoted: false,
+ winRate: 0,
+ yesRate: 0,
+ avgTimeBeforeEnd: 0,
+ proposals: [],
+ });
+ });
+
it("should return proposals with user votes and analytics", async () => {
repo.firstVoteTs = 1699000000;
repo.paginationResult = {You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit db90edd. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: db90edd16d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
This comment was marked as resolved.
This comment was marked as resolved.
Chore/prod deploy fixes
|
🔍 Vercel preview: https://anticapture-6rm4ao3ao-ful.vercel.app |


Note
Medium Risk
Touches auth credential boundaries (usage-only vs provisioning keys), new DB migrations in Authful, and wallet RPC routing—misconfiguration could break sign-in or RPC until env vars are set correctly.
Overview
Adds an end-to-end 30-day daily request chart for self-service API keys: Gateful buffers
user:*traffic and flushes idempotent batches to Authful via a new usage-only credential (USAGE_API_KEY/TOKEN_SERVICE_USAGE_API_KEY) that cannot mint or revoke; Authful persiststoken_usage_dailywith tenant-scoped read/write rules; User API exposesGET /me/api-keys/usage; the dashboard renders a filterable stacked bar chart and related API Keys UX (docs link, per-row delete, agent commands in the save modal).Dashboard wallet RPC no longer uses
NEXT_PUBLIC_ALCHEMY_KEY—wagmi routes through a same-origin/api/rpc/<chainId>proxy that injectsERPC_SECRETserver-side and forwards trusted client IP for per-IP limits.DAO API proposal-activity queries now exclude canceled proposals (including first-vote timestamp alignment). Indexer corrects ENS token
startBlock. eRPC configs gain dashboard integration docs, trusted forwarders, failsafe/rate-limit/cache tuning, and Chainstack fallback tagging; monitoring adds Postgres/Railway exporter docs and alert guidance. Minor panel layout and whitelabel sign-in (direct SIWE) fixes; AGENTS.md documents ClickUp issue tracker and agent skills.Reviewed by Cursor Bugbot for commit db90edd. Configure here.