feat: agentic engg grants#1353
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds Agentic Engineering grant support: DB fields on GrantTranche, grant-type detection and fixed-ask logic, extended tranche creation/validation and UI, image-upload config for agentic receipts, and a CDN proxy rewrite. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant App as ApplicationModal
participant Schema as grantApplicationSchema
participant API as create/route.ts
participant DB as Prisma
Note over User,App: Application flow (Agentic vs normal)
User->>App: Open & fill application form
App->>App: compute isAgenticEngineering, fixedAsk
Note over App: hide/init ask from fixedAsk when agentic
User->>App: Submit
App->>Schema: validate with isAgenticEngineering
Schema-->>App: validated data
App->>API: POST application (ask = fixedAsk ?? ask)
API->>API: recompute fixedAsk, validate
API->>DB: create GrantApplication with ask
DB-->>API: created
API-->>App: success
App-->>User: success
sequenceDiagram
participant User as User
participant TrancheUI as TrancheFormModal
participant Schema as createTrancheFormSchema
participant Route as request-tranche/route.ts
participant Helper as createTranche
participant DB as Prisma
Note over User,TrancheUI: Tranche submission with agentic proofs
User->>TrancheUI: Fill tranche form (may include colosseum/github/aiReceipt)
TrancheUI->>TrancheUI: detect isAgenticEngineering, show fields
User->>TrancheUI: Submit
TrancheUI->>Schema: validate (URL/file checks for agentic)
Schema-->>TrancheUI: validated data
TrancheUI->>Route: POST tranche with new fields
Route->>Helper: call createTranche(..., colosseumLink, githubRepo, aiReceipt)
Helper->>Helper: normalize/validate inputs, compute requiresAgenticFinalProof
Helper->>DB: create GrantTranche with new fields
DB-->>Helper: created
Helper-->>Route: created
Route-->>TrancheUI: success
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/features/grants/hooks/useApplicationState.ts (1)
62-69:⚠️ Potential issue | 🟠 Major
KYC APPROVEDis unreachable in the new special-tranche flow.Line 68 repeats the
trancheNumber === 0check from Line 66, so approved, KYC-verified applications with no valid tranches always remain inKYC PENDING. Because agentic grants now enterhasSpecialTranches, those users will keep theSubmit KYCCTA even after verification. IfKYC APPROVEDis the intended state here, you’ll also need a matching button config.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/grants/hooks/useApplicationState.ts` around lines 62 - 69, In useApplicationState, the second trancheNumber check inside the hasSpecialTranches branch repeats trancheNumber === 0 making 'KYC APPROVED' unreachable; update the second condition (the one that currently repeats trancheNumber === 0) to the intended check (e.g., trancheNumber > 0 or !== 0) so that when application.user.isKYCVerified is true and there are valid tranches setApplicationState('KYC APPROVED') will be reachable; ensure this change is applied where trancheNumber and setApplicationState are used and, if 'KYC APPROVED' is intended, add or verify the corresponding button config elsewhere.src/features/grants/utils/grantApplicationSchema.ts (1)
68-100:⚠️ Potential issue | 🟠 MajorThe fixed-ask path becomes impossible for 0/0 reward grants.
When
isAgenticEngineeringis true andminReward === maxReward === 0, Lines 68-72 setfixedAsktoAGENTIC_ENGINEERING_FIXED_ASK, but Line 100 still capsaskatmaxReward(0). That makes the schema unsatisfiable: preprocess injects the fixed ask while the numeric bounds reject anything above0. This also disagrees withgetGrantFixedAsk()instGrant.ts, so different call sites derive different fixed asks for the same grant.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/grants/utils/grantApplicationSchema.ts` around lines 68 - 100, The schema's numeric bounds for ask can reject AGENTIC_ENGINEERING_FIXED_ASK injected by the preprocess; compute effective bounds that include fixedAsk so the preprocess value can pass: calculate originalMin = Math.max(1, minReward), effectiveMin = Math.min(originalMin, fixedAsk ?? originalMin), effectiveMax = Math.max(maxReward, fixedAsk ?? maxReward), and replace the .min(...) and .max(...) calls in the ask z.number() validation with those effectiveMin/effectiveMax values (update the error messages to use those computed values); refer to fixedAsk, AGENTIC_ENGINEERING_FIXED_ASK, isAgenticEngineering, minReward, maxReward and the ask z.preprocess block to locate the changes.
🧹 Nitpick comments (2)
src/features/grants/utils/grantAmount.ts (1)
3-9: Add an explicit return type tograntAmount.Please annotate the top-level function return type explicitly (
: string) to satisfy the TypeScript module-function rule.Suggested change
export function grantAmount({ minReward, maxReward, }: { minReward: number; maxReward: number; -}) { +}): string {As per coding guidelines,
**/*.ts: Declare return types for top-level module functions in TypeScript (exception: React components returning JSX).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/grants/utils/grantAmount.ts` around lines 3 - 9, The top-level function grantAmount is missing an explicit return type; update its signature to declare the return type as string (e.g. function grantAmount(...): string) and ensure any return paths inside grantAmount return strings to satisfy the TypeScript rule for module-level functions.src/features/grants/queries/get-grant-by-slug.ts (1)
3-3: Consider adding an explicit return type declaration.Per coding guidelines, top-level module functions should declare their return types. This improves readability and catches accidental type changes.
♻️ Suggested return type
+import type { GrantWithApplicationCount } from '@/features/grants/types'; + -export const getGrantBySlug = async (slug: string) => { +export const getGrantBySlug = async (slug: string): Promise<GrantWithApplicationCount | null> => {Note: You may need to adjust the type or create a more specific return type if the spread includes additional fields like
_countthat aren't part ofGrantWithApplicationCount.As per coding guidelines: "Declare return types for top-level module functions in TypeScript (exception: React components returning JSX)".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/grants/queries/get-grant-by-slug.ts` at line 3, The function getGrantBySlug lacks an explicit return type; add a TypeScript return annotation for the top-level async function (e.g., Promise<GrantWithApplicationCount | null> or a more specific union/type if the implementation spreads extra fields like _count), update the function signature to include that return type, and adjust or create the GrantWithApplicationCount type if necessary to reflect any additional properties returned by getGrantBySlug.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/features/grants/hooks/useApplicationState.ts`:
- Around line 108-114: The useEffect that calls setApplicationState depends on
grant.title indirectly because isInCooldownPeriod() reads grant.title; update
the dependency array for that useEffect (the one containing application,
grant.id, grant.isNative, hasSpecialTranches, setApplicationState) to also
include grant.title so changes to the title retrigger the effect and avoid stale
cooldown checks in isInCooldownPeriod().
In `@src/features/grants/utils/stGrant.ts`:
- Around line 246-250: The predicate isAgenticEngineeringGrant should not rely
on title substring matching; update it to read a stable persisted flag on the
grant (e.g. grant.type === 'agentic-engineering' or
grant.metadata?.flags?.agenticEngineering === true) to determine agentic
behavior, and only fall back to title matching if that flag is absent for
backward compatibility; modify isAgenticEngineeringGrant to check the stable
field(s) first (using grant?.type or grant?.metadata?.flags) and return a
boolean accordingly so validation, tranche creation, and UI logic are driven by
persisted metadata rather than title text.
---
Outside diff comments:
In `@src/features/grants/hooks/useApplicationState.ts`:
- Around line 62-69: In useApplicationState, the second trancheNumber check
inside the hasSpecialTranches branch repeats trancheNumber === 0 making 'KYC
APPROVED' unreachable; update the second condition (the one that currently
repeats trancheNumber === 0) to the intended check (e.g., trancheNumber > 0 or
!== 0) so that when application.user.isKYCVerified is true and there are valid
tranches setApplicationState('KYC APPROVED') will be reachable; ensure this
change is applied where trancheNumber and setApplicationState are used and, if
'KYC APPROVED' is intended, add or verify the corresponding button config
elsewhere.
In `@src/features/grants/utils/grantApplicationSchema.ts`:
- Around line 68-100: The schema's numeric bounds for ask can reject
AGENTIC_ENGINEERING_FIXED_ASK injected by the preprocess; compute effective
bounds that include fixedAsk so the preprocess value can pass: calculate
originalMin = Math.max(1, minReward), effectiveMin = Math.min(originalMin,
fixedAsk ?? originalMin), effectiveMax = Math.max(maxReward, fixedAsk ??
maxReward), and replace the .min(...) and .max(...) calls in the ask z.number()
validation with those effectiveMin/effectiveMax values (update the error
messages to use those computed values); refer to fixedAsk,
AGENTIC_ENGINEERING_FIXED_ASK, isAgenticEngineering, minReward, maxReward and
the ask z.preprocess block to locate the changes.
---
Nitpick comments:
In `@src/features/grants/queries/get-grant-by-slug.ts`:
- Line 3: The function getGrantBySlug lacks an explicit return type; add a
TypeScript return annotation for the top-level async function (e.g.,
Promise<GrantWithApplicationCount | null> or a more specific union/type if the
implementation spreads extra fields like _count), update the function signature
to include that return type, and adjust or create the GrantWithApplicationCount
type if necessary to reflect any additional properties returned by
getGrantBySlug.
In `@src/features/grants/utils/grantAmount.ts`:
- Around line 3-9: The top-level function grantAmount is missing an explicit
return type; update its signature to declare the return type as string (e.g.
function grantAmount(...): string) and ensure any return paths inside
grantAmount return strings to satisfy the TypeScript rule for module-level
functions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 82f8891b-2bef-4cc5-bd38-c7044c25b6fa
📒 Files selected for processing (18)
prisma/schema.prismasrc/app/api/grant-application/create/route.tssrc/app/api/grant-application/request-tranche/route.tssrc/app/api/grant-application/update/route.tssrc/features/grants/components/Modals/ApplicationModal.tsxsrc/features/grants/components/Modals/TrancheFormModal.tsxsrc/features/grants/hooks/useApplicationState.tssrc/features/grants/queries/get-grant-by-slug.tssrc/features/grants/utils/createTranche.tssrc/features/grants/utils/grantAmount.tssrc/features/grants/utils/grantApplicationSchema.tssrc/features/grants/utils/stGrant.tssrc/features/sponsor-dashboard/components/GrantApplications/ApplicationDetails.tsxsrc/features/sponsor-dashboard/components/Traches/TrancheDetails.tsxsrc/lib/image-upload/config.tssrc/lib/image-upload/schemas.tssrc/lib/image-upload/types.tssrc/pages/earn/dashboard/grants/[slug]/applications.tsx
| }, [ | ||
| application, | ||
| grant.id, | ||
| grant.isNative, | ||
| hasSpecialTranches, | ||
| setApplicationState, | ||
| ]); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/features/grants/hooks/useApplicationState.ts | head -150 | tail -60Repository: SuperteamDAO/earn
Length of output: 2066
🏁 Script executed:
cat -n src/features/grants/hooks/useApplicationState.ts | sed -n '60,115p'Repository: SuperteamDAO/earn
Length of output: 2704
🏁 Script executed:
cat -n src/features/grants/hooks/useApplicationState.ts | sed -n '40,75p'Repository: SuperteamDAO/earn
Length of output: 1541
🏁 Script executed:
grep -n "isInCooldownPeriod" src/features/grants/hooks/useApplicationState.tsRepository: SuperteamDAO/earn
Length of output: 135
🏁 Script executed:
cat -n src/features/grants/hooks/useApplicationState.ts | sed -n '15,40p'Repository: SuperteamDAO/earn
Length of output: 912
Add grant.title to the useEffect dependency array.
isInCooldownPeriod() reads grant.title (line 25), but the dependency array only includes grant.id and grant.isNative. If the title changes without affecting these properties or hasSpecialTranches, the cooldown check will use stale data.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/features/grants/hooks/useApplicationState.ts` around lines 108 - 114, The
useEffect that calls setApplicationState depends on grant.title indirectly
because isInCooldownPeriod() reads grant.title; update the dependency array for
that useEffect (the one containing application, grant.id, grant.isNative,
hasSpecialTranches, setApplicationState) to also include grant.title so changes
to the title retrigger the effect and avoid stale cooldown checks in
isInCooldownPeriod().
| export const isAgenticEngineeringGrant = ( | ||
| grant: { title?: string | null } | null | undefined, | ||
| ): boolean => { | ||
| return grant?.title?.toLowerCase().includes('agentic engineering') ?? false; | ||
| }; |
There was a problem hiding this comment.
Use a stable grant-type flag here instead of title matching.
This predicate now gates validation, fixed-ask behavior, tranche creation, and dashboard rendering, but it only checks whether grant.title contains a substring. Renaming the grant or returning a payload without title silently disables all agentic-specific behavior. Please key this off persisted grant metadata instead.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/features/grants/utils/stGrant.ts` around lines 246 - 250, The predicate
isAgenticEngineeringGrant should not rely on title substring matching; update it
to read a stable persisted flag on the grant (e.g. grant.type ===
'agentic-engineering' or grant.metadata?.flags?.agenticEngineering === true) to
determine agentic behavior, and only fall back to title matching if that flag is
absent for backward compatibility; modify isAgenticEngineeringGrant to check the
stable field(s) first (using grant?.type or grant?.metadata?.flags) and return a
boolean accordingly so validation, tranche creation, and UI logic are driven by
persisted metadata rather than title text.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/features/grants/utils/stGrant.ts (1)
246-250:⚠️ Potential issue | 🟠 MajorDon’t key agentic behavior off the grant title.
This predicate is still the root switch for agentic-specific branching, so a title edit or any partial payload without
titlesilently disables fixed-ask and validation behavior. Please read a persisted grant-type field here and keep title matching, at most, as a backward-compatible fallback.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/grants/utils/stGrant.ts` around lines 246 - 250, The current isAgenticEngineeringGrant predicate relies solely on grant.title which can be missing or edited; update isAgenticEngineeringGrant to first check a persisted grant-type field (e.g., grant.type or grant.grantType) for the canonical agentic value and return true if that field matches, and only if that field is absent/falsy fall back to the existing title-based check (normalize casing and guard nulls) so title remains a backward-compatible fallback; ensure the function still returns a boolean and handles null/undefined grant objects.
🧹 Nitpick comments (1)
src/features/grants/utils/stGrant.ts (1)
5-73: These copy models are becoming a mutable bag of optionals.
ApplicationCopyandTrancheCopynow encode multiple grant variants with many?fields, so it's easy to omit variant-specific copy and still satisfy the type. Since these are static copy definitions, split them into per-grant readonly shapes (or a discriminated union) and model intentionally absent fields asT | undefinedinstead of optional properties.As per coding guidelines, use discriminated unions to prevent the "bag of optionals" problem, use
property: Type | undefinedinstead ofproperty?: Typefor TypeScript type definitions, and usereadonlyproperties for object types by default in TypeScript.Also applies to: 75-125
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/features/grants/utils/stGrant.ts` around lines 5 - 73, The ApplicationCopy (and similarly TrancheCopy) type is a mutable "bag of optionals"—refactor by defining per-grant readonly shapes (or a discriminated union) instead of many optional properties: create distinct readonly interfaces for each grant variant (e.g., interface GrantAApplicationCopy { readonly kind: "grantA"; readonly projectTitle: { ... } } and other variants) or a discriminated union type ApplicationCopy = GrantAApplicationCopy | GrantBApplicationCopy, and replace property?: Type with property: Type | undefined for intentionally absent fields so the absence is explicit; update any places that construct or consume ApplicationCopy/TrancheCopy to use the new discriminant (kind) when narrowing the union.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/features/grants/utils/stGrant.ts`:
- Around line 483-486: The description string for the form field with label
'Link to the Github Repo' contains an unreplaced placeholder '<>@superteam.fun';
replace that placeholder in the description property with the actual account or
team email/username applicants should grant access to (e.g., the real
bot/service account), updating the description text accordingly in stGrant.ts so
private-repo instructions are actionable.
- Around line 184-208: extractHostedPath incorrectly treats inputs like
"github.com/owner/repo" as path-only; update the normalization logic (using
input, trimmed, prefix, hosts, minSegments inside extractHostedPath) to detect
bare-host inputs and prepend a scheme so URL parsing captures the hostname: if
the trimmed input begins with a host from hosts (allow optional leading "www.")
and has no "http(s)://" scheme, build normalizedInput as "https://"+trimmed
(after stripping leading slashes) before creating the URL; keep the existing
hostname check, path extraction and minSegments validation unchanged.
---
Duplicate comments:
In `@src/features/grants/utils/stGrant.ts`:
- Around line 246-250: The current isAgenticEngineeringGrant predicate relies
solely on grant.title which can be missing or edited; update
isAgenticEngineeringGrant to first check a persisted grant-type field (e.g.,
grant.type or grant.grantType) for the canonical agentic value and return true
if that field matches, and only if that field is absent/falsy fall back to the
existing title-based check (normalize casing and guard nulls) so title remains a
backward-compatible fallback; ensure the function still returns a boolean and
handles null/undefined grant objects.
---
Nitpick comments:
In `@src/features/grants/utils/stGrant.ts`:
- Around line 5-73: The ApplicationCopy (and similarly TrancheCopy) type is a
mutable "bag of optionals"—refactor by defining per-grant readonly shapes (or a
discriminated union) instead of many optional properties: create distinct
readonly interfaces for each grant variant (e.g., interface
GrantAApplicationCopy { readonly kind: "grantA"; readonly projectTitle: { ... }
} and other variants) or a discriminated union type ApplicationCopy =
GrantAApplicationCopy | GrantBApplicationCopy, and replace property?: Type with
property: Type | undefined for intentionally absent fields so the absence is
explicit; update any places that construct or consume
ApplicationCopy/TrancheCopy to use the new discriminant (kind) when narrowing
the union.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 527b2792-5448-493e-baef-876b183905f8
📒 Files selected for processing (1)
src/features/grants/utils/stGrant.ts
| const trimmed = input.trim(); | ||
| const normalizedPrefix = prefix.endsWith('/') ? prefix : `${prefix}/`; | ||
| const normalizedInput = | ||
| trimmed.startsWith('http://') || trimmed.startsWith('https://') | ||
| ? trimmed | ||
| : `${normalizedPrefix}${trimmed.replace(/^\/+/, '')}`; | ||
|
|
||
| try { | ||
| const url = new URL(normalizedInput); | ||
| const hostname = url.hostname.toLowerCase().replace(/^www\./, ''); | ||
|
|
||
| if (!hosts.includes(hostname)) { | ||
| return null; | ||
| } | ||
|
|
||
| const path = `${url.pathname}${url.search}${url.hash}`.replace(/^\/+/, ''); | ||
| const pathSegments = url.pathname.split('/').filter(Boolean); | ||
| if (pathSegments.length < minSegments) { | ||
| return null; | ||
| } | ||
|
|
||
| return path; | ||
| } catch { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Accept bare-host links here.
extractHostedPath currently treats inputs like github.com/owner/repo as host-less paths, so it returns github.com/owner/repo instead of owner/repo. Anywhere that path is later rebuilt into a full URL will end up with the host doubled.
🐛 Proposed fix
const trimmed = input.trim();
const normalizedPrefix = prefix.endsWith('/') ? prefix : `${prefix}/`;
- const normalizedInput =
- trimmed.startsWith('http://') || trimmed.startsWith('https://')
- ? trimmed
- : `${normalizedPrefix}${trimmed.replace(/^\/+/, '')}`;
-
- try {
- const url = new URL(normalizedInput);
- const hostname = url.hostname.toLowerCase().replace(/^www\./, '');
-
- if (!hosts.includes(hostname)) {
- return null;
- }
-
- const path = `${url.pathname}${url.search}${url.hash}`.replace(/^\/+/, '');
- const pathSegments = url.pathname.split('/').filter(Boolean);
- if (pathSegments.length < minSegments) {
- return null;
- }
-
- return path;
- } catch {
- return null;
+ const candidates =
+ trimmed.startsWith('http://') || trimmed.startsWith('https://')
+ ? [trimmed]
+ : [
+ `https://${trimmed.replace(/^\/+/, '')}`,
+ `${normalizedPrefix}${trimmed.replace(/^\/+/, '')}`,
+ ];
+
+ for (const candidate of candidates) {
+ try {
+ const url = new URL(candidate);
+ const hostname = url.hostname.toLowerCase().replace(/^www\./, '');
+
+ if (!hosts.includes(hostname)) {
+ continue;
+ }
+
+ const path = `${url.pathname}${url.search}${url.hash}`.replace(/^\/+/, '');
+ const pathSegments = url.pathname.split('/').filter(Boolean);
+ if (pathSegments.length < minSegments) {
+ continue;
+ }
+
+ return path;
+ } catch {
+ continue;
+ }
}
+
+ return null;
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/features/grants/utils/stGrant.ts` around lines 184 - 208,
extractHostedPath incorrectly treats inputs like "github.com/owner/repo" as
path-only; update the normalization logic (using input, trimmed, prefix, hosts,
minSegments inside extractHostedPath) to detect bare-host inputs and prepend a
scheme so URL parsing captures the hostname: if the trimmed input begins with a
host from hosts (allow optional leading "www.") and has no "http(s)://" scheme,
build normalizedInput as "https://"+trimmed (after stripping leading slashes)
before creating the URL; keep the existing hostname check, path extraction and
minSegments validation unchanged.
| label: 'Link to the Github Repo', | ||
| description: | ||
| 'If the repo is private, share access with <>@superteam.fun.', | ||
| placeholder: 'owner/repo', |
There was a problem hiding this comment.
Replace the placeholder access target in the private-repo copy.
<>@superteam.fun looks like an unreplaced placeholder. If this ships, applicants with private repos won’t know which account to grant access to.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/features/grants/utils/stGrant.ts` around lines 483 - 486, The description
string for the form field with label 'Link to the Github Repo' contains an
unreplaced placeholder '<>@superteam.fun'; replace that placeholder in the
description property with the actual account or team email/username applicants
should grant access to (e.g., the real bot/service account), updating the
description text accordingly in stGrant.ts so private-repo instructions are
actionable.
Summary by CodeRabbit
New Features
Chores