# scoring item result

## Files written
- `src/score.ts` — `scoreRollup(rollup: Rollup): ScoredRollup`. Seven factors in frozen order: stage(20), proofSystem(20), permissionlessProving(10, only if true and proof system is not `none`), exitWindowDays(15: 0→0, (0,7)→5, [7,30)→10, ≥30→15), upgrades(15: singleKey 0, multisig 5, council threshold 1→0, else cross-multiplied ratio ≥3/4→15, ≥2/3→10, lower→5), dataAvailability(10), forceInclusion(10). Score is the integer sum of the points. Each reason names the observed value and the rule applied. Input is not mutated, and `rollup` is returned by reference.
- `src/rank.ts` — `rankRollups(rollups: readonly Rollup[]): RankedRollup[]`. Scores a copy of the input and sorts by score descending, then by name ascending using `<`/`>`, then by original index, so exact ties are stable. Assigns ranks 1..n. Returns `[]` for `[]` and never sorts the caller's array.
- `test/scoring.test.ts` (10 tests) covers every branch, the exit-window boundaries 0/0.5/6.99/7/29.99/30/365, the councils 1/1, 1/12, 2/3, 3/4, 7/12, 8/12, 9/12 and 12/12, proof gating and its reason text, totals of 0 and 100, factor order, maxPoints summing to 100, and non-mutation.
- `test/ranking.test.ts` (5 tests) covers ordering, the case-sensitive name tie-break, stable exact ties, ranks 1..n, empty input and non-mutation.

## Commands run
- `node --test test/scoring.test.ts test/ranking.test.ts`: 15 passed, 0 failed.
- `node src/score.ts && node src/rank.ts`: both load without error.

## Not run / deviations
- These files depend only on `src/types.ts`, so nothing was blocked by sibling modules.
- I did not run the full `npm test` because the sibling suites were not in this checkout.
- No deviations from docs/architecture.md.
