Feature 04 task 3: Household settings seeding and API #20

Closed
dev_agent wants to merge 1 commits from task/household-settings_3d2d9d03-ae7b-4659-84fc-525e0dee3598 into feature/49e2f2e2-c9c1-4c1b-8d66-753ceeadbf75-platform-services
Member

Implements Feature 04 task 3 (3d2d9d03). Done-condition: first boot seeds household_settings from MEALQUEST_DEFAULT_TZ (boot fails clearly if unset/invalid while no row exists) with dinner 17:30, reminder 16:30, review 09:00, plan draft Fri 09:00, suggestions Sun 08:00, chat autosend Sat 08:00; later boots never overwrite; GET/PATCH /api/v1/settings/household with IANA/HH:MM/dow validation and updated_by; in-process subscribers notified on change; tests cover seeding, no overwrite, each validation error and the notification; quality floor passes.

Evidence (developer-run): gofmt empty; go vet clean; TZ=UTC go test -race all packages pass; CGO_ENABLED=0 build ok; make test/build ok; sqlc-check ok; docker build ok and a real container run seeded the row, refused an invalid zone, persisted a PATCH and kept settings across reboots. Embeds tzdata to fix the task-2 gap.

Implements Feature 04 task 3 (3d2d9d03). Done-condition: first boot seeds household_settings from MEALQUEST_DEFAULT_TZ (boot fails clearly if unset/invalid while no row exists) with dinner 17:30, reminder 16:30, review 09:00, plan draft Fri 09:00, suggestions Sun 08:00, chat autosend Sat 08:00; later boots never overwrite; GET/PATCH /api/v1/settings/household with IANA/HH:MM/dow validation and updated_by; in-process subscribers notified on change; tests cover seeding, no overwrite, each validation error and the notification; quality floor passes. Evidence (developer-run): gofmt empty; go vet clean; TZ=UTC go test -race all packages pass; CGO_ENABLED=0 build ok; make test/build ok; sqlc-check ok; docker build ok and a real container run seeded the row, refused an invalid zone, persisted a PATCH and kept settings across reboots. Embeds tzdata to fix the task-2 gap.
dev_agent added 1 commit 2026-10-03 10:05:09 -04:00
Seed household settings at boot and serve the settings API
Independent review Codex gpt-6-sol high: CHANGES_REQUIRED (1 high, 1 medium)
CI / ci (push) Successful in 1m26s
CI / ci (pull_request) Successful in 1m26s
7629cab8f4
On first boot create the single household_settings row with the zone from
MEALQUEST_DEFAULT_TZ and the seed times and days (dinner 17:30, reminder
16:30, rotation check 09:00, plan draft Fri 09:00, suggestions Sun 08:00,
chat autosend Sat 08:00). Boot fails if the row is missing and the zone is
unset; an existing row is never overwritten. Config validates the zone
whenever it is set.

Add household.SettingsService with Get, a validating Update (IANA zone,
zero-padded 24-hour HH:MM, day of week 0-6) that records updated_by, and
in-process Subscribe for the scheduler. Serve it as GET and PATCH
/api/v1/settings/household; invalid input is a 400 in the standard error
body. Migration 0002 adds household_settings.updated_by, and
internal/actor carries the member name in the request context.

Link time/tzdata from internal/household so zones load in the minimal
image, which has no system zone database.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
review_agent left a comment
Member

Independent review — Codex gpt-6-sol, reasoning high

Verdict: CHANGES_REQUIRED
Reviewed SHA: 7629cab8f49fbd3befeb0f5fd03bafb53897eede

{
  "verdict": "CHANGES_REQUIRED",
  "reviewed_sha": "7629cab8f49fbd3befeb0f5fd03bafb53897eede",
  "summary": "Seeding, validation, notifications, and bundled tzdata are implemented. gofmt, go vet, and TZ=UTC go test -race -count=1 ./... pass. The exposed settings API lacks the required authentication and cannot record updated_by in production.",
  "findings": [
    {
      "id": "F1",
      "severity": "high",
      "location": "internal/server/server.go:41; internal/server/settings.go:53",
      "failure_case": "An unauthenticated request can change household settings without a CSRF header. Its updated_by value is always null in the production server.",
      "evidence": "The router registers GET and PATCH directly, with no session or CSRF middleware. PATCH reads actor.From(request context), but production code never calls actor.With; the passing API test injects it manually. docs/ARCHITECTURE.md:130-132 requires a session cookie and CSRF header for non-GET API requests.",
      "suggested_correction": "Require an authenticated session and CSRF header before PATCH, populate the actor from that session, and test requests through the production router without manually injecting an actor."
    },
    {
      "id": "F2",
      "severity": "medium",
      "location": "internal/config/config.go:61",
      "failure_case": "A later boot with an existing valid settings row fails if MEALQUEST_DEFAULT_TZ remains set to an invalid value, although that first-boot default is no longer used.",
      "evidence": "config.Load validates DEFAULT_TZ before opening the database; SeedSettings ignores it when a row exists. The reboot tests cover a different valid default and an unset default, but not an invalid one.",
      "suggested_correction": "Defer default-zone validation until SeedSettings determines the row is absent, and add a reboot test with an invalid default and an existing row."
    }
  ]
}

Posted unaltered by review_agent. This is transport, not a second review.

## Independent review — Codex `gpt-6-sol`, reasoning high Verdict: **CHANGES_REQUIRED** Reviewed SHA: `7629cab8f49fbd3befeb0f5fd03bafb53897eede` ```json { "verdict": "CHANGES_REQUIRED", "reviewed_sha": "7629cab8f49fbd3befeb0f5fd03bafb53897eede", "summary": "Seeding, validation, notifications, and bundled tzdata are implemented. gofmt, go vet, and TZ=UTC go test -race -count=1 ./... pass. The exposed settings API lacks the required authentication and cannot record updated_by in production.", "findings": [ { "id": "F1", "severity": "high", "location": "internal/server/server.go:41; internal/server/settings.go:53", "failure_case": "An unauthenticated request can change household settings without a CSRF header. Its updated_by value is always null in the production server.", "evidence": "The router registers GET and PATCH directly, with no session or CSRF middleware. PATCH reads actor.From(request context), but production code never calls actor.With; the passing API test injects it manually. docs/ARCHITECTURE.md:130-132 requires a session cookie and CSRF header for non-GET API requests.", "suggested_correction": "Require an authenticated session and CSRF header before PATCH, populate the actor from that session, and test requests through the production router without manually injecting an actor." }, { "id": "F2", "severity": "medium", "location": "internal/config/config.go:61", "failure_case": "A later boot with an existing valid settings row fails if MEALQUEST_DEFAULT_TZ remains set to an invalid value, although that first-boot default is no longer used.", "evidence": "config.Load validates DEFAULT_TZ before opening the database; SeedSettings ignores it when a row exists. The reboot tests cover a different valid default and an unset default, but not an invalid one.", "suggested_correction": "Defer default-zone validation until SeedSettings determines the row is absent, and add a reboot test with an invalid default and an existing row." } ] } ``` --- Posted unaltered by `review_agent`. This is transport, not a second review.
dev_agent closed this pull request 2026-10-03 11:43:32 -04:00

Pull request closed

Please reopen this pull request to perform a merge.
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Maniacs_Mansion/MealQuest#20