Alpha test, 16/10/2026: how auto-matching did
Suggestions and Suspense on the production server (app.ledgermap.in). Data: a read-only copy of the production database and its usage events, taken 17/10/2026.
The answer in short
- Exact matches work. 80 of 168 exported entries (48%) were saved by the server. Users changed none of them.
- Suspense is too full, and mostly by mistake. 50 entries (30%, ₹12.27 lakh) went to Suspense. For 21 of them (₹9.80 lakh, 80% of that money), the app already showed the right-looking ledger, but no one saved it.
- Truly unknown is small. 63 entries (38%) started with nothing known. In the end 28 of them (17% of entries, ₹2.41 lakh) were exported to Suspense with nothing known; 26 of these are in KESARI NANDAN ART, mostly small UPI payments to people.
- Main cause: the export sends every unsaved entry to Suspense, also one with a 97% suggestion, and it does not warn.
- Second cause: a cheque number makes each cheque look like a new payee, so one choice (for example SELF cheque → Cash) never fills the other cheques automatically.
- First fixes: an export check for unsaved suggestions, accept-all in the Suspense step, and no cheque numbers in the payee pattern. Together they can bring Suspense from 30% to about 17% of entries (₹2.47 lakh).
0Who used it
3
user accounts (Kelvin Bhuva, Dhaval, Test)
4
parties with PDFs (of 670 parties, most from a bulk company import)
12
PDFs saved, 1,415 entries read
3
imports exported to Miracle (168 entries, ₹46.65 lakh)
All use was on 16/10/2026 between 17:32 and 20:17 IST, from the Windows app 0.3.0. ASMARK ENGINEERS (Kelvin) opened its review twice (56 entries) but saved nothing and did not export, so most numbers below come from the three exported imports.
1How it performed
Each bar is one exported import. A segment shows what happened to its entries in the end.
Exact match, saved by the server
Suggestion accepted
User chose a ledger by hand
To Suspense, but a suggestion was shown
To Suspense, nothing known
Show as a table
Step by step
At bank link
78 of 168
- Saved as exact matches before review started.
- 2 more came during review (GST UPI ID learned from one choice).
- 34 different ledgers. Changed or removed: 0.
Suggestions step
27
- 18 accepted as shown (17 with Ctrl+Shift+Enter).
- 2 changed (both wrong suggestions).
- 7 not saved: all went to Suspense.
Suspense step
63
- 21 got a real ledger: 19 by the user, 2 by the server from a learned UPI ID.
- 42 went to Suspense.
- 14 of those 42 got a 72–97% suggestion during review (from the user's own choices), but stayed unsaved.
Export
50 to Suspense
- The export page showed only "N to Suspense".
- It did not say that 21 of them had a suggestion.
Entries nothing was known about at the start
These are the entries that went to the Suspense step when review started: no exact match, no suggestion and no Miracle history clue. In KESARI NANDAN ART that was 49 of 123 entries (40%, ₹7.65 lakh). The 33% in the bar above is a different number: it is how many entries were exported to Suspense in the end, from both steps.
Each of these entries was exported in one of two ways: with a real ledger, or to Suspense. The orange part splits the Suspense entries by what the app knew at export. During review, the user's own choices taught the app, so 13 of them had a suggestion by then (for example Cash Account for a SELF cheque), but the user never saved it. The gray part is what the app never knew anything about. It includes 1 entry where the user picked the Suspense ledger by hand; the result is the same.
Exported with a real ledger
Exported to Suspense, but the app had a suggestion by then
Exported to Suspense, nothing known
KESARI NANDAN ART 49 unknown at the start
PITRUKRUPA SELECTION 10 unknown at the start
TEJANI GUMMING POINT 4 unknown at the start
| Import | Unknown at start | Real ledger | Suspense, suggestion by then | Suspense, nothing known |
| KESARI NANDAN ART | 49 (40%) · ₹7.65 lakh | 10 · ₹1.74 lakh | 13 · ₹4.50 lakh | 26 (21% of 123) · ₹1.41 lakh |
| PITRUKRUPA SELECTION | 10 (30%) · ₹5.42 lakh | 7 · ₹4.12 lakh | 1 · ₹30,000 | 2 · ₹1,00,001 |
| TEJANI GUMMING POINT | 4 (33%) · ₹82,388 | 4 · ₹82,388 | 0 | 0 |
| All three | 63 (38%) | 21 | 14 | 28 (17% of 168) · ₹2.41 lakh |
What the 26 entries in KESARI NANDAN ART that nothing was known about are (all exported to Suspense):
- 24 UPI payments to people and small shops, ₹72,504 in all. 9 are under ₹1,000 (the smallest is ₹10). The books have no ledger that clearly names these payees.
- 3 payees repeat: one UPI ID 3 times (₹9,000), two others 2 times each. One choice for the first would match the rest (the UPI ID is learned), but the user chose nothing for them. The UPI ID that repeats 3 times (JOSHIISHWAR59) may be the ledger ISHWARLAL PRADIPBH JOSHI (Unsecured Loans). That is a possible match only; the user should confirm it.
- 1 cheque to LIFE INSURANCE CORP (₹9,844). The books have no insurance ledger, so Suspense may be right here.
- 1 cheque deposit printed "MINARVASAL ESCORPN" (₹59,125). This is a matcher miss: the ledger MINARAVA SALES CORPORATION (Sundry Debtors) is in the books. The bank glued the words, spelled the name differently and shortened CORPORATION to CORPN.
So in KESARI NANDAN ART, of the 40 entries exported to Suspense, 26 were unknown to the app, and those were mostly small: 21% of entries but only 5.9% of the money (₹1.41 lakh of ₹23.88 lakh). At least 1 of the 26 (₹59,125) has a ledger in the books, and 3 more may have one. Of the other 14, 13 had a suggestion that was not saved (₹4.50 lakh), and 1 had a weak "same amount" clue from the books that the user turned down.
Time spent
| Import | Entries | Review to export | Notes |
| KESARI NANDAN ART (Dhaval) | 123 | 18 min 20 s | Suggestions 1 min 55 s for 18. Suspense 7 min 14 s for 49 (11 resolved). Review 5 min 45 s. |
| PITRUKRUPA SELECTION (Test) | 33 | 5 min 55 s | Suggestions 2 min 33 s for 5 (1 saved). Suspense 2 min 9 s for 10 (9 given a ledger, 2 of them the Suspense ledger "?"). |
| TEJANI GUMMING POINT (Test) | 12 | about 5 min | 94 of the PDF's 106 entries were before Miracle's last entry for the bank, so they did not come in (as designed). |
What worked well
- Exact name matches are safe. 80 entries, ₹23 lakh, 0 corrections, 0 rejections. I read all 64 ledgers matched in the 12 PDFs; every one looks right, including glued names such as SHIVAMPRINT → SHIVAM PRINT and BLUETEX(I)P… → BLUE TEX (I) PRIVATE LIMITED.
- Learning from one choice works for UPI IDs. The user chose GST Provisional A/c. for one GST UPI payment, and the server saved 2 more at once. A later upload of that bank then got 6 UPI and 6 account matches from the export.
- Accept-all is used. Ctrl+Shift+Enter accepted 17 suggestions in one key press.
- Search works. Hand choices took 2–4 typed letters, and the wanted ledger was first or second in 23 of 26 picks.
- Miracle history clues help with cash. All 4 "recurring" clues pointed to Cash Account for cash withdrawals, which looks right.
2Bugs found
Confirmed means seen in the production data and traced in the code. Suspected means seen in the code only.
HighUnsaved suggestions go to Suspense without a warning
- What happens
- The Ledger box shows a suggestion, but it is not saved until the user presses Enter. At export, every entry without a saved choice goes to Suspense (
frontend/src/lib/voucher-export.ts:182). The export page shows only "N to Suspense".
- Evidence
- 21 of 50 Suspense entries (₹9.80 lakh) had a suggestion: 10 SELF cheques with Cash Account at 97%, JAY BHAGVATI at 95%, SHIV SAKTI ART at 97%, JAY ART at 97%, 3 ATM withdrawals with Cash at 69%, and others. Table below.
- Fix
- Before saving, the export says "21 entries going to Suspense have a suggestion" with Accept them, Show them and Export anyway.
HighCheque numbers stop learning from one choice
- What happens
- The payee pattern adds the numbers from the reference column (
server/ledger_match.go:669, patternKey). A cheque's reference is its cheque number, so every cheque gets its own pattern. A choice for one cheque never becomes an exact match for the next one. It is only a 97% suggestion, which then waits for a key press (bug above).
- Evidence
- "SELF-CHQPAID- SARDARCHOWK" ×10: Cash Account was saved for 2, and the other 8 stayed open with key
SELFCHQPAIDSARDARCHOWK 0000000000000160, …163 and so on. "CHQ PAID-…-JAYART" ×2: the same. Checked by running the production matcher on this data.
- Fix
- Leave cheque numbers (the reference of cheque rows) out of the pattern, as for transfer references. Keep the exact-match rules as they are.
MediumNew suggestions in the Suspense step are easy to miss
- What happens
- Steps are fixed at the start, by your rule. So when a save teaches the server, the new suggestions appear on rows in the Suspense step. That step has no accept-all (only the Suggestions step has it,
statement-entries.tsx:689), and nothing points at the new suggestions.
- Evidence
- 14 entries got a 72–97% suggestion in the Suspense step and stayed unsaved. Example: the user chose BIKE FUEL EXPENSES for a petrol pump UPI payment at 18:14:25 IST; 1 second later 2 more payments to the same pump had it at 97%; both went to Suspense.
- Fix
- Keep rows in their step. Add a line "5 entries in this step now have a suggestion" with Ctrl+Shift+Enter to accept them, and a mark on those rows.
MediumA tie looks sure
- What happens
- When 2 or 3 ledgers match in the same way, each gets the same confidence, and the first one is filled in with a green or yellow mark. The order between them is by name, not by meaning.
- Evidence
- HARIKRUPA TRADERS. (Sundry Debtors) and HARIKRUPA TRADERS (Sundry Creditors): 99% each. Trimurti Tools And Electricals / Trimurti Tools & Electricals: 99% each. BANK SERVICES CHARGES EXPENSES / BANK CHARGES EXPENSES: 91% each. On a term-loan statement, "Interest" got INTEREST ON TERM LOAN, INTEREST TO PARTNER and INTEREST ON LATE PAYMENT OF TDS at 80% each.
- Fix
- Break ties by direction and group (a receipt goes to the debtor, a payment to the creditor) and by the bank ledger (a term loan's interest goes to INTEREST ON TERM LOAN). If a tie stays, split the confidence, so it shows yellow or red.
MediumCash rules miss "SELF-CHQPAID" and rate ATM too low
- What happens
- The cash rule needs SELF with the word CHQ or PAID (
server/ledger_signals.go:314). This bank prints "CHQPAID" as one word, so the rule does not see it. ATM withdrawals ("ATW-…") are found, but shown at 69% (yellow).
- Evidence
- 14 SELF cheques (₹8.4 lakh) started with no suggestion from the server; only the Miracle history helped 4 of them. 3 ATM withdrawals at 69% were left unsaved and went to Suspense.
- Fix
- Read glued forms (CHQPAID, CHQPAIDSELF). Give ATM/ATW/NWD rows their own confidence row, measured in the replay; it should be above 90%.
LowThe filled-in suggestion is not always the most likely
- Evidence
- "ITD TAX REFUND … (the owner's name)": the box showed a person's ledger at 78%, while the third choice was 88%. All three were wrong: the user chose INCOME TAX TDS 2025-26. Recommendations are ordered by rule, not by confidence.
- Fix
- Read "ITDTAXREFUND" / "TAX REFUND" as the income-tax category. Order the list by confidence when the rules give different numbers.
LowA masked UPI ID is learned from its last letters
- Evidence
- "UPI-GSTPAYMENTS-*****************MENT@HDFCBANK" was learned as the UPI ID
ment@hdfcbank and exact-matched once (to the right ledger). Any other masked ID that ends in "MENT@HDFCBANK" would match it too.
- Fix
- Do not learn a UPI ID that follows a run of * or X.
LowTracking counts single modifier keys
- Evidence
ui.keys holds "Alt+Alt", "Ctrl+Control" and "Ctrl+Shift+Shift": a press of Alt or Ctrl alone. This is noise in the shortcut counts, not a matching bug.
- Fix
- Skip key events whose key is itself a modifier.
Suspected from the code, not seen in the data (5)
- An entry that loses its exact match after the split is put in Suspense, because the server sends no suggestions for an entry that had a choice (
ledger_match.go:1546) and the split is already fixed.
- An exact match the server has not saved yet is removed from the suggestions (
decide, ledger_match.go:1245), so the entry can get a weaker suggestion or none.
- Exact name matches do not check the direction or group (a customer's name on a payment still saves).
- Short two-word names such as "Ram Traders" or "Jay Enterprise" can exact-match.
- A hidden copy of an entry in an overlapping PDF can be matched again after the user clears it (
entry_ledgers.go:434).
The 21 entries that went to Suspense with a suggestion
| Entry (shortened) | Count | Amount | Suggestion shown | Where |
| SELF cheque paid (cash withdrawal) | 10 | ₹5,90,000 | Cash Account, 97% | Suspense step, after the user saved one |
| Cheque deposit, JAY BHAGVATI DYEING… | 1 | ₹1,60,000 | JAY BHAGVATI DAYING & PRINTING WORK, 95% | Suggestions step |
| Transfer from SIDDHESHWAR COTTON PRINTS | 1 | ₹1,00,000 | SIDDHESWAR COTTON PRINT, 61% | Suggestions step |
| Cheque paid to JAYART | 1 | ₹49,952 | JAY ART, 97% | Suspense step, after the user saved 1 |
| ATM withdrawal | 3 | ₹40,000 | Cash Account, 69% | Suggestions step |
| IMPS from SHIVSHAKTI ART | 1 | ₹30,000 | SHIV SAKTI ART, 97% | Suspense step, after the user saved 2 |
| GST paid through BillDesk UPI | 2 | ₹8,708 | GST Provisional A/c., 72% | Suspense step, after the user saved 1 |
| Petrol pump UPI | 2 | ₹840 | BIKE FUEL EXPENSES, 97% | Suspense step, after the user saved 2 |
| Total | 21 | ₹9,79,500 | | 7 in Suggestions, 14 in Suspense |
3What can be done better
Users chose a real ledger by hand for 18 entries. The matcher could find 15 of them with better rules. The other 29 Suspense entries with nothing known are mostly small UPI payments to people with no ledger in the books; they may be right in Suspense.
| Bank text (shortened) | User chose | Why the matcher missed it | Rule to add |
| UPI GOODSANDSERVICESTAX…, UPI GST PAYMENTS (BillDesk), NEFT RESERVE BANK OF INDIA … GSTPMT | GST Provisional A/c., GST A/C ×4 | The GST rule does not read these forms. | GST category for GOODSANDSERVICESTAX, GST PAYMENTS, GSTPMT, RBI GST. |
| CHQ PAID … JAYART; IMPS … SHIVSHAKTI ART; CHQ PAID … OLYMPICDYESTUFF; … KISHANENTERPRISE; CHQ PAID … HAZIKRPATRADERS | JAY ART, SHIV SAKTI ART, OLYMPIC DUE STUFF, KISHAN ENTRPRISE, HARIKRUPA TRADERS ×5 | Short glued names, and names that the bank or the books spell differently. | Compare with spaces taken out, allow one or two letters off. Suggest only, never auto-save. |
| NEFT … UNION ASHVIN … (to the owner's own savings account) | UNION BANK JETPUR S/A ×2 | Bank ledgers are never suggested, and choices of bank ledgers are not learned (ledger_match.go:589). | Learn bank-ledger choices as suggestions when no contra pair exists. |
| SELF-CHQPAID | Cash Account | Glued "CHQPAID" (bug above). | Read glued forms. |
| CHQ DEPRET-FUNDS INSUFFICIENT (₹1,60,000, same day as the deposit) | JAY BHAGVATI DAYING & PRINTING WORK | No rule for a bounced cheque. | A return of the same amount within 3 days gets the ledger of the cheque it returns. |
| ITD TAX REFUND … (owner's name) | INCOME TAX TDS 2025-26 | Found the owner's name instead. | Income-tax category for TAX REFUND / ITDTAXREFUND. |
| NEFT … APARNA … | Aparna Enterprises | One-word names do not match. | Suggest a ledger whose only distinctive word is the payee field. |
Other things seen
- A "same amount" clue from the Miracle books is weak. It was shown 3 times at 50%: once rejected, once right, and once probably wrong (a ₹50,000 credit that names the company itself, probably a transfer from its own HDFC account, was saved to Dee Ech Print N Pack Llp). Show it only in the list, not as the filled-in choice.
- The company's own name gives no suggestion. On ASMARK and TEJANI, rows that name the company itself got nothing. They are usually transfers between its own banks; list its bank ledgers.
- Loan statements need their own rules. On ASMARK's term-loan PDFs, "LOAN SANCTIONED" got an unsecured loan of another firm (69%), and the GST rows after each charge got nothing. A GST row printed right after a charge row should follow the charge.
4How the system can be improved
In order of value for the work. Gains are measured on the 168 exported entries; they are an estimate from one day.
- Export check for unsaved suggestions. Small change, app only.
Up to 21 entries (12.5%) leave Suspense. Suspense: 30% → about 17%.
- No cheque numbers in the payee pattern. Server, matching. Run
bun run matcheval before and after.
One choice then auto-saves every same cheque payee: 11 entries here, and all later SELF cheques. Fewer key presses, and nothing left behind.
- "Now suggested" in the Suspense step, with Ctrl+Shift+Enter. Rows stay where they are.
Covers the 14 entries that got a suggestion during review, also when the user does not export yet.
- New category rules: GST forms, glued cash, ATM confidence, tax refund, bounced cheque.
About 7 hand choices become suggestions; ATM rows become green.
- Ties: break them by direction, group and bank ledger; split the confidence when they stay.
Prevents wrong green choices between duplicate ledgers (debtor or creditor).
- Glued and misspelt names (suggest only).
About 5 hand choices become suggestions.
- Own name and own banks: suggest bank ledgers; learn bank-ledger choices as suggestions.
2 more here (the owner's own savings account), and fewer one-sided transfers.
- Keep measuring. The tracking events now give this funnel per import. Turn this page's queries into the first part of the admin view: exact / accepted / changed / left unsaved / Suspense, per server build. Add the production cases above to the replay corpus on this PC (
.local/, never committed).
Items 1–3 deal with the same 21 entries in three ways, so they do not add up. With them, Suspense goes from 30% to about 17% of entries, and from ₹12.27 lakh to about ₹2.47 lakh. Items 4–7 mostly save the user's time: about 15 of the 18 hand choices would be suggested.
5How this was measured
- Read-only SELECT queries on the production database (no changes), copied to this PC's
.local/prod-review-1017/. It is not committed.
- Sources: saved choices (
statement_entry_ledgers), exports, and 1,663 usage events (entry.suggested, entry.ledger, import.step, picker.search, books.suggested, export).
- "Had a suggestion" means the last
entry.suggested event for the entry named a ledger. The causes were checked by running the production matcher (commit f53c89a) on the same entries.
- "Right" for exact matches means that no user changed it and that it reads right. The books were not compared.
- Small sample: one evening, three accounts, 168 exported entries. One account is a test account.