← Henry Nawrocki · SAMPLE AUDIT

Explore the interactive case →

Your system is telling you a story. I measure it.

A claims-vs-reality audit, run on my own platform. Public summary of the findings and their limits.


A production system can work while the information used to operate it is wrong. These three cases from DiTrack show how I compare a claim with an observation, separate findings from hypotheses, and identify a check that can flag future drift.

This is a public summary, not a complete client evidence pack. It illustrates the method without publishing operational logs or device identifiers.


Findings at a glance

These are historical observations from my own platform, summarized for public review. Raw logs, queries and device identifiers are not published here, and the observations have not been independently reverified. A client deliverable includes reproducible evidence within the agreed access and confidentiality boundaries.

Claim Reported observation Evidence basis Confidence and limits Consequence Follow-up check
The tracker dies at a reported battery percentage Transmission stopped at 3,596–3,632 mV while buffering continued 14 silence episodes across six devices; parameter readings Observed in this sample; internal cause and battery health remain unproven Review the displayed battery interpretation before replacing hardware Voltage alert, with delivery and threshold validation
The mirrored parameter reference is complete Offline counts of 388/388/398 versus live counts of 558/573/599 Comparison of mirror and live expansions for three models Demonstrates a gap in these snapshots, not all vendor references Rebuild the affected reference from a current source Check source revision before use
Architecture documentation matches production Dead target, absent columns, wrong connection mechanism and stale status Commands cited in six documents compared with production Covers the inspected documents and commands only Correct the documents before relying on them for changes Re-run selected evidence checks and review changes

Case 1. The tracker that "dies at 26% battery"

The claim. Our own internal doctrine had one line: "a02 = battery % via AVL 113." Field units on internal battery were going silent while reporting around 30%. Everyone read it the same way: the battery dies early, the hardware is weak, replace it.

The measurement. I pulled 14 silence episodes across 6 devices, from the device buffers and from parameters read off the units themselves.

Without external power a unit transmits for 78 to 97 minutes. Somewhere between 3,596 and 3,632 mV the modem goes quiet. Real power-off happens much later, at 3,401 mV, and one device proved it: last frame at 3,401 mV, then a version query 68 minutes afterwards came back showing an init. A reboot. Between those two thresholds the unit keeps logging to its buffer at the exact same cadence. In these observations, loss of transmission preceded the final recorded power-off. The platform stopped hearing a device that continued buffering.

And AVL 113 was never charge. It's voltage, quantized in steps of 10, on two different curves: 3,757 mV reads 70 while discharging and 10 while charging. Above roughly 3,950 mV it pins at 100. That "30%" at silence was a voltage reading wearing a percent sign.

Alternative explanations and limits. Parameter 102 read 0 (sleep disabled); recorded cadence changed from 50.5 to 55.4 seconds. Charging voltages of 4,069–4,125 mV do not establish battery capacity or rule out degradation. Temperatures ranged from 27 to 43 °C; this sample alone does not rule out temperature effects. Controlled discharge testing would be needed to separate these causes.

Second path. I pulled the vendor's firmware changelog, revision 112907 (April) to 116488 (August), covering 3.7.0 to 3.7.3. No version mentions a low-battery threshold or a modem cutoff by voltage. Units on 3.7.0 and units on 3.7.3 go quiet in the same band. This is consistent with a threshold-related behavior absent from the reviewed changelog; it does not establish the firmware’s internal cause. The changelog also cleared a separate myth: a "DOUT1 stuck" bug we had blamed on 3.7.0 was already fixed in 3.7.0 and only triggers in a flow we don't use.

The delta. One wrong line in our own doc, plus one undocumented behavior in someone else's firmware. Together they produced a hardware replacement plan for a problem that needed a config decision and an alert.

Tripwire left behind. A read-only poller that logs real millivolts, and an alert when any unit on internal battery crosses 3,650 mV. The threshold is intended to warn before the observed silence band. Sampling intervals, connectivity and alert delivery must be tested; warning is not guaranteed.


Case 2. The reference that was 30% incomplete and looked whole

The claim. Our parameter database for one device family was complete. Built by me, from a mirror of the vendor's wiki, with no reason to doubt it.

The measurement. The mirrored template was revision 109672, from December. The live page was revision 117278, edited that same morning. The revision IDs and dates showed that the snapshots differed; subtracting IDs does not tell us how many times this page changed.

So I expanded the parameter list both ways for three models, offline from the mirror and server-side from the live wiki. Offline gave 388, 388 and 398 parameters. Live gave 558, 573 and 599. Zero of the offline ones were invented; everything it produced exists. Roughly 30% was simply missing, and two models came out identical when one of them carries Bluetooth parameters the other doesn't have. Another 26 values differed, and none of that was my method. Nine months of wiki edits: a maximum going from 1 to 2, a minimum from 0 to 1.

Separately, 776 parameters for the family had never entered our index at all. Not a scraping failure. The indexer's prefix list didn't include the family, so the parser never looked.

The lesson, in one line. A sound method on a stale source produces incomplete data with a complete face.

The delta. The vendor had also changed the mechanism. The template now resolves through 251 conditionals in a server-side Lua module, and the pin table it used to read no longer exists. Our existing offline expansion no longer reproduced the live result; a different offline implementation would need validation against the current server-side dependencies. That went into the doctrine so nobody retries it by hand.

Tripwire left behind. A revision check against the live page before any parameter from the mirror is trusted. Cheap. Runs before the work, not after.


Case 3. Six architecture docs, measured against production

The claim. The architecture documentation was current. Most of it was mine, and recent.

The measurement. Every command each doc cited, re-executed, answer compared to the prose.

One alert-flow doc pointed at a server that had been destroyed months before. A contracts doc declared 7 columns the table doesn't have. One diagram drew a TCP edge between two services where the real mechanism is a row inserted into a table that a poller reads. And a monitoring doc said "not wired" about a service that had been live since April.

Six docs. Four types of discrepancy: dead target, phantom schema, wrong mechanism, stale status.

The delta. None of these were bugs. Every service was working. The map was wrong, and a map that's wrong in four different ways trains the next engineer to break production with confidence.

Tripwire left behind. A drift detector that hashes one verifiable command per doc and runs daily. It never reads prose. It only says CHANGE, and which doc. Plus a verification queue that re-runs every cited command and rejects the doc if the evidence doesn't reproduce.


The pattern

I look for four recurring sources of discrepancy:

  1. Intent presented as measurement. A field you wrote (cut = true) shown as a state you observed (the relay is cut). Dashboards are full of these.
  2. Docs describing a past system. Accurate the day they were written. Never touched again.
  3. References that moved silently. Vendor wikis, API docs, changelogs. Your copy was right. The world changed.
  4. Fluent output nobody verified. This is the new one. Code, docs and answers written by AI agents read as finished. In 2026 most teams have a lot of it and no apparatus for checking it.

The fourth is why I'm writing this page. I run an AI partner on my own systems every day. Early on it wrote me that confident, fictional analysis. So I built the rules it lives under: three classes of claim (inference, conditional, evidence), no "done" without an artifact, corrections that outrank facts in its memory, a truth cache for every volatile number. I use that machine daily. I would build you a smaller one.


Henry Nawrocki. Founder of DiTrack, a fleet-tracking business in Peru, with hands-on platform engineering since 2025. Previously VP of AI & Engineering at Target Test Prep. Ruby on Rails, Python, PostgreSQL, GPS integrations and production operations. Based in Lima, Peru.

The offer

Claims-vs-reality audit. Two weeks, one operator, one system. Fixed scope and fee agreed after a 20-minute call.

  • A findings table comparing agreed high-risk claims with observations, evidence and confidence
  • The measurements behind each finding: the command, query or reading that produced it
  • An agreed automated check, installed and tested with your team, with ownership and maintenance instructions
  • A 90-day action list prioritized by operational impact

Scope: One production system and a written set of high-risk claims agreed before work begins. The two-week engagement starts once the required read-only access, evidence and technical contact are available. Changes to production checks require your approval. Ongoing monitoring and maintenance are separate from the engagement.

Good fit: Teams with a production system and an important decision held up by conflicting dashboards, stale documentation or unverified AI output.

Outside scope: Ongoing backlog delivery, a full code rewrite or a comprehensive security or compliance audit.