← All decisions

Systematic DevOps tooling organization: a researched taxonomy (kind, packaging weight, fixture placement, discoverability) for tools/, not an ad hoc layout

architecturetoolsdevopsdocumentationdeno

Context

User feedback: tools/ (tools/decisions/ as a Gleam package, tools/browser_check.ts and tools/check_warnings.ts as flat Deno scripts, tools/expected_warnings.json as a flat data fixture) looked like DevOps tools 'randomly thrown' together, with no visible rule for what goes where or how it scales. Asked for the same cross-referenced, researched rigor already applied to the Core/Shell split and modularization thresholds, applied to tools/ specifically, documented in the standard place (ARCHITECTURE.md).

Options considered

Reorganize tools/ into kind-based subdirectories immediately (tools/checks/, tools/verification/, tools/cli/) ahead of having more than one example of each kind — rejected
Would contradict this project's own already-established, already-learned practice of not building speculative structure ahead of a real need (the exact lesson decision 0031 drew from glemy/cs sitting unused). Three tools, three kinds, one example each -- introducing category subdirectories now has no real organizational benefit and is itself the kind of premature structure this project has already burned itself on once.
Invent a project-specific fixture/config convention from scratch rather than borrowing an established one — rejected
Checked Deno's own official docs directly first: no built-in fixture-directory convention exists in Deno. Rather than inventing a bespoke, unprecedented layout, cross-referenced Go's `testdata/` convention -- a real, toolchain-recognized (go build specially ignores it) precedent for exactly this problem (a golden/baseline file belonging to a specific piece of code, not sitting flat as if it were code itself), and adopted it directly rather than reinventing it.
Formalize a taxonomy in ARCHITECTURE.md and apply it now: three kinds of tool (record-keeping CLI, build-artifact gate, live-system verification), a packaging-weight rule cross-referenced against Rust's cargo-xtask pattern and Deno's own documented workspace model, testdata/ for fixtures (Go precedent), and deno task entries for discoverability (Deno's own documented tasks mechanism) — chosen
Every piece of this is backed by a real, checked, cross-referenced precedent rather than a single source or an invented rule -- cargo-xtask (used by Cargo itself, not just a blog post about it), Deno's official workspace/tasks documentation (fetched and read directly, not assumed), and Go's testdata convention (confirmed to be toolchain-recognized, not just a community habit). Confirms rather than contradicts the current layout is mostly already correct: tools/decisions/ already matches the packaging-weight threshold exactly (real hex dependencies + its own test suite), and neither .ts script crosses that threshold today, which is why they stay flat files -- the actual gaps found were the fixture placement and the missing task-based discoverability, both now fixed.

Decision

Added a 'DevOps tooling organization' section to ARCHITECTURE.md (positioned before 'Compiler warnings', which it now cross-references and vice versa): the three-kind taxonomy, a packaging-weight table with concrete trigger conditions (own dependency manifest needed, or own dedicated test suite -- either promotes a flat script to a self-contained package), the testdata/ fixture rule, and the deno task discoverability rule. Applied immediately: moved tools/expected_warnings.json to tools/testdata/expected_warnings.json, updated check_warnings.ts's BASELINE_PATH and all its own doc-comment/output-string references (including one that had been easy to miss -- a hardcoded path string in the PASS console.log, not just the BASELINE_PATH constant). Added a tasks field to the root deno.json (browser-check, check-warnings) with the exact permission flags each script already documented, so both are now invoked as deno task <name> rather than requiring the full flag incantation to be copied out of a header comment. Updated every cross-reference across CLAUDE.md, ARCHITECTURE.md, and docs/development-plan.md to the new task-based invocation and the new fixture path -- swept the whole repo afterward (not just the files touched) to confirm no stale reference to the old flat path or the old raw command remained.

Verification

Both new deno tasks (deno task check-warnings, deno task browser-check) run successfully end-to-end after the move, including a real headless-Chromium session for browser-check (zero page errors) and the warnings gate correctly reading the relocated baseline (49/49 matching, PASS message itself now correctly printing the new tools/testdata/ path -- confirmed the hardcoded-string bug was actually fixed, not just the path constant). 164 Erlang / 187 JavaScript gleam test cases still passing on both targets, unaffected (this change touches only tooling, no game source). A repo-wide sweep (every .md/.gleam/.ts/.mjs file, not just the ones directly edited) confirmed zero remaining references to the old tools/expected_warnings.json path or the old raw deno run invocation as the primary documented command.

Consequences

tools/ now has an explicit, cross-referenced rule for where a new dev-tool belongs, at what packaging weight, and how its own fixtures/baselines are kept separate from its code -- the exact 'why does this look random' question this decision answers directly rather than leaving implicit. The three-kind taxonomy and the packaging-weight table are the concrete reference for the next tool this project adds, the same way the Core/Shell split and modularization thresholds already are for game code.

References