Main branch build is broken: duplicate `validateTeamSplits` export in utils.ts fails `next build` (TS2393)
I maintainer di solito rispondono entro 1 giorno
@rudra496 ci sta già lavorando.
Dal 17/8/2026.
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
Overview
src/lib/utils.ts currently exports two separate implementations of validateTeamSplits, back to back:
export function validateTeamSplits(splits: { percentage: number }[]): { valid: boolean; sum: number; message?: string } {
if (!splits || splits.length === 0) return { valid: true, sum: 0 };
const sum = splits.reduce((acc, s) => acc + (s.percentage ?? 0), 0);
const tolerance = 0.01; // 0.01% tolerance for floating point
const valid = Math.abs(sum - 100) <= tolerance;
return { valid, sum, message: valid ? undefined : `Team splits sum to ${sum.toFixed(2)}% (expected 100%)` };
}
export function validateTeamSplits(
splits: Array<{ percentage: string | number }>,
tolerance = 0.01
): { valid: boolean; sum: number; message?: string } {
const percentages = splits.map((s) =>
typeof s.percentage === "string" ? Number(s.percentage) : s.percentage
);
const sum = percentages.reduce((a, b) => a + b, 0);
const valid = Math.abs(sum - 100) <= tolerance;
return {
valid,
sum,
message: valid ? undefined : `Team splits sum to ${sum.toFixed(2)}% (expected 100%)`,
};
}
This isn't a style nit — it's a hard compile failure. I built the app from a clean clone of main (HEAD 9c8f4b3, "Merge pull request #67 from legend4tech/feat/statcard-edge-cases") to verify:
$ npx tsc --noEmit
src/lib/utils.ts(50,17): error TS2323: Cannot redeclare exported variable 'validateTeamSplits'.
src/lib/utils.ts(50,17): error TS2393: Duplicate function implementation.
src/lib/utils.ts(58,17): error TS2323: Cannot redeclare exported variable 'validateTeamSplits'.
src/lib/utils.ts(58,17): error TS2393: Duplicate function implementation.
$ NEXT_PUBLIC_STELLAR_NETWORK=TESTNET NEXT_PUBLIC_API_URL=http://localhost:4000/api npx next build
▲ Next.js 16.2.10 (Turbopack)
Error: Turbopack build failed with 1 errors:
./src/lib/utils.ts:58:17
the name `validateTeamSplits` is defined multiple times
next build genuinely aborts. And .github/workflows/ci.yml's build-and-lint job runs exactly that command on every push/PR to main (step run: npm run build, after verify:env and before verify:headers) — so as of this HEAD, CI on main is red, and anyone pulling main to start a fresh feature can't produce a production build.
The interesting part is why nobody noticed: npm run lint (ESLint via eslint-config-next) doesn't flag this (no-redeclare isn't catching it here), and npm test (Jest via ts-jest) also passes cleanly — 11/11 green — because Jest never runs a whole-program type-check, and at the raw-JS level a second function validateTeamSplits(...) {} declaration is perfectly legal (it just silently shadows the first). So the app runs in next dev and tests pass, while next build/tsc --noEmit — the only two checks that do a full-program TypeScript pass — both fail. That's exactly the kind of break that slips through review if CI's build step isn't actually being watched.
Root cause, from git log -- src/lib/utils.ts: the second implementation (with tolerance as a parameter and string-or-number percentage) was added by commit 7c8260c "Fix #5: add team-split validation with rounding tolerance", on top of the first implementation that was already there from the initial commit — the PR that closed #5 appended a new implementation instead of replacing the old one.
Requirements
- Delete one of the two
validateTeamSplitsimplementations and keep the other, reconciling them into a single implementation and signature. - The kept implementation must satisfy both prior use cases: (a) accept
percentageas eitherstring | number(the second implementation's improvement, needed becauseTeamSplit.percentageis anumberaftercoercePercentagebut raw backend splits may arrive as numeric strings before coercion), and (b) support a configurabletoleranceparameter (the second implementation's addition) while preserving a sane default (0.01). - Update every call site (
src/lib/adapters.ts'sadaptBounty, and any test/consumer) to the single, final signature. - Re-run
npx tsc --noEmitandnpm run buildlocally and confirm both are clean before considering this closed — passingnpm testalone is not sufficient evidence, as demonstrated above. - Add a check to CI (or to
npm run lint) that would have caught this class of error going forward — at minimum, confirmtsc --noEmitis actually part of thelintscript or add it as its own CI step, sincenpm run buildcatching it only at the very end of the CI pipeline (afterverify:env) wastes CI time on a build that was always going to fail structurally.
Acceptance Criteria
-
src/lib/utils.tsexports exactly onevalidateTeamSplitsfunction. -
npx tsc --noEmitexits 0 with no errors. -
NEXT_PUBLIC_STELLAR_NETWORK=TESTNET NEXT_PUBLIC_API_URL=http://localhost:4000/api npx next buildcompletes successfully (Turbopack build succeeds, no "defined multiple times" error). -
npm testcontinues to pass, and an existing/new test exercisesvalidateTeamSplitswith both string and numberpercentageinputs and a non-defaulttolerance. -
src/lib/adapters.ts'sadaptBounty(the only current call site) still compiles and behaves identically for the existing test fixtures. - CI's
build-and-lintjob is confirmed green on the fix branch.
Additional Notes
Precise references (confirmed against main @ 9c8f4b3):
src/lib/utils.ts:50-56— firstvalidateTeamSplitsimplementation ({ percentage: number }[], fixed 0.01 tolerance).src/lib/utils.ts:58-72— secondvalidateTeamSplitsimplementation (Array<{ percentage: string | number }>, configurabletolerance).src/lib/adapters.ts:56-62,80— the only current call site, insideadaptBounty:teamSplitsValid: splits ? validateTeamSplits(splits) : undefined, wheresplitsis alreadyTeamSplit[](i.e.percentage: number) at that point, so the string-handling branch of the second implementation is currently unreachable from this call site — worth keeping anyway since it's a reasonable defensive API for future callers (e.g. a future maintainer-facing "create team split" form that reads raw string input from a percentage field before it's coerced)..github/workflows/ci.yml:30-34— the CI steps, in order:npm ci→npm run lint→npm run verify:env→npm run build→npm run verify:headers→npm audit.npm run buildis the step that fails.git log --oneline -- src/lib/utils.ts:7c8260c("Fix #5: add team-split validation with rounding tolerance") is the commit that introduced the second implementation without removing the first;b1eb0f4and3a4eed2precede it.
Edge cases to preserve in the merged implementation:
- Empty/undefined
splitsarray — first implementation explicitly short-circuits to{ valid: true, sum: 0 }; the second implementation does not have this guard and would instead run[].reduce(...)→sum: 0, thenMath.abs(0 - 100) <= tolerance→valid: falsefor an empty array, which is a behavioral regression from the first implementation if the second is kept as-is verbatim. Whichever implementation is kept as the base, explicitly carry over the empty-array short-circuit — this is a real, silent behavior difference between the two, not just a signature difference. - Mixed string/number
percentagevalues in the same array (partial coercion) — only the second implementation handles this. - A single split at exactly 100% (no team split, i.e. solo bounty) — should be
valid: true.
Test/reproduction plan: add unit tests in a new src/lib/utils.test.ts (there currently is no test file for utils.ts at all — the only existing test file in the repo is src/components/ui/StatCard.test.tsx) covering: empty array, single 100% split, splits summing to exactly 100, splits within tolerance (e.g. 99.995/0.005), splits outside tolerance, string-typed percentages, and a custom non-default tolerance argument. Then re-run npx tsc --noEmit and npm run build as the actual regression guard for the compile-breaking half of this bug — no test can catch this class of duplicate-declaration bug, which is exactly why it shipped past npm test in the first place.
- Lingua principale
- TypeScript
- Stelle
- 1
- Fork
- 94
- Merge medio
- 1h 2m
- PR unite (30g)
- 25
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di MergeFi/frontend
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
I maintainer di solito rispondono entro 1 giorno
-
bug testing
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 84/100
I maintainer di solito rispondono entro 1 giorno
-
accessibility bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
MergeFi/frontend#835 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di MergeFi/frontend
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
zapcooking/frontend#946 ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement good first issue
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
WiliamRosa/cosmos-semantic-platform#40 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 77/100
liberation-data/drivine#733 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 64/100
makecindy/cindy#10062 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno