Skip to content

v0.6.59 — backend test coverage, dead-code cleanup and defect fixes - #282

Open
roncodes wants to merge 690 commits into
mainfrom
dev-v0.6.59
Open

v0.6.59 — backend test coverage, dead-code cleanup and defect fixes#282
roncodes wants to merge 690 commits into
mainfrom
dev-v0.6.59

Conversation

@roncodes

@roncodes roncodes commented Aug 2, 2026

Copy link
Copy Markdown
Member

v0.6.59

Release branch consolidating the Fleet-Ops backend test-coverage campaign, the dead-code cleanup it uncovered, and the production defects found along the way.

⚠️ This must not merge to main until fleetbase/core-api 1.6.55 is released. One test on this branch asserts a contract that only holds after that fix — see "Known failing test" below.

What's in this release

Backend test coverage: 79.53% → 99.74%

server/src line coverage went from 79.53% to 99.74%. Tests are organised under server/tests/Unit/... and server/tests/Feature/Http/{Api,Internal}/... rather than adding to the flat root-level sprawl.

Milestone Line coverage Uncovered statements
Campaign start 79.53% ~7,000
#277 + #281 consolidated 99.57% 145
Relation callbacks and push channels 99.62% 131
Observer guards, metric queries, geojson fallbacks 99.67% 114
Shift, simulation, analytics and registry seams 99.69% 104
Relation fallbacks, import defaults and skip guards 99.74% 89

The coverage gate itself is wired into the Composer workflow — composer coverage:baseline writes a Clover report and composer coverage:check enforces --fail-under=100. The gate is intentionally still red; see "Remaining work".

Fifteen production bugs found and fixed

Examining every uncovered line turned up real defects, not just missing tests. Highlights:

  • Place::insertFromMixed() crashed on any plain address string. It called insertFromGeocodingLookup(), which existed nowhere on Place or any ancestor — every such call raised BadMethodCallException. Defined as the insert-side twin of createFromGeocodingLookup, mirroring insertFromGoogleAddress.
  • Invalid coordinates were silently reverse-geocoded at Null Island. GeocoderController::reverse() validated after converting with getPointFromCoordinates(), which is typed : Point and falls back to Point(0, 0) — so the "Invalid coordinates provided." guard never fired. An existing test had codified the buggy behaviour.
  • Place::insertFromCoordinates() never detected empty reverse-geocoding results!$results->count() === 0 compares a bool to an int, so places were silently inserted at 0,0 instead of returning false.
  • Lalamove::getQuotationForMarket() passed the market into the bool $sandbox slot, so market-scoped quotations silently ran against the sandbox host with the market dropped.
  • OrderConfig::default() declared a non-nullable self return while returning first(), fataling for companies without a stored transport config.
  • ServiceRate called Collection::sortByDesc() with no argument, throwing whenever a parcel outsized every fee tier.

Unreachable code removed or repaired

A large share of what looked like "untested" code turned out to be unreachable — branches shadowed by a broader arm above them, guards on values a type declaration forbids, fallbacks after an unconditional assignment. Each was handled deliberately:

  • Reordered where the guard's intent was real, so it now fires with behaviour unchanged (the spatial casts).
  • Deleted only where the shadowing arm was genuinely equivalent.
  • Annotated @codeCoverageIgnore with a reviewable reason where a type or an earlier validate() makes the state impossible.

One case is worth calling out: Casts/MultiPolygon's shadowed arm returned a bare geometry while the arm above it wraps in SpatialExpression. Reordering it verbatim would have silently flipped MultiPolygon writes from wrapped to bare — on the zone/service-area/location write path. It was reordered and matched, and behaviour preservation is evidenced by the spatial suites passing with their original assertions.

Found while covering — not fixed here

Utils::getPointFromMixed() has two fallback arms (Support/Utils.php:275 and :279) that recurse with a bare coordinate pair pulled out of a GeoJSON envelope. The array reader at :296:297 resolves positionally, taking index 0 as latitude and 1 as longitude — the reverse of GeoJSON's [lng, lat]. A pair that reaches either fallback therefore comes back transposed.

server/tests/PointResolutionTest.php asserts the behaviour as it stands, with a comment saying so. Correcting it touches every location write path, so it is deliberately left for its own change rather than folded into a coverage commit.

Known failing test

server/tests/Feature/Http/Internal/OrderControllerUpstreamNotFoundTest.php fails on this branch, deliberately.

Internal\v1\OrderController::nextActivity() wraps Order::findByIdOrFail() in a catch (ModelNotFoundException) that never fires today: core-api's findByIdOrFail() calls a getModelNotFoundException() method that does not exist on Eloquent's builder, so a missing order raises BadMethodCallException, escapes the catch, and surfaces as a 500 instead of a 404. core-api#231 fixes it on dev-v1.6.55.

The test asserts the post-fix contract on purpose — asserting today's BadMethodCallException would codify the defect. It currently fails with exactly Call to undefined method Builder::getModelNotFoundException() and turns green when the release lands.

To keep this branch measurable while that is outstanding, scripts/coverage-file-runner.php gained an opt-in FLEETOPS_COVERAGE_CONTINUE_ON_FAILURE=1: a failing file is recorded rather than aborting the run, the Clover report is still written, and the process still exits non-zero. Without it, the runner exit()s inside its per-file loop — every later file is skipped, no report is written, and the stale clover.xml is left behind.

Remaining work before this ships

Roughly 89 statements are still uncovered, in three groups:

  • Coverable — the bulk. Guard branches, controller arms and import fallbacks reachable by shaping the input, following the same seam and sweep patterns used so far.
  • Provably dead (~19) — shadowed branches, guards on values a type declaration forbids, and method_exists checks on methods that are declared. These get the delete-or-annotate treatment already applied in Remove unreachable backend code and fix two defects it was hiding #281. Two were reclassified during execution: OrderDispatched:151-152 and OrderPing:158-159 sit behind a method_exists($resource, 'toWebhookPayload') check where $resource is an unconditional new OrderResource(...) and Order::toWebhookPayload() is declared — so the elseif can never run.
  • Environment-blocked (~4) — the extension_loaded('geos') branch, the "core-api absent" throws, and ProofController::createSignatureFile, whose File creation resolves a disk, a url and app()->environment() and so needs a real Application rather than the container the harness builds.

Then wire composer coverage:check into .github/workflows/server.yml, and pull core-api 1.6.55 to confirm the gated test turns green.

Scope note on the test suite

Worth being explicit, since a coverage percentage invites over-reading: this suite runs on in-memory SQLite with eval'd function shims, container stand-ins and hand-registered spatial UDFs. It is good at proving branch logic and contracts, and poor at proving real-MySQL behaviour — the spatial write paths especially, where a fixture's prepareBindings override compensates for a real cast divergence. A green run means "the branches behave as described", not "the feature works against a real database". Manual verification against MySQL is still warranted for zones, service areas, and location save/update.

roncodes and others added 30 commits July 28, 2026 14:27
Adds server/tests/Feature/Http/Internal/WorkOrderAndConfigSurfacesTest.php
covering the internal WorkOrderController sendEmail flow (missing
assignee and missing email 422 guards, and the success path sending the
dispatch mail through a mailer fake with activity logging disabled),
the excel export/import delegation helpers, the OrderConfigController
delete flow with the core-service guard and soft deletion, and the
SensorFilter public-relation resolution with company scoping against
SQLite.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Models/OrderPurchaseAndDriversTest.php covering
the Order purchase helpers against SQLite: service quote resolution by
uuid and public id with purchase-rate creation, the unresolvable-quote
failure, the no-quote fallback creating an internal dispatch
transaction, purchase-rate attachment relinking the new transaction to
the order and voiding the superseded one, and closest-driver discovery
through the spatial company/user/driver chain with the located-pickup
requirement.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Support/OrchestrationPayloadBuilderTest.php
covering the OrchestrationPayloadBuilder computation helpers: payload
demand aggregation across entities with gram/pound weight conversion and
centimetre dimension normalization into litres, the order-meta fallback
for entity-less payloads, vehicle-only VROOM entries with location
requirements, capacity arrays, and max-task handling, safe meta access
swallowing accessor failures, and coordinate validation with
place-location resolution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Feature/Http/Api/DeviceControllerCrudTest.php covering
the API DeviceController against SQLite: find/delete with not-found
handling and soft deletion, detach with the missing-device 404 and the
failure branch logging, device creation/update persistence helpers with
resource wrappers, input mapping building last-position points from
latitude/longitude, blank-attachable clearing, and the attachment
failure logging helpers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Feature/Http/Internal/FleetAssignmentsAndTriggersTest.php
covering the internal FleetController static helpers against SQLite:
fleet/driver/vehicle uuid lookups with missing fallbacks, driver and
vehicle assignment existence/creation/deletion, operations-monitor cache
invalidation through a cache fake, and json responses. Also covers the
ProcessMaintenanceTriggers helpers: sandbox/mysql connection selection,
the active-schedule query with due-marker filters, open work-order
existence, work-order counting and creation, and the triggered-event
dispatch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Feature/Http/Internal/MaintenanceScheduleControllerSurfacesTest.php
covering the internal MaintenanceScheduleController against SQLite with
an excel fake: export downloads, the import pipeline with the
invalid-file error branch, schedule lookups by uuid and public id with
relation loading, the active calendar-schedule window query, session
user resolution, the ical response seam, and work-order derivation from
schedule attributes with priority and category mapping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Observers/PurchaseRateObserverAndOrderJobsTest.php
covering the PurchaseRateObserver protected helpers against SQLite (uuid
generation, relation loading, service-quote currency/amount/item access,
company and currency resolution, transaction and transaction-item
creation, and payload-based order resolution with the null fallback),
the FinalizeInternalOrderCreation job firing OrderReady with the
missing-order exit, and the OrderCanceled notification mail seams with
waypoint tracking plus the fcm/apn delegation seams.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Console/FixCommandsAndMaintenanceControllerTest.php
covering the FixCustomerCompanies command helpers against SQLite
(customer/user/company lookups, membership checks, and existing-user
assignment persistence), the polymorphic namespace fixer traversing all
five configured models, and the internal MaintenanceController export
download, import pipeline, line-item lookup, and parts/total cost
recalculation from quantity and unit costs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Support/OsrmProofAndIssueFilterTest.php covering
the OSRM routing client with faked HTTP and cache (point routes, the
minimum-points guard, multi-point routes with cache reuse, nearest,
table, and trip endpoints), the internal ProofController subject lookups
by uuid and public id across order/waypoint/entity types with the
unknown-type fallback, proof creation, signature storage through a
filesystem fake, and response payloads, plus the IssueFilter relation
subqueries across uuid/public-id/free-text variants and date-window
filtering.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Support/OptimizeOrderRouteCapabilityTest.php
covering the OptimizeOrderRouteCapability against SQLite as an admin
session user: the not-ready-preview, missing-order, and
insufficient-waypoint guards, the successful apply transaction updating
payload waypoints and marking the order route-optimized with the
completed resource payload, prompt matching for route-optimization
phrasing, and order resolution from prompt search terms.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Models/ServiceRatePersistenceAndServicabilityTest.php
covering ServiceRate's setServiceRateFees update/insert normalization,
setServiceRateParcelFees dedupe/update/soft-delete/replace flows, the
servicable-for-waypoints and servicable-for-places geometry lookups with
real containment checks through a SQLite-backed brick PDO engine (WKB
decoded into bounding-box coordinate text), and the point-to-point quote
returning base-fee line items via the calculate distance provider.

Also raises the coverage merge step's memory limit in
scripts/coverage-file-runner.php: merging 330 per-file snapshots into the
clover report exceeded the default 128M as the suite grew.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Support/UtilsGeoMatrixAndVendorTest.php covering
Utils company transaction currency resolution through ledger settings and
the USD fallback, getPointFromMixed across spatial models, raw query
expressions, arrays with public ids and nested locations, place/driver
public-id and uuid database lookups, pipe-delimited strings and
Feature-wrapped GeoJSON, strict point and coordinate accessors, OSRM
distance matrices for both redis-cached and live HTTP-faked routes,
integrated vendor id checks against the database, and the formatting,
vincenty, timezone, circle, centroid, model-class and GeoJSON conversion
helpers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Models/OrderPayloadConfigAndDistanceTest.php
covering the Order model against SQLite: time-window normalization
injecting the scheduled/created reference date for epoch-dated values,
createPayload and insertPayload resolving embedded pickup/dropoff/return
places, getPayload callbacks, purchaseQuote creating and attaching a
purchase rate, preliminary and accurate distance-and-time setters with the
payload-less guard and driver-assigned origin override, order-config
resolution preferring the config uuid then the company transport default
with ensureOrderConfig normalizing type, assigned-driver loading, dynamic
notifiable resolution, dispatched-status lookups, the order tracker
factory, no-op driver reassignment, and one-time first dispatch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Feature/Http/Api/CustomerControllerHelperSeamsTest.php
covering the customer API controller's protected helper layer against
SQLite: identity and base64 checks, active/login/verification user
lookups, user creation and uuid updates with a fake hasher, verification
code existence and retrieval, file and contact lookups with
first-or-create semantics, the CustomerAuth binding round-trip, place and
payload helpers, order record creation and findRecordOrFail, request-based
order and place queries through queryWithRequest with the directives
permission surface, device first-or-create, resource wrappers, sanctum
token issuance, resolution and revocation, and phone normalization.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Models/PlaceCreationAndImportTest.php covering
Place avatar url resolution for direct values and uuid-shaped keys,
coordinate-based creation and uuid insertion with an empty geocoder,
mixed-input resolution for public ids, uuids and strict coordinate
arrays, geocoding query composition, shared-place matching with parsed
and unresolvable location values plus the owner-scoped guard, and
import-row creation for both single-address rows falling back through
the keyless geocoder and multi-column rows defaulting their location.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Models/PayloadWaypointsAndEntitiesTest.php covering
Payload entity destination resolution through place import ids, waypoint
keys and search-uuid metadata for both setEntities and insertEntities,
waypoint insertion with nested place payloads, existing place uuids and
contact customer association, waypoint updates resolving places by uuid
and public id, current/next waypoint tracking with the place setter, and
the destination correction helpers.

Also fixes a latent bug in Payload::findDestinationFromKey: the
search-uuid fallback read an undefined $attributes variable, so the
console search-uuid resolution branches were unreachable dead code. The
fallback now checks the actual destination key against places and their
search-uuid metadata.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Support/CreateOrderPreviewDraftingTest.php covering
the CreateOrderPreviewCapability drafting seams against SQLite:
prompt-to-draft conversion resolving quoted pickup/dropoff addresses
through saved-place search with dispatch, relative scheduling, notes and
signature proof-of-delivery detection, the quoted, from-to and labeled
address pair extraction phrasings with address cleaning, place resolution
returning serialized saved places, provisional place shapes, controller
response failure detection and order unwrapping, order-config, driver and
vehicle identifier resolution including user-name and plate-number
matches, and pod method normalization from string and array config.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Support/OrchestrationRouteAndVehicleTasksTest.php
covering OrchestrationPayloadBuilder with in-memory models: route tasks
carrying stops, meta service times, scheduled and explicit time windows
and orchestrator priorities, invalid-coordinate and no-routable-stop
reasons, the deprecated job builder filtering invalid tasks, capacity
tasks for orders with and without payloads, route stop candidates from
waypoint markers and plain waypoint places, vehicle entries resolving
driver start positions, depot returns, max tasks, driver-first time
windows and merged skills for the full, vehicle-only and capacity
builders, and skill code hashing from string arrays and boolean custom
fields.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php
covering the VROOM orchestration engine with a faked HTTP layer: full
allocation building shipment and job payloads from in-memory orders and
mapping routes back to assignments with delivery-step ids, unknown-step
skips, unassigned and invalid-order merging, the capacity-only strategy
returning early without any HTTP call when every task is invalid, job and
shipment mapping guards for stops without locations, the uniform matrix
builder, runtime errors raised from failed solves, and connection
settings resolved from organization then system settings rows with
whitespace values falling through and binary endpoints skipping /solve
while appending the api key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Tracking/TrackingIntelligenceAndContextTest.php
covering the tracking stack against SQLite: track and eta results
produced through a stubbed provider manager with cache-remember
passthrough and tagged attribute caching, cache-key composition and
default provider capabilities, context building resolving driver origins
with stale-location warnings, the missing-driver fallback to the payload
pickup origin, stop collection from payload service stops, and waypoint
status resolution through tracking-number statuses with stop construction
for in-progress and completed waypoints.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Models/VehiclePositionsAndImportTest.php covering
Vehicle avatar url resolution for direct values and uuid-shaped keys,
position creation with order context persisting order and destination
references while skipping unmoved vehicles inside the fifty-meter
threshold, attribute-normalized position creation from location objects
and latitude/longitude pairs with destination uuids, and import-row
creation parsing make and model from combined vehicle names plus
resolving and assigning drivers by identifier. The SQLite spatial
function shims now return packed WKB so stored points rehydrate through
the spatial casts on re-read.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Support/PlaceSearchRankingTest.php covering
PlaceSearch saved-place searching with relevance-ranked LIKE matching,
no-query orderings for latest, default and nearby-distance modes, geocode
fallbacks through the geocoder facade including swallowed failures, the
query ranking ladder and strong-match normalization helpers, and the
Geocoding google geocoder construction with place mapping from a bare
GoogleAddress.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Feature/Http/Api/OrderControllerNearbyFiltersTest.php
covering the API OrderController query() nearby filters against SQLite:
coordinate-based nearby lookups building pickup and waypoint
distance-sphere subqueries with the company adhoc-distance option,
driver-based nearby lookups resolving the driver location by public id,
address-string lookups falling through unsaved place creation, and the
facilitator and customer morph relation filters.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds
server/tests/Unit/Support/Telematics/Providers/AfaqyProviderTransportTest.php
covering the AFAQY provider transport with faked HTTP: authentication
resolving fresh tokens with missing-credential, failed-login and
missing-token errors, authenticated posts refreshing rejected tokens and
retrying once, immediate failures when refresh credentials are absent,
non-auth failure propagation with provider error context, connection
timeouts surfacing transport exceptions, and the byte-count, ignition,
fuel-level and sensor identity/name extraction helpers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds
server/tests/Unit/Integrations/Lalamove/LalamoveQuoteAndServiceOrderTest.php
covering the Lalamove integration with a mocked Guzzle client:
preliminary-stop and payload quote requests resolving markets from stop
countries, persisting service quotes with generated uuids and
base/vat quote items through the model event dispatcher, and the full
createOrderFromServiceQuote flow resolving the sender from the first
waypoint, recipients from remaining stops with parsed phones, POD flags
from the request, and company/service-quote metadata posted to the
orders endpoint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Feature/Http/Internal/ServiceQuotePreliminaryQueryTest.php
covering the internal ServiceQuoteController preliminary flow against
SQLite: single-service quotes recalculating distance through the
calculate matrix provider and persisting quotes with items, best-quote
selection for single requests across all servicable rates, and the
integrated-vendor branches returning empty single and list payloads when
the vendor cannot be resolved in both the payload-backed and preliminary
query paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Feature/Http/Api/DriverControllerSwitchOrgAndGeofenceTest.php
covering the API DriverController against SQLite with a stand-in
SwitchOrganizationRequest, unblocking the previously fatal core
form-request path: successful organization switches validating company
membership, moving the user session, issuing a sanctum token for the
target driver profile and returning the organization payload, the
driver-not-found 404 branch, and the geofence crossing processor
upserting entry states with triggered events, skipping untriggered
entries, and closing exited states with dwell duration calculations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds
server/tests/Feature/Http/Internal/DriverControllerExistingUserAdoptionTest.php
covering the internal DriverController createRecord unique-conflict branch
against SQLite with a contract-implementing failing validator: phone
conflicts adopting an existing organization member by creating a driver
profile with the default location and skipping company assignment for
members, email conflicts returning the already-existing driver profile,
and non phone/email conflicts falling through to the validation error
response seam.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Unit/Models/MaintenanceWorkOrderImportTest.php covering
Maintenance and WorkOrder import-row creation against SQLite:
maintainable and target resolution by plate number with the equipment
name fallback, driver performer and vendor assignee resolution, persisted
imports, start/complete lifecycle guards for non-eligible statuses,
duration efficiency null fallback without estimated hours, work-order
code generation on create, and line-item normalization from json strings
and scalar rejection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds server/tests/Feature/Http/Api/PlaceAndServiceQuoteSeamsTest.php
covering the API PlaceController helper seams against SQLite — uuid and
value lookups, model class resolution, or-value fallbacks, first-or-new
places, find-or-fail, geocoding-backed creation through the empty
geocoder, search options and coordinate parsing with the search endpoint —
plus the API ServiceQuoteController preliminary flow resolving pickup
places by public id and dropoffs from mixed arrays into single-service
quotes with persisted items, the payload-backed integrated-vendor branch
returning empty collections for missing vendors, and the preliminary
missing-vendor unset-quote error seam.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
roncodes and others added 30 commits July 30, 2026 12:01
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two defects surfaced while auditing unreachable code.

GeocoderController::reverse validated coordinates only after converting them
with Utils::getPointFromCoordinates(), which is typed `: Point` and falls back
to Point(0, 0) for unusable input. The 'Invalid coordinates provided.' branch
was therefore unreachable and garbage input silently reverse-geocoded Null
Island. Resolve strictly instead so the guard works. An existing test asserted
the old behaviour (reverseCalls[0] === [0.0, 0.0]) and now asserts the error
fires with no lookup attempted.

Casts/Polygon returned the raw geometry from its GeometryInterface arm while
Casts/Point and Casts/MultiPolygon return a SpatialExpression. Only inserts
survive the raw form, because SpatialTrait::performInsert wraps the attribute
itself; there is no performUpdate, so on updates the value is bound directly and
BaseBuilder::cleanBindings only expands a SpatialExpression into the WKT and SRID
bindings that ST_GeomFromText(?, ?) needs. A bare Geometry has no __toString and
cannot be bound. Align Polygon with the other two casts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deletes branches no input can reach: concrete spatial-type arms shadowed by
instanceof GeometryInterface; a duplicate isCoordinatesStrict test inside a
branch already gated on it; Lalamove __callStatic's 'instance' case, which a
declared public static never routes there; guards a type declaration makes
redundant (getLocationAsPoint(): SpatialPoint, Request::date()'s Carbon,
Find::httpResourceForModel() always resolving, Str::isUuid on a model);
DriverController's company re-check after an early return; and the order-type
fallback after an unconditional assignment, replaced by ?? at the assignment.

Relocates Place::insertFromMixed's address-key check out of the is_string branch
(empty() on a non-numeric string offset is always true) into the array branch,
and moves the GoogleAddress arm above is_array||is_object so it is not swallowed
and flattened. Makes coordsToCircle's loop exclusive so the ring is closed
explicitly rather than by recomputing the 0-degree vertex, removing a duplicated
point; output is otherwise identical.

Keeps and annotates three guards that are deliberate: Casts/Point's
SpatialExpression arm (the guard shadowing it skips the geometries bookkeeping,
so the asymmetry is documented rather than erased), the globe-data ISO check
(all 255 bundled features carry both codes), the post-validate photo check, and
updateActivity's not-found guard pending the upstream core-api findByIdOrFail
fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review feedback on #281: deleting a shadowed arm erases the intent it
documented. Reorder so each previously-unreachable guard fires, with runtime
behaviour unchanged.

Casts/Point checks SpatialExpression before the generic Expression guard that
was swallowing it. Casts/Polygon and Casts/MultiPolygon check their concrete
type before the broader GeometryInterface guard. MultiPolygon's restored arm
must wrap in a SpatialExpression exactly as the general arm does — reordering
it verbatim would have flipped MultiPolygon writes from wrapped to raw, which
is the write path this review was guarding.

Reverts the Casts/Polygon SpatialExpression alignment. Polygon returning a bare
geometry while Point and MultiPolygon wrap is a real divergence on the update
path, but it is a write-path behaviour change that deserves its own review with
MySQL verification, so it is documented and tested rather than altered here.

Also corrects two misleading comments: the company guard note in DriverController
sat on a line whose subject is , and the updateActivity annotation implied
its guard becomes reachable once core-api is patched when in fact findOrder() is
typed ': Order' and it stays unreachable regardless.

Adds a deliberately failing test for the nextActivity not-found branch, which
becomes live when core-api 1.6.55 ships the findByIdOrFail fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The nearby-filter fixture registered ST_X, ST_Y and ST_Distance_Sphere as
constants (103.8, 1.3, 100.0), so the distance filter those tests exercise was
never actually evaluated. Decode the packed point for ST_X/ST_Y and compute
st_distance_sphere with the haversine formula on MySQL's 6370986m earth radius.

This verifies selection semantics rather than MySQL's exact arithmetic. Two
further defects in this file are left as-is and reported: the assertions use
toBeGreaterThanOrEqual(0), which cannot fail, and cross-test connection
isolation leaks so the controller can query a previous test's rows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…anup

Remove unreachable backend code and fix two defects it was hiding
…ge-100

Improve Fleet-Ops server test coverage
The per-file loop exited on the first non-zero file, so every later file was
skipped, the merge and Clover write never ran, and the previous report was left
in place reading as current — which has already caused stale numbers to be
mistaken for a fresh run.

Add opt-in FLEETOPS_COVERAGE_CONTINUE_ON_FAILURE=1, alongside the existing
PEST_FILE_TIMEOUT and FLEETOPS_COVERAGE_MEMORY_LIMIT env conventions. Failures
are collected, any partial coverage artifact is still merged, the report is
still written, and the run still exits non-zero with the failed files listed.
Default behaviour is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(place): update PhoneInput onInput handler to mutate place phone
fix(labels): correct entity label to use entity data instead of stale waypoint/order fallbacks
Resolves the conflict in Geocoding.php. The release branch centralised
geocoder construction into makeGeocoder() so a test double can be injected
through the fleetops.geocoder container binding, which removed the three
inline construction sites this PR edited. The locale logic now lives in
makeGeocoder(), so it applies to every caller rather than being repeated.

Two adjustments to the original change:

Locale and region are read from separate config keys. GoogleMaps' second
constructor argument is region biasing (a ccTLD such as `us`), not language —
language is the StatefulGeocoder argument. Passing one value to both worked
for locales that happen to also be ccTLDs (ru, es, fr) but the `en` default is
not a valid region, and it replaced the null passed previously. getLocale()
keeps this PR's key and drives language; getRegion() reads
services.google_maps.region and drives region bias.

Both getters use `?:` rather than a config() default. This key is stored in
the settings table, so it exists-but-empty on installs that never filled it
in, and config()'s default only applies when a key is absent entirely — a
stored empty value would otherwise return null from a `: string` method and
raise a TypeError on every geocode call.

Also drops a duplicated docblock left above getLocale(), and adds coverage
for both getters.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(geocoding): support configured google maps locale in geocoding re…
The whenLoaded callbacks on the WorkOrder, Maintenance, MaintenanceSchedule
and ServiceRate resources were never entered: the existing tests exercised the
type-stamping helpers directly but left every relation unloaded, so the closure
that calls them was skipped. Loading the relations reaches the callbacks and,
in passing, the fixtures they pull behind them.

Waypoint::setCustomerType is the same shape as Entity's but reads the morph
class off the resolved waypoint rather than the wrapped place, so it needs the
protected property populated to stamp anything; both are private here, hence
the reflection.

OrderAssigned's fcm/apn seams get the treatment already applied to
OrderDispatched and OrderFailed — the transports are unavailable in the
harness, so the assertion is that the delegation bodies execute and fail
inside the transport rather than before reaching it.

Line coverage 99.57% -> 99.62% (33957/34088).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The contact save guards for email and phone reuse are private, so they can
only be reached through saving() with a contact that genuinely collides on a
real table — the fake-backed observer tests could never trip them. Same for
OrderObserver::deleted, which no test invoked at all, and the parcel-fee
branch of ServiceRateObserver::updated, which the existing test walked past
with parcelService off.

The metric query builders were being overridden by the recorders the
behaviour tests install, so the real construction never ran. The bulk API's
registry-wide arm is covered by giving it a schema broad enough for all
fifteen metrics to resolve and value against empty tables.

Utils::getPointFromMixed's nested-geometry fallback is now covered, and the
test documents that it comes back transposed: the arm recurses with a bare
coordinate pair, which the array reader resolves positionally as [lat, lng]
rather than GeoJSON's [lng, lat]. Asserted as-is rather than corrected —
changing it touches every location write path.

Line coverage 99.62% -> 99.67% (33974/34088).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Another pass over the one-line seams the behaviour tests stub out: the shift
listener's schedule lookup and driver notification, the driving simulation's
chain dispatch, the fuel provider registry's config load, and the payload
lookup query behind the accessor trait.

AbstractFuelProvider::headers is an extension point nothing calls — PetroApp
is the only driver and it overrides it — so the empty default is asserted
directly through a minimal subclass.

The analytics controller funnels every widget endpoint through run(), which
reports and degrades to a 500 rather than letting a widget failure reach the
client. That branch needs report() to exist, which the bare harness container
does not provide, so the test declares it.

ProofController::createSignatureFile is left uncovered: File creation resolves
a disk, a url and app()->environment(), which needs a real Application rather
than the container the harness builds.

Line coverage 99.67% -> 99.69% (33984/34088).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Models fall back to a direct uuid lookup when a relation comes back empty,
but relations resolve fine on unsaved models, so leaving a fixture
unpersisted does not reach those arms — they need a relation that genuinely
returns nothing.

The import fallbacks only fire on rows that omit a column every fixture
supplies: a vehicle name the parser cannot decompose, an issue row with no
location at all. Zone centroids resolve the geometry engine before inspecting
the border, so even the null-island path needs an engine registered.

Route sequencing skips orders with no payload and waypoints whose place is
gone; neither aborts the run. The order preview draft now resolves both ends
of the prompt rather than only the pickup, and integrations that declare no
service bridge return no service types.

Line coverage 99.69% -> 99.74% (33999/34088).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
getPointFromMixed() resolves a GeoJSON envelope in two passes. When the first
declines and Point::fromJson() then throws, two fallback arms recursed with
the bare coordinate value — which hands it to the positional array reader in
the same method, where index 0 is read as the latitude and 1 as the
longitude. That is the reverse of GeoJSON's [lng, lat], so any pair reaching
either arm came back transposed.

Well-formed points never get that far: pointFromGeoJson() returns early for
them. Reaching the fallback needs an envelope isGeoJson() accepts but
Point::fromJson() rejects, whose coordinate value is still a single pair — a
Point carrying extra members, or a multi-coordinate type whose coordinates is
a flat pair rather than an array of pairs.

Both arms now read the value as GeoJSON first, through a thin wrapper over the
existing pointFromGeoJson(), whose mapping is already correct. It returns null
for anything that is not a usable numeric pair, so nested Polygon and
LineString rings decline there and still fall through to the old recursion
untouched. Only the bare-pair case changes.

PointResolutionTest asserted the transposed result with a comment recording
that it documented the defect rather than the intent. That expectation is
flipped here, deliberately, since this is a behaviour change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
composer.json has carried a coverage:check script since the campaign started
and nothing ever called it. This wires the assertion into the server workflow.

The step runs scripts/coverage-summary.php against the clover report the
preceding baseline step already wrote, rather than `composer coverage:check`,
which re-runs test:coverage:clover first — a second full pass of the suite
under coverage for no new information.

Expected red on arrival, on two counts, neither a regression: coverage is at
99.74% with 89 statements still to close, and the job already fails earlier at
Run Tests because OrderControllerUpstreamNotFoundTest asserts the post-fix 404
contract that only holds once core-api 1.6.55 ships.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both quote controllers branch on `single`, and every existing test passed it,
so the arms that wrap a quote in a collection were never entered — on either
the named-service path or the all-rates path, and in both the API and internal
controllers.

The API probe also swallowed the callback that getServicableServiceRates()
hands a query builder, which left the company scoping the controller applies
untested. It now runs the callback against a recorder and asserts the
constraint, which is why the existing collection test grew a session: it
reaches code that reads one now.

Line coverage 99.74% -> 99.76% (34006/34088).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every stripe fixture builds an unsaved quote, so the arm that persists the
product id rather than staging it in memory was never taken. Asking for the
price before the product covers the provisioning path the same fixtures skip
by fetching the product first.

previousActivity() resolved its context off the config exactly like the
forward helpers, but every test passed one explicitly. The assertion pins the
current activity in the same chain because the no-activity fallback returns an
empty collection too, so the count alone would not say which arm ran.

ServiceQuote:214 stays uncovered and is not reachable: it returns null when
Payment::getStripeClient() is falsy, but that method is nullable in signature
only and always returns a new StripeClient.

Line coverage 99.76% -> 99.77% (34010/34088).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ompany

The entity label action reached for a new internal `labels/{id}` route wired
across into the public `Api\v1\LabelController`. The internal namespace already
exposes `orders/label/{id}` via `Internal\v1\OrderController@label`, which
already resolves `type=entity` through `findEntityLabelSubject()`, so no new
backend route is needed. `$type` also defaults to `strtok($publicId, '_')`, so
an `entity_*` public id resolves on its own and the query param can go.

- drop the added internal `labels` route group
- call `orders/label/{public_id}?format=base64`, matching `viewWaypointLabel`
- reuse `modals/order-label` instead of cloning it, as the waypoint action does,
  with an `@options.subject` fallback so the object alt still resolves
- fix the `Failed to load entity label.s` typo and add the two new keys to the
  six other locales that already carry the waypoint equivalents

Also scopes label subject resolution to the session company. The lookups matched
on identifier alone, so any authenticated user could render a label for any
order, waypoint or entity in another organization by supplying its public id.
The identifier match is grouped in a closure — appending the company constraint
to the existing chain would read as `public_id = ? OR (uuid = ? AND company_uuid
= ?)` and still leak. Resolution fails closed when there is no company session.
Applied to both the internal and public API paths, with regression coverage for
the foreign-company, precedence and no-session cases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feat(labels): add view label action for individual entities
Read GeoJSON fallback coordinates in GeoJSON order
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants