Agent: catalog and garden tools, and a ready date on every describe group
- update_seed_lot / delete_seed_lot: correct or drop a recorded purchase
("it was three packets, not two"); the plant a lot is for stays fixed.
- delete_plant: remove a duplicate from the user's catalog. The service
already refuses while plantings (past seasons included) or a lot reference
it; the tool turns that sentinel into words the model can pass on, and
tells it not to clear those references to get its way.
- create_garden: a new place, with the service's defaults; the prompt says a
plan is still a copy_garden.
- describe_garden groups carry readyAround — planting date plus days to
maturity for the plops still in the ground — so "what can I pick this
week?" is a lookup rather than arithmetic the model got wrong live.
Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
@@ -920,3 +920,67 @@ func TestDescribeGardenByYear(t *testing.T) {
|
||||
t.Errorf("describe(20026) err = %v, want ErrInvalidInput", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestDescribeGroupSaysWhenReady — "what can I pick this week?" is a lookup
|
||||
// when the group carries the date, and a sum the model gets wrong when it
|
||||
// doesn't. Planting date plus days to maturity, for the plops still in the
|
||||
// ground; nothing for a plant the catalog has no days for.
|
||||
func TestDescribeGroupSaysWhenReady(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
s := newTestService(t, openConfig())
|
||||
owner := seedUser(t, s, "[email protected]")
|
||||
g, err := s.CreateGarden(ctx, owner, GardenInput{Name: "Harvest", WidthCM: 2000, HeightCM: 2000})
|
||||
if err != nil {
|
||||
t.Fatalf("garden: %v", err)
|
||||
}
|
||||
bed := seedFillBed(t, s, owner, g.ID, 400, 400)
|
||||
sixty := 60
|
||||
radish, err := s.CreatePlant(ctx, owner, PlantInput{Name: "Radish", Category: domain.CategoryVegetable, SpacingCM: 5, Color: "#c33", Icon: "🌱", DaysToMaturity: &sixty})
|
||||
if err != nil {
|
||||
t.Fatalf("radish: %v", err)
|
||||
}
|
||||
mint := seedNamedPlant(t, s, owner, "Mint", 30) // no days to maturity
|
||||
|
||||
plant := func(plantID int64, x float64, on string) *domain.Planting {
|
||||
t.Helper()
|
||||
pl, err := s.CreatePlanting(ctx, owner, bed.ID, PlantingInput{PlantID: plantID, XCM: x, YCM: 0, RadiusCM: 10, PlantedAt: &on})
|
||||
if err != nil {
|
||||
t.Fatalf("plant: %v", err)
|
||||
}
|
||||
return pl
|
||||
}
|
||||
plant(radish.ID, -100, "2026-05-01")
|
||||
plant(radish.ID, 0, "2026-05-11")
|
||||
pulled := plant(radish.ID, 100, "2026-03-01")
|
||||
on := "2026-04-20"
|
||||
if _, err := s.RemovePlanting(ctx, owner, pulled.ID, pulled.Version, &on); err != nil {
|
||||
t.Fatalf("pull: %v", err)
|
||||
}
|
||||
plant(mint.ID, 150, "2026-05-01")
|
||||
|
||||
groups := func(year *int) map[string]DescribeGroup {
|
||||
t.Helper()
|
||||
desc, err := s.DescribeGarden(ctx, owner, g.ID, year)
|
||||
if err != nil {
|
||||
t.Fatalf("describe: %v", err)
|
||||
}
|
||||
out := map[string]DescribeGroup{}
|
||||
for _, gr := range desc.Objects[0].Plantings {
|
||||
out[gr.Plant] = gr
|
||||
}
|
||||
return out
|
||||
}
|
||||
now := groups(nil)
|
||||
if got := now["Radish"].ReadyAround; got != "2026-06-30…2026-07-10" {
|
||||
t.Errorf("radish readyAround = %q, want %q", got, "2026-06-30…2026-07-10")
|
||||
}
|
||||
if got := now["Mint"].ReadyAround; got != "" {
|
||||
t.Errorf("mint has no days to maturity but readyAround = %q", got)
|
||||
}
|
||||
// The season view lists the pulled radish too, but its harvest is behind
|
||||
// us: the range is still the two still growing.
|
||||
y := 2026
|
||||
if got := groups(&y)["Radish"]; got.Removed != 1 || got.ReadyAround != "2026-06-30…2026-07-10" {
|
||||
t.Errorf("2026 radish = removed %d, readyAround %q; want 1 and the live plops' range", got.Removed, got.ReadyAround)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user