Skip to content

test(ember): drive addon/ coverage behind a per-file 100% gate - #310

Draft
roncodes wants to merge 104 commits into
mainfrom
feature/fleetops-addon-coverage-loop-cfd7dd
Draft

test(ember): drive addon/ coverage behind a per-file 100% gate#310
roncodes wants to merge 104 commits into
mainfrom
feature/fleetops-addon-coverage-loop-cfd7dd

Conversation

@roncodes

@roncodes roncodes commented Sep 4, 2026

Copy link
Copy Markdown
Member

Drives addon/ toward 100% coverage behind a per-file gate, with the LCOV uploaded to Codecov under a frontend flag.

This is a draft: the gate is still red on purpose. pnpm run test:ci exits 1 because the campaign is not finished — 83 blueprint it renders scaffolds have never been green (DEFECTS #4) and coverage is at 32%, not 100%. The branch is green in the sense that matters day to day: no test that passes today fails because of this work, and every iteration has been verified against a full run.

Where it stands

baseline (iteration 1) now
statements 3,213/18,831 (17.1%) 6,042/18,609 (32.5%)
branches 1,862/12,335 (15.1%) 4,035/12,099 (33.3%)
functions 1,092/5,526 (19.8%) 1,795/5,491 (32.7%)
tests 832: 502 pass / 330 fail 1,289: 1,206 pass / 83 fail

309 files are at 100% on all four metrics. 69 commits: 48 test, 21 fix.

What is in it

Phase A — the gate. ember-cli-code-coverage + ember-window-mock, coverage config with the pnpm-symlink excludes, stamp-coverage-run / check-coverage / check-coverage-test, the Testem.afterTests upload (a plain QUnit.done truncates the multi-MB POST size-dependently), the test:ci script set, codecov.yml with backend and frontend flags both carrying forward, and the Test with coverage job. The gate enforces 100% on all four metrics per file, that every eligible addon/ file appears in the report, and that the artifacts came from the run that just finished.

Getting the baseline honest. It started at 775/827 red. Eight harness root causes are fixed and recorded (undeclared tracked-built-ins, host-console module shims, initializer test paths, ember-intl locale hydration, a missing dummy model, testem's bail_on_uncaught_error, fetch's config.API).

Phase B — the grind, file by file with each batch slice-verified before commit.

Production fixes found while covering

21 of them, each in its own commit, never bundled into a coverage commit. A representative few:

  • fix(order) — the route-optimization error reached nobody: the component called intl.t(...) in a catch without injecting intl, and asked for a key that does not exist. Two commits.
  • fix(map) — the device drawer showed the wrong list, and its Device column opened a panel bound to the event rather than the device.
  • fix(order) — every selected document uploaded twice; the tracking lookup form reloaded the page; the active tracking stop matched on undefined ids.
  • fix(components) — seven components had no app/ re-export at all, so the resolver could not find them; four app-tree templates were shadowing the addon's co-located ones.
  • fix(vehicle,driver) — 23 form fields ignored the write permission.
  • fix(map)assignPane handed a layer the whole { pane, paneName } pair where Leaflet wants the name.

Decisions waiting on you

DEFECTS.md carries the full worklist. Three entries are genuinely yours to call, and I have not picked for you:

  • fix: Place creation and validation #37 / feature: Internationalization #38 custom-entity/form — the image upload reads a config nothing provides, and the dasherized type never sticks.
  • v0.4.16 #83 services/leaflet-draw-restriction.js — an entire service with no consumer anywhere in addon/, reading this.map and this.notifications it never declares, so its guards cannot bind and its six user-facing warnings are all no-ops. Wire it up or delete it.

One more is outside this package: #75, six fleetops-data models declare a custom-field-value relationship no package defines. Worked around in the dummy app so the suite can run.

Reviewing

The per-iteration ledger is COVERAGE-PROGRESS.md — numbers, what each batch covered, and the traps found. DEFECTS.md is the worklist, in the format the ember-ui campaign used: every unreachable-code claim is traced to the caller, template or constant that closes it off, never "appears unused".

Phase A of the addon/ coverage campaign. Ports the ember-ui coverage
setup (ember-cli-code-coverage 3.1.0 behind COVERAGE=true, per-file
100% gate with artifact-freshness check and its self-test, Testem
afterTests upload, codecov.yml with backend+frontend flags, a "Test with
coverage" CI job that uploads with if: always()) and repairs the harness
so the existing suite can run at all.

Baseline before: 775/827 tests red, no coverage artifact possible.
Baseline after:  832 tests, 502 pass / 330 fail (223 of the failures
are untouched `ember generate` scaffolds, DEFECTS #4).

Coverage baseline (denominator for the campaign):
  Statements 3213/18831 (17.1%) · Branches 1862/12335 (15.1%)
  Functions  1092/5526  (19.8%) · Lines    3123/17868 (17.5%)
  530/746 addon files have gaps; 3 never load (see ledger).

Harness root causes fixed (DEFECTS #1-#3, #5-#11): ember-core imports
tracked-built-ins without declaring it; ember-core imports host-console
modules (config/environment, extensions, the `fetch` AMD shim) and reads
config.API at load; ember-intl hydrates every bundled locale and the
browser lacks mn-mn ICU data; the dummy app had no file model, no
hostRouter, and EXTEND_PROTOTYPES off while the console runs with it
on; testem's bail_on_uncaught_error truncated runs; a test assigned the
real window.location and navigated the browser away; eight tests
imported non-existent dummy/ initializer paths.

Coverage plumbing traps: ember-cli-code-coverage 3.x has no included
hook, so the istanbul plugin is wired in index.js; for an ember-engines
buildEngine addon the babel key must be top-level in that config; the
json reporter must be requested; and both plugin and middleware read
coverage.js from ember-addon.configPath (tests/dummy/config).
…currency-decorators import

- addon/helpers/is-active-route.js re-exported @fleetbase/console/helpers/is-active-route,
  a module that exists nowhere; nothing referenced the helper (DEFECTS #12).
- order/details/proof.js imported ember-concurrency-decorators, which this package does not
  declare; ember-concurrency (already used everywhere else) exports the same task decorator
  (DEFECTS #13).

Both modules threw on evaluation and were absent from the coverage report.
All 20 real tests in layout/fleet-ops-sidebar-test.js now pass (13 were red).
Every failure was test-side, against ember-ui's current navigator markup:

- the nested view's back control is a sibling <button>, so :first-of-type
  and :nth-of-type(n) never addressed menu items; items are now looked up
  by their own index through findAll
- qunit-dom includesText only inspects the first match; container-level
  checks are used where the test meant "any item"
- search results are portaled to #application-root-wormhole; the suite
  mounts that inside #ember-testing (ember-ui's idiom) and asserts on the
  full result list, since branch items legitimately match by keyword
- the universe stub lacked the Evented surface the component subscribes to
- common.create-new-resource is a host-console translation; added
  tests/helpers/host-translations.js, applied via addTranslations for every
  rendering test

Coverage: 3213/18831 -> 3219/18856 statements (17.07%); tests 502 -> 513 pass.
fleet-ops-sidebar.js 77/94 statements, 43/48 functions.
addon/helpers/format-duration.js only re-exported ember-ui's helper; nothing imports
the addon module and templates resolve the helper from ember-ui's own app re-export.
Being a pure re-export it also never entered the coverage report (DEFECTS #14).
Replaces the two blueprint scaffolds under layout/fleet-ops-sidebar/ with real
rendering suites: store queries and their params, error reporting, universe-driven
reloads, live-map focusing (ready and deferred, including a failed transition),
panel-title routing with the fleets-index collapse, permission-gated panel
dropdown, and every row dropdown action delegating to the actions services.
FleetListingPanel is replaced by a template-only stand-in so the listing is
tested in isolation.

Coverage: 3219 -> 3280/18856 statements (17.39%); tests 513 -> 534 pass (851 total).
driver-listing.js 43/43 statements, fleet-listing.js 40/43.
Adds a registry-and-search suite for the sidebar: items and panels other extensions
register through the universe menu registry (root, per-section, in-place footer
components, nested panels, pinned items, priority ties), the API search provider
(merged after local matches; empty and failing responses swallowed), the primary
action, and the default-orders-landing predicate including a null router URL.

Removes nine fallbacks in the component that no caller can reach (DEFECTS #15):
five default arguments, the eight @Tracked list initializers the constructor always
overwrites before any read, the ?? [] in withRegistryItems, the console.-prefix guard
in fullRoute and the ?? 0 in defaultPriorityForRoute. The empty-query guard in
searchNavigation stays behind an istanbul ignore naming the navigator's own filter.

fleet-ops-sidebar.js: 83/83 statements, 41/41 branches, 48/48 functions.
Coverage: 3280 -> 3290/18845 statements (17.45%); tests 534 -> 543 pass (860 total).
Adds an actions-and-layout suite for the sidebar operations monitor: store
normalisation (including hosts without pushPayload and record-like fleets),
request failure, universe-driven reloads, live-map sources, per-tab filters and
empty states, fleet expansion with embedded members, filtered fleet rows, every
row dropdown action, locate flows, alternative fleet identifiers and null entries,
and the list-height observers with all three boundary fallbacks.

Removes code no path can reach (DEFECTS #16): three unreferenced getters, the
empty-query guard in resourceMatches, the expandedFleetIds initializer, two
never-nullish ?? 0 fallbacks and nine default arguments; the trailing tab check in
performEmptyStateAction is now unconditional. Non-browser host guards, the
did-insert ordering guard and the EXTEND_PROTOTYPES-shadowed Array.isArray branch
carry istanbul ignores naming their reason.

operations-monitor.js: 242/242 statements, 98/98 branches, 113/113 functions.
Coverage: 3290 -> 3359/18827 statements (17.84%); tests 543 -> 563 pass (880 total).
Real suites for order-route-type, part-identity, equipment-identity, driver-identity,
device-identity and vehicle-identity; the driver-name, vehicle-name and place-address
scaffolds replaced; residue cases appended to attached-vehicle, telematic-device and
telematic-provider. The pre-existing resource-identities suite passes again: its red
tests passed @column={{hash}}, and a bare helper as a named argument is rejected at
template compile time in Ember 5 ({{(hash)}} invokes it).

Removes three click guards the templates already enforce (DEFECTS #17): the
attached-vehicle hasVehicle check, the telematic-provider `?? row` fallback and the
driver-identity `column ?? {}` in a compact-only getter.

All 12 files in addon/components/cell/ are at 100% statements, branches and functions.
Coverage: 3359 -> 3462/18825 statements (18.39%); tests 563 -> 627 pass (935 total).
…fully

Rewrites the 14 red `Unit | Utility` suites (13 of them `assert.ok(result)`
scaffolds, one stale against commit f784e71) and adds order-route-summary,
to-calendar-date and waypoint-label tests. All 16 utils are at 100% on every
metric; the loader suite is deterministic (no network, no free-running
timers).

Source, all recorded in DEFECTS #18-#22:
- leaflet-to-geojson: createFeatureCollectionFromLayers passed an object to a
  constructor that needs an array and always threw; fixed. normalizeToRings'
  duplicate trailing return merged.
- utils/geojson/geo-json.js: dead duplicate importing a missing sibling;
  deleted with its app shim and scaffold.
- map-drawer-dropdown-position: reads window via ember-window-mock.
- leaflet-plugin-loader: dead defaults at single-caller internals deleted,
  non-browser guards istanbul-ignored with reasons.
- setup-customer-portal, to-calendar-date, to-multi-polygon: unreachable
  defensive fallbacks deleted.
- utils/leaflet: Leaflet global resolved lazily instead of at module load.

Coverage: statements 3462/18825 -> 3682/18813, branches 2135 -> 2364,
functions 1197 -> 1243; tests 627 pass / 308 fail -> 690 / 290; files fully
covered 229 -> 246.
Two harness root causes, recorded in DEFECTS #23:
- ember-local-storage caches storageFor proxies at module level; the first
  test app destroys them and later apps assert "Cannot create a new tag ...
  after it has been destroyed" on any currentUser/appCache read. The shared
  setup helpers now reset that cache after every test.
- route-optimization and leaflet-routing-control register through
  universe.getApplicationInstance(), which only the console sets; those
  suites hand the universe the test owner.

Six suites corrected to the source contract (DEFECTS #24): stubs moved off
getter-only @action members onto the host router, the contextmenu removal
count, device panel.view's warning return, and geofence's multi-hop reload
wait.

Coverage: statements 3682 -> 3808/18813, branches 2364 -> 2412,
functions 1243 -> 1277; tests 690 pass / 290 fail -> 709 / 271. No
source change.
…r/route suites

- Move 16 unit tests from connectivity/telematics/index/* to the current
  connectivity/telematics/* paths (the subtree was moved without its tests);
  drop one stale duplicate and one mis-generated duplicate (DEFECTS #25).
- Add the two missing app/ re-export shims for controllers/operations/orders/
  index and controllers/operations/routes/index; the dummy app could not
  resolve either (#26).
- Correct the orders-details route test to the route's delegation to the
  controller teardown methods, fix the attachments assertion count, and
  replace the register-osrm scaffold with a real registration test (#27).
- Record the pre-existing "Failed to fetch" spill from form scaffolds (#28).

Coverage: statements 3808 -> 3891/18813, branches 2412 -> 2449,
functions 1277 -> 1299; tests 709 pass / 271 fail -> 735 / 244.
Eight tests corrected to the source contract (DEFECTS #29): the
vehicle-details controller passes the vehicle public id (a9eed9c), the
map settings payload carries the tile-url keys, two prototype-based fakes
shadow getters / bind @action through an inheriting object, and the three
helper scaffolds became real tests.

Both Leaflet initializer tests now drive the initializer's 100ms poll
through a captured setInterval. They used to leak that poll into the next
test, and in a full run the polyfill's leaked poll crashed on the stub
Leaflet global the next test installed. Both initializers are at 100%.

Everything outside `Integration | Component` is green.

Coverage: statements 3891 -> 3904/18813, branches 2449 -> 2459,
functions 1299 -> 1300; tests 735 pass / 244 fail -> 747 / 236; files
fully covered 246 -> 249. No source change.
…p tile-url arguments

Replaces the scaffolds for fuel-report, warranty, place, integrated-vendor,
service-area and zone details with real suites (13 tests) and adds a shared
register-template-only helper that stands in ember-ui's network-backed
CustomField::Yield and CountryName.

Source (DEFECTS #30): five map templates passed `@url={{leaflet-tile-url}}`
as a bare named argument, which Ember 5 rejects at render, so the place,
service-area and zone details views and the two map modals could not render.
All five now use `{{(leaflet-tile-url)}}`. The helper's dead `= {}` hash
default is trimmed and it has its own test.

Coverage: statements 3904 -> 3916/18813, branches 2459 -> 2465,
functions 1300 -> 1304; tests 747 pass / 236 fail -> 761 / 230; files
fully covered 249 -> 250.
Replaces the fuel-report, warranty, place, integrated-vendor, service-area
and zone form scaffolds with real suites (13 tests). A shared helper stands
in the store-backed ember-ui inputs and provides a record-like fixture whose
modelName/isNew let `cannot-write` resolve a real permission, so both the
enabled and disabled states are exercised. All six form components are at
100%.

Source (DEFECTS #31): fuel-report/form's onAutocomplete and
integrated-vendor/form's showAdvancedOptions/toggleAdvancedOptions were
referenced by no template; deleted.

Coverage: statements 3916 -> 3921/18808, branches 2465 -> 2469,
functions 1304 -> 1306; tests 761 pass / 230 fail -> 772 / 224; files fully
covered 250 -> 253.
…omponents

Replaces nine scaffolds with real rendering suites: modals/place-details,
modals/point-map, device/pill, driver/pill, vehicle/pill, entity/card,
vehicle/card, driver/panel-header and vehicle/panel-header (23 tests).

Source (DEFECTS #32): vehicle/pill.hbs passed `@this.resource=` instead of
`@resource=` to the Pill, so click handlers got no vehicle and the online
dot was always offline, and its tooltip invoked a string as a helper. Both
fixed.

Coverage unchanged (these components carry no JS to count); tests
772 pass / 224 fail -> 791 / 215.
Real suites for route-optimization-engine-select-button, order-progress-bar,
display-place, order-list-overlay/order and fleet/form (15 tests); all five
components are at 100% on every metric. The shared model-select stand-in
gained a clear button so relationship-clearing paths are testable.

Source (DEFECTS #33): fleet/form's unread `writePermission` getter and
`statusOptions` field, and order-progress-bar's dead lazy `progress`
initializer and unread `order` field, are deleted.

Coverage: statements 3920 -> 3930/18804, branches 2469 -> 2484,
functions 1306 -> 1311; tests 791 pass / 215 fail -> 806 / 210; files fully
covered 253 -> 258.
…order progress card

Real suites for vendor/form, sensor/form, contact/form and
order-progress-card (14 tests); all four components are at 100%.

Source (DEFECTS #34): the sensor form's never-invoked photo-upload task and
its injections are deleted, and the progress card's tracker guard tests the
order before dereferencing it, so a card without an order returns instead
of throwing 100ms after render.

Coverage: statements 3930 -> 3977/18800, branches 2484 -> 2507,
functions 1311 -> 1325; tests 806 pass / 210 fail -> 818 / 206; files fully
covered 258 -> 262.
…he entity form

Real suites for vendor/details, customer/details, driver/details and
entity/form (10 tests); all four components are at 100%.

Source (DEFECTS #35): vendor/details now branches on
`@resource.isIntegratedVendor` and passes `@vendor` to
IntegratedVendor::Details (the integrated view was unreachable and
mis-wired); customer/details labels the phone field correctly;
driver/details and order/details/detail call `join` with the separator
first; entity/form loses a dead lazy initializer and an unreachable
null-clear guard.

Coverage: statements 3977 -> 3986/18799, branches 2507 -> 2511,
functions 1325 -> 1330; tests 818 pass / 206 fail -> 828 / 202; files fully
covered 262 -> 264.
…nd global search

Real suites for driver-onboard-settings, widget/fleet-ops-key-metrics and
global-search (8 tests); all three components are at 100%. Both fetching
components were origins of the DEFECTS #28 fetch spill, which halves.

Source (DEFECTS #36): the onboarding settings load coalesces a null payload
instead of throwing on it; unreachable guards, parameter defaults and lazy
tracked initializers in both components are deleted.

Coverage: statements 3986 -> 4039/18794, branches 2511 -> 2541,
functions 1330 -> 1349; tests 828 pass / 202 fail -> 836 / 199; files fully
covered 264 -> 267.
…atar picker and custom entity form

The last "Failed to fetch" origin was ember-ui's CountryName mounted by
Vendor::PanelHeader; its suite now stands the component in and a full
run logs zero spills (DEFECTS #28 closed).

Real suites replace the scaffolds for device/form, avatar-picker and
custom-entity/form. A dead post-load guard in the avatar picker and an
uncalled save action in the custom entity form are deleted (#39). Two
findings are recorded for decision: the custom entity image upload reads
a config nothing provides (#37) and its dasherized type handler is
overwritten by the two-way Input (#38).

Coverage: statements 21.49% -> 21.66%, branches 20.71% -> 20.9%,
functions 24.42% -> 24.55%, lines 21.83% -> 22.01%; 850 pass / 194 fail
(+14 pass); 271 files fully covered (+4).
…completes

The admin settings passed `@disable` to ember-ui's Toggle, which only
knows `@disabled`, so the toggle stayed active while the panel below it
said onboarding had to finish first.
…activity form and event selector

Real suites replace the scaffolds for customer/admin-settings,
device/manager, activity/event-selector and activity/form; all four are
at 100% on every metric. Dead code found while profiling is deleted
(DEFECTS #41): an unread field, an uncalled save task, twelve optional-
chain branches around an injected intl service, a lazy initializer and
two guards for a no-resource render the template cannot survive.
DEFECTS #38 is amended with the activity form's key/code inputs, which
share the two-way Input race.

customer/admin-settings now reads `window` through ember-window-mock and
the dummy config mirrors the console's `stripe` block.

Coverage: statements 21.66% -> 22.09%, branches 20.9% -> 21.12%,
functions 24.55% -> 24.91%, lines 22.01% -> 22.45%; 862 pass / 190 fail
(+12 pass); 275 files fully covered (+4).
…ate every vehicle field on write permission

Both forms handed `this.controller` to their RegistryYield components, a
property neither component defines, so registered extensions always
received `undefined` even though both routes pass `@controller`. The
vehicle form also left four `<Input>`s and nineteen shorthand
InputGroups without the `cannot-write` gate the rest of the form uses.
A real suite replaces the vehicle/form scaffold: every bound text input
in DOM order, the eleven selects, the unit/money/date pickers, the five
registries, driver assignment, status pick, checkbox toggle, upload
success and failure, and the no-write state. Two unused actions and an
unused field are deleted (DEFECTS #44); the template fixes for the
controller argument and the ungated fields landed separately (#42, #43).

Coverage: statements 22.09% -> 22.13%, branches 21.12% -> 21.14%,
functions 24.91% -> 24.98%, lines 22.45% -> 22.49%; 864 pass / 189 fail
(+2 pass); 276 files fully covered (+1).
Both "create user" action buttons sent `subject_uui` for the upload's
subject, so the uploaded avatar was never associated with the user record.
A real suite replaces the driver/form scaffold: bindings, the user
details block, the three model selects, status, upload success and
failure, the create-user action button through its modal callbacks, and
the no-write state. The `subject_uui` typo it exposed landed separately
(DEFECTS #45).

Coverage: statements 22.13% -> 22.16%, functions 24.98% -> 25.05%,
lines 22.49% -> 22.53%; 867 pass / 188 fail (+3 pass); 277 files fully
covered (+1).
…ction buttons

The customer/form integration suite is rewritten on real record fixtures
and per-suite stand-ins: bindings, the address flow, the welcome-email
opt-in with and without existing meta, the hidden states and the
read-only state. The form's never-rendered "create user" action-button
block and its two injections are deleted (DEFECTS #47); the translation
typo it exposed landed separately (#46).

Coverage: statements 22.16% -> 22.24%, functions 25.05% -> 25.16%,
lines 22.53% -> 22.61%; 871 pass / 183 fail (+4 pass, -5 fail); 278
files fully covered (+1).
…ides carry

`matchesStop` compared `stop.id === activeStop.id` even when neither had
an `id`, so `undefined === undefined` made the first stop the active one
whenever stops were keyed by `uuid`/`public_id` alone; the "now heading
to" label and marker then pointed at stop 1 regardless of progress.
…hole component

Three harness faults kept all eleven order/details/tracking tests red: a
stub without `viewLabel`, an order builder whose trailing spread replaced
its merged tracker payload, and a "Due now" expectation for a rendering
removed in 9356fb6 (DEFECTS #49). Nine tests are added over the
lifecycle fallbacks, confidence and diagnostics, active-stop labelling,
reported ETA lookup, progress fallbacks, ping driver and the
assign-driver no-op; three unrendered getters and seven guards the
template already makes are deleted (#50). The active-stop matching bug
the suite exposed landed separately (#48).

Coverage: statements 22.24% -> 22.47%, branches 21.16% -> 21.5%,
functions 25.16% -> 25.28%, lines 22.61% -> 22.84%; 891 pass / 172 fail
(+20 pass, -11 fail); 280 files fully covered (+2).
Profiled the residue by kind first, then wrote one test per shape
rather than walking methods. services/map-adapter/google.js goes
992/1117 -> 1033/1117 statements, 639/791 -> 674/781 branches,
126/148 -> 134/148 functions on eight tests.

The coordinate readers and map centring across a usable point, an
unusable one and no event; invalidateSize; applyViewSettings adding,
reusing and detaching the traffic and transit layers and appending
caller styles to the base set; toggleDrawControl; panBy; a labelled
route marker drawn as a badge on the advanced path; and the API loader
both short-circuiting on an API already present and reporting a script
that will not load.

Statements 6327 -> 6368, branches 4160 -> 4195, functions 1838 -> 1846,
lines 6010 -> 6047.
Seven tests for the public editPolygon (the one geofence reaches through
map-manager): its three refusals, a focus fitted before the edit opens,
Save resolving with the ring as it now stands, Cancel restoring the
captured ring, and the settled guard. The classic marker tooltip's
pointer tracking end to end, the context menu's outside-click close, and
a defaults sweep across applyViewSettings, showContextMenu, addPolyline,
fitBounds padding and an unreadable environment config.

Five gaps were unreachable rather than untested and were deleted, not
covered (DEFECTS #87, #88): #ensureTooltipOverlayView, a private method
whose name appears once in the file — its own declaration — along with
the permanently-null _tooltipOverlayView it was the only writer of; and
four defaults their callers always supply, including addRoutingControl's
`?? []` below a guard that has already proved route.waypoints non-empty.

map-adapter/google.js  1033/1117 -> 1065/1105 stmts,
                        674/781  -> 702/772   branches,
                        134/148  -> 143/145   functions
Totals  statements 6368 -> 6400 (34.41%)  branches 4195 -> 4223 (34.96%)
        functions  1846 -> 1855            lines    6047 -> 6076
Tests 1322 -> 1329, passing 1239 -> 1246; failures unchanged at 83.
Seven tests: a marker tooltip carrying markup and a pointerless move
falling back to the origin; a layer stamped with __labelText after it
was drawn getting its label when next shown — the real google-live-map
path for a service area first drawn while it had no name; the three ways
a label cannot be built; a ring of plain numbers and a ring of rings; the
overlay left alone when the projection gives nothing; bounds collected
through a null; and a polygon hovered after its map has gone.

Most of this block's residue was unreachable and was deleted, not
covered (DEFECTS #89): #normalizeDrawEvent, a second private method whose
name appears once in the file, and five `if (!x) return` guards that each
duplicate a test the immediate caller already makes. One fallback was
kept behind an istanbul ignore instead — it is the contract for the
__labelText stamping google-live-map.js does from outside this file.

map-adapter/google.js  1065/1105 -> 1068/1094 stmts,
                        702/772  -> 706/747   branches
Totals  statements 6400 -> 6403 (34.45%)  branches 4223 -> 4227 (35.06%)
        lines      6076 -> 6072            functions 1855 (unchanged)
Line coverage reads 34.44% -> 34.43%: the deletions and the pragma took
covered lines out of the numerator along with the uncovered ones.
Tests 1329 -> 1336, passing 1246 -> 1253; failures unchanged at 83.
Eleven tests close the last four pieces and the defensive arms under
them: rectangle and circle drafts saving as their own geometry through
editPolygon; a draft with no __overlayType announced as a polygon; the
API loader resolving when the injected script calls back; the classic
marker path; an advanced marker moved by assignment and a frame already
dispatched when the cancel lands — driven through a hand-stubbed
requestAnimationFrame so no platform gets a vote on that race; polyline
points given as objects; destroyMap cancelling a running animation; and
the small defensive arms around them.

Nine redundant arms and #drawEvent were deleted rather than covered
(DEFECTS #90) — the third private method in this file whose name appears
exactly once, after #87 and #89.

map-adapter/google.js is now 100% on all four metrics:
  1076/1076 stmts, 718/718 branches, 145/145 fns, 995/995 lines.
It is the addon's largest file; iterations 48-55 took it from 113/1114.

Totals  statements 6403 -> 6411 (34.52%)  branches 4227 -> 4238 (35.24%)
        functions  1855 -> 1857            lines    6072 -> 6080
Files fully covered 309 -> 310.
Tests 1336 -> 1347, passing 1253 -> 1264; failures unchanged at 83.
The workbench had no test file at all. This adds the rendering harness —
the five Orchestrator panels and LeafletMap stubbed as template-only
stand-ins, since ember-leaflet is not installed here and <LeafletMap>
cannot otherwise resolve — and thirteen tests over the lifecycle and
orchestration flow: the five parallel loads and what each asks for, every
load failing, the toolbar panels, both side panels collapsing, a run
proposing a plan and drawing one routing control per vehicle, the
formatters the plan viewer is handed, a run that places nothing, a run
and a commit the server refuses, committing and reloading, and discarding
taking the routes off the map.

The plan-viewer stub calls the formatter callbacks it is handed, exactly
as the real one does, so the wiring is what is under test.

orchestrator-workbench.js  0/428 -> 274/428 stmts,
                          13/261 -> 127/261 branches,
                          17/94  -> 51/94   functions
Totals  statements 6411 -> 6685 (36.00%)  branches 4238 -> 4366 (36.30%)
        functions  1857 -> 1908            lines    6080 -> 6334
Tests 1347 -> 1360, passing 1264 -> 1277; failures unchanged at 83.
…hases

Thirteen more tests: all three selection toggles and clears, with
clearing drivers releasing their vehicles; a selection narrowing the run,
including the driver-tab resolution to a vehicle_id; an order dragged
onto a vehicle joining the plan, one already in it rewritten in place,
and two drops that change nothing; two phases running in sequence with
prior_assignments carried forward and autoCommit landing between them;
the run message dismissed, the import modal reloading the pool, card
fields saving, the left panel collapsing, and both resize handles dragged
through their stops.

The phase-builder and map stubs became real components reading from a
test-bed service: a template-only stand-in has only @Args, so it cannot
hand the component a value the test chose, and onMapLoad needs a real
map instance to call setView on.

orchestrator-workbench.js  274/428 -> 377/428 stmts,
                           127/261 -> 174/261 branches,
                            51/94  ->  84/94  functions
Totals  statements 6685 -> 6788 (36.55%)  branches 4366 -> 4413 (36.70%)
        functions  1908 -> 1941            lines    6334 -> 6430
Tests 1360 -> 1373, passing 1277 -> 1290; failures unchanged at 83.
Builds the yielding LeafletMap stand-in — it yields (hash tile= marker=)
and the marker yields (hash popup= tooltip=), matching ember-leaflet's
shape, with div-icon/icon/point-to-coordinates registered as helpers that
hand back their named args. That unlocked the half of the template that
had never rendered.

Ten tests: order stops pinned as P/D badges with popups and tooltips; a
multi-drop order pinned per waypoint in its own order, with 0,0 dropped;
_placeCoords across the shapes it accepts and three it does not; a driver
pinned with their status; several stops fitted as a box and one zoomed
to; the browser location centring the map, arriving late and being
ignored, and being refused; a plan's A1/A2/B stop labels; and a driver
matched to a group by vehicle_id.

Three selection getters were deleted rather than covered (DEFECTS #91) —
the callers a grep appears to find are the sub-components' own
identically-named getters, and the workbench template never reads them.

orchestrator-workbench.js  377/428 -> 409/425 stmts,
                           174/261 -> 223/261 branches,
                            84/94  ->  91/91  functions (all of them)
Totals  statements 6788 -> 6820 (36.73%)  branches 4413 -> 4462 (37.10%)
        functions  1941 -> 1948            lines    6430 -> 6458
Tests 1373 -> 1383, passing 1290 -> 1300; failures unchanged at 83.
Eight tests, one per shape: a response missing the key it was asked for;
a selected driver with no vehicle; a commit reporting no count; a route
returned with no geometry skipped while the other is still drawn; a plan
naming an unknown vehicle tagged through the whole ?? chain; a waypoint
that is itself the place; a group with no timings getting an empty
summary; a map mounting after the orders and re-centring on them; and the
formatters at their edges.

DEFECTS #92 (NEEDS DECISION): formatIsoTime's try/catch cannot fire —
new Date() does not throw on bad input and toLocaleTimeString returns the
string "Invalid Date" rather than throwing, so the '' the catch exists to
produce is unreachable and an unparseable time window is shown to a
dispatcher as the words "Invalid Date". The dead catch is deleted
(behaviour-neutral); the one-line real fix is left for Ron, since it
changes behaviour on a path no test exercises against real data.

orchestrator-workbench.js  409/425 -> 415/423 stmts,
                           223/261 -> 246/261 branches
Totals  statements 6820 -> 6826 (36.77%)  branches 4462 -> 4484 (37.29%)
        lines      6458 -> 6460            functions 1948 (unchanged)
Tests 1383 -> 1391, passing 1300 -> 1308; failures unchanged at 83.
Seven tests close the last reachable residue: a run reporting no
assignments key; a drop onto a plan of several; the dark tile theme; a
stop on the equator pinned but unable to anchor a route leg; null island
rejected in all four shapes; unnumbered waypoints keeping their order;
and a card-fields read that raises before returning a promise.

Traced-dead and deleted: commitPlan's plan-length guard and
onDropOnVehicle's two ?? operands (every caller has already proved them),
the _resizing field, and _draggingOrder with its three writes — nothing
reads either.

Five @Tracked initialisers are pragma'd with the specific writer that
beats them: with the decorator transform an initialiser evaluates on
first read, so a field written first never runs it.

orchestrator-workbench.js  255/255 branches, 91/91 functions (both done)
                           415/423 -> 409/411 stmts (99.51%)
Two initialisers remain, recorded as DEFECTS #93 (OPEN): the statementMap
is offset from the source, and I could not place them to the standard §4
asks for. Not pragma'd on inference — an untrue reason is worse than an
uncovered line.

Totals  statements 6826 -> 6820 (36.76%)  branches 4484 -> 4493 (37.38%)
        lines      6460 -> 6454            functions 1948 (unchanged)
Tests 1391 -> 1398, passing 1308 -> 1315; failures unchanged at 83.
Closes DEFECTS #93. The two remaining statements could not be placed from
the coverage map — its positions land on the divider comments — so they
were identified by bisection: pragma a candidate, re-run, and watch
whether the uncovered count falls or only the denominator does.

They were not the same kind of thing. availableEngines is genuinely
unreachable: its only reader is the phase builder, rendered only while
that panel is open, so loadEngines assigns it before anything reads it
and the lazy @Tracked initialiser never evaluates. It now carries a
pragma naming that gate.

cardFields was the harness, not the component. The real OrderPool reads
@cardFields; the stand-in for it did not, and Ember argument references
are lazy — the getter runs only when a child consumes the argument. The
stub now renders it as the real component does, and a test asserts the
settings endpoint's fields arrive.

orchestrator-workbench.js is now 100% on all four:
  410/410 stmts, 255/255 branches, 91/91 fns, 375/375 lines.
Iterations 56-61 took it from 0/428.

Files fully covered 310 -> 311.
Totals  statements 6820 -> 6821  branches 4493 -> 4494  lines 6454 -> 6455
Tests 1398, passing 1315; failures unchanged at 83.
Stands up the harness for the 962-line customer order form and covers its
lifecycle: the enabled-order-configs filter picking only what the
customer is entitled to and applying the first to the order, both
settings reads failing and being reported, the payments config, and an
order carrying its own customer versus falling back to the session.

This replaces the generated `it renders` stub, which failed because the
component reads this.order.customer in its constructor while the stub
rendered it with no arguments — so this is the first of the 83 blueprint
scaffolds to be retired, and DEFECTS #4's count is now 82.

Harness notes: ember-file-upload and ember-model-select are not installed
here, so FileDropzone and friends need stand-ins; order.customer is a
polymorphic belongsTo and rejects a plain object; and the component calls
order.set(), so the order must be a real record.

create-order-form.js  5/395 -> 56/395 stmts, 7/197 -> 13/197 branches,
                      6/67  -> 10/67  functions
Totals  statements 6821 -> 6872 (37.04%)  branches 4494 -> 4506 (37.49%)
        functions  1948 -> 1957            lines    6455 -> 6505
Tests 1398 -> 1403, passing 1315 -> 1321, failures 83 -> 82.
A thin iteration: create-order-form.js 56/395 -> 75/395 statements on one
new test. Most of the time went on harness discovery.

What landed: an abilities stub, without which every control on this form
is disabled — `cannot "fleet-ops create order"` gates the entity buttons,
the notes textarea and the dropzone; a DragSortList stand-in that yields
|item index| and reports reorders through @dragEndAction; and a
ModelSelect stand-in reporting the choice from a test-bed service.

What did not: setPayloadPlace cannot be driven without a real Leaflet
map, because previewDraftOrderRoute does control.addTo(this.map) and
leaflet-routing-machine throws from its own onAdd when that is undefined.
Giving the harness an L.map is next iteration's setup and unlocks the
whole route-preview block.

create-order-form.js  56/395 -> 75/395 stmts, 13/197 -> 17/197 branches,
                      10/67  -> 12/67  functions
Totals  statements 6872 -> 6891 (37.14%)  branches 4506 -> 4510
        functions  1957 -> 1959            lines    6505 -> 6524
Tests 1403 -> 1404, passing 1321 -> 1322; failures unchanged at 82.
A sized div inside #ember-testing with window.L.map() on it, passed as
@Map and torn down in afterEach. That was the unlock: choosing a pickup
and a dropoff through the place selects now runs setPayloadPlace,
updatePayloadCoordinates, createPlaceArrayFromPayload,
previewDraftOrderRoute, removeRoutingControlPreview and getRoute, and
attaches a real routing control.

DEFECTS #94 (OPEN), a live bug found while covering:
previewDraftOrderRoute warns when there is nothing to route and then
carries on — no return — so it calls map.flyToBounds([]) and Leaflet
throws reading .lat off an undefined corner. The template's "remove
address" links call setPayloadPlace(prop, null), so a customer clearing
their only address takes the exception. The fix is a one-line return,
left for Ron.

The defect could not be pinned by a test: the throw escapes Ember's error
handling — it neither rejects the click promise nor reaches setupOnerror,
because Leaflet throws from flyToBounds' own animation frame. That path
is left uncovered and the DEFECTS entry carries the testing note.

create-order-form.js  75/395 -> 124/395 stmts, 17/197 -> 38/197 branches,
                      12/67  ->  23/67  functions
Totals  statements 6891 -> 6945 (37.43%)  branches 4510 -> 4530 (37.69%)
        functions  1959 -> 1972            lines    6524 -> 6576
Tests 1404 -> 1405, passing 1322 -> 1323; failures unchanged at 82.
ember-ui's Toggle renders a <span role="checkbox" aria-checked> — neither
a button nor an input, which is why an earlier probe missed it. Three
tests: switching multiple-dropoffs on adds the first waypoint row; a
waypoint takes a place through its own select, a second is added and one
of the two removed; and proof of delivery takes `scan` by default and
gives it up when switched off.

DEFECTS #95 (OPEN), found while reading: clearWaypoints calls
this.previewRoute(false), and previewRoute is not defined anywhere in the
file — one call site, no declaration, no mixin supplying it. Since
isViewingRoutePreview is set by previewDraftOrderRoute, turning
multiple-dropoffs off after entering any waypoint address throws, leaves
the waypoints uncleared and the pickup/dropoff half-applied. The intended
call is almost certainly removeRoutingControlPreview().

Two live defects in this component now (#94, #95) shape how it can be
tested: anything reaching previewDraftOrderRoute with nothing to route
hits #94, so the removal test starts from two waypoints, and the
multi-drop off path cannot be driven until #95 is fixed.

create-order-form.js  124/395 -> 162/395 stmts, 38/197 -> 51/197 branches,
                       23/67  ->  31/67  functions
Totals  statements 6945 -> 6979 (37.62%)  branches 4530 -> 4544 (37.80%)
        functions  1972 -> 1979            lines    6576 -> 6608
Tests 1405 -> 1408, passing 1323 -> 1326; failures unchanged at 82.
Four tests over createOrder: submitting with no route does nothing and
says nothing, since isValid refuses silently and the disabled controls
are the only feedback; a routed order saves once, fires the creating and
created universe events, is tracked, and is handed back through
@onOrderCreated; custom fields that fail validation stop the submission
and list every missing field in one message; and a save the server
refuses is reported with the order kept and no created event.

Harness: the custom-fields stand-in now answers validateRequired() and
saveTo(), the universe and events stubs record what they are told, and
order.save is overridden on the record itself rather than through an
adapter — the component calls it directly.

create-order-form.js  162/395 -> 202/395 stmts, 51/197 -> 68/197 branches,
                       31/67  ->  34/67  functions
Totals  statements 6979 -> 7019 (37.83%)  branches 4544 -> 4561 (37.95%)
        functions  1979 -> 1982            lines    6608 -> 6647
Tests 1408 -> 1412, passing 1326 -> 1330; failures unchanged at 82.
Four tests over getQuotes: a routed order asks service-quotes/preliminary
once there are two coordinates and normalises the response into records;
a response that is not a list is taken as no quotes rather than an error;
a refused request is reported; and no quotes are asked for while a
checkout session is being completed, which also brought
restoreFromServiceQuote into coverage.

DEFECTS #96 (OPEN), found while reading: the quote request body includes
a `service` key that is not a local. There is no declaration anywhere in
the file — the only `service` in scope is line 4's `import { inject as
service }`, so the request sends Ember's inject decorator, JSON drops it,
and the field never reaches the wire. No linter catches it: no-undef is
satisfied by the import and no-unused-vars sees it used. The test pins it
with typeof body.service === 'function'.

That is the third live defect in this component (#94, #95, #96), all
found by reading or by asserting what the code does, all recorded rather
than fixed.

create-order-form.js  202/395 -> 231/395 stmts, 68/197 -> 93/197 branches
Totals  statements 7019 -> 7049 (37.99%)  branches 4561 -> 4586 (38.15%)
        functions  1982 -> 1983            lines    6647 -> 6677
Tests 1412 -> 1416, passing 1330 -> 1334; failures unchanged at 82.
…locked

An honest no-progress iteration on coverage. create-order-form.js is
unchanged at 231/395 statements — the one test that landed asserts real
behaviour (returning from a checkout puts up a dialog that cannot be
dismissed by clicking away) but crosses only lines the previous
iteration already reached. Three of the four tests I set out to write do
not work yet.

isPaymentRequired() needs four conditions, and from the test's side all
four hold — verified by probe. The branch is still not taken. Two
candidates remain and I did not separate them: the addon's ember-get-config
may not be the module instance the test mutates, or selectedServiceQuote
may not survive the quote round-trip. The ledger records both and the
cheapest experiment to tell them apart.

One real cause was found and fixed on the way: getQuotes reads
serviceQuotes.firstObject, so a plain array response leaves
selectedServiceQuote unset silently. Quote fixtures now use A([...]).

Totals  statements 7049 -> 7048  branches 4586 -> 4585  lines 6677 -> 6676
Tests 1416 -> 1417, passing 1334 -> 1335; failures unchanged at 82.
Four tests: returned quotes render as a radio group with the first
chosen; a dropped file is queued, uploaded under the order-files path and
attached on success; a file already sent is ignored while a failed one is
retried and then dropped from the queue; and editing an item opens the
entity modal, whose uploadNewPhoto holds a new item's photo aside and
shows it from an object URL.

Closes the iteration-68 blocker as untestable (DEFECTS #97). Both
candidates are eliminated: the radio-group test proves
selectedServiceQuote is set, and config was never at fault —
dummy/config sets stripe.publishableKey to '', and typeof '' === 'string'
passes that conjunct unaided, so last iteration's config mutation was
wasted effort. What remains is paymentsEnabled/paymentsOnboardCompleted,
which the template never references, so no rendering test can observe
them. The block stays uncovered with the trace recorded.

create-order-form.js  231/395 -> 249/395 stmts, 93/197 -> 99/197 branches,
                       35/67  ->  40/67  functions
Totals  statements 7048 -> 7066 (38.09%)  branches 4585 -> 4592 (38.20%)
        functions  1983 -> 1988            lines    6676 -> 6693
Tests 1417 -> 1421, passing 1335 -> 1339; failures unchanged at 82.
Seven tests over `restoreFromServiceQuote` and the item surface it unlocks.
The restore path is the only way a *saved* entity reaches `this.entities`
(`addEntity` only ever createRecords), so `removeEntity`'s destroyRecord arm
and `editEntity`'s immediate-upload arm had to come with it rather than as a
separate batch.

Found while writing the harness — DEFECTS #98: `confirm` replays a new item's
held-back photo with `modal.invoke('uploadNewPhoto', pendingFileUpload)`, but
`invoke`'s second positional is `modalId`, so no modal is found and the
callback never runs. The photo is silently dropped. Recorded, not fixed; the
test asserts current behaviour and names the entry.

create-order-form.js 249/395 -> 301/395 statements, 99/197 -> 127/197
branches, 40/67 -> 48/67 functions.
Global: statements 7066 -> 7118 (38.36%), branches 4592 -> 4620,
functions 1988 -> 1996, lines 6693 -> 6744. Tests 1421 -> 1428;
failures unchanged at 82, none new. Lint 0.
Seven tests: switching the order type, the overlay cancel, editing a chosen
address, reordering stops (and the no-op drop), the map's re-centre down both
the single-point and fitted arms, deleting an attached file, and the quote
payload's per-model serialisation.

Two wrong assumptions the tests caught: only configs named by the settings
call are offered, and `sortWaypoints` redraws the preview without re-pricing.

Also §4, in the source: `isServicable` deleted (DEFECTS #99) — its only
apparent caller reads `order/form/service-rate.js`'s own same-named getter.
`createPlace` pragma'd, not deleted (DEFECTS #100, NEEDS DECISION) — nothing
reaches it, but whether the form should offer "new address" is a product call.
Both landed on uncovered code: denominators fell 395->392 statements and
67->65 functions while covered held.

create-order-form.js 301/395 -> 321/392 statements, 127/197 -> 137/197
branches, 48/67 -> 56/65 functions.
Global: statements 7118 -> 7138 (38.47%), branches 4620 -> 4630,
functions 1996 -> 2004, lines 6744 -> 6763. Tests 1428 -> 1435;
failures unchanged at 82, none new. Lint 0.
`createResponsiveHandler` registered a window `resize` listener as an inline
arrow and the component had no `willDestroy`, so it outlived the component.
The `if (!this.el) return` guard never fired because `el` was never cleared,
leaving a detached element whose `parentElement` is null — `getFullGridSize`
then threw on `parentElement.offsetWidth`.

Latent until now: nothing in the suite could construct a `JointGraph`, because
`joint` was undefined in the dummy app. Once it could, two unrelated
`operations-monitor` tests went red — they are the next tests that dispatch a
window resize.

Stores the handler, removes it and nulls `el` in `willDestroy`, and also
guards on `parentElement` so a detached element is skipped rather than
throwing. DEFECTS #101.
…ad JointJS

`index.js` copies `@joint/core` into the *host* app's public tree, so a real
app has `joint` on the global before the engine boots. The dummy app has no
host, so `joint` was undefined and neither `joint-graph.js` nor any of
`activity-flow.js` could execute. One `app.import` in `ember-cli-build.js`
fixes that, the same way Leaflet is already handled there; it builds only the
dummy app and leaves the published addon untouched.

Nothing about JointJS is stubbed — the tests drive a real paper and graph.
Six tests: the default flow, a saved flow, zoom in/out including both limits,
reset, save (children serialised by code, no node on the wire), and redraw on
`onConfigChanged`.

Retires one of the blueprint scaffolds from DEFECTS #4.

activity-flow.js 0/369 -> 283/369 statements, 0/179 -> 107/179 branches,
0/79 -> 56/79 functions; joint-graph.js 0 -> 39/56.
Global: statements 7138 -> 7438 (40.08%), branches 4630 -> 4742,
functions 2004 -> 2062, lines 6763 -> 7061. Tests 1435 -> 1440;
failures 82 -> 81, none new. Lint 0.
Ten tests over everything iteration 72 did not touch: opening an activity in
the context panel, the immutable / core_service / permission guards, the add
tool and its duplicate-code refusal, closing without saving, the remove tool
(proved through a follow-up save, not just the drawing), the two-way scrollbar
sync, and an activity opened by @context.

The element tools are real `joint.elementTools` in the SVG and the tests click
the actual markup; the context-panel stand-in keeps each definition so the
component's own saveTask and onClose closures are what run.

One wrong assumption corrected: `deserializeActivity` regenerates `internalId`
on every deserialise, so it cannot be learned by rendering twice — a saved flow
carries its own ids, which is how the real round-trip works.

activity-flow.js 283/369 -> 352/369 statements, 107/179 -> 137/179 branches,
56/79 -> 77/79 functions.
Global: statements 7438 -> 7508 (40.46%), branches 4742 -> 4772,
functions 2062 -> 2084, lines 7061 -> 7125. Tests 1440 -> 1450;
failures unchanged at 81, none new. Lint 0.
Seventeen unit tests over the scheduler controller: active and unscheduled
orders, the sidebar search and its debounce, the type filter, driver rows and
workload bars, the resource-label and event-tile HTML, selection, the
view-range mapping, and calendar navigation (including with no calendar
attached, which is the state before the template mounts).

A unit test rather than a rendering one: the controller only ever talks to
@event-calendar/core through setOption/getOption/prev/next, so a stand-in for
that API exercises its own logic without pretending to run the calendar.

Three findings, recorded not fixed. DEFECTS #102: `driver.max_daily_orders`
appears on one line in the whole codebase and is not an attribute, so every
capacity bar is measured against 10. #103: the priority filter reads
`o.priority`, which OrderModel does not have. #104 (NEEDS DECISION): nothing
ever assigns to `activeFilters`, so the filter block never runs at all — which
is why #103 is harmless today.

scheduler/index.js 0/325 -> 94/325 statements, 0/197 -> 55/197 branches,
0/79 -> 43/79 functions; create-full-calendar-event-from-order.js and
to-calendar-date.js now fully covered.
Global: statements 7508 -> 7609 (41.00%), branches 4772 -> 4834,
functions 2084 -> 2128, lines 7125 -> 7210. Tests 1450 -> 1467;
failures unchanged at 81, none new. Lint 0.
Twenty-three more unit tests: dragging a card from the sidebar, the drag-over
highlight and drop cursor, leaving versus moving onto a child, and the drop —
assigned to the row it landed on at the wall-clock time it was dropped at.
Then every refusal (nothing dragged, no calendar, an unplaceable point, no
driver row, a scheduler refusal, a clash). Rescheduling covers the same
outcomes plus the shift-block arm. Sockets open one company channel and one
per driver, and the handlers are invoked rather than just captured.

The timezone assertions pin real instants — 22:30 in Asia/Singapore is
14:30Z — so an inverted conversion fails rather than passing quietly.

Two fixtures of mine were wrong, neither a product bug: a timeline event
always carries a resourceId, and `scheduler.shift-updated` does resolve.

scheduler/index.js 94/325 -> 240/325 statements, 55/197 -> 126/197 branches,
43/79 -> 65/79 functions.
Global: statements 7609 -> 7755 (41.79%), branches 4834 -> 4905,
functions 2128 -> 2150, lines 7210 -> 7342. Tests 1467 -> 1490;
failures unchanged at 81, none new. Lint 0.
Thirty-three tests. The modal block: opening an order, rescheduling from a
date or a picker wrapper, saving (success, info when the date is cleared, a
straight close when nothing changed, a refusal that keeps the modal open),
unscheduling, the shift modal's save and delete including both failures,
one-off and recurring shifts (new schedule and reusing an existing one), bulk
assign, and the conflict modal's assignAnyway/autoAdjust.

Then the residue: four statements were `@tracked` initialisers nothing reads,
and thirty branches were sparse-data fallbacks — no id or tracking, no
workload, an order answering through get(), a timeline with no inner grid or
none at all, an event dragged off every resource row.

The last branch is genuinely unreachable — DEFECTS #105. `formatToParts` is
built from a literal options object requesting exactly the six types the
helper asks for, so the `?? '0'` cannot run. Hoisted into a local const so the
pragma attaches, with the trace in the comment. Behaviour unchanged.

scheduler/index.js 240/325 -> 326/326 statements, 126/197 -> 195/195
branches, 65/79 -> 79/79 functions, 290/290 lines.
Global: statements 7755 -> 7841 (42.25%), branches 4905 -> 4974,
functions 2150 -> 2164, lines 7342 -> 7422. Fully covered files 312 -> 313.
Tests 1490 -> 1523; failures unchanged at 81, none new. Lint 0.
Twenty-four tests replacing the blueprint scaffold. The component has two
provider branches behind one class; the Google branch renders a single child,
so standing that in reaches the lifecycle, load task and resource handlers
without ember-leaflet or a real map.

Covers the provider switch, initial position, zoom validation, the geofence
subscription (company known at construction and arriving later), location
updates, teardown of all four listeners, the load task and its permission and
failure paths, bounds serialised from all three provider shapes plus four
unusable ones, resources arriving with their layers, panel clicks, and the
viewport-reload locks.

Most of the time went on the harness: 21 injected services, and two of the
gaps failed *silently* — an adapter with no `getBounds` (load falls through to
`this.map.getBounds()` when the manager reports none) and a geofence stub with
no `toggleDrawControl` (bound while building the context menu). Both throws
are swallowed by `load`'s own try/catch. The universe event trail localises
them. Checked before claiming: neither is a product bug.

Also fixed two assertions of mine that compared a value with itself and could
not fail.

leaflet-live-map.js 39/345 -> 162/345 statements, 10/201 -> 85/201 branches,
4/70 -> 22/70 functions.
Global: statements 7841 -> 7957 (42.87%), branches 4974 -> 5045,
functions 2164 -> 2180, lines 7422 -> 7533. Tests 1523 -> 1546;
failures 81 -> 80, none new. Lint 0.
Thirteen tests: the Leaflet branch registering its map with both managers,
viewport watching and unwatching, the tile URL, the draw control and feature
group, then the context menus — the map menu, driver and vehicle menus
including items registered through menuService, and the service-area and zone
menus with their edit and delete callbacks driven through to what they remove.

A build change I made and reverted: `app.import`ing leaflet-draw and
leaflet-contextmenu made the branch render, and broke fourteen existing
map-adapter/leaflet tests — leaflet-draw 1.0.4 against Leaflet 1.9 leaves
`layer.editing` without `enabled()`, and those tests had only run with the
plugin absent. Rather than patch Leaflet globally to chase coverage, the test
file now sets just the four readiness markers the component reads and restores
the global afterwards. Same coverage, nothing else affected.

The lazy-argument trap again: a layer stand-in that accepts `@url` without
rendering it never causes `tileUrl` to be computed, so the getter reads as
dead code. The stand-in has to consume it.

leaflet-live-map.js 162/345 -> 254/345 statements, 85/201 -> 113/201
branches, 22/70 -> 40/70 functions.
Global: statements 7957 -> 8049 (43.37%), branches 5045 -> 5073,
functions 2180 -> 2198 (40.08%), lines 7533 -> 7622. Tests 1546 -> 1559;
failures unchanged at 80, none new. Lint 0.
Ten tests: the driver and vehicle context-menu callbacks driven through to the
panels and action services they call, a menu item registered elsewhere invoked
with its resource and layer, the geofence enter/exit flashes, the viewport
reload (only the spatially-filtered resources, the suspend/resume lock, and
unusable bounds), and the plugin-loading path.

`#flashGeofenceLayer` restores its style through a raw setTimeout guarded by
`if (!layer._map) return`. Rather than add a second two-second wait to reach
that guard, `eachLayer` yields two layers for the same geofence — one attached,
one already removed — so one waitUntil proves both arms: the attached layer
goes back to its drawn colours, the removed one is never restyled.

leaflet-live-map.js 254/345 -> 296/345 statements, 113/201 -> 134/201
branches, 40/70 -> 53/70 functions.
Global: statements 8049 -> 8091 (43.60%), branches 5073 -> 5094,
functions 2198 -> 2211, lines 7622 -> 7661. Tests 1559 -> 1569;
failures unchanged at 80, none new. Lint 0.
Nine tests: markers vs polygons on registration, re-centring on user.located,
the service-area menu's blur/create-zone/edit-boundaries callbacks (and
edit-boundaries correctly absent on Google Maps), the zone menu's boundary
editing, a zone in a plain array removed through `set`, and loadResource's
onLoaded/onFailure options — no in-repo caller, but reachable through the
component published on the universe, so covered as an extension would.

DEFECTS #106: `#getValidLatitude` and `#getValidLongitude` each appear exactly
once — their own declarations — and are never called. The constructor reads
`location.getLatitude()` raw, while the line above it wires the sibling
`getValidZoom()`. A NaN or out-of-range coordinate reaches Leaflet as the map
centre and the fallback is dead. Two lines would fix it, but that is a
behaviour change; recorded, pragma'd with the trace, and the test pins current
behaviour so the fix has an assertion to update.

leaflet-live-map.js 296/345 -> 304/345 statements, 134/201 -> 141/201
branches, 53/70 -> 57/70 functions.
Global: statements 8091 -> 8099 (43.64%), branches 5094 -> 5101,
functions 2211 -> 2215, lines 7661 -> 7669. Tests 1569 -> 1578;
failures unchanged at 80, none new. Lint 0.
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