Bug Checks, Security Reviews, and Honest Logs
The process behind every PortSide release, and why it matters more than any single feature.
Part 3 of 3 in Building PortSide: A Developer's Field Notes

The process behind every PortSide release, and why it matters more than any single feature
A feature is not done when it compiles
It would have been easy to treat every PortSide feature as finished the moment its code was written and its interface looked right. I rejected that standard from very early in the project. Instead, I built a recurring set of habits around the actual feature work, all aimed at one goal: catching a real problem before it reaches someone relying on the app to reach a live server, move a real file, or store a real password.
The most basic of these habits is a simple rule that shows up constantly across the project's history: never guess at how a third party library actually behaves. Whenever a feature touched Citadel for SSH and SFTP, swift nio ssh for lower level protocol details, or SwiftTerm for terminal rendering, I cloned and read the actual pinned version of that library's source code directly before writing any code against it. This single habit resolved a striking number of real defects over time: a wrongly guessed function name, a type that turned out to carry different fields than expected, an error type that looked public but had no accessible way to construct it. I found each of those by reading real source rather than relying on memory or a plausible sounding guess, and each would have shipped as a real bug otherwise.
The standing bug and security check
After nearly every meaningful round of changes, I ran a dedicated bug and security pass, often before the resulting build was ever packaged and delivered. Two mechanical checks ran every time: a comment and string aware balance check across every brace, parenthesis, and bracket in the changed files, and a project wide search for any leftover reference to a function, type, or property I had just renamed or removed. Neither check is glamorous, but together they catch an entire category of mistake that is otherwise very easy to miss when a change touches several files at once.

Beyond the mechanical checks, a genuine security minded review looked specifically for the kinds of mistakes that do real harm: resource and connection leaks, race conditions, path handling that trusts input it should not, and credentials or secrets ending up somewhere other than the Keychain. Several real issues came out of these reviews over time. An SFTP browsing connection that never actually closed when its window closed, quietly staying open for the life of the app. A second credential prompt that could silently overwrite a first one still waiting for an answer, leaving that earlier connection attempt stuck forever. A file download path built directly from a server reported filename, which a malicious or compromised server could have used to write a file somewhere it should never have been allowed to write. I found, fixed, and wrote up each of these honestly rather than quietly patching it and moving on.
One of the clearest recent examples involved a new transfer progress bar for SFTP. Shortly after it shipped, a dedicated security check found that a very large file size reported by a remote server, larger than a certain internal limit, could actually crash the app outright rather than simply displaying an odd number. That is not a cosmetic bug. It is a way a hostile or malfunctioning server could deliberately crash a client, and I found and fixed it specifically because a bug and security check happens as a matter of course after this kind of change, not only when something goes visibly wrong.
Treating a failed build as a diagnostic, not a setback
Every proposed fix gets a careful, deliberate review before I consider it done, but the real compiler and a real running app are what ultimately confirm whether a fix actually holds, and that confirmation always comes from an actual Xcode build. I treat those two steps, the careful review and the real build, as equally necessary rather than interchangeable, since neither one catches everything on its own. One early example made the value of that combination obvious: my first real compiled build surfaced a batch of thirty four genuine compiler errors at once. Rather than treating that as a crisis, I fixed each error against its exact real message, one at a time, cross checked against the pinned library source where needed, and closed out the whole batch in a single pass.
That same discipline carried through a much harder stretch later on, when a specific file kept failing to compile across five separate rounds in a row, each attempt fixing something real but not the actual underlying cause. Rather than declaring victory prematurely on any of those rounds, I documented every fix attempt honestly as still unconfirmed until the next real screenshot came back. The fifth round finally traced the true cause by laying every prior screenshot side by side and noticing that the failure had only started appearing after an earlier round's own change, meaning the real fix was to revert that specific change rather than add another layer on top of it. That is a genuinely uncomfortable thing to write down in a project log, and I wrote it down anyway, because an honest record of what did not work the first four times is worth more than a tidy story that skips the detours.
Project management as a living document
Underneath all of this sits a single, continuously updated progress log that has tracked every phase, every feature, every bug found, and every fix applied since the very first scaffolding commit. Each entry follows the same shape: what was reported or asked for, what the actual root cause turned out to be, what was changed, what was checked afterward, and which build the fix shipped in. That consistency is what makes it possible to look back months later and answer a very specific question, such as which exact commit fixed a particular authentication bug, without relying on memory.

That same commitment to an honest record applies even when the mistake belongs to the process itself rather than to the app. While I was preparing an update to this very progress log, an editing error briefly replaced the entire document with placeholder text instead of the intended new entry. Rather than quietly rewriting history once I caught the mistake, the log now includes its own short, plain explanation of what happened, what I could recover from a backup copy, and what I could not reconstruct word for word. That kind of transparency is not a formality. It reflects the same standard I apply to every feature in this series: when something goes wrong, find out exactly why, fix what can be fixed, and say so clearly rather than smoothing it over.
Why this matters as much as any feature
None of this process is visible in a screenshot or a feature list. Nobody opens a terminal app because of its bug tracking discipline. But every feature described earlier in this series, from the first working SSH session to the newest code editor with live diagnostics, only stayed trustworthy because of the habits described here: verify against real source before writing code, check for balance and stale references after every change, run a genuine security minded review rather than a cosmetic one, treat an unresolved bug as unresolved until it is actually confirmed fixed, and keep an honest, continuously updated record of all of it, mistakes included. That combination is what lets a project like this keep adding real features for months on end without slowly accumulating the kind of hidden debt that eventually makes an application impossible to trust.
Building PortSide: A Developer's Field Notes
- 1.The Idea Behind PortSide
- 2.From SSH to Syntax Highlighting
- 3.Bug Checks, Security Reviews, and Honest Logs (you are here)
Related posts


Comments
No comments yet. Be the first.