--- phase: 04-cli-scaffolding-i18n-and-mail plan: 04 subsystem: testing tags: [scaffold, phrasebook, postcard, mailpit, testcontainers, i18n] requires: - phase: 04-cli-scaffolding-i18n-and-mail provides: six make commands, phrasebook Translator, postcard Mailer and drivers provides: - adversarial unit coverage for CLI scaffolding, catalog lookup, and mail safety - Mailpit testcontainer SMTP receipt via HTTP API - scripts/check-phase4.sh root/hello/race/SMTP sign-off gate affects: [plugin-porting, 05-data-layer] tech-stack: added: [] patterns: - copied hello workspace drives public make/build APIs then go build and go vet - Mailpit receipt is asserted through a separate HTTP API after go-mail SMTP send - testing.Short skips only Mailpit; missing Docker fails the full test key-files: created: - postcard/templates_test.go - postcard/smtp_test.go - postcard/mailpit_test.go - scripts/check-phase4.sh modified: - internal/build/build_test.go - cmd/summer/main_test.go - phrasebook/translator_test.go - party/registry_test.go - examples/hello/hello_test.go key-decisions: - "Mailpit image is axllent/mailpit:v1.31.1; receipt is polled from /api/v1/messages then /api/v1/message/{ID}" - "fstest.MapFS WalkDir cannot host '..' keys; malformed lang paths are extra-segment and wrong-suffix files" patterns-established: - "Phase gate scripts refuse missing Docker instead of skipping SMTP" - "Hello activation tests obtain Translator from backpack and pass towel.WithLocale" requirements-completed: [CLI-02, I18N-01, I18N-03] duration: 8min completed: 2026-09-18 --- # Phase 4 Plan 04: Unit tests and Mailpit Summary **Adversarial coverage for six make artifacts, pl/en phrasebook lookup, and postcard mail, plus a real Mailpit SMTP receipt and `scripts/check-phase4.sh`** ## Performance - **Duration:** 8 min - **Started:** 2026-09-18T12:04:31Z - **Completed:** 2026-09-18T12:12:42Z - **Tasks:** 3 - **Files modified:** 9 ## Accomplishments - Copied hello-app tests generate all six artifacts, compile and vet the workspace, reject malformed names/traversal/duplicates, and leave handwritten `plugin.go` untouched - Phrasebook catalog tests cover nested groups, invalid YAML/pipes, compass `app.locale`/`fallback_locale`, and hello activation through `towel.WithLocale` - Postcard memory tests preserve To/Cc/Bcc/ReplyTo and keep unsafe HTML out; SMTP TLS stays explicit; Mailpit HTTP API proves go-mail receipt; `scripts/check-phase4.sh` is the phase gate ## Task Commits Each task was committed atomically: 1. **Task 1: Close scaffold and CLI command boundary coverage** - `85bdb51` (test) 2. **Task 2: Close translation lookup and catalog boundary coverage** - `918e941` (test) 3. **Task 3: Close mail safety, driver, and Mailpit receipt coverage** - `9f6fbad` (test) **Plan metadata:** (this commit) ## Files Created/Modified - `internal/build/build_test.go` - exact paths, workspace build/vet, malformed artifact names - `cmd/summer/main_test.go` - five make argument forms, `--no-migration`, public CLI execution - `phrasebook/translator_test.go` - catalog, pipe, locale-config, and substitution boundaries - `party/registry_test.go` - activation errors name plugin, file, and key - `examples/hello/hello_test.go` - backpack translator via `towel.WithLocale`; unknown mail template - `postcard/templates_test.go` - recipients, HTML safety, registration ownership - `postcard/smtp_test.go` - TLS policy and credential-free SMTP errors - `postcard/mailpit_test.go` - `TestSMTPMailpit` against `axllent/mailpit:v1.31.1` - `scripts/check-phase4.sh` - root vet/test, hello vet/test, focused race; Docker required ## Decisions Made - Mailpit receipt is observed through the HTTP API after SMTP send, not by trusting `Send`'s return value - `testing.Short` skips only the Mailpit container test; a full `go test ./postcard -run TestSMTPMailpit` fails when Docker is unavailable - Malformed lang-path cases use extra segments and wrong suffixes because `fstest.MapFS` `WalkDir` recurses on `..` keys ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 1 - Bug] fstest.MapFS cannot walk `..` fixture keys** - **Found during:** Task 2 (path traversal catalog case) - **Issue:** `lang/en/../pl/lang.yaml` in `fstest.MapFS` caused `WalkDir` to recurse until a stack overflow - **Fix:** Cover malformed paths with extra-segment, `.yml`, and non-`lang/` prefixes; `parseLangPath` still rejects `..` when it appears in a cleaned path - **Files modified:** `phrasebook/translator_test.go` - **Verification:** `go test ./phrasebook -short -count=1` PASS - **Committed in:** `918e941` (Task 2 commit) **2. [Rule 3 - Blocking] cobra help omits optional-arg descriptions** - **Found during:** Task 1 (CLI argument-form assertions) - **Issue:** `make:migration --help` prints `[plugin] [name]`, not the Arg Description `vendor.plugin` - **Fix:** Assert the real Usage forms `[plugin] [name]` and `--no-migration`; keep `vendor.plugin` on required `make:plugin` - **Files modified:** `cmd/summer/main_test.go` - **Verification:** `go test ./cmd/summer -run TestToolCommandNames -count=1` PASS - **Committed in:** `85bdb51` (Task 1 commit) --- **Total deviations:** 2 auto-fixed (1 bug, 1 blocking) **Impact on plan:** No production API changes. Tests cover the same contracts with fixtures cobra and `fstest` can actually execute. ## Issues Encountered None ## User Setup Required None - no external service configuration required. Mailpit runs in Docker via testcontainers; production SMTP stays in `mail.*` / `SUMMER_MAIL__`. ## Next Phase Readiness Phase complete, ready for next step. Scaffolding, phrasebook, and postcard contracts now have failing-when-broken tests including a real SMTP receipt. `scripts/check-phase4.sh` is the sign-off gate and requires Docker. ## Verification - `go test ./internal/build ./cmd/summer -run 'TestScaffoldAllArtifacts|TestModelsLeaf|TestToolCommandNames' -short -count=1` — PASS - `go test ./phrasebook ./party -short -count=1 && go -C examples/hello test ./...` — PASS - `go test ./postcard -run 'TestMail|TestSMTPMailpit' -short -count=1` — PASS (Mailpit skipped under `-short`) - `go test ./postcard -run TestSMTPMailpit -count=1` — PASS (Docker/Mailpit receipt) - `./scripts/check-phase4.sh` — PASS (root vet/test including Mailpit, hello vet/test, race) ## Self-Check: PASSED --- *Phase: 04-cli-scaffolding-i18n-and-mail* *Completed: 2026-09-18*