Engineering Notes

A support chatbot needs to be designed for what it won’t answer, not just what it will

A support chatbot needs to be designed for what it won’t answer, not just what it will Background The support chatbot on our landing page has a simple job: answer questions about the product’s features, pricing, and troubleshooting. But a conversational AI built to answer questions shares a common weakness. Left unguarded, it tends to comply with requests designed to surface its own system prompt verbatim, or with phrasing that falsely claims special authority to unlock a different kind of answer. The chatbot works by feeding a knowledge base file to the LLM as its system prompt, then letting it answer whatever the user asks. Rather than implementing this defense …

Read more
Engineering Notes

The free plan wasn’t actually “no registration required” — fixing a landing page claim that contradicted itself

The free plan wasn’t actually “no registration required” — fixing a landing page claim that contradicted itself Background An external marketing review flagged what looked like a contradiction in our landing page’s FAQ. Checking it against the actual code confirmed the claim was accurate. Two statements coexisted on the same page: Quick Start, step 2: “Register with your email to start for free” The FAQ answer: “The Free plan requires no registration and allows up to 1 site, 3 runs per month — completely free.” One says “please register.” The other says “no registration needed.” Checking the implementation confirmed that the Free plan requires an email address to be registered …

Read more
WordPress Maintenance

Comparing pricing models across four WordPress maintenance tools — what the shape of a price reveals about cost structure

Comparing pricing models across four WordPress maintenance tools — what the shape of a price reveals about cost structure Background While surveying the major WordPress maintenance tools (ManageWP, MainWP, WP Umbrella, and InfiniteWP), one thing stood out once their pricing was laid side by side: this isn’t just a matter of “cheaper vs. more expensive.” The shape of the pricing itself differs completely from company to company. And that shape isn’t arbitrary — it closely mirrors how each company actually delivers its service. Four companies, four pricing shapes ManageWP: free core, stacked per-site add-ons The core dashboard is free. Features like Backup, Security, Reports, and White-Label are sold separately as …

Read more
Engineering Notes

A tabbed form that silently refused to submit — required fields hidden behind another tab

A tabbed form that silently refused to submit — required fields hidden behind another tab Background The site edit modal kept accumulating fields — site name, category, SSH connection details, WordPress install location — until editing anything meant scrolling up and down a single long form to find the right field. To clean this up, we split it into three tabs: “Registration info,” “SSH,” and “WordPress info.” That change broke form submission itself, in a way that was hard to spot at first. What tabbing broke The tab implementation itself is straightforward. Each tab’s fields live in a <div class=”site-tab-content” data-tab=”…”>, and CSS toggles which one is visible. .site-tab-content { …

Read more
Engineering Notes

SPF, DKIM, and DMARC together — why the missing DMARC record was blocking registration emails

SPF, DKIM, and DMARC together — why the missing DMARC record was blocking registration emails Background Registration confirmation emails were not reliably reaching users on Gmail and Outlook outside Japan — sometimes landing in spam, sometimes not arriving at all. Investigation pointed to a single root cause: the wpmm.jp domain had SPF and DKIM configured, but no DMARC record. What each of the three does SPF (Sender Policy Framework) declares in DNS which IP addresses are authorized to send mail for a domain. Receiving servers check the sending IP against the SPF record to confirm the source is legitimate. DKIM (DomainKeys Identified Mail) adds a cryptographic signature to the message …

Read more
Engineering Notes

Resuming email verification after the app is closed — the pending_email state that prevents re-sending

Resuming email verification after the app is closed — the pending_email state that prevents re-sending Background On first launch, the desktop app asks the user for an email address, sends a confirmation email, and completes registration once the user clicks the link in that email. There was a trap here for anyone who closed the app before clicking the link. Email does not always arrive immediately. Closing the app with the intention of clicking the link once the email shows up, then reopening later, is a perfectly natural way to use it. But on restart the app decided that registration was still incomplete and showed the first-launch screen (the email …

Read more
Engineering Notes

The cp932 crash in the build gate that only happened on Windows — static detection, behavioral testing, and a negative check

The cp932 crash in the build gate that only happened on Windows — static detection, behavioral testing, and a negative check The symptom During the Windows build for v1.6.11, the build gate reported “version number consistency check failed.” But the version numbers were correct everywhere. The real cause was not a version mismatch. The build gate in build_app.py calls tools/bump_version.py via subprocess and checks its exit code. The success messages in bump_version.py contained emoji (✅ and similar). On Japanese Windows, the default code page is cp932, which cannot encode those characters. Python raised a UnicodeEncodeError on the very first write to stdout, the process exited non-zero, and the build gate …

Read more
WordPress Maintenance

The excluded-plugin setting that Playwright ignored — fixing browser-mode updates and false residual warnings

The excluded-plugin setting that Playwright ignored — fixing browser-mode updates and false residual warnings The symptom In browser-mode maintenance (Playwright, no SSH), plugins marked as “excluded from update checks” were still being updated. After the run, a “plugin updates remaining” WARNING email arrived every time. The excluded plugins were intentionally left behind, but the residual check treated them as unfinished updates and fired a warning — a two-part problem: wrong behavior and a misleading alert. SSH path vs. Playwright path On SSH-capable sites, WP-CLI’s –skip-plugins flag carries the ignored_plugins list into the update command. That path already excluded them correctly. The Playwright path was different. browser_update_remaining_plugins() worked by clicking the …

Read more
Engineering Notes

Site list scrolls to top on every delete — fixing the missing keepScroll argument across 6 call sites

Site list scrolls to top on every delete — fixing the missing keepScroll argument across 6 call sites The symptom Every time a site was deleted from the WordPress Maintenance Manager site list, the page jumped back to the very top. In environments managing many sites, removing an item in the middle of the list forced users to scroll back down before they could act on the next one. The same behavior occurred in five other operations: drag-and-drop reordering, thumbnail fetching (running behind an open modal), category deletion, tag deletion, and after maintenance completion. Root cause: omitting the keepScroll argument The fetchSites() function accepts two arguments: keepPage and keepScroll. When …

Read more
Engineering Notes

When maintenance ends with an error, the plugin update badge disappears — designing a backend marker and frontend count sync

The WordPress maintenance tool shows a badge on each site card when there are pending plugin updates. Under normal operation, when maintenance completes successfully, the badge clears until the next dashboard scan picks up fresh data. That’s correct behavior. But a report came in: when maintenance ends with a warning or an SSH error partway through, the badge disappears even if plugins were left unupdated. “If the update didn’t finish, I need to know — but the badge is telling me there’s nothing left to do.” Why the badge was disappearing Tracing the bug, the root cause was in the frontend badge-update logic, which was built on a hard-coded assumption: …

Read more