chore(config): ServerConfig proto + YAML loader (S01 Step 1)

Summary

Step 1 of the merged S01 implementation plan (docs/plans/2026-05-20-s01-http-server-and-routing.md). Ships the ServerConfig proto (with ServerTimeoutsConfig and ShutdownConfig) plus the Go-side internal/config package — Load, serverFromProto, ParseSize with typed DurationParseError and SizeParseError. Tests cover AC #14 (config load + protovalidate) and AC #15 (size-string parsing).

Refs #89 (closed).

Reviewability note (~917 reviewable LOC)

This MR exceeds the 500-LOC ceiling, but ~495 LOC of that is heavily mechanical test-table content:

  • internal/config/config_test.go — 5 table-driven tests + 3 TestLoad_RequiredMessageRejection subtests
  • internal/config/server_test.go — 1 typed-error-shape test + 1 table-driven TestServerConfig_FromProto_InvalidDuration (8 rows)
  • internal/config/size_test.goTestParseSize (18 rows including the two overflow rows) + 1 envelope-shape test

The ~300 LOC of novel logic lives in:

  • internal/config/config.goLoad (LabKit v2 wrapper + error pathing)
  • internal/config/server.goserverFromProto + the two private field-aware parse helpers
  • internal/config/size.go — public ParseSize + the private field-aware parseSize (with the IEC suffix table)
  • internal/config/errors.goDurationParseError / SizeParseError envelope types

The proto file gains three messages (~55 lines) per spec verbatim plus three required = true markers on message-typed parents (see "Spec adherence note" below). The regenerated gen/.../config.pb.go is excluded from the reviewable count per docs/dev/development-model.md (generated files don't count).

Resolved spec ambiguities

  • ParseSize suffix semantics — IEC. KB=10³, MB=10⁶, GB=10⁹; KiB=2¹⁰, MiB=2²⁰, GiB=2³⁰. The spec admits both suffix sets without semantic specification; the plan listed both as accepted suffixes, forcing a choice. IEC is the only standard reading that distinguishes them. 5MB parses to 5,000,000 bytes (~4.77 MiB).

Spec adherence note

The proto adds (buf.validate.field).required = true to Config.server, ServerConfig.timeouts, and ServerConfig.shutdown. The spec's proto block doesn't show these markers. The change is purely additive (every YAML valid under the spec's schema remains valid under the tighter schema; the spec's own YAML example sets all three blocks explicitly). Intent: surface missing-block configs at protovalidate time with a clear "field is required" message rather than at parse time with a misleading leaf-field error. A follow-up spec MR to mirror this in the spec's proto block is recommended but not bundled into this MR.

There's also a pre-existing spec inconsistency: §Security Considerations describes the default as "the 5 MiB default limit" while the YAML default is "5MB". Under the IEC reading the implementation parses "5MB" to 5,000,000 bytes (~4.77 MiB), tracking the proto/YAML value. The spec prose needs a separate amendment.

Validation trail

  • /validate-step (first pass): ADVISORIES ONLY
  • /review-branch: APPROVE with 2 WARN + 7 OBSERVATION; all actionable items fixed in 196724c
  • /validate-step (second pass): ADVISORIES ONLY (one spec-adherence WARN per the note above)
  • Full local go test -race -short -count=1 ./... green
  • golangci-lint run ./internal/config/... ./gen/artifactregistry/config/v1/... — 0 issues
  • go mod tidy no-op (module tidy)

Test plan

  • CI: build, vet, lint, format, tests all green
  • CI: markdownlint, vale, lychee clean
  • CI: proto-freshness check confirms .pb.go is in sync with .proto
  • Reviewer: spot-check the IEC suffix table in size.go against the test expectations in size_test.go
  • Reviewer: confirm the spec-adherence note (required-true markers
    • 5MB vs 5 MiB) is acceptable as-is, or request a paired spec MR
  • Reviewer: verify the test-table majority claim by sampling config_test.go, server_test.go, size_test.go
Edited by Suleimi Ahmed

Merge request reports

Loading
Loading