# Quality scorecard (the ratchet) Cheap to measure (`grep -c`, `wc -l`, `clj-kondo`), recorded **before/after each migration** in the commit message and in the results table below. **No metric may regress for the touched modal** without a written exception in `gotchas.md`. These are directional evidence, not targets to game — always paired with the e2e parity gate. ## Heuristics | # | Heuristic | Measure | Target | |---|-----------|---------|--------| | 1 | Faked cursor positions (not cursors themselves) | `grep -cE 'with-cursor\|MapCursor\.'` re-roots + `grep -c 'defn.*-no-cursor'` | → 0 (top-rooted cursors are fine) | | 2 | Implicit state merges (snapshot/cursor) | count merge sites | → 0 (forms); explicit `put-step` only (wizards) | | 3 | Branching complexity | `clj-kondo`, or count `cond`/`condp`/`case`/nested `if` + max depth | net ↓ | | 4 | Lines of code | `wc -l` on the modal's file(s) | net ↓ | | 5 | Reuse / cross-form similarity | cookbook components reused; duplicated-block count | reuse ↑, dup ↓ | | 6 | Route count | count routes for the modal | → 2 (+1 for add-row) | | 7 | OOB swaps | `grep -c hx-swap-oob` | → 0 unless a justified disjoint-region case is documented | | 8 | Attribute consistency | mixed `:x-`/`"x-"` encodings in migrated template | → 0 | ## How to measure (copy/paste) ```bash F=src/clj/auto_ap/ssr/.clj echo "LOC $(wc -l < $F)" echo "no-cursor twins $(grep -c 'defn.*-no-cursor' $F)" echo "faked-cursor roots $(grep -cE 'with-cursor|MapCursor\.' $F)" echo "snapshot merges $(grep -c ':multi-form-state :snapshot' $F)" echo "branch forms $(grep -cE '\(cond |\(condp |\(case |\(when-not ' $F)" echo "hx-swap-oob $(grep -c 'hx-swap-oob' $F)" echo "mixed string hx- $(grep -cE '\"hx-[a-z]' $F)" # route count: count this modal's entries in src/cljc/auto_ap/routes/*.cljc ``` ## Results Each migration appends one row (after-numbers), referencing the before in the diff. | Phase | Modal | LOC | Routes | no-cursor twins | faked roots | snapshot merges | OOB | mixed hx- | cookbook reused / added | |-------|-------|-----|--------|-----------------|-------------|-----------------|-----|-----------|-------------------------| | 1 (baseline) | Transaction Edit `transaction/edit.clj` | 1608 | ~12 | 1 | 2 | ~75 | 0 | 8 | — / seeded 7 entries | | 2 (in progress) | Transaction Edit `transaction/edit.clj` | 1555 | ~12 | **0** | 2 | ~75 | 0 | 8 | — / 0 | > **Phase 2 progress (partial).** Achieved with parity held (swap spec 6/6 + Shared > Location green): deleted the dead `*-no-cursor*` twin (no-cursor 1→0, −53 LOC) and fixed > a real production bug (`:mode` leaking into the upsert → 500 on every advanced manual > save). **Still open** for this modal — and intentionally *not* forced under parity risk: > faked cursor roots (2 — de-faking needs the render-fn rewrite, see `gotchas.md`), the > snapshot round-trip (~75 — removed by the wizard→plain-form reclassification), Selmer > conversion of the render fns, and route collapse (~12 → ~3). These are the bulk of the > modal migration and require restructuring the modal's rendering wholesale rather than > isolated edits; track as the continuation of Phase 2.