Skip to content

feat: agentic engg grants#1353

Merged
a20hek merged 3 commits into
mainfrom
feat/agentic-grants
Mar 30, 2026
Merged

feat: agentic engg grants#1353
a20hek merged 3 commits into
mainfrom
feat/agentic-grants

Conversation

@a20hek
Copy link
Copy Markdown
Member

@a20hek a20hek commented Mar 26, 2026

Summary by CodeRabbit

  • New Features

    • Introduced Agentic Engineering grant type with tailored application and tranche workflows
    • Added tranche submission fields: Colosseum Arena URL, GitHub repo URL, and AI receipt uploads for qualifying grants
    • Implemented automatic fixed-ask amounts for certain grants and enforced them during submission
    • Forms and UI adapt per grant type: dynamic field visibility, validation, labels, and step flows
  • Chores

    • Added support for agentic receipt image uploads and CDN proxy routing (token icon support)

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 26, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
earn Ready Ready Preview Mar 27, 2026 1:43pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 26, 2026

Walkthrough

Adds 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

Cohort / File(s) Summary
Database Schema
prisma/schema.prisma
Added nullable String fields on GrantTranche: colosseumLink, githubRepo, aiReceipt (@db.VarChar(500)).
Grant copy & helpers
src/features/grants/utils/stGrant.ts
Typed copy objects; agentic-engineering helpers (isAgenticEngineeringGrant, getGrantFixedAsk); URL extract/display helpers; AGENTIC_ENGINEERING_GRANT_COPY and related constants.
Application validation
src/features/grants/utils/grantApplicationSchema.ts
New isAgenticEngineering param, fixed-ask computation/enforcement, and preprocessing to coerce/require ask when fixed.
Tranche creation logic
src/features/grants/utils/createTranche.ts
Extended CreateTrancheProps with colosseumLink, githubRepo, aiReceipt; added normalization helpers and conditional validation; persisted new fields to Prisma.
Form UIs
src/features/grants/components/Modals/ApplicationModal.tsx, src/features/grants/components/Modals/TrancheFormModal.tsx
Derive applicationCopy/trancheCopy; conditionally show/require fields; add agentic-only fields and labels/placeholders; hide ask when agentic.
API routes
src/app/api/grant-application/create/route.ts, src/app/api/grant-application/update/route.ts, src/app/api/grant-application/request-tranche/route.ts
Compute isAgenticEngineering and fixedAsk during validation; persist ask = fixedAsk ?? validatedData.ask; pass new tranche fields to createTranche.
Grant state & queries
src/features/grants/hooks/useApplicationState.ts, src/features/grants/queries/get-grant-by-slug.ts
Replaced isST with hasSpecialTranches (includes agentic); serialized createdAt/updatedAt to ISO strings.
Sponsor dashboard
src/features/sponsor-dashboard/components/.../ApplicationDetails.tsx, .../Traches/TrancheDetails.tsx
Unified label sourcing via copy objects; render agentic-specific InfoBoxes (colosseumLink, githubRepo) and aiReceipt gallery; conditional projectUpdate rendering.
Image upload
src/lib/image-upload/config.ts, src/lib/image-upload/schemas.ts, src/lib/image-upload/types.ts
Added grant-agentic-receipts upload config and allowed image source; included as a large-file source.
Misc
src/features/grants/utils/grantAmount.ts, src/pages/earn/dashboard/grants/[slug]/applications.tsx, next.config.ts, src/server/tokenList.ts
Single-value reward formatting when min==max>0; use hasSpecialTranches for tranche tab visibility; added CDN rewrite and token icon proxy mapping for bin.bnbstatic.com.

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐇 I hopped through code with a curious twitch,
New agentic grants found a cozy niche,
Colosseum links and repos shine,
Receipts in clouds, neat and fine,
I thumped my foot—deploy! —and munched a carrot, rich 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title "feat: agentic engg grants" accurately describes the main objective of the changeset, which adds comprehensive support for a new agentic engineering grant type across the application.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/agentic-grants

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

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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 APPROVED is unreachable in the new special-tranche flow.

Line 68 repeats the trancheNumber === 0 check from Line 66, so approved, KYC-verified applications with no valid tranches always remain in KYC PENDING. Because agentic grants now enter hasSpecialTranches, those users will keep the Submit KYC CTA even after verification. If KYC APPROVED is 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 | 🟠 Major

The fixed-ask path becomes impossible for 0/0 reward grants.

When isAgenticEngineering is true and minReward === maxReward === 0, Lines 68-72 set fixedAsk to AGENTIC_ENGINEERING_FIXED_ASK, but Line 100 still caps ask at maxReward (0). That makes the schema unsatisfiable: preprocess injects the fixed ask while the numeric bounds reject anything above 0. This also disagrees with getGrantFixedAsk() in stGrant.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 to grantAmount.

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 _count that aren't part of GrantWithApplicationCount.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 54b2516 and d67acba.

📒 Files selected for processing (18)
  • prisma/schema.prisma
  • src/app/api/grant-application/create/route.ts
  • src/app/api/grant-application/request-tranche/route.ts
  • src/app/api/grant-application/update/route.ts
  • src/features/grants/components/Modals/ApplicationModal.tsx
  • src/features/grants/components/Modals/TrancheFormModal.tsx
  • src/features/grants/hooks/useApplicationState.ts
  • src/features/grants/queries/get-grant-by-slug.ts
  • src/features/grants/utils/createTranche.ts
  • src/features/grants/utils/grantAmount.ts
  • src/features/grants/utils/grantApplicationSchema.ts
  • src/features/grants/utils/stGrant.ts
  • src/features/sponsor-dashboard/components/GrantApplications/ApplicationDetails.tsx
  • src/features/sponsor-dashboard/components/Traches/TrancheDetails.tsx
  • src/lib/image-upload/config.ts
  • src/lib/image-upload/schemas.ts
  • src/lib/image-upload/types.ts
  • src/pages/earn/dashboard/grants/[slug]/applications.tsx

Comment on lines +108 to +114
}, [
application,
grant.id,
grant.isNative,
hasSpecialTranches,
setApplicationState,
]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n src/features/grants/hooks/useApplicationState.ts | head -150 | tail -60

Repository: 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.ts

Repository: 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().

Comment on lines +246 to +250
export const isAgenticEngineeringGrant = (
grant: { title?: string | null } | null | undefined,
): boolean => {
return grant?.title?.toLowerCase().includes('agentic engineering') ?? false;
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/features/grants/utils/stGrant.ts (1)

246-250: ⚠️ Potential issue | 🟠 Major

Don’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 title silently 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.

ApplicationCopy and TrancheCopy now 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 as T | undefined instead of optional properties.

As per coding guidelines, use discriminated unions to prevent the "bag of optionals" problem, use property: Type | undefined instead of property?: Type for TypeScript type definitions, and use readonly properties 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

📥 Commits

Reviewing files that changed from the base of the PR and between ac82d5b and 671ed3c.

📒 Files selected for processing (1)
  • src/features/grants/utils/stGrant.ts

Comment on lines +184 to +208
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;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Comment on lines +483 to +486
label: 'Link to the Github Repo',
description:
'If the repo is private, share access with <>@superteam.fun.',
placeholder: 'owner/repo',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

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.

@a20hek a20hek merged commit d5ef0d1 into main Mar 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant