kelly-deal-scorer · git:20260806.bed1b85 · 2026-08-06 · sha256 d3e12154a1b5b283

kelly-deal-scorer git:20260806.bed1b85A

Immutable. This exact content is served forever at /api/v1/blob/d3e12154a1b5b283.

---
name: kelly-deal-scorer
description: Busabase App-in-Skill review queue that scores candidate SME financing deals (revenue-based/RBF-style credit) with a deterministic, fully auditable rule-based rubric — never an LLM or API call. Use when the user invokes $kelly-deal-scorer or /kelly-deal-scorer, wants to review a deal-underwriting queue, score financing candidates, compute a composite score breakdown, see a suggested revenue-share rate range, or record approve/send-back/reject decisions for a private-credit or RBF-style lending pipeline.
---

# Deal Scoring Desk

## Overview

Use this skill as a Busabase-backed review-queue desk for a generic SME
financing deal desk (private-credit / revenue-based-financing style). It
holds a mock queue of candidate businesses (name, category, city, monthly
revenue history, requested principal, red flags) and computes a deterministic
composite score (0-100) per candidate with a full, hand-recomputable
breakdown: each sub-factor's raw score, weight, and contribution, plus a
suggested revenue-share rate range. This is a generic, brand-free tool — it
does not reference any specific real company, lender, or fund.

**The scoring rubric is plain arithmetic in `app/app/js/scorer-model.js`, not
an LLM or API call.** Every number the app shows can be recomputed with a
calculator from the candidate's raw fields and the rubric weights in the
`settings` Base.

Default behavior is AirApp-first. Unless the user explicitly asks only for
explanation, ensure the mock queue exists (run the seed script below if the
`candidates` Base is empty) and give the user the clickable AirApp URL (or
the local preview URL when local preview is explicitly requested). Use
chat-only mode only when the user says "纯聊天", "chat only", "不要打开 UI", or
similar.

## App UI Screenshots

<table>
  <tr>
    <td width="50%"><img src="assets/screenshots/overview.webp" alt="Deal Scoring Desk overview"></td>
    <td width="50%"><img src="assets/screenshots/candidate-detail.webp" alt="Deal Scoring Desk candidate detail"></td>
  </tr>
  <tr>
    <td><strong>Overview</strong><br>Queue-level summary header — score distribution, counts needing review vs. high-confidence — plus the candidate list.</td>
    <td><strong>Candidate detail</strong><br>Revenue history, red flags, requested principal, and the decision row (approve for term sheet / send back for more data / reject).</td>
  </tr>
  <tr>
    <td width="50%"><img src="assets/screenshots/score-breakdown.webp" alt="Deal Scoring Desk score breakdown"></td>
    <td width="50%"></td>
  </tr>
  <tr>
    <td><strong>Score breakdown</strong><br>Per-factor raw score, weight, and contribution with an arithmetic trace for every sub-factor, plus the suggested revenue-share rate range.</td>
    <td></td>
  </tr>
</table>

## Mandatory Dependencies

1. Read and follow `$kelly-app-skill-creator` for product behavior, visual quality, responsive layout, and the complete canonical `app/` artifact.
2. Read and follow `$busabase` for connection, target Space, node discovery, ChangeRequests, review, and merge behavior.
3. Read and follow `$busabase-app-creator` for resource modeling, AirApp runtime limits, security, validation, and deployment.

If a dependency is unavailable, preserve this skill's local artifact and product contracts, stop before the unavailable Busabase operation, and report the exact missing dependency. Do not invent a second data backend.

## Boundary

- Review-only. The skill scores a candidate queue and records human
  decisions in Busabase; it never wires money, signs a term sheet, or
  contacts a business.
- NEVER treat the composite score as legal or financial advice, and never
  auto-approve: a human decision (`approve_term_sheet` / `send_back_for_data`
  / `reject`) is always required before `scripts/execute_decisions.mjs` marks
  a candidate `done`.
- The AirApp reads and writes its own two Busabase Bases only.
- Treat candidate financials as sensitive review data; the composite score
  and every intermediate number are always recomputed client-side from the
  candidate's raw fields, never fabricated.

## Busabase Resources

Two Bases under one application Folder (`kelly-deal-scorer`), declared in
`app/app/js/config.js` and `app/resource-map.json`:

- `candidates`: one row per candidate business — raw underwriting fields
  (category, city, requested principal, monthly revenue history, red flags)
  plus the reviewer's decision (`decision-action`/`decision-comment`/
  `decided-at`) and workflow `status`, all written directly onto the same
  row. The composite score breakdown is never stored — it is recomputed
  client-side from the raw fields on every read.
- `settings`: up to two rows, keyed by `record-id`/`kind`: `config`
  (base currency + an optional rubric override for the fund's underwriting
  policy) and `run` (the current queue's batch id + generated-at).

Resources provision lazily through an idempotent Busabase ChangeRequest the
first time the app runs in a Space; see `references/scoring-schema.md` for
exact field shapes.

## First Run And Onboarding

On invocation, check the `candidates` Base. If it's empty, run the trusted
seed script to generate the fixed mock queue:

```bash
node skills/kelly-deal-scorer/scripts/generate_batch.mjs --apply
```

There are no credentials to collect beyond Busabase itself — onboarding is
just confirming the rubric weights and category risk tiers in the `settings`
Base's `config` row match the fund's underwriting policy (defaults apply if
omitted).

## Local App

Default behavior is AirApp-first — give the user the clickable AirApp URL.
Start `pnpm --dir app dev` only when local preview/debugging is explicitly
requested.

Required app views (hash routes):

- `#/overview`: queue-level summary — score distribution (high-confidence /
  needs review / low-confidence), workflow counts, and the candidate list.
- `#/candidates` and `#/candidates/<id>`: the full queue, filterable by
  status; detail shows revenue history, red flags, requested principal,
  score breakdown, suggested revenue-share range, and the decision row.
  Decisions write directly onto the candidate record through `busabase-sdk`.
- `#/settings`: sanitized rubric summary (weights, thresholds), active data
  provider, and onboarding state.

## Demo Mode

- `?demo=1` opens a deterministic, fully offline mock queue (8 candidates
  across F&B/Retail/Fitness/Education) for documentation and screenshots.
  Demo mode never reads or writes Busabase.
- `lang=en` or `lang=zh` forces UI chrome language for screenshots.

UI language: English and Chinese chrome with `Auto` default.

## Workflow

1. `node scripts/generate_batch.mjs --apply` (dry run without `--apply`)
   writes the fixed 8-candidate mock queue to the `candidates` Base
   (resetting every candidate's decision fields to `needs_review`) and
   refreshes the `settings` Base's `run` row — run it once at setup, and
   again any time the demo queue needs resetting.
2. Open the app. **Overview** shows the score distribution and workflow
   counts; **Candidates** lists every candidate, filterable by status.
3. For each candidate, open the detail view, review the revenue history
   chart, red flags, and the full score breakdown (every sub-factor's raw
   score/weight/contribution with an arithmetic trace), then record
   `Approve for term sheet` / `Send back for more data` / `Reject` with an
   optional note — written straight onto the candidate record.
4. `node scripts/execute_decisions.mjs --apply` (dry run without `--apply`)
   re-reads Busabase and marks every `approved` candidate `done`, preparing
   the local term-sheet-draft artifact at the suggested revenue-share rate.
   It performs no external side effect — no wiring, no signing, no
   contacting the business.

Read `references/scoring-schema.md` before editing the app, scripts, or
`app/app/js/scorer-model.js`.

## The Rubric (not a model)

`app/app/js/scorer-model.js` documents and implements the entire scoring
rubric: five weighted 0-100 sub-factors (revenue stability, growth trend,
category risk tier, principal-to-revenue ratio, track record & scale), each
with a human-readable arithmetic trace in `detail`. `computeScore()` is a
pure function — same inputs always produce the same composite score and
suggested revenue-share range, so a human reviewer can check every number
with a calculator. It backs the trusted seed script
(`scripts/generate_batch.mjs`), the live Busabase read path
(`app/app/js/providers/busabase-provider.js`), and the offline `?demo=`
scenario (`app/app/js/providers/demo-provider.js`), so all three always
agree on scoring.

## Safety

- Deterministic scoring only: never call an LLM or external API to produce a
  candidate's score — `app/app/js/scorer-model.js` is plain arithmetic so
  every number is auditable.
- Never auto-execute a decision the human has not made.
- Do not invent candidates outside the fixed seed set; if the user wants a
  different queue, add to `app/app/js/scorer-model.js`'s `CANDIDATE_SEEDS`
  and re-run the seed script.

## Useful Commands

```bash
node skills/kelly-deal-scorer/scripts/generate_batch.mjs --apply
node skills/kelly-deal-scorer/scripts/execute_decisions.mjs --apply
pnpm --dir skills/kelly-deal-scorer/app dev
```