For a long time, one of the easiest ways to describe Blupoli Puzzles was the size of the catalogue. Every new game made growth visible. That number was useful while we were proving that many different mechanics could live in one product. It became much less useful once we started comparing the strongest games with the oldest prototypes.
A card in a catalogue can hide a wide range of maturity. One game may have a solver, reproducible generation, useful difficulty settings, keyboard interaction, persistence, statistics and onboarding. Another may open, accept a few moves and reach a victory state, yet fall apart as soon as you reload, change viewport, ask for a harder puzzle or try to understand why a generated instance is valid.
That gap changed our priorities. Instead of treating the existence of a route as proof that a game was finished, we started auditing older entries as product debt. The immediate result was a wave of work across different mechanics: classic sliding puzzles, placement puzzles, competitive games, number paths, region-based logic and other families. The larger result was more important: a new definition of what “finished” has to mean in a platform.
The audit changed the first question
We used to begin with “does the game work?” It is still a necessary question, but it is no longer enough. The better opening question is: what would this game need in order to feel as deliberate as the best experiences already in the catalogue?
That immediately expands the scope beyond rules. A perfectly correct engine can still be a poor product if the difficulty labels are arbitrary, if mobile controls are too small, if the first move is unclear, if a reload destroys the session, or if the statistics mix variants that are not meaningfully comparable.
Our audits therefore move through several layers: rules, generation, solver or validator, interaction, victory feedback, persistence, history, statistics, accessibility, onboarding, localisation and integration with the shared shell. The purpose is not to make every puzzle look identical. It is to establish a product contract around very different mechanics.
A puzzle is not finished when it stops crashing. It is finished when the product no longer needs excuses for the parts around the rules.
The 15 Puzzle: simple rules expose shallow implementations quickly
The classic 15 Puzzle is a good example because the rules are so small. Fifteen numbered tiles, one empty space and orthogonal movement on a 4×4 board. It is easy to build a demo: shuffle tiles, let the player slide them and count moves.
A product-ready version has more edge cases. The shuffled state must remain solvable. Difficulty needs a meaningful interpretation rather than “shuffle more randomly”. Keyboard and touch interaction should both feel natural. The current session should survive a reload where appropriate. Undo should restore a valid previous state. Completion should produce a result that the rest of the product can understand.
None of those requirements makes the mathematical rule more complex. They make the experience complete. That distinction became a recurring theme in the audit: engine complexity and product completeness are not the same axis.
Akari: uniqueness becomes part of the product promise
Akari asks the player to place lights so every open cell is illuminated, lights do not see one another and numbered walls satisfy their local constraints. A naive generator can easily create something that looks like Akari but has several valid completions or a difficulty profile that bears little relationship to the label shown in the interface.
That is why generation and solving have to work together. The product needs a way to inspect candidate puzzles, reject ambiguity and collect signals about how demanding the instance is. The solver is not simply a developer convenience hidden behind the game. It becomes a quality-control instrument.
This idea is developed further in Generating is not solving: finding one solution proves existence, not uniqueness, interest or appropriate difficulty. A puzzle product has to care about those extra properties because the player experiences the consequences when they are wrong.
Ataxx: completing a competitive game means completing the opponent
A game against the system has a different definition of completion from a solitary logic puzzle. Ataxx made that obvious. The board and legal moves are only part of the experience; the CPU is also part of the mechanic the player is evaluating.
Difficulty therefore needs to change the opponent meaningfully. Search depth, evaluation and move choice have to produce distinct behaviour rather than four labels over the same strategy. Persistence has to understand whose turn it is. Undo cannot necessarily reverse one isolated mutation if that leaves the player in the middle of a CPU response cycle.
This is why shared infrastructure must be flexible. Statistics can still have a common destination, but a competitive result needs win, loss or draw rather than “solved”. History can still be common, but the meaningful unit may be a full round rather than one action. The product contract is shared at the boundary, not imposed on the mechanic internally.
Hidato: sometimes the generator needs rebuilding, not polishing
Hidato depends heavily on how the clues expose a hidden consecutive path. You can make a visually plausible board very easily and still create something trivial, ambiguous or structurally uninteresting. In cases like this, UI polish cannot rescue a weak generator.
The audit therefore has to be willing to go deep. If a puzzle family needs a stronger generation model, repairing the shell is only half the work. The engine should be able to produce reproducible candidates, validate them independently and expose enough information for difficulty and statistics to make sense.
It also needs teaching. A generic tutorial can explain where buttons live, but Hidato’s first useful insight concerns the relationship between consecutive numbers and available positions. Onboarding becomes part of the game model because the mechanic has something specific to teach.
Balance Loop: owning a mechanic can be the right product decision
Not every external integration needs replacing. Mature open-source puzzle engines can be excellent. But when an integration cannot support the product guarantees we want — reliable variants, persistence, validation, interaction or consistent state — the engine boundary deserves another look.
Balance Loop was one of the cases that reinforced this. Moving to a native implementation gave us control over rules, metadata, seeded generation and validation. The important lesson was not “native is always better”. It was that the engine abstraction only earns its place when it allows the surrounding product to remain strong.
Battleship: a fleet logic puzzle is not the guessing game
The logic-puzzle version of Battleship is structurally different from the competitive game many people know. The player is deducing a hidden fleet from clues and constraints. That means ship segments, adjacency, counts and global consistency have to be modelled explicitly.
A generator that merely hides a randomly placed fleet does not necessarily create a good puzzle. We need to know whether the clues determine a unique answer and whether the difficulty comes from real deductions rather than just fewer visible hints.
This is another place where labels such as Easy, Normal, Hard and Expert need a theory behind them. Removing clues can make a puzzle emptier without making it better. The solver trace, branching, forced moves or other mechanic-specific signals provide a stronger basis than visual scarcity alone.
Aquarium: keeping a good core can be the best engineering choice
Auditing does not mean rewriting everything. Aquarium already had a core worth preserving. The work around it was more about completing the product surface and correcting concrete reliability issues in generation.
That distinction matters because rewriting carries risk. A mature audit asks what is actually wrong. If the rules and core generation model are sound, we should not discard them just to make the diff look decisive. Product completeness can come from persistence, history, responsive behaviour, keyboard support, feedback and localisation around an existing engine.
The same reasoning applies when a generator relies on too many retries. “Keep generating until one works” can hide a structural problem. If a parameter choice produces too many ambiguous or expensive candidates, changing the model is often healthier than increasing the retry budget indefinitely.
Takuzu: a fixed prototype is not a scalable game
A fixed small board can prove that the interaction is understandable. It does not prove that the product can support meaningful variants. Takuzu’s audit therefore had to think in terms of reproducible generation, uniqueness, several sizes and difficulty levels that are separate from size.
That last point has become important across Blupoli Puzzles. A larger board is not automatically harder. It can simply contain more repetitions of easy reasoning. If size and difficulty are conceptually different, they should be represented separately in state, generation and results.
Unique solutions are no longer optional when the mechanic promises one
One of the clearest changes in our standards is that uniqueness has moved from “nice to have” to evidence we expect when the puzzle family requires it. If a logic puzzle presents itself as a deduction problem and several incompatible completions are valid, the product has asked an unfair question.
The exact proof technique varies. Backtracking, constraint propagation, exact cover, graph algorithms and family-specific solvers all have a place. What matters is that the generation pipeline can challenge its own output instead of assuming validity because the candidate was produced by our code.
That turns generation into a sequence: propose, solve, count or prove, measure, accept or reject. Seeds make failures reproducible. Validators preserve discovered edge cases. Difficulty signals can be recorded instead of guessed. The pipeline becomes a small manufacturing system rather than a function that returns a board.
Four difficulty labels must represent four real experiences
We aim for several meaningful difficulty levels when the mechanic honestly supports them. That requirement is not satisfied by assigning four names to arbitrary parameter values. The levels need a relationship to the reasoning the player is expected to perform.
The useful signals depend on the family: branching depth, forced moves, clue density, region structure, available combinations, route bottlenecks or techniques required. No universal metric can describe every puzzle equally well. The shared standard is not the metric itself; it is the expectation that the label can be explained.
We would rather document an honest exception than invent fake variety. A classic mechanic with a historically meaningful board size does not become more complete merely because we add three distorted sizes to fill a selector. Product consistency should create useful guarantees, not checkbox theatre.
Persistence and history change how state must be modelled
“Save the game later” is an expensive plan. If the engine does not clearly distinguish initial puzzle, current state, variant, seed and move history, persistence either serialises too much implementation detail or cannot reproduce enough to resume safely.
The audit therefore treats persistence as a state-design concern. A session should know which puzzle instance it represents and what player actions are necessary to continue. That usually means giving the generated puzzle a reproducible identity rather than relying on transient random state.
Undo also reveals mechanic differences. In a placement puzzle, one move may be the right unit. In a CPU game, a complete player-and-opponent round may be the right unit. A shared history service is useful only when it lets the engine define what a meaningful reversible action is.
Statistics need variant context
Counting solved games and elapsed time is easy until variants proliferate. A small Hidato and a large one are not equivalent attempts. Beating an easy CPU opponent is not the same result as beating the hardest one. A Takuzu run should carry enough information to know which board and difficulty were played.
That is why engines increasingly report variant details at completion. The statistics layer can stay shared while receiving enough context not to flatten meaningful differences. The same principle feeds the new result contracts behind the evolving Blupoli Puzzles lobby, progress and history.
The result of a game is a product boundary
We once treated victory detection as the end of engine work. It is better understood as a hand-off. At that moment the engine knows the variant, elapsed time, move count, score or competitive outcome. If every engine exports that information differently, the rest of the platform has to know engine-specific details.
A common result contract gives the shell a stable hand-off without pretending every game has the same metrics. A logic puzzle can report solved state and moves. A CPU game can report win, loss or draw. A score-based game can add its own values. The contract standardises the envelope, not the meaning of every field.
This is how audit work becomes platform work. Fixing one game reveals a boundary that, once clarified, improves the next one.
Responsive and accessibility can no longer be final-stage checks
The same period that produced engine audits also produced shared improvements to control sizing and mobile navigation. That is not accidental. Once the catalogue is large, a shell defect multiplies across every otherwise-good engine.
We now prefer fixing shared patterns first and game-specific problems second. A focus-state improvement in a common control should help many games. A better touch target should not require separate patches. A keyboard interaction rule should be encoded where possible rather than remembered during every audit.
Accessibility is particularly valuable as an architectural test. If a game state can only be understood from colour, or an action only exists on hover, the implementation is exposing an assumption about input or perception that may also hurt usability more generally.
An audit should be able to fail before production
Manual playtesting remains important because software cannot fully measure whether a puzzle feels satisfying. But a review process does not scale if every regression requires someone to stumble into it by hand.
Properties we can verify should become checks: supported variants generate, known bad seeds remain rejected, solution counts match expectations, required publication metadata exists, onboarding coverage is present, and game results contain the fields the platform needs.
The important word is independent. If possible, the generator should not be the only code declaring its own output valid. A separate solver, simple invariant or alternative validation path can provide evidence that would catch the same bug appearing on both sides of a shared implementation.
Product debt is not fixed by refactoring alone
Some audited games needed deeper engines. Others mostly needed product work: clearer instructions, better feedback, persistence, a responsive layout or meaningful result handling. Rewriting the algorithm would not have fixed those weaknesses.
That is why we audit from the outside in and from the inside out. We play the game as a newcomer, observe where the interface creates uncertainty, then inspect whether the state model and engine boundaries make those problems easy or difficult to solve.
Technical debt and product debt often meet at that seam. If a session cannot resume because the model does not represent a stable puzzle identity, the issue is both technical and experiential. If onboarding needs to explain an interface inconsistency, the copy is revealing design debt.
A shared standard still needs honest exceptions
Blupoli Puzzles aims for multiple sizes and difficulty levels when the mechanic reasonably supports them. The important clause is “when it supports them”. We do not want to damage a classic puzzle merely to satisfy a generic selector.
The same applies to undo, hints and statistics. Shared contracts are valuable because they remove repeated product decisions. They should not force every mechanic to pretend it has the same nature. An explicit documented exception is healthier than a fake variant created to pass a checklist.
This balance mirrors our shared UI approach: predictable product expectations around a board that remains free to express the mechanic honestly.
The audit is changing how we add the next game
The biggest return from this work is not the set of games already improved. Each audit reduces the probability of repeating the same class of incompleteness.
We now know to think about result data early. Difficulty needs an explanation. Onboarding cannot be a generic paragraph added at the end. Persistence needs a reproducible puzzle identity. Responsive design includes controls, not just the board. Uniqueness should be verified rather than assumed.
Once repeated expectations become templates, contracts and checks, the audit stops being a cleanup operation and becomes architecture for future work.
Quality work needs a stopping rule too
A stricter definition of done can fail in the opposite direction: an audit can expand forever. There is always another animation to polish, another statistic to record and another rare edge case to investigate. Product quality needs explicit release criteria so that “careful” does not become “never shippable”.
For us the useful distinction is between contract failures and refinements. A puzzle that can generate ambiguous instances when uniqueness is promised has a contract failure. A board that is unusable with keyboard navigation has a contract failure. Missing persistence when the product presents sessions as resumable is a contract failure. A slightly nicer transition or an additional optional statistic may be valuable, but it should not quietly move the finish line every time the audit gets close.
This makes the process easier to repeat. We can publish when the mechanic, variants, generation evidence, interaction, accessibility, localisation and result contract are sound, then continue improving from a stable base. The point of an audit is not perfection. It is to replace accidental incompleteness with an explicit, defensible standard.
The catalogue becomes more honest when readiness is visible
A quality-first process also changes how we present unfinished work. If a game is still under audit, marking it as coming soon is more honest than exposing a shallow route simply because some implementation exists. A catalogue should describe what a player can rely on now, not the maximum number of experiments in the repository.
That honesty removes pressure from the engine work. We can take a puzzle out of the published set, repair generation or onboarding, and return it when the evidence is stronger. The public count may grow more slowly, but each published card means more. In the long run that trust is a more useful product metric than the raw number of routes.
More depth before more catalogue
We still want new puzzle families. The catalogue is not closed. The order of priorities has changed, though. A new card only improves the product when the experience behind it reaches the same bar we expect from what is already public.
Completing older entries therefore creates more value than adding one more shallow prototype simply to increase a count. The paradox is that this slower-looking phase makes later growth easier. Every reconstructed engine leaves behind better validators, result contracts, onboarding patterns, persistence conventions and UI decisions.
Early Blupoli Puzzles grew mainly by adding games. The next stage is about making a game near the beginning of the catalogue and a game near the end feel as though they genuinely belong to the same product, even when their mathematics are completely different.
That is difficult to capture in one screenshot. It is also one of the most important changes we can make.