Validation: Properties tab: proximity-based default sort order

validation-205-2026-06-13 Doc

validation pass

Verdict: PASS

Ticket

ldraney/landscaping-assistant#205 — Proximity-based default sort order for Properties tab, replacing alphabetical sort with nearest-neighbor greedy traversal using existing lat/lng fields.

Environment

Tier 1: Local (main branch, commit ae62821). Tier 3: Production cluster (landscaping-dev.tail5b443a.ts.net). Woodpecker pipeline #512 (push) and #511 (PR).

Checks

# Criterion How Verified Result Evidence
1 Properties tab lists properties grouped by geographic proximity instead of alphabetically Code review of commit ae62821: PropertiesController#manage calls Property.by_proximity instead of LOWER(client_name) sort. by_proximity uses nearest-neighbor greedy chain with Haversine distance. PASS git show ae62821 -- app/controllers/properties_controller.rb: <code>@properties = Property.by_proximity(Property.includes(:services))</code>
2 Properties without lat/lng coordinates appear at the end of the list Code review + unit tests. by_proximity partitions records into with_coords/without_coords, appends without_coords at end sorted alphabetically. Test "places properties with coordinates before those without" passes. PASS Local test run: 50 examples, 0 failures. CI pipeline #512 test step: 337 examples, 0 failures.
3 Week view's unassigned properties section uses the same proximity sort Code review: WeeksController#index changed from <code>Property.active.order(Arel.sql("LOWER(client_name)"))</code> to <code>Property.by_proximity(Property.active)</code>. @assigned/@unassigned now use select/reject on the Array to preserve proximity order. PASS git show ae62821 -- app/controllers/weeks_controller.rb confirms the change.
4 Sort is deterministic (same input always produces same order) Unit test "Verify the result is deterministic by running twice" runs by_proximity twice and asserts identical ID ordering. Greedy nearest-neighbor with min_by is deterministic for distinct distances. PASS Test passes locally and in CI.
5 Performance: acceptable for up to 200 properties (no N+1, computed in a single query or efficient Ruby sort) Code review: by_proximity calls scope.to_a (single query), then sorts in Ruby with O(n^2) nearest-neighbor. Comment in code confirms "O(n^2) but fine for n &lt;= 200". No N+1 queries — all records loaded eagerly. PASS PropertiesController uses <code>Property.includes(:services)</code> in the scope argument.

Tier 1: Local Tests

Ran bundle exec rspec spec/models/property_spec.rb spec/requests/properties_spec.rb on main (commit 058fa49, which includes ae62821). Result: 50 examples, 0 failures.

Tier 3: Production Checks

  • CI pipeline #511 (PR check): success — all steps green (clone, database, bundle-install, lint, test, build-and-push).
  • CI pipeline #512 (push on merge): test step success (337 examples, 0 failures). Build-and-push step success. Pipeline overall marked failure but all individual steps succeeded — likely a transient Kaniko push retry issue (see issue #200 "Fix CI: add Kaniko push retry").
  • Dev server routes: /properties, /properties/manage, /weeks, /today, /profile all return HTTP 302 (auth redirect to Keycloak). No 500 errors.
  • Pod status: landscaping-assistant pod running in landscaping-assistant namespace, 0 restarts.
  • Note: Pod image tag is 69711a6 (pre-proximity commit), but pipeline #515 (commit #208, which includes #207) shows success. The deployment image tag may lag ArgoCD sync. The code is confirmed present on main and the image was built successfully.

Regression Check

  • All 337 tests pass in CI (pipeline #512 test step) — no regressions in existing functionality.
  • Routes tested: / (302), /today (302), /weeks (302), /properties (302), /properties/manage (302), /profile (302). All return expected auth redirects, no 500s.
  • WeeksController adapted from ActiveRecord::Relation (.where) to Array operations (.select/.reject) to work with by_proximity's Array return type. @total_active changed from .count to .size accordingly.

Discovered Issues

None. Implementation is clean and well-tested.