X-ray and rebuild of a public Access warranty app
We ran our full method on a real Microsoft Access app that its author published as open source. The X-ray found 3 confirmed defects, 10 potential ones and 2 decisions for the owner. We then rebuilt the whole app and checked it against 1,574 results recorded from the original.
This is a technical demonstration of our discovery and verification methodology, not a completed customer migration. Nobody commissioned it, nobody uses the rebuild, and it isn't deployed.
| The app | Warranty claims and repair orders for a motorcycle dealer's service department, Microsoft Access, built 2003–2012 |
|---|---|
| Size | 8 forms, 25 queries, 20 tables plus 1 linked file, 3 reports, about 2,900 lines of VBA |
| Data in the copy | 14 repair orders, 21 warranty claims, 93 part and labour lines, 22 customers |
| Business rules | About 45, each catalogued with where it lives in the app |
| Findings | 3 confirmed, 10 potential, 2 decisions; plus 3 usability bugs and 5 defects in code nothing calls |
| Rebuilt | Every screen and live rule, in Django and PostgreSQL. How it was checked |
On this page:The sourceFindingsHow we checkedThe rebuildFound while rebuildingDecisionsCost
The source, and what we changed
The app is ob080270/Husqvarna-Warranty on GitHub, published by its author under the MIT licence. We chose it because it's public: anyone can check our findings against the original. It isn't a client project. Legacy X-ray has no connection with the app's author, its users, or the brand in the repository's name.
We changed the data only, never the code, queries or forms:
- Replaced with test values: customer names, addresses and birthdays (the year was kept), 6 staff usernames, number plates, engine numbers, and dealer names, phones, addresses and bank details, plus long digit runs in free text. The author had already replaced VIN serials, customer phones and dealer emails.
- Checked afterwards: none of the 232 original identifying values survive, all 5,074 data cells the business rules use are unchanged, and both recorded scenarios give identical results before and after.
- Environment: the app ran in a dedicated Windows virtual machine with 32-bit Access. We set a Ukrainian system locale so its Cyrillic text displays correctly, as it would have for its original users. Its amounts are in hryvnia, Ukraine's currency.
What the X-ray found
Every finding is classified. Confirmed: we reproduced it in the original app and its consequence is shown. Potential: it's in the app, but we haven't reproduced its consequence (often because the shipped data never triggers it). Decision: behaviour the owner should choose to keep or change.
| Status | Finding | What it can cost | Evidence |
|---|---|---|---|
| Confirmed | Warranty tags always print claim #15 (the number is hard-coded in the tag query) | Wrong parts tagged for return. 9 of 21 claims affected. | The original's own query, run on the shipped data |
| Confirmed | The exchange-rate table is a link to a file on the original developer's PC | No default rate on any other machine | The link fails when the app runs anywhere else |
| Confirmed | That file stores every rate divided by 100 (found while rebuilding) | Where the link works, every new repair order defaults to 0.435 per euro instead of 43.51. A wrong reimbursement wasn't reproduced: see below. | Reproduced in the original app |
| Potential | Every price, rate and quantity is stored as a 32-bit float | Stored amounts drift from what was typed (10,433.48 is held as 10,433.4801828861); no wrong total found in the shipped data | Database file, running app |
| Potential | Repair-order totals add lines from any other order with the same number | Wrong totals once order numbers repeat; none repeat in the shipped data | Database file |
| Potential | Screen and printout round differently | Screen and paper can disagree by 0.01; they agree on every shipped claim | Database file |
| Potential | The audit field records the Access user, which is "Admin" without user security | Nobody could tell who marked a claim as filed. Older records still show real users: the trail broke when the app was converted to the newer file format, which dropped Access user security. Not observed in a run. | Database file, data |
| Potential | Claim and customer numbers are "highest + 1" | Two people adding at once get the same number | Database file |
| Potential | Dates are typed with 2-digit years | From 2030, a typed "30" becomes 1930. Birthdays before 1930 can't be entered. | Database file |
| Potential | Part and labour lines have no primary key | Duplicate lines can't be prevented or told apart | Database file |
| Potential | Three input-loss bugs | Ticking a tag on a labour line wipes that line's edits; an unknown defect code erases the description; clearing a reimbursement leaves the old amount (that one can't happen through the shipped screens) | Form code, in the database file |
| Decision | Nobody can type a reimbursement on screen, yet every line has one | Who enters reimbursements, and where, is a question for the business | Running app |
| Decision | Codes are compared without regard to case, and a quarter of the defect categories are stored in lowercase | Keep (the rebuild does); changing it would split existing data | Data, running app |
Also found: the repair-order form opens editable when its own code says it should be locked (confirmed when we ran it); and, in the form code, a crash when searching for a claim that doesn't exist and an empty warning box after every customer save (potential). Five more defects sit in code that nothing calls.
How we checked
- Read the published code. 2,837 lines of VBA flagged 15 suspected problems.
- Extracted the real database file. That gave us all 149 objects, including the queries and form settings the code depends on. Two suspicions were false alarms (plate search and labour billing both work), and 10 new defects surfaced, among them the hard-coded claim #15 and the 32-bit floats.
- Ran the original app and recorded it. A suspected compile error turned out not to stop the app, and the repair-order form proved to open editable. Access itself recomputed the totals for all 14 repair orders and 21 claims, which became the reference results.
- Rebuilt it and compared. Two findings surfaced only then: the exchange-rate file's values, and the reimbursement field that nobody can type into.
Every finding above was checked in the database file itself, which holds the forms' code as well as the data, not just in the published code. The two false alarms never reached the report.
The rebuild, and how it was checked
We rebuilt every screen and every live business rule as a Django web app on PostgreSQL, then checked it against the original. The expected answers weren't written by us: Access itself produced them, by running the original app's own queries, lookups and reports on the anonymised copy.
| Part of the app | Rebuilt? | Checked against the original |
|---|---|---|
| Customers, motorcycles and search | Yes | Every recorded search returns the same customers |
| Repair orders, claims, part and labour lines, money totals | Yes | 133 of 133 money totals match; lists, lookups and find-by-claim match |
| Defect-code picker (Russian and English) | Yes | Groups, lists, search and descriptions match |
| Warranty-admin screen | Yes | List order and every computed field match |
| Warranty labels and the claim printout | Yes | Printed data, line order and totals match (labels for the claim on screen: defect 1 fixed) |
| Email notifications | As drafts | Same recipients and subjects; the person reviews and sends them, as in the original |
| Reimbursement entry | Read-only | As in the original, where the field is disabled; how reimbursements get in is an open decision |
The numbers: 1,574 of 1,574 recorded results and 133 of 133 money totals match, and 70 automated tests pass. Recording the original a second time, after restarting the machine, gave byte-identical results. As a check on the checks, we deliberately broke the rebuild in 16 different ways, re-introducing the original's defects and plausible mistakes, and the tests caught every one.
What the tests do and don't check. Of the app's 44 business rules, 20 are checked against behaviour recorded from the original, 21 against our written catalogue of the rules (our reading of the code, which the owner would sign off on a real project), and 3 (cursor placement and the clearing of search boxes) have no automated test. Each sign-off decision has its own test.
Not yet validated: how the screens and printouts look next to the original (layout isn't tested), several people using it at once in real work (conflicting edits are detected and refused, and tested, but no team has used it), deployment to a real server, and moving a live customer database across. Nobody uses this rebuild; it isn't deployed.
The tests earned their keep. The first money run matched 125 of 133: the original keeps each converted reimbursement line to 4 decimal places and rounds only the total, while our first migration rounded every line. Nobody would have spotted that on screen. Keeping 4 decimal places fixed it.
Found while rebuilding
- The exchange-rate spreadsheet stores every rate divided by 100. The app's link to it only works on the original developer's PC (defect 5). We pointed it at the same file in our test machine: the app read 0.435 for the euro instead of 43.51, and every new repair order took that rate as its default. That much we reproduced in the original app. We could not reproduce a wrong reimbursement, because of the next finding.
- Nobody can type a reimbursement on screen. The field is disabled in the original, yet all 93 lines in the data carry one, so they were entered some other way. Who enters reimbursements, and where, is a question for the business.
- About a quarter of the defect categories are stored in lowercase, and 7 of 21 claims carry lowercase codes. The original ignores case, so nobody ever noticed; the rebuild had to do the same.
Keep or fix: the decisions
Copying the old app blindly would also copy the claim #15 tags. So before the rebuild, each defect got a decision, under one policy: fix anything that corrupts money or data, crashes, or loses input, and keep interface quirks as they are. The tests check the decided behaviour, while the recordings keep the old behaviour as evidence. For this sample, we made those decisions ourselves, acting as the client. On a real project, you make them.
What this says about price
Not a price, yet. The rebuild took our engineering tools well under an hour of working time once the method existed, but that leaves out the parts a customer project adds: our review, your sign-offs, moving your live data, deployment and two weeks side by side. Until a customer project has been delivered, we won't quote this sample's size as a price.
For a real app, the diagnostic establishes the full scope, timeline and fixed price before implementation begins. Rebuilds start at $6,000 for smaller applications.
The full sample report is available on request: [email protected].
Want the same for your app?
Send us one app for a free X-ray. You get the report two business days after we accept your submission.