De-monolith cmd/ward: 77-file package main -> internal packages (the package-first prerequisite for #265) #630

Open
opened 2026-07-07 09:44:29 +00:00 by coilysiren · 0 comments
Owner

Why

cmd/ward is a 77-file, 21,223-LOC package main - 93% of ward's Go, one flat package, everything package-private to everything else. That monolith is the first-order blocker for ward#265: you cannot migrate the engine-general slices down (or even reason cleanly about which slices are engine-general) when there are no internal seams to cut along. This is the package-first step. The migration (ward#265) is step two, and it only becomes tractable after this.

Measured 2026-07-07: cli-guard is 23.6k src across 61 packages (biggest 4.7k); ward is 22.7k across 9, with the 21.2k bulk in this one package main. The shape, not the size, is the debt.

What

Break cmd/ward into internal packages along the concern lines the file names already draw:

  • agent/ - agent.go (1762), agent_director*, agent_reserve, agent_reply, agent_dispatch_broker, ... (the warded lifecycle)
  • container/ - container.go, container_bootstrap (1477), container_compute (1023), container_reap (883), ... (the container lifecycle)
  • ops/ - the ward ops forgejo / aws / ... shadows
  • keep package main as a thin cmd/ward entrypoint that wires the packages together.

Pure structural refactor, no behavior change: move files into named internal packages, export only what crosses a boundary, keep tests green. The ~0.87 test-to-src density makes this survivable, the same way it let the opcore extraction (cli-guard#197) land "all tests green."

Done

  • cmd/ward main is a thin wiring shell; the bulk lives in named internal packages.
  • No behavior change, ward vet / ward test green.
  • The engine-vs-product boundary is now visible at the package level, so ward#265's per-slice migration (and the cli-guard#190 "orchestration stays out of cli-guard" test) becomes a package-level decision instead of an archaeology dig.

How to run it

Ward-internal, no cross-repo dependency, so it can start now. But it is a big, careful, cross-cutting refactor of a 21k monolith - interactive / high-risk, in the same class as ward#266 / #267, not a blind headless fire. Flagging for Kai on whether to hand-run it or drive it as a closely-watched run.

ward#265 (the tracking epic this unblocks - the package-first prerequisite it conflated with migration), cli-guard#190 / #196 (the boundary the migration applies per slice), cli-guard#197-199 (opcore - the name-it / package-it / move-it pattern to mirror).

## Why `cmd/ward` is a **77-file, 21,223-LOC `package main`** - 93% of ward's Go, one flat package, everything package-private to everything else. That monolith is the first-order blocker for ward#265: you cannot migrate the engine-general slices down (or even reason cleanly about which slices *are* engine-general) when there are no internal seams to cut along. This is the **package-first** step. The migration (ward#265) is step two, and it only becomes tractable after this. Measured 2026-07-07: cli-guard is 23.6k src across **61 packages** (biggest 4.7k); ward is 22.7k across **9**, with the 21.2k bulk in this one `package main`. The shape, not the size, is the debt. ## What Break `cmd/ward` into internal packages along the concern lines the file names already draw: - **`agent/`** - `agent.go` (1762), `agent_director*`, `agent_reserve`, `agent_reply`, `agent_dispatch_broker`, ... (the `warded` lifecycle) - **`container/`** - `container.go`, `container_bootstrap` (1477), `container_compute` (1023), `container_reap` (883), ... (the container lifecycle) - **`ops/`** - the `ward ops` forgejo / aws / ... shadows - keep `package main` as a thin `cmd/ward` entrypoint that wires the packages together. Pure structural refactor, **no behavior change**: move files into named internal packages, export only what crosses a boundary, keep tests green. The ~0.87 test-to-src density makes this survivable, the same way it let the opcore extraction (cli-guard#197) land "all tests green." ## Done - `cmd/ward` main is a thin wiring shell; the bulk lives in named internal packages. - No behavior change, `ward vet` / `ward test` green. - The engine-vs-product boundary is now **visible at the package level**, so ward#265's per-slice migration (and the cli-guard#190 "orchestration stays out of cli-guard" test) becomes a package-level decision instead of an archaeology dig. ## How to run it Ward-internal, no cross-repo dependency, so it can start now. But it is a **big, careful, cross-cutting refactor** of a 21k monolith - interactive / high-risk, in the same class as ward#266 / #267, not a blind headless fire. Flagging for Kai on whether to hand-run it or drive it as a closely-watched run. ## Related ward#265 (the tracking epic this unblocks - the package-first prerequisite it conflated with migration), cli-guard#190 / #196 (the boundary the migration applies per slice), cli-guard#197-199 (opcore - the name-it / package-it / move-it pattern to mirror).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#630
No description provided.