Fill mode: a "grid" layout that plants individual plants in rows #95

Merged
steve merged 2 commits from feat/fill-mode into main 2026-07-22 04:22:46 +00:00
2 Commits
Author SHA1 Message Date
steveandClaude Opus 4.8 c80cf15bf1 Address fill-mode review: grid edge inset + drop dead coverage append
Build image / build-and-push (push) Successful in 18s
Gadfly findings on #95:

- Correctness (3 models): the shared inset formula radius-spacing/2
  collapses to 0 in grid mode (radius = spacing/2), so grid's outer row
  planted flush on / overhanging the bed edge instead of the half-spacing
  in that the rule wants. The inset genuinely differs by layout — a grid
  plant sits AT the plop centre (inset spacing/2), a clump's plants reach
  its rim (inset radius-spacing/2, overhanging by a half). Split it into a
  new edgeInset(radius, spacing, layout); hexCenters now takes a
  precomputed inset and is pure geometry (no spacing/layout knowledge).
  Regression guard: grid plants land at ±25 on a 60cm bed, not ±30.

- Performance (2 findings): the in-loop `existing = append(existing, *p)`
  was dead — every plop in one fill shares a radius and sits on a distinct
  lattice point, and a plop is "covered" only when wholly inside another,
  impossible between equal-radius circles at different centres. Removing it
  stops the coveredByExisting scan growing during the fill (an empty-bed
  grid fill's check was needlessly quadratic in the plop count).

- Docs: FillRegion/fillLoaded/hexCenters comments and the DESIGN.md bullets
  updated for plopRadiusFor/edgeInset (were still citing defaultPlopRadius
  and "written out in hexCenters").

- Test hygiene: split the grid + bad-layout cases out of TestFillAndClearAPI
  into TestFillLayoutAPI (one concern per test).

The enum-tag finding is a non-issue: majordomo's DefineTool derives its arg
schema from the same struct-tag reflection as Generate (proven by the vision
SeedPacket enum), and the service validates mode regardless.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ
2026-07-22 00:21:47 -04:00
steveandClaude Opus 4.8 7c1faa1515 Fill mode: a "grid" layout that plants individual plants in rows (#77)
Build image / build-and-push (push) Successful in 6s
Gadfly review (reusable) / review (pull_request) Successful in 12m51s
Adversarial Review (Gadfly) / review (pull_request) Successful in 12m51s
Steve chose option 3: keep clumps as the default primitive, add a grid/rows
fill mode, so sketching and planning are different operations with different
outputs rather than one model forced to be both.

A plop is a CLUMP, not a plant — great for "a few plops of garlic in a corner",
useless for drawing a plantable 8-rows-of-garlic bed (that came out as ~15
blobs, #77). FillLayout selects what a fill packs:
- clump (default, unchanged): radius 1.5×spacing, ~7 plants per plop.
- grid: radius spacing/2, pitch = spacing, ONE plant per plop — rows you could
  actually plant from.

The geometry is the SAME hexCenters lattice and the SAME #75 half-spacing edge
rule; only the radius→spacing relationship differs (plopRadiusFor). Grid keeps
no 15cm floor — its whole point is true spacing — while clump keeps it so a
tiny-spacing plant doesn't make invisible clumps.

Threaded through FillRegion/FillNamedRegion (empty layout = clump, so existing
callers are unchanged; unknown layout = ErrInvalidInput), the REST /fill
endpoint (`layout`), and the agent's fill_region tool (`mode`, enum clump|grid),
so "plant the bed in rows" works.

Tests: grid produces many more, single-plant plops than clump on the same bed
(radius spacing/2, derived count 1); unknown layout is refused at both the
service and the API. maxFillPlops still caps a grid fill of a huge bed.

No frontend fill affordance exists yet (fill is agent-only in the UI; the fill
UI was deferred in #82), so the mode toggle rides along when that's built —
noted. Docs: DESIGN placement-model decision.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01H3zbym8Doka2d7D48maSgZ
2026-07-22 00:01:27 -04:00