Software engineer — backend & product
A Go crossword generator with one non-negotiable invariant: 150 filled cells, proven by a solver before the API responds.
Go · solver · Next.js · 2026
Go API, solver · Next.js editor · 2026
Diretas generates Diretas-style crossword pages — the Portuguese-language kind where a clue sits inside the grid itself instead of in a side list — and manages the bank of clue → answer pairs behind them. The interface is deliberately small: one button to generate a page, one screen to manage the answer bank. The engineering is in what the API refuses to return.
A generated crossword page is only useful if it's actually solvable and complete. A page with an empty cell, an orphaned letter, or a clue missing its associated answer isn't a draft that needs polish — it's broken, and handing it to an editor to catch by hand defeats the point of generating it at all.
The generation endpoint doesn't return a best-effort page. It runs generation, then hands the candidate to a solver; if the solver can't prove the grid is fully and validly filled from the current bank, the API does not respond with a page at all. Composition and verification are separate steps, and the second one is a hard gate on the first.
Measure bank supply by answer length during construction
A mutation only survives if the solver still completes the page
Among complete solutions, select the best composition
The zero-empty-cells contract is unforgiving on purpose, which means the failure mode isn't a bad page — it's a rejected request when the current bank genuinely can't fill a 150-cell grid. That's a real, expected outcome as the bank shrinks or shifts composition, not a bug: the interface has no draft or partial state for a reason, so an unsolvable bank has to surface as "generate again once the bank changes," not as a broken export.
The zero-empty-cells rule is exactly right for the current two-screen scope. If the legacy magazine/reservation model ever comes back into the active path, the solver-as-gate approach needs to extend to that world too — it isn't obvious yet that the same all-or-nothing check still makes sense once answers can be reserved across multiple pages.