# Pilot Readiness Pack

**Retail Pharmacy Platform · Ten-store pilot**
**Caresoft Systems Private Limited · v1.0 · 28 August 2026**

Companion to `retail-pharmacy-platform-SOW-v1.md`. Where the two disagree,
this document wins — it reflects what the build actually found.

---

## 1. Where the build stands

| | |
|---|---|
| Test suites | **49 suites, 1,602 assertions**, all passing against live databases |
| Screens | **15**, and every one is executed under jsdom, not just parsed |
| API | **86 routes**, every one called by a smoke test; none returns a 500 |
| Schema | **25 packs, 108 tables** |
| Counter Helper | **compiles and runs.** Raw printing still never executed — see 2.3 |
| Cold start | package → install → shop → sale → backup → restore → invariants, in one suite |

**Measured on this build, re-measured on every run:**

| Metric | Budget | Measured |
|---|---|---|
| Keystroke to suggestion, 20k catalogue | 50 ms | **1.6 ms** |
| Bill commit, p95 | 200 ms | **2.6 ms** |
| Four-line bill, p95 | 200 ms | **5.0 ms** |
| Slip render | 5 ms | 0.13 ms |
| Purchase auto-match, learned | ≥90% | 100% |
| Three tills billing at once | no failures | **120 of 120, zero errors** |

`tests/test_perf.php` fails the build if a budget is exceeded, so these
are current rather than remembered. The earlier version of this table
claimed a 6.4 ms commit from a measurement taken months before the bill
path grew loyalty, cross-sell and print queueing.

Those numbers came from a laptop against MariaDB. They will be worse on a
2015 shop PC with a spinning disk. Re-measure on real hardware before
believing them.

---

## 2. What must happen before store one

These are gates, not tasks. Nothing goes live until each is closed.

### 2.1 Legal — start this week, these have lead times

| # | Item | Owner | Why it blocks |
|---|---|---|---|
| L1 | **Counsel reviews the ex-Marg sales head's engagement letter** | You | Non-compete, non-solicit, confidentiality. His contribution must be documented as domain knowledge and market judgment only. No Marg customer lists, pricing data, source or internal documents enter this project — ever, including "just for reference". |
| L2 | Counsel confirms the **migration export path** in writing | You | We import files the chemist exports from his own licensed copy. We never parse a competitor's file format. Get this blessed before a partner improvises. |
| L3 | Counsel reviews the **Phase 2 consumer structure** | You | Chemist as seller of record, sale at licensed premises, no title to stock, geo-fencing to licensed area, pharmacist verification gate. Must be signed off before a single consumer order. |
| L4 | **Payment aggregator selection and onboarding** | You | Cashfree Easy Split vs Razorpay Route. Split settlement only — Caresoft never holds customer funds. Onboarding a marketplace flow takes weeks. |
| L5 | DPDP consent language reviewed | You | The consent text shown at counter and storefront is what a regulator reads. |

### 2.2 Meta / WhatsApp — submit now, approval takes days and can be refused

Submit these four templates immediately. The unapproved-template gate is
tested and working, which means an unapproved template simply will not
send — you will be blocked at pilot, not at scale.

| Template | Category |
|---|---|
| `INVOICE` | Transactional |
| `ORDER_RECEIVED` | Transactional |
| `PAY_LINK` | Transactional |
| `REFILL_DUE` | **Marketing** — must carry the STOP line in the body |

### 2.3 Counter Helper — compiles, runs, has never printed

It is no longer unverified. It compiles (one missing `using` in 788
lines), starts, generates its own token, refuses unauthenticated calls,
and answers `/v1/health`, `/v1/printers` and `/v1/spool`. Running it
found two faults that reading it had not: health reported `OK` while the
printer was unreachable, and the error was eight lines of .NET loader
paths. Both fixed.

**What is still untested is the only part that matters.**
`DllImport("winspool.drv")` binds at runtime, so the raw-printing path
compiles and has never executed — there is no Windows here. The
self-contained win-x64 exe has never been built either; that needs a
NuGet feed this environment cannot reach.

So the physical work below is unchanged:

- **Five genuinely old LX-300 units sourced from real shops**, not new
  stock. Clone firmware varies and that is where the surprises live.
- The three cheapest 80 mm thermal units on the local market, not the
  reference model.
- A **counter assistant — not a developer** — billing 50 real customers
  during an evening rush.
- **Timed side by side against Marg, same hardware, same shop.**

> **Kill criterion.** If we are not faster at the counter, stop the
> roadmap and fix it before anything else proceeds. Nothing in this
> product matters if the slip is slower than what the chemist already
> has. This is not negotiable and it is not a "we'll optimise later".

### 2.4 Data

| # | Item | Note |
|---|---|---|
| D1 | **Drug catalogue source decided** | Licensed dataset, built in-house, or partner-supplied. On the critical path — everything downstream waits on it. |
| D2 | DPCO ceiling list loaded | The counter refuses to bill above ceiling. Wrong data here blocks legitimate sales. |
| D3 | Catalogue quality spot-check | 200 random SKUs verified against physical packs by someone who knows drugs. |

### 2.5 Commercial

| # | Item |
|---|---|
| C1 | **Unit economics signed off** (SOW §10.2). If contribution margin does not clear cost-to-serve at a realistic support rate, cut scope — price is capped by the market. |
| C2 | Partner commercials agreed: recurring share, term, migration incentive |
| C3 | Partner agreement includes the clauses in §5 below |

---

## 3. Go-live runbook — one store

Target: **one afternoon, one partner engineer, no Caresoft attendance.**

### T-7 days — the shop's homework

- [ ] Owner runs the stock export from his current software. Full export,
      all categories, all locations.
- [ ] Owner runs customer and supplier exports.
- [ ] Owner writes down his **closing stock value at cost** on paper. This
      is the number that gets checked in step 6 and he must produce it
      *before* seeing ours.
- [ ] Partner confirms: printer make and model, number of counters,
      internet type, whether a second godown exists.

> The second godown question catches the single commonest migration
> failure. Stock held somewhere not in the export shows up as a 20%+
> variance and a chemist who thinks the software cannot count.

### Day 0 — install, about 3 hours

| Step | Time | Verified by |
|---|---|---|
| 1. Install node + Counter Helper, activate licence | 15 min | Licence returns the shop's details |
| 2. Confirm shop details, GSTIN, **both drug licences** | 10 min | GSTIN checked against the portal |
| 3. Printer setup, **test print, read the ruler on the paper** | 20 min | Ruler does not wrap |
| 4. Catalogue download | 30 min | Search returns results in under a second |
| 5. Migration dry run, review exceptions with the owner | 45 min | **Rows lost = 0** |
| 6. **Owner compares opening stock against his own figure** | 20 min | Within 2% → go. 2–10% → investigate, then go. **Over 10% → stop, re-export** |
| 7. Number blocks, counter setup | 10 min | First bill number issued |
| 8. Bill three real customers with staff watching | 20 min | Slips print, correct amounts |
| 9. **Pull the network cable and bill again** | 10 min | Works. Staff see it work. |
| 10. Leave the printed F-key card on the counter | 2 min | — |

Step 9 matters more than it looks. Every chemist has been told "it's on
the cloud" and heard "it stops when the internet stops". Showing him
otherwise, physically, on day one, is worth more than any amount of
explaining.

### Day 1–3 — partner checks in by phone, not in person

- [ ] Day 1 evening: call. How many bills? Anything slow?
- [ ] Day 2: check the support log. Any contact at all is a signal.
- [ ] Day 3: confirm the first GST period is accumulating correctly.

### Day 7 — first review

- [ ] Sale register reconciles to the owner's own cash tally
- [ ] Purchase auto-match rate recorded
- [ ] Support contacts recorded
- [ ] **Ask the owner directly: what is worse than before?** Write down
      the answer verbatim. That sentence is your product roadmap.

---

## 4. Support playbook

### 4.1 Who does what

| Level | Who | Scope |
|---|---|---|
| L0 | In-app guides, WhatsApp bot | "How do I…" |
| L1 | **Partner** | Install, training, printer, hardware, user questions |
| L2 | Caresoft support | Data, sync, reports, GST, migration |
| L3 | Caresoft engineering | Defects, only via L2 |

**No on-site visits after go-live.** Contractual (§5). If a store needs a
visit within three months of install, that is a **product defect** to be
logged as such — not a service to be quietly absorbed.

### 4.2 Triage — most common first

| Symptom | First check | Usual cause |
|---|---|---|
| "Nothing prints" | `/v1/health`, then `/v1/spool` | Printer off or out of paper; job is spooled and will print |
| "Amounts are cut off on the bill" | Print a test, read the ruler | Template wider than the carriage. Pick a narrower profile. |
| "Stock doesn't match" | Rebuild balances from the ledger | Self-heals. Ledger is truth; balance is a cache. |
| "Negative stock" | Negative stock report | Two counters sold the last strip offline. Expected. Reconcile. |
| **"Try again" when saving a bill, more than once** | `bin/rx-worker run-job invariants.check`, look for `SEQ_ALLOCATOR_AHEAD` | The event allocator has fallen behind the log — a restore or an import inserted events without advancing `counter.last_event_seq`. **L2. Do not retry; it will not clear.** |
| **A screen comes up blank** | Version in the footer vs the release | Wrong files copied. Re-run `rx-install`. Every screen's JavaScript is parsed before release, so this is a deployment fault, not a code one. **Do not edit HTML on a counter machine.** |
| "Bill saved but no slip" | `/v1/spool` on the counter | The job is queued. `SENT` is not `PRINTED` — the Helper acknowledges only what actually came out. Paper, power, cable. |
| "The reorder list is the same every day" | Are purchase orders being **sent**? | A drafted order does not count as on-order until it is sent, so the same items keep being suggested. |
| "Points did not come off the bill" | Is the line a medicine? | Points never pay for prescription medicine. Working as intended; say so plainly to the customer. |
| "GSTR-2B shows credit we did not claim" | `/gst/reconcile-2b` for the period | A supplier filed late or not at all. This is the shop's money — chase the distributor, do not adjust the books. |
| "Purchase entry is slow" | Auto-match rate for that store | Alias table still cold, or the distributor sends no e-invoice |
| "Bill number jumped" | Number block, `is_fallback` | Counter exhausted its block offline. Flagged, reconcilable. |
| "Customer says no bill on WhatsApp" | `message_outbox` for that order | Template unapproved, consent withdrawn, or a permanent send failure |
| "GST return doesn't match" | Sale register vs GSTR-1 for the period | If these disagree, escalate to L3 immediately — it is a defect |

### 4.3 The one number that decides the business

**Support contacts per store per month.** Reviewed every Monday.

| Rate | Meaning |
|---|---|
| < 0.3 | On track. The ₹500/month model works. |
| 0.3 – 1.0 | Watch. Find the top cause and fix the product. |
| > 1.0 | The model is broken. Stop onboarding and fix before adding stores. |

Track it by *cause*, not by volume. Ten calls about one thing is one
product defect. Ten calls about ten things is a design problem.

---

## 5. Partner agreement clauses

These make the support-cost rules enforceable instead of aspirational.
Written as intent for counsel to draft properly.

1. **No customisation.** The Partner shall not represent that bill
   formats, reports or workflows can be customised for a Customer.
   Eight to ten fixed bill templates are the complete set. *(Rule S1 —
   this is the clause that will be tested first, by the first partner
   who loses a deal over it. Hold it.)*
2. **No on-site visits after go-live.** Install and training are the
   Partner's, once. Recurring on-site support is not part of the
   service. A Customer requiring repeated visits is escalated to
   Caresoft as a product defect.
3. **Self-service install.** The Partner installs using the setup
   wizard. Caresoft engineering does not attend installations.
4. **Migration is Customer-run.** The Customer exports his own data from
   his own licensed software. Neither Partner nor Caresoft accesses or
   parses another vendor's data files.
5. **No competitor confidential material.** The Partner warrants that no
   confidential material of any other software vendor is provided to or
   used by Caresoft.
6. **Customer data belongs to the Customer.** Caresoft does not
   disintermediate the chemist's customers. State this plainly in the
   sales conversation too — it is the category's biggest objection.
7. **Commission on non-medicine only.** No platform fee on any drug
   line, ever. Visible to the chemist on his own screen, per order.
8. **No exclusivity in year one.** Partners must be able to survive
   incumbent retaliation.

---

## 6. Pilot success criteria

Measured over 30 consecutive days, ten stores.

| # | Criterion | Threshold |
|---|---|---|
| 1 | Counter performance budgets met on real hardware | p95 within §1 |
| 2 | **Faster at the counter than the incumbent** | Timed, same shop |
| 3 | On-site visits after go-live | **0** |
| 4 | Support contacts per store per month | < 1.0, trending to < 0.3 |
| 5 | Data-loss incidents | **0** |
| 6 | Counter/cloud reconciliation defects | **0** |
| 7 | 48-hour WAN outage, clean reconnect | Pass |
| 8 | GSTR-1 includes both channels, one series | Pass |
| 9 | Migration opening balance vs owner's figure | Within 2% |
| 10 | Customisation requests accepted | **0** |
| 11 | Stores still live at day 30 | ≥ 9 of 10 |
| 12 | Owner would recommend it to another chemist | ≥ 8 of 10 |

Criterion 12 is the only one that predicts the next hundred stores. Ask
it in person, and accept the answer.

---

## 7. Ten-store schedule

Deliberately slow at the start. The first three stores exist to find what
the tests could not.

| Week | Stores | Purpose |
|---|---|---|
| 1 | 1 | Friendly shop, close by, owner tolerant of problems. Partner and Caresoft both present. |
| 2 | — | **Fix what store 1 found.** No new stores. |
| 3 | 2 | Two different printer models. Partner alone, Caresoft on call. |
| 4 | — | Fix. Confirm the support rate. |
| 5–6 | 3 | Partner alone, no Caresoft. First real test of the wizard. |
| 7–8 | 4 | Include one multi-store owner and one 2-counter shop. |
| 9–12 | — | 30-day measurement window. No new stores. |

> The temptation will be to compress this because partners are waiting.
> Do not. Ten stores installed badly in three weeks will produce a
> support load that convinces you the model does not work, when the real
> problem was the schedule.

---

## 8. What we will NOT do during the pilot

Written down so it can be pointed at, in a meeting, in month two.

- Custom bill formats — for anyone, at any price
- Per-customer code changes
- On-site support visits
- Live stock on the storefront (order-request only until data quality is
  proven over months)
- Commission on medicine
- New feature requests, unless they block a store from operating
- Adding stores while criterion 4 is breached

---

## 9. Findings that change the SOW

The build turned up five things worth carrying into v2. **A later
hardening pass turned up more, and they are worse** — every one was a
feature that was built, tested, and could not be used:

- **The double-entry ledger was never posted.** No route, no job. A shop
  would have reached its first GST filing with empty books.
- **No stock could enter the shop.** `purchase_invoice` existed and
  nothing could create one; a store could only sell what was seeded.
- **No bill could be printed.** The counter said "sent to the printer"
  while requesting nothing.
- **STOP did not work.** Every marketing message promises it and nothing
  could receive the reply — a DPDP obligation, not a feature.
- **Two tills could not bill at once.** Two thirds of bills refused under
  same-counter contention.

The common shape: **the reader existed and the writer did not.** 54
engine capabilities had no route, no job and no screen. That is now
enforced — `tests/test_reachability.php` fails the build if a new one is
stranded.

The lesson for v2 planning: a module passing its own suite says nothing
about whether anything calls it.

1. **MRP is not in the e-invoice schema.** Verified against the notified
   standard. `UnitPrice` is the purchase rate. A pharmacy cannot post
   inward stock without a per-batch MRP, so e-invoice alone can never
   complete a purchase. `BchDtls` is optional too, so batch and expiry
   frequently arrive empty. The honest target is not "zero typing" — it
   is auto-filling the 15 fields the standard carries and confirming the
   2 it cannot. Anyone who scopes this as fully automatic has not read
   the schema.
2. **Migration cannot read the incumbent's files.** Not a technical
   limit — a legal one, and materially sharper now that their former
   sales head works here. The Customer-run export path is the design,
   and it works.
3. **The incumbent already has a consumer channel.** Paas Ki Dukaan
   launched in 2021, plus a cloud product and a digital-health add-on.
   We are not first. Our differentiation is execution and economics, not
   novelty — and the fact that they have not cracked it in five years is
   the thing to investigate before Phase 2 scope is frozen. **Interview
   20 chemists who were pitched it and declined.**
4. **Accounting posting must stay out of the counter path.** Billing
   commits in 6 ms; double-entry posting runs afterwards off the event
   log. Never put ledger maths between a customer and their slip.
5. **Excel exports needed a real XLSX writer.** CSV destroys long batch
   and policy numbers permanently. Written, tested, 300 lines, no
   dependencies.

---

## 10. Open decisions

Still needed, in order of how much they block:

1. Drug catalogue source (blocks everything)
2. Unit economics sign-off (blocks build approval)
3. Payment aggregator (blocks Phase 2)
4. Hardware policy — bundle or agnostic
5. Partner commercials
6. Product name and brand
7. The 20 chemist interviews (blocks Phase 2 scope freeze)

---

## Appendix — the sentence to keep

> If a store needs a visit in the next three months, that is a fault in
> the product, not in the shop.

Everything in this document is downstream of holding that line.
