Most tool sites publish a feature list. This page is the opposite: a short, dated record of the failures that made the tools better. It exists for two reasons. First, a claim that a tool is tested is only useful if you can see what the tests caught. Second, the honest answer to “why should I trust this converter?” is not a badge — it is a trail of bugs found, reproduced and fixed.
Why the site has no ad boxes yet
The layout used to render a dashed “Advertisement” frame wherever an ad could go. With no ad unit configured, every page showed empty frames that looked like a broken layout. That is a bad first impression for a reader, and an unnecessary one: an ad slot that has nothing to show should not reserve a visible box.
The component now renders nothing when no client or slot is configured. The AdSense script and
ads.txt remain in place, so the site is still verifiable; when real units are
created, the slots render and the existing layout rules apply. The site is intended to be
funded by advertising — see how the site is funded
— but a placeholder is not an ad.
Lesson: do not show a frame for a product that is not there. Reserve space when there is something to put in it.
The guide that shipped a NUL byte
A guide about invisible characters included shell examples such as
grep -nP '[^\x00-\x7F]' file.txt. The examples lived inside a JavaScript template
literal, where \x00 is not four printable characters — it is an escape that
produces a NUL byte. The same applied to \x7F, \xe2\x80\x8b and
\xc2\xa0. The published HTML contained a literal NUL and several mojibake
sequences, and the shell examples were wrong on the page.
Doubling the backslashes fixed the page. The release check now scans every rendered HTML file for NUL bytes, and the content audit passes with zero warnings. The guide's updated date moved to the day of the fix, because a silent correction is still a change.
Lesson: content is code. An escape sequence in a code sample needs the same review as an escape sequence in an engine, and the rendered output needs a byte-level check.
The date picker that spoke Chinese on an English page
The pages are written in English and declare lang="en", but a browser's native
date control does not follow the document language. It follows the browser's own UI language.
In a Chinese-language Chrome the date field showed Chinese year/month/day labels and the file
input showed a Chinese “choose file” label, which made an English page look half-translated
and, worse, made the format ambiguous.
The fix was to stop using the native controls where the locale leaks. Nine date fields across
the date-diff, age, week-number, invoice and receipt tools became plain
YYYY-MM-DD text fields with a small English calendar (Today, Clear, arrow keys,
Enter, Escape). Sixteen file inputs were wrapped by one helper that renders
“Choose file / No file chosen / Choose another file” itself while keeping the original input id
and drag-and-drop behaviour. The test suite now drives the calendar and asserts the file-picker
wording, instead of trusting the platform.
Lesson: a native control is not automatically the accessible choice when its language is out of your hands. If the format or the wording matters, own the control.
The text diff that ate 10 GB of memory
The first version of the text diff used a full longest-common-subsequence table. It produced excellent output on small inputs and was quietly disastrous on large ones. A 20,000-line comparison took about seven seconds and 1.5 GB of memory; a 50,000-line comparison would have allocated roughly 10 GB and crashed the tab. The page's FAQ claimed the input was capped. It was not. A comment is not a limit.
The rewrite trims the common prefix and suffix first, then falls back to a linear line-by-line
diff when the edited region is too large for the quadratic table. The same 20,000-line case
went from 7,023 ms to about 10 ms. The detailed diff functions now return a
linearised flag, so the page can say when the result is an approximation instead
of implying that every line was matched optimally. The FAQ was corrected in the same change.
Lesson: test the resources a tool consumes, not only whether the output looks right. A correctness test on a small input will never find the allocation that kills the tab.
The copy button that said “Copied!” when it had not
The copy feedback component showed “Copied!” as soon as the click handler ran. It never checked
whether navigator.clipboard.writeText resolved, and it had no fallback when the
Clipboard API was missing. In a browser that denied the permission, or on a page where the API
was unavailable, the interface claimed success while the clipboard still held the old value.
The wrapper now awaits the write, falls back to a hidden textarea and
execCommand('copy') when the API is absent, and reports a failure instead of a
success when both paths fail. Three states are exercised in the tests: normal, API missing and
permission denied. The accessor is also protected so a later edit cannot bypass the check and
show the old unconditional message again.
Lesson: a success message is a claim about an operation, not a reaction to a click. Tie it to the result.
An emoji is not seven characters
The counter counted JavaScript string length, so the family emoji 👨👩👧👦
counted as seven. That is technically the number of code points, but it is not what a reader
means by “characters”, and it is not what a text field with a character limit counts either.
The page now reports grapheme clusters through Intl.Segmenter alongside code
points and UTF-8 bytes, and names each one. The point is not that one number is correct and the
others are wrong; the point is that “character” is ambiguous, and a counter that hides the
ambiguity is easy to misread.
Lesson: when a unit has more than one meaning, show the meanings and label them. Do not pick one silently.
Why this is public
None of these entries is a marketing story. Each one is a case where the site was wrong, a reader could have been misled, and the fix is visible in the code and the tests. If you find a case that is still wrong, the feedback form and the contact page both reach the same person. A confirmed bug is added to the test set before it is fixed, so the same mistake cannot return silently.
The longer standards explanations are in the guides; the test layers and the limits of those tests are on the methodology page.