Miler rider app: surface system, visible design language, backend lifecycle

Design system
- MilerSurface ladder (canvas → working → raised → floating) with MilerPanel
  as layer 1; canvas moved to #DEE3EA so white separates at 1.290:1.
- Visible vocabulary applied across Home, Deliveries, Activity, Account and
  the sheets: hero heads (tabular numeral + small caption, clamped at 1.3x),
  canvas wells for anything that opens, small filled tags for shelf labels,
  demoted placeholders. Recorded in DESIGN_SYSTEM.md §6.
- One icon family: 222 Material glyphs migrated to Lucide; none left outside
  lib/xpress.
- Colour semantics corrected: amber only for what is genuinely owed, brand red
  reserved for the live stop, disabled primaries go neutral rather than pale.

Data and lifecycle
- lib/data/lifecycle.dart reads mutations for what they prove; route_order.dart
  makes admin sequence the single ordering authority; service_day.dart, and
  stop_area.dart rewritten against live Coimbatore addresses (digit-token
  stripping, city stoplist, street suffixes, stammer collapse).
- countLabel states the load once, in bags.

Testing
- 1440 tests passing; golden shot harnesses for Home, Deliveries, Activity,
  sheets and verify, with test/failures/ now gitignored (diff debris).
- New pins: home_gutter_test, stop_area_test, plus updated structural bounds.

Note: this commit also carries pre-existing working-tree deletions that were
present before this work (API_SPEC.md, README.md, demo test fixtures).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-22 05:40:35 +05:30
parent c8350563d9
commit d7348e253f
387 changed files with 80693 additions and 12272 deletions

View File

@@ -0,0 +1,109 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:miler/data/meal_run_mock.dart';
import 'package:miler/data/mock_backend.dart';
import 'package:miler/data/service_profile.dart';
import 'package:miler/providers/pickup/pickup_provider.dart';
/// ─────────────────────────────────────────────────────────────────────────
/// A MISSING BACKEND IS A STATE, NOT A FIXTURE
///
/// The `/miler/*` contract serves bookings and consignments. Kitchens, crates
/// and subscribers are not concepts it has — there is no endpoint that returns
/// a meal run. That is a backend capability that does not exist yet.
///
/// It was being papered over by [MealRunMock], which was on by default in every
/// debug build. So the meal line *looked* integrated, and the gap was invisible
/// until somebody built a release.
///
/// These pin the boundary: the fixture is opt-in only, and with it off the
/// provider **refuses** rather than returning an empty list — because "no work
/// today" and "your hub has not switched this on" are different answers and the
/// rider acts differently on each.
/// ─────────────────────────────────────────────────────────────────────────
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
tearDown(() {
MockBackend.enabled = kMockBackend;
MealRunMock.reset();
ServiceProfile.setActive(ServiceProfile.parcel);
});
group('the capability is named, not implied', () {
test('the lines whose work IS bookings are served', () {
expect(ServiceProfile.parcel.hasBookingsEndpoint, isTrue);
expect(ServiceProfile.delivery.hasBookingsEndpoint, isTrue);
});
test('the milk-man line is served too — the hub dispatches it', () {
// This asserted `isFalse`, and that is what kept a real rider empty:
// tenant 13 resolves to this profile, the hub assigns him bookings in the
// console, and the app refused to ask for them. The console reads the
// round from /admin/bookings and assigns with
// /hub/bookings/:id/auto-assign — the same rows /miler/bookings returns.
expect(ServiceProfile.milkMan.hasBookingsEndpoint, isTrue);
});
test('the capability does not depend on the fixture', () {
// Whichever way it answers, an opt-in dev flag must not be what decides.
MockBackend.enabled = true;
expect(
ServiceProfile.milkMan.hasBookingsEndpoint,
isTrue,
reason: 'the fixture must never be what answers a backend capability',
);
});
});
group('with the fixture off, which is the default', () {
setUp(() => MockBackend.enabled = false);
test('a milk-man rider is not refused — he is dispatched bookings', () {
// Asserted on the capability rather than by calling, for the same reason
// as the parcel case below: the path now proceeds to a real request.
//
// This used to expect a [LineNotServedException]. It was the assertion
// that made the bug look intentional: a rider the hub had assigned work
// to could not be handed it, because his line was believed to have no
// endpoint. The refusal is still reachable — see [LineNotServedException]
// and the test below — it is just no longer this line's answer.
ServiceProfile.setActive(ServiceProfile.milkMan);
expect(ServiceProfile.active.hasBookingsEndpoint, isTrue);
});
test('the refusal explains itself', () {
expect(
const LineNotServedException().toString(),
contains('not served by the backend yet'),
);
});
test('a parcel rider is never refused — he has an endpoint', () {
// Asserted on the capability rather than by calling: the parcel path
// proceeds to a real request, and a test that reaches the network is a
// test about the network.
ServiceProfile.setActive(ServiceProfile.parcel);
expect(ServiceProfile.active.hasBookingsEndpoint, isTrue);
});
test('the fixture is unreachable while it is off', () {
ServiceProfile.setActive(ServiceProfile.milkMan);
expect(MealRunMock.active, isFalse);
});
});
test(
'the fixture is reachable only when asked for, and only on its line',
() {
MockBackend.enabled = true;
ServiceProfile.setActive(ServiceProfile.milkMan);
expect(MealRunMock.active, isTrue);
// And still not by a parcel rider, whatever else is true.
ServiceProfile.setActive(ServiceProfile.parcel);
expect(MealRunMock.active, isFalse);
},
);
}