PtahCast's test suite is at 849 automated tests and climbing. On its own, that number tells you almost nothing — a large test suite that checks the wrong things is worse than a small one that checks the right things. What actually matters is what those tests catch, and one from the recent board-column-management work is worth walking through in full, because it's a genuine example of the kind of mistake that's easy to make and expensive to ship.
The feature: letting a board's columns actually change
Until recently, a PtahCast board's columns were fixed at creation — five defaults (Backlog, To Do, In Progress, Review, Done), created once, never added to or removed. That's a real limitation: an agency's workflow evolving past five stages is normal, and it became a hard blocker for the Jira/Trello import work, since mapping an external system's richer set of statuses onto PtahCast columns requires being able to create the columns to map them onto in the first place. So columns needed to become addable, editable, reorderable, and deletable.
Deletable is the interesting one. What should happen if someone deletes a column that still has tickets sitting in it?
The mistake that almost shipped
The safe-sounding rule is: block deletion if the column has any active ticket in it. Move your tickets out first, then delete. That's what got built first, and it's a reasonable-sounding rule — until you look at how archiving actually works elsewhere in the codebase.
An archived ticket in PtahCast isn't moved anywhere. It stays in its column, just hidden from the active board — that's precisely how "unarchive" is able to put it back in exactly the same place it came from. Which means an archived ticket still has a real `column_id` foreign key pointing at its column, and that foreign key is set to cascade on delete. A column-delete rule that only checks for active tickets would look at a column holding nothing but archived history, see zero active tickets, allow the delete — and the cascade would silently take every one of those archived tickets down with it. Comments, forecasts, throughput history, gone, with no warning and no undo. Exactly the data archiving exists to protect, destroyed by the one feature that was supposed to be a safe, reversible way to tidy up a board.
That's not a hypothetical. It's what the first version of the delete-column logic actually did, before a test written specifically to check "does deleting a column with an archived ticket in it behave safely" failed and said otherwise.
The fix, and the actual rule
The corrected rule is stricter than the original plan: block deletion if the column has any ticket at all, active or archived — not just active ones. It's a one-line difference in the code and a completely different outcome for anyone who'd hit it. The test that caught it, test_delete_column_blocked_by_archived_ticket, now runs on every single change to the codebase, forever, specifically so this exact mistake can never quietly come back.
This is the actual value of a large test suite — not the number itself, but that every one of these narrow, specific lessons stays enforced permanently instead of depending on someone remembering it. The Jira/Trello import work turned up a nearly identical pattern in the data model: deleting a board needed to cascade its integration settings and status mappings, and on SQLite (used in the test suite and any non-production environment) the database-level cascade rule alone doesn't actually fire, so the application has to declare the same cascade twice — once for real databases, once for SQLAlchemy's own bookkeeping. Three tests failed before that gap was closed too.
Why this is worth telling you, specifically
PtahCast's whole pitch is trusting a board's history enough to forecast a client-facing date from it. That trust has to extend to the history itself staying intact — a forecast built on data that quietly lost some of its archived tickets isn't wrong in an obvious way, it's wrong in a way nobody would notice until the numbers stopped making sense. Testing isn't a separate quality initiative bolted on afterward here; it's the thing standing between "a board's history is reliable" and "a board's history is reliable most of the time, probably."
849 isn't a target number and it isn't going to be announced again for its own sake. It's just where the suite happens to be after building the things this blog has been writing about — column management, Jira/Trello import, the sync logic underneath it — the same way the count was 595 before any of that work started.