Ai-setup scoring-checks
Adds a new deterministic scoring check in src/scoring/checks/. Follows the Check[] return pattern, uses constants from src/scoring/constants.ts, and integrates in src/scoring/index.ts. Use when user says 'add scoring check', 'new check', 'modify scoring logic'. Do NOT use for display/UI changes, test modifications, or scoring display formatting.
git clone https://github.com/caliber-ai-org/ai-setup
T=$(mktemp -d) && git clone --depth=1 https://github.com/caliber-ai-org/ai-setup "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.cursor/skills/scoring-checks" ~/.claude/skills/caliber-ai-org-ai-setup-scoring-checks-0ad063 && rm -rf "$T"
.cursor/skills/scoring-checks/SKILL.mdScoring Checks
Critical
- All checks must be deterministic: No randomness, no timestamps. Same input → same output.
- Return type is always
: Each check hasCheck[]
,id
,name
,weight
,maxScore
,score
.reasons - Weights must sum to 100 across all checks in
. Verify:src/scoring/index.ts
.existenceWeight + qualityWeight + groundingWeight + accuracyWeight + freshnessWeight + bonusWeight + sourcesWeight === 100 - Only import from
for weight/threshold values. Never hardcode thresholds.src/scoring/constants.ts - Check logic is synchronous. No async/await in check functions.
Instructions
Step 1: Define the check function in a new file
Create
src/scoring/checks/<checkName>.ts.
Use this template:
import { Check } from '../types.js'; import { <CONSTANT_NAME> } from '../constants.js'; export function <checkName>( fingerprint: Fingerprint, config: ParsedConfig, ): Check[] { const checkId = '<checkName>'; let score = 0; const reasons: string[] = []; // Logic here: inspect fingerprint/config, calculate score 0–maxScore // Add reason strings for each deduction return [ { id: checkId, name: 'Check Display Name', weight: <WEIGHT_CONSTANT>, maxScore: 100, score, reasons, }, ]; }
Verify the function returns exactly one
Check object (or multiple if logically grouped). Verify score is between 0 and maxScore.
Step 2: Export from src/scoring/checks/index.ts
src/scoring/checks/index.tsAdd the import and export:
export { <checkName> } from './<checkName>.js';
Verify file is listed in the barrel export.
Step 3: Call the check in src/scoring/index.ts
src/scoring/index.tsIn the
score() function, add a line:
const <checkName>Results = <checkName>(fingerprint, config); allChecks.push(...<checkName>Results);
Verify placement is before the weight-sum validation at the end of
score().
Step 4: Update weight constants in src/scoring/constants.ts
src/scoring/constants.tsIf adding a new check type (not modifying an existing one), add the weight constant:
export const <CHECK_NAME>_WEIGHT = <number>;
Then update all other weight constants so the sum remains 100. Verify the weights comment block lists all active checks.
Verify: Run
npm run test -- src/scoring/__tests__/index.test.ts to ensure weight validation passes.
Step 5: Write or update the test
In
src/scoring/__tests__/, create or update <checkName>.test.ts. Test both pass and fail cases:
it('returns maxScore when condition is met', () => { const result = <checkName>({ /* fingerprint */ }, { /* config */ }); expect(result[0].score).toBe(100); }); it('returns 0 when condition is not met', () => { const result = <checkName>({ /* fingerprint */ }, { /* config */ }); expect(result[0].score).toBe(0); expect(result[0].reasons.length).toBeGreaterThan(0); });
Verify: Run
npm run test -- src/scoring/__tests__/<checkName>.test.ts.
Examples
User says: "Add a scoring check that penalizes repos without a CLAUDE.md file."
Actions:
- Create
(or modify if exists).src/scoring/checks/existence.ts - Check if
exists and is non-empty: if yes,config.claudeMdPath
; if no,score = 100
with reason "CLAUDE.md not found".score = 0 - Add export to
.src/scoring/checks/index.ts - Call
inexistenceResults = existence(fingerprint, config)
and push tosrc/scoring/index.ts
.allChecks - Ensure weight is defined in
(e.g.,constants.ts
).EXISTENCE_WEIGHT = 20 - Test:
.npm run test -- src/scoring/__tests__/existence.test.ts
Common Issues
Error: "Weights do not sum to 100"
- Check
at the end ofsrc/scoring/index.ts
: find the validation that sums all weights.score() - List all active checks and their weights from
.constants.ts - Adjust the weight constant so the sum equals 100. Example: if adding a new check with weight 15, reduce an existing check's weight by 15.
Error: "Check returned undefined score"
- Ensure the check function always initializes
to a number before any logic.score - Verify no conditional path leaves
unset.score - Check must always return a
object withCheck
field.score
Error: "Test fails with 'score out of bounds'"
- Verify
is >= 0 and <=score
(usually 100).maxScore - Check logic should cap:
.Math.max(0, Math.min(maxScore, score)) - Verify no negative deductions drop score below 0.
Error: "Check is called twice or results are duplicated in allChecks"
- Ensure
is called exactly once in<checkName>()
.src/scoring/index.ts - Verify you push the result array with spread:
notallChecks.push(...result)
.allChecks.push(result)
Error: "Fingerprint/config types are unknown"
- Import
fromFingerprint
andsrc/fingerprint/types.js
fromParsedConfig
(or check existing check files for the correct imports).src/commands/types.js - Match the type signature of an existing check function.