Commit Graph

4 Commits

Author SHA1 Message Date
1ea936c7d8 Doormile AI: document the rules that are load-bearing
CLAUDE.md for the assistant folder, plus the capability roadmap.

The rules worth reading before editing either file:
- `truncated` is not optional to handle; an intent that reads scan.rows and
  ignores it reintroduces the silent under-reporting this replaced.
- Order status comes from utils/orderStatusGroups.js, not api.js's
  Deliveries taxonomy, and the two must not be merged.
- State questions ("how many are assigned") must not default to today;
  flow questions ("how many orders today") still do.
- orderQuery must not widen to claim single-dimension questions.
- Never put a React element in message state — localStorage round-trips it.

ROADMAP.md carries the analysis and the L0-L8 capability ladder, including
what is deliberately still out of scope: write actions pending a confirm
gate, and any LLM step pending a decision on where its key would live.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:54:12 +05:30
51667d1c9f Doormile AI: make the numbers trustworthy, then composable
Data-layer work on the assistant, in the order it mattered.

Correctness first:

- getBookingsPage keeps the envelope's `total`/`page`. getBookings threw
  them away, so no caller could tell a full result from a truncated one.
- Every booking read now drains pages up to a budget instead of taking page
  one at the API's 1000-row cap. Past 1000 lifetime bookings, every count
  and sum in this file silently under-reported while the source line beside
  it still read "complete". Row order is detected per call, so a backend
  that stops returning newest-first degrades to a full scan rather than to
  a wrong answer.
- A capped scan now says "At least N", appends what it scanned versus the
  total, and marks its source call as failed.
- Revenue excludes cancelled orders, sums every service option rather than
  the first, and is labelled estimated — it is a quote, not settled money.
- A strong order reference that isn't found is answered "I couldn't find
  it" instead of falling through to a broader intent, which used to answer
  "142 orders created today" to a question about one order.

Then agreement with the Orders page:

- utils/orderStatusGroups.js is now the single definition of which raw
  booking enums make up each status; orders.js builds its tabs from it and
  the assistant matches against it. The assistant had been using api.js's
  Deliveries taxonomy, which keeps miler_assigned on `pending`, so the
  Orders page showed 19 Assigned while the bot answered 0. The two
  taxonomies stay separate on purpose — Orders tracks the operator's
  action, Deliveries tracks the rider's.
- A status question with no date named is no longer scoped to today. "How
  many orders are assigned" describes the queue right now, which is what
  the Orders page's tabs show; they apply no date filter either.
- The Orders header said "Today" over counts that were never date-filtered.
  Corrected the label rather than adding a filter, since filtering would
  hide currently-visible rows — a product decision, not a bug fix.

Then capability:

- delayedOrders answers "which orders are delayed" from the promised
  delivery time. deliveries.js and Dispatch.js both rejected that field for
  batch bucketing because an ETA is not the wave an order belongs to; that
  reasoning does not carry over to lateness, where a promise that never
  gets re-stamped is exactly the right baseline. If no order carries an
  ETA it says so rather than reporting a reassuring "0 delayed".
- orderQuery composes status x batch x tenant x rider, plus rankings. It
  claims a question only when two or more of those are present, so
  single-dimension questions keep their proven intents. A date is not
  counted as a dimension — counting it re-routed four working questions.
- An unresolved tenant/rider name falls through instead of having its
  filter silently dropped, which was the original defect.
- orderLookup resolves the rider's name and reads the tracking trail
  defensively, since that endpoint's response shape is undocumented.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:54:01 +05:30
5165e9d697 Doormile AI: replace the bot popover with a right-side slide-over
Renames the operator assistant to "Doormile AI / Operations Copilot" and
moves it from a header Popover to a portalled slide-over panel.

- DoormileAI/ — trigger, panel, welcome, message, composer and shared
  primitives. Assistant turns are deliberately NOT bubbles; that is what
  keeps this reading as part of the dashboard rather than a bolted-on
  chatbot.
- pageContext.js — route-aware suggested questions. Every suggestion is a
  phrasing the matcher actually resolves; a chip that returns "I can't
  answer that" is worse than no chip.
- DoormileAI.css — panel styling, animation, responsive and reduced-motion.
  Selectors that style an Astryx Stack are written `.dai-root .x` because
  `padding={0}` emits a StyleX atomic at the same specificity as a bare
  class, so a single class can lose on stylesheet order.
- Messages are JSON round-tripped through localStorage, so icons are
  referenced by key rather than stored as React elements — an element does
  not survive the trip and the rehydrated value crashes the next render.
- Errors now render a polished state and log the real error to the console,
  instead of surfacing raw API messages in a toast.

The route, sidebar entry and i18n key for the old standalone Assistant page
are removed with it — this is a header surface, not a page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:53:40 +05:30
e420223622 updatess on the ui changs 2026-08-18 12:46:50 +05:30