Skip to content

changelog

All notable changes to this product are documented here. The format is based on Keep a Changelog, and this product adheres to Semantic Versioning.

  • Receiving takes a delivery another team pushes, and its first tab is Receipts (TH-234) (flows/inventory-manager, flows/technical-specialist-kaag). A vendor that delivers straight to a team (Telpo to Telematics) is pushed to Inventory from the team’s new Deliveries to Inventory page: a register (Pending, Partly received, Received, Cancelled), a four-step push (vendor and warehouse from the existing lists, the date and who on the team received it, catalogue lines with unit cost or Not known and one serial per unit, proof of delivery under any name with at least one file) and a record that can be cancelled while nothing is counted. On the Inventory Manager, the first Receiving tab is renamed Receipts, the table gains a Source column (Procurement or the team, the sent date folded beneath it to stay in the width budget), and the receive dialog and receipt detail show Sent by, who on the team received it and the proof files in the photo lightbox. The count itself is unchanged, except that a serial the team did not push is refused by name.
  • Conversion station manager — a keke that comes back inside its first three months (flows/retrofit-manager). A station’s quality numbers stopped at the door: first-pass yield and rework rate both measure the work before it leaves, so a station could hold both at ninety percent while sending out kekes that came back in a month. A 3-month breakdown rate now sits in the dashboard’s KPI grid, and the measure is the failure rate, not its complement — three months breakdown-free buries a rise inside a large number, where 94 to 91 reads as a good score slipping and 6 to 9 reads as half again as many kekes coming back. The denominator is kekes whose three months have elapsed, because one converted last week has not had its chance to fail; the ones still inside their window are stated on the register instead, so the six rows it lists and the five the rate counts reconcile on the page rather than in the reader’s head. The clock starts at collection, or at Ready for pickup where none was recorded, and only motor, harness, VCU and battery wiring count — a snapped brake lever on the same keke rides the record for context and never the rate. A pattern line names a repeating component at three or more and says nothing otherwise. The riders register flags the row, Broke down 23 days after conversion, on riders who have collected only. Opening one gives one keke’s timeline: the conversion step by step with who did each, QA, collection, then the failure from field rescue, the serials fitted at conversion beside it, the bay’s record read-only, and the parts table pairing a removed serial to the one this station fitted (fitted at conversion 1 Jun 2026, removed at Ikorodu bay 25 Jun 2026), marked This station or Not ours. The cause — Workmanship, Component, Rider use, Not conversion-related — can only be set once the bay closes the case; until then the record offers no action and reads Maintenance in progress, because a cause settled before the diagnosis is a guess entered as a fact. A new Reports page holds the export and the deeper cuts, with summary cards that read the filtered list rather than the register behind it and a grouping by component, step, technician, batch and vendor.
  • Head of Maintenance — what came off and what went on (flows/head-of-maintenance). Parts were fixed at the hour the work order was raised, so a technician who opened a keke and found the harness scorched could not record what actually happened. Parts can now be added from the bay’s own inventory, with a quantity the form refuses to take past what the bay holds and a serial chosen from the stock the bay actually has free. Replacing a serialised part returns the old unit to stock in the same movement; removing one returns it to stock and nowhere else, because the bay does not judge a part it takes off and a quarantine decision belongs to whoever receives it. The line carries no status column, mirroring the shipped WorkOrderPart, and a new At the warehouse column reads plain 0 where the warehouse holds none. A work order can also be blocked by hand for a reason off a list — Waiting for battery, Waiting for R&D, Waiting for Telematics — escalating to a named person who is mailed the case consolidated into one brief, with the block stamped, the banner saying since when, and unblocking requiring a reason, since nothing arrives to clear waiting for R&D.
  • Onboarding PM — a Pilots heading with the Expansion PM screens (flows/pm-onboarding). A new sidebar group between Product command and Rider Onboarding, holding the four Expansion Project Manager screens the PM does not already have: Clusters (register, filters, create and edit, cluster record), Swap stations (register, add and edit with a map pin, station record with setup checklist, staff, activate and deactivate, attach to a cluster), Station activity (turnout strip, swaps, riders who swapped, not swapped today) and Telemetry (rider search, vehicle location on a map, swaps). Riders and Release are left out because the PM already has them, and Batteries for now. Activity rows that used to open a rider record open that rider in Telemetry instead. The code is a port of the Expansion flow with its own seeded data (separate from the PM Stations page), so edits to those screens have to be made in both flows. Loading, empty and error states stay previewable with ?state=loading, ?state=empty and ?state=error, since the PM has no Settings selector for them. The filter chips use their own px- classes so the PM global filter does not overwrite them. The PM only; APM is unchanged.
  • VP Tricycle Hardware — rebuilt from the console it is meant to document (flows/vp-tricycle-hardware). The flow was built to the Argo VP Console PRD — a portfolio heat grid, a decisions queue, a risk register, resourcing, a weekly business review — and none of that is in the code. v.vp-tricycle-hardware.tsx declares three groups of twelve items, of which only the seven under Issue management carry a renderer; the five under Portfolio and the two under Insight have a label and an icon and nothing else, so ViewShell lands each on the canon Register in build screen, and the console opens on Overview because groups[0].items[0] is its initial view. This flow shows them that way rather than inventing pages the console does not have. Issue management is read only, as the route says: the VP reads cases, teams, workflows, business units, issue types and routing rules off core’s issue-management admin surface and carries no create, assign or edit control, because those belong to the operating roles below this seat. SLA policies are the exception, gated on issue-management.sla.manage, so the register keeps New policy, Edit and Delete, and the global default cannot be deleted because something has to catch an issue type nobody has written a policy for. Three things the code settled that would otherwise have been guesses: the status tab does not scope the KPI band (CaseSlaSummary carries open, met and missed in one response, which it could not if the status filter applied to all of them, so the open-side tiles are struck over open cases and the resolution rate over resolved ones), a business day is ten hours so the SLA label reads 2d 3h rather than converting at twenty-four, and only Cases and Teams carry an onRowClick, so the other five registers declare allow-static-rows rather than getting handlers that go nowhere. Item approvals is carried over from the old flow and grouped apart under Governance, because it is a rung this seat holds and the route does not model yet: a unit head signs a request and above the threshold the VP decides whether it is bought, approving a new item mints it in the catalogue, a warehouse request is raised on Inventory either way with the requester told and Procurement copied, and declining requires a reason both the unit head and the requester read. Spliced onto the starter template because atlas-shell-parity needs the role switcher, account menu, notifications page, settings page and theme toggle and none of those classes are in rechaj-ds.css; the login screen and the template’s demo pages, handlers and New work order dialog did not come with it. Departures from the code, all documented: no page subtitles (the canon forbids them on a page head), no em dashes in the SLA select, and the status ladder stays a .pseg under allow-pseg-filter. The sidebar still reads Retrofit rather than conversion, because the word changed in October and the route has not. Canon lint 0 errors, flow-diff 0 gaps, runtime probe clean over 32 view-themes with nothing baselined, canvas audit clean at 15 sections and 22 frames, share card regenerated, and the flow’s stale canon baseline deleted so it sits at zero tolerance.
  • Procurement · Item pricing, shipping rates and the cost of a rider’s parts (flows/procurement-manager, flows/inventory-manager). The console could say what was bought and not what it costs to buy again. A new Costing sidebar group holds Item pricing and the Bill of materials, out of Purchasing so the request-order-requisition sequence reads as one. Item pricing lists every catalogue item against its unit cost with the date, the cost per rider (what one rider takes of it, times that cost) and the change against the buy before, carrying the figure it was struck against; tiles partition the catalogue into priced, risen, fallen and never bought and each is the filter for what it counts. A price is what an order committed to, so the register’s drafts, its pending requisitions and the one Polaris rejected set none, and a line at zero is a buy and not a price: a vendor’s free replacement is the newest thing on the item and must not become its cost, so the price is the newest buy that charged, the zero line reads No charge on the history, and the comparison skips past it; buys older than the order register live in a price book and are read through the same orderCosting, so a figure here and a figure on the order cannot disagree. No actual unit cost on the item sheet: a line’s logistics share is apportioned by its share of that order’s value, so the landed figure is a fact about an order line, and the change is struck on the unit cost rather than reporting a shift in the freight ratio as a move in the vendor’s price. Two currencies never compare or sum — the row reads Currency changed and no total spans two. The item’s record carries its whole purchase history, each buy stating what it did to the price against the one before (the oldest reads First buy), and a By vendor card listing every vendor with the currency each quoted in, cheapest first inside a currency. The order form shows the last unit cost under the price field. An item nobody has bought can be given a quoted cost, labelled Quoted everywhere it reaches and superseded by the first purchase order. A Shipping tab prices freight on a load — a 20ft container, a 10t truck, an air pallet — with the rider kits it carries, the per-rider share being the division between them; the kit count is optional and a rate without one is offered nowhere that needs it. The bill of materials costs each line and totals the lines on screen in its foot, with the shipping method chosen in the card head, naming what it is missing and what of it is not a purchase. On Inventory, the item record’s summary figures carry the current unit cost read only, with no history and nothing editable. The pricing register reads the union of the order form’s catalogue and the stock snapshot’s, which are not the same names — a patch over a split that wants fixing at the source. Canon-lint 0 errors on both flows, runtime probe clean over 56 view-themes with nothing baselined.
  • Expansion — Release record and rider record tabs (flows/expansion-project-manager). A row on Release now opens a lean release record: the release checklist pinned on the right, primary station assignment, battery assignment and the wallet (balances and virtual accounts, or Create wallet and virtual accounts when the rider has none, also offered on the checklist row). The rider record gains Rider details and Keke details tabs in front of Station, Battery and Release. The Release register loses its Work order column and its checks-based filter: it filters by station, cluster and released today, and the notification and settings copy talk about release progress. Profile fields, balances and virtual account numbers are mock data.
  • Expansion — Expansion Project Manager dashboard, under a new Expansion heading (flows/expansion-project-manager). Built to the PM’s own screen brief for Precious, who sets up and runs a pilot without depending on other teams. Seven sidebar screens: Clusters (register with State, LGA and no-manager filters, create and edit with unique names and enabled areas only, a cluster record with attached stations and Add station), Swap stations (register with five filters, Add station with map search, a record with the Location, Manager, Active and In a cluster checklist, staff management, activation that needs a manager, and attach-to-cluster with a replace warning), Riders (primary station only, a rider record with Station, Battery and Release tabs and an Open in Telemetry link, Set primary station with the move-cluster warning), Batteries (rider fitting with inline refusal reasons, station stock requests, pack lookup with movement history), Release (six checks, 4 of 6 minimum, station picker only when needed, kit and VCU read Waiting on retrofit team), Station activity (station and date, headline strip that partitions assigned riders, Swaps, Riders who swapped and a today-only Not swapped today tab) and Telemetry (search by name, phone or plate, vehicle location card with no-permission, no-data and error states, swap tiles, recent swaps with a date range). Every register has search, a Filters dialog for three or more filters with chips, and CSV export. Loading, empty and error states are previewable through a Data state select in Settings or ?state=. A cluster is the zone; there is no pilot object and no station capacity, since neither is modelled yet. New catalog category expansion; the sidebar subtext reads EXPANSION.
  • Onboarding — Edit agent for the RAMs and PM (flows/rider-acquisition-manager, flows/regional-rider-acquisition-manager, flows/pm-onboarding, flows/apm-onboarding). The agents table gets a horizontal row menu with Edit agent and View riders, and the rows themselves are no longer links: the menu is the one place to choose between editing an agent and seeing their riders. Edit agent is a centred dialog with four editable fields: first name and last name (2 to 51 characters: letters, spaces, hyphens, apostrophes, periods), phone number (a valid Nigerian number, checked for duplicates against other agents) and cluster. State and LGA follow the cluster and show read-only. Email, level, role, parent agent and account status are shown but not editable, and account status keeps its own toggle. An optional reason goes into the agent’s change log with who and when; reopening the dialog shows the last edit. A rename follows the agent into riders, filters and prior-period data. In the Regional RAM, moving an agent to another cluster takes them out of that manager’s scope and says so before saving. Mock data only: the cluster-to-state-and-LGA pairs, phone numbers and the level, role and parent agent values are placeholders.
  • PM, Tricycle Hardware — Rider overview, one row per rider carrying retrofit and maintenance together (flows/pm-tricycle-hardware). A new #pg-riders page under the Overview group. Retrofit held the conversion, the kit and the retrieval; Maintenance held the cases; answering “how is this rider doing” meant opening two pages and joining them by plate. The register is the console’s own rider-to-plate map, so it can never name a different rider for the same keke than the Maintenance page does. A four-cell summary reads retrofit complete, awaiting retrofit, riders with an open case (with the case count and how many are on a repeat fault) and vehicles up for retrieval; a .grid2 puts where riders are in retrofit beside open cases by priority; the table carries rider, plate, retrofit stage, cases and open cases, last fault, retrieval stage and where the keke was last seen, filterable by retrofit stage, case state (open / none / repeat fault), retrieval state and the page’s own from/to range — the same window every other page uses, so a case count here and one on Maintenance are the same number over the same weeks. The kit is named only where it is still on the keke: a retrieved kit is already fitted to another one, and printing its id on both rows read as one kit fitted twice, so a vehicle whose kit came off reads Kit retrieved with no id and where it went is on the record’s kit history. A rider with no lifecycle row now opens — openRider refused a plate with no TUNIT record, which made the two riders whose kit was retrieved and the one never fitted unreachable; it falls through to a record carrying the rider, plate, case count, last known position, cases, retrieval and kit history. The rider record gains a Maintenance tab listing every case on that keke newest first, each opening the case record. Each rider carries their phone number under their name, on the row and on the record, in the format the Head of Maintenance console holds it (Musa Ibrahim is on both consoles and is on one number), and the search matches it. The five-cell summary band leads with active riders, which is the Onboarding consoles’ word used with their definition rather than a second one: pm-onboarding’s riderIsActive is retrofit completed, activated, the account enabled and at least one swap logged, and rdActive() is that. This console already carried the first two — the record’s onboarding rows carry the activation fee and the lifecycle says when the keke was converted — so what it adds is the account and the swap history. The account is read from the retrieval the fleet raised: of the three reasons a retrieval is raised, no swap in 28 days and a wallet in arrears are account states that disable the rider, while efficiency under 90% is a performance flag that leaves the account alone. Swaps accrue from the day the retrofit completed at a rate seeded off the plate, so a rider converted last week reads a smaller lifetime than one converted in May and a keke still queued has never swapped. The number reads back off the rows beneath it — of the six retrofit-complete riders one is up for retrieval for no swap in 28 days — and the rider record carries the four facts behind it: rider status, account with the reason it was disabled, swaps lifetime and last swap. A new .mstat-5 carries the five cells, stacking to two then one at the existing 900px and 640px breakpoints. Also adds the canonical .tbl th.r,.tbl td.r{text-align:right} rule the flow’s markup already used but never defined, so the right-aligned count columns on Rider overview, Retrofit and Inventory are right-aligned. Canon-lint 0 errors, flow-diff 0 gaps, verified in the browser at 1440x900 and 375px.
  • Facilities — Location Acquisition Manager lifecycle pushed up into the PM and VP tiers (cross-tier alignment) at flows/facilities-pm/index.html, flows/facilities-vp/index.html and flows/facilities-location-scout/index.html. Reconciles the three facilities exec flows so one record reads identically at every tier, taking the Location Acquisition Manager’s newer lifecycle as canonical. Stage vocabulary: the PM and VP gain the Approved entry stage (grey) the scout flow already had, so a project runs Approved → Leased → Design → Construction → Handover in all three; PRJ-017 Ijebu-Ode now reads Approved everywhere, and the PM’s accept action mints a project at Approved (lease not yet filed) rather than Leased. Sagamu graduates: PRJ-012 Sagamu Charge-Swap was commissioned (handed over 28 Mar 2026), so per the lifecycle it leaves the pipeline and joins the estate — dropped from the PM and VP project pipelines and added as a live site (the estate is now 39; health holds at 92% PM / 82% VP), and the scout’s FAC-03 name is aligned to Sagamu Charge-Swap Station. Location → decision bridge: the PM’s Awaiting your decision queue and the VP’s Awaiting PM decision count now mirror the scout’s actually-submitted locations (status review) — a single location, Epe workshop (LOC-12, case report REP-112), sharing the same id and case-report notes/media across tiers; LOC-14 Ifo (draft) and LOC-13 Agbara (surveyed) are correctly absent since the scout has not submitted them (this shrank the PM queue from 2 to 1). Cluster naming: the scout’s invented Lagos-Mainland cluster becomes Lagos (matching the PM’s region vocabulary; the VP keeps its finer Ikeja/Lekki clusters, which sit within Lagos). Verified: canon lint 0 errors, flow-diff 0 structural differences on all three (the blocking gate), flow-probe clean (scout 5/5, VP 6/6; the PM’s pre-existing read-only detail-table findings are unchanged by this work), no console errors, and every derived count reconciles at runtime.
  • Facilities — Location Acquisition Manager (renamed from Estate Manager) + the acquisition lifecycle at flows/facilities-location-scout/index.html. Builds the persona’s end-to-end lifecycle and renames it a second time: the remit now spans sourcing, survey, approval, leasing and handover, so Estate Manager becomes Location Acquisition Manager across the flow, its design.md, PRD.md, flows/README.md and site/src/data/products.ts, with the EM role monogram now LA. The flow slug, folder and URL deliberately stay facilities-location-scout so existing links keep resolving; the PRD carries a naming-history note (Location Scout → Estate Manager → Location Acquisition Manager). Scouting nav relabelled: the sidebar is now Overview / Requirements / Locations / Projects, and the Overview dashboard heading is Cluster (internal #pg-* ids unchanged). Acquisition lifecycle — a record moves through one status at a time and lives in exactly one tab: Locations (pre-approval) runs Draft (location created) → Surveyed (case report attached) → In review (submitted to PM/VP) → Rejected (dead-ends); an approved location leaves Locations for Projects (post-approval) as Approved → Leased (scout uploads lease details) → Design → Construction → Handover, the stage read-only for this persona (only the PM/VP advance it, FR-11); a completed lifecycle leaves Projects for a new Facilities tab (terminal, read-only). Actions carry the new verbs — “File location”, attach report → Surveyed, submit → In review, add lease → Leased — and every transition was verified at runtime. Overview is now a Lagos lens derived from the real Locations / Projects / Facilities records rather than a disconnected areas dataset: a Leaflet map centres on the Lagos cluster and plots each item coloured by phase (Facility / In development / Pipeline), and the KPIs and pipeline table are computed from the same records so they match the other tabs; the Overview filter moved to ov-* ids, closing a latent duplicate-id collision with the Locations filter. The rename is propagated through every other flow’s role registry (cpo, facilities-pm, facilities-vp, facilities-manager, facilities-regional-manager, facilities-station-manager, cluster-manager, rider-support-agent, rider-support-supervisor, swap-support-specialist, vp-swap, starter-template, screens/issue-management-dashboard.html); avatars that happen to read EM as a real person’s initials are left untouched. Canon lint 0 errors under the current ruleset (including web-undefined-class, which caught a borrowed .readonly-box → .note-box), flow-probe 5/5 at 1440, no console errors.
  • Revenue Assurance dashboards — layout + palette revisions at flows/revenue-assurance-lead/index.html and flows/relationship-manager/index.html. RA-Lead Cluster SRRR card gains an All / per-cluster scope dropdown (regional view; the gauge and gap-chip follow the selection while the KPI tile stays cluster-wide). RM dashboard: SRRR by station → SRRR by mesh; the accountability card moved below the SRRR cards and was recomposed from a full-height seven-bar block into a compact score-ring + two-column mini-metric grid. Palette tightened across both dashboards to green (brand / good) · amber (below target) · red (breach) · grey (neutral): dropped the decorative blue KPI-tile icons and recoloured the no-swap-volume bars from amber to neutral grey, so colour now carries meaning instead of decoration. Canon-lint 0/0; every interaction re-verified.
  • Procurement & Inventory PRD — every requirement ID is unique and the sections run in sequence (docs/procurement-inventory-prd.md). Five FR IDs each named two different requirements; the later-added or uncited row of each pair took the next free number (the 28 Aug FR-C8/FR-C9 rows → FR-C11/FR-C12; the §7.13 location-transfer FR-T6 → FR-T8; the §7.14 feedback pair FR-F10/FR-F11 → FR-F16/FR-F17, keeping the §7.6 returns rows that FR-K8 cites), the duplicated §17 became §18 and the skipped §20 is filled. No requirement text changed. The procurement-manager design note now cites spend analytics as FR-R17.
  • Maintenance is its own group in the /flows catalog. The four maintenance personas had been filed under Tricycle Hardware, which is the vehicle programme rather than the discipline that keeps the fleet running, so they were listed beside Production, Retrofit, Inventory and Procurement roles they share nothing with. FLOW_CATEGORY_ORDER in site/src/pages/flows.astro gains a { key: 'maintenance', label: 'Maintenance' } heading directly after Tricycle Hardware, and PM Maintenance, Head of Maintenance (FVMT Manager), Cluster Maintenance Manager and Field Validation Engineer move to category: 'maintenance'. Tricycle Hardware goes from 15 flows to 11; Maintenance lists 4. PM Tricycle Hardware stays under Tricycle Hardware and keeps its Maintenance page unchanged — it is a programme console that carries a maintenance view, not a maintenance persona. Grouping is driven entirely by FLOW_CATEGORY_ORDER, so no other surface needed changing; astro.config.mjs carries no flow categories. Verified on the served catalog: nine headings render in order, the four personas sit under Maintenance, and lint-flow-titles passes.
  • Onboarding Goal Tracker — year-end pace tracking for Total/Active Riders (Onboarding_Goal_Tracker_PRD_v1_1), across all four Onboarding personas: flows/pm-onboarding, flows/apm-onboarding, flows/rider-acquisition-manager (Country RAM) and flows/regional-rider-acquisition-manager (Regional RAM). Lives as a new card on each file’s Overview page — deliberately not a sidebar item, per the PRD’s own framing — linking through to a single combined view-goal-tracker page (Goal Summary + Pace Detail + Per-Agent Accountability read together, not split into tabs, matching §1’s “full insight” framing). Goal Summary: Total Riders and Active Riders as big numbers against a 2,500 year-end target each, a progress bar and a status pill (On track / Needs faster pace / Behind pace / Goal reached, thresholds exactly per §8 — ≥97% of required pace / 70–97% / <70%). Pace Detail: Required pace ((target − current) ÷ periods remaining) and Actual pace (trailing average of period-over-period deltas — last 7 days / 4 weeks / 2 months for Day/Week/Month) per metric, plus a cumulative-progress trend chart with a dashed trajectory line projecting to the deadline — a new renderGoalTrendChart(), distinct from the existing renderLineAreaChart(), since this one needs an x-domain that extends past “today” into the future with a genuinely reserved gap (not just one more slot) so the last-actual-date and deadline-date labels don’t collide. Per-Agent Accountability: every active agent’s own pace against an even split of Total Riders’ required pace (§9 — deliberately even, not weighted by history), sorted worst-gap-first, with a Meeting/Not Meeting badge; a zero-active-agents empty state and a goal-already-reached state (no negative required-pace figure) are both built in (§12). Goal Configuration (§10.4, PM/APM only) extends the existing Settings → Onboarding pane with Total/Active Riders target+deadline fields, reusing the exact {field,oldValue,newValue,who,when}-shaped confirm-dialog-before-mutate audit pattern already established there for the daily activation target — hidden entirely from both RAM files, which have no Settings → Onboarding pane at all and see the goal numbers read-only. Country RAM sees the full national numbers and an unfiltered per-agent table; Regional RAM sees the same national totals (PRD §3: the Country/Regional split scopes only the per-agent table, not the top-line goal) with its per-agent table naturally limited to its own South West roster, and its per-agent target uses the true 18-agent national count (not just its own smaller roster) so a given agent’s target reads identically from either RAM’s dashboard. Mock daily-addition series for both metrics are rescaled (with a round-robin drift-correction that never clamps a day to negative) so their cumulative sum exactly matches the PRD’s own validated 2026-09-01 snapshot — 603 Total Riders, 582 Active Riders — rather than typing the “current” figure and the daily series independently and risking them silently disagreeing. Verified: lint 0 errors, flow-diff 0 new gaps (same known baseline on pm/apm-onboarding, 0 on both RAM files), all views (plus the new page, probed directly since it has no sidebar entry for the automatic scan to discover) runtime-probed clean at 1440×900, apm-onboarding mirror reconfirmed at exactly the 7 known substitution pairs. Design-reviewer pass (all four files, before PR): an independent design-reviewer sweep surfaced two critical and several major findings, all now fixed and re-verified. Critical — data honesty: goalAgentRows() on all four files sourced each agent’s “actual pace” from a dataset disconnected from the page’s own national actual-pace figure, so the per-agent rows could each read “Meeting” while the team headline read “Behind pace” — a direct contradiction. Every agent’s actual is now apportioned from goalActualPace() by relative weight (Country RAM’s national actual split by MTD-onboarded share; Regional RAM first takes South West’s fair headcount share of the national figure, then splits that regional share across its own roster, so it never overstates one region as the whole country), guaranteeing the rows always sum back to the number already on screen. Critical — dark mode + scale: renderGoalTrendChart()’s six hardcoded hex colours are now design tokens (var(--border-soft)/var(--text-3)/var(--brand)/var(--border)/var(--surface)), and its y-axis no longer force-scales to the 2,500 target when history only spans a few hundred — it now scales to the real data with 20% headroom, clipping the dashed trajectory at the chart’s top edge with an arrow + “↗ target by deadline” annotation when the target exceeds that range, instead of crushing the actual trend to an unreadable sliver. Major fixes across all four files: .pg-back on the new page was a bare <div> + &lsaquo; glyph instead of each file’s own canonical button+SVG-chevron pattern; .mbanner‘s close-button padding was scoped out of the base class into a new .mbanner.has-close modifier so it stops adding dead padding to every other banner in the file; &mdash; entities in new copy became &middot;; the Overview mini-card’s and Goal Summary’s .pstat-top swapped a bare status badge for a tonal icon (matching every other .pstat-top in these files), with the status verdict moved to a .pstat-sub colored arrow+text line (new goalVerdictHtml(), mirroring the existing ar-count-verdict convention) instead of a badge chip; Pace Detail’s Required/Actual tiles gained the .pstat-top wrapper + icon they were missing entirely. pm-onboarding/apm-onboarding only: Settings → Onboarding’s new save/cancel rows now use the canonical .set-foot alignment class instead of a bare flex div. Both RAM files only: the per-agent Gap column now uses .trend/.trend-up/.trend-down (new goalGapTrendHtml()) instead of hand-rolled inline colour styling. Regional RAM only: the sole scope disclosure had been inside a permanently-dismissable banner with no equivalent label on the Overview card; a persistent .pg-sub under the page title and a .card-sub on the Overview card now both read “National totals · not scoped to South West” independent of the banner, and the per-agent table’s .card-sub gained a row count. Re-verified: lint 0 errors and flow-diff 0 new gaps on all four files, all views (including the new page) runtime-probed clean at 1440×900, apm-onboarding mirror reconfirmed at exactly the 7 known substitution pairs (28 diff lines). Two follow-up findings from a second review pass, both fixed: pm-onboarding/apm-onboarding’s Settings save/cancel rows were still nested inside the fields’ own .set-sec instead of a sibling .set-sec.set-foot — restructured to match the pre-existing daily-activation-target section’s shape exactly. Regional RAM’s fair-share fix (above) sized regionalShare for South West’s real 6-agent headcount but then apportioned the whole thing across only the 3 agents AGENT_DATA actually tracks, so each shown agent silently absorbed a slice of the other 3’s unlisted output; a further visibleShare = regionalShare*(AGENT_DATA.length/CLUSTER_DATA[0].agents) scales the distributed total down to what the 3 tracked agents can honestly account for before splitting it by weight — the per-agent table’s own “3 of 6” disclosure and its numbers now agree with each other. Re-verified clean on both.
  • PM, Tricycle Hardware — cross-domain monitoring & analytics cockpit at flows/pm-tricycle-hardware/index.html. Replaces the placeholder with the Product Manager’s unit-wide console: one read-only surface that rolls up every persona so the PM can answer any question about any domain at a glance. Overview stacks a six-tile north-star KPI band (units built, fleet-ready, first-pass yield, 30-day recurrence, days of cover, rider-days lost), a Domain Health board (a RAG tile per domain with headline metrics + sparkline), a cross-domain attention watchlist and the field signal. Domain pages drill into Production (throughput, output by line, holds), Maintenance (fleet-ready, vehicle-health bands, top cohorts, open WOs), Retrofit (conversions, rider pipeline, quality) and Inventory (stock cover, low-stock alerts, procurement in transit). A global reporting-period selector scopes the trend charts and every table carries its own status/priority filter; the palette is a restrained green/amber/red status system; the signed-in PM is Hadiza Mamudu; console access is role-based (read-only rollups, no cross-role console launch). A Tech feedback page collects inbound bug reports and improvement requests (name, email, source app, note) and is actionable end to end: each item opens a detail with the full note and Start / Mark resolved / Dismiss / Reopen controls that update status and recount the KPIs live. Feedback arrives untyped (just a note); each triage action emails the sender with an attached note (acknowledgement on Start, note-required on Resolve, confirm-with-reason on Dismiss). Domain health status is computed from each domain’s metrics against targets (worst band wins; click a status badge for the breakdown), not hard-coded. A single global from/to date filter in the topbar scopes both the graphs and the dated tables. Maintenance shows Median time to resolve (was MTBF) and work-order status reads With technician / With FVE. Notifications click through to the relevant page with Mark-all-read. A Personas directory gives a domain-filterable scorecard for all eight built roles (row → full KPI scorecard), Analytics carries four cross-domain trend charts + a by-site breakdown, and Field signal tracks the requests and console adoption coming up from the field. Boots to Overview, no login gate, honours ?scenario=; every metric reconciles with the underlying persona consoles (Ikeja cluster, Forge · Sango, 362-tricycle fleet). Built on the canonical atom system (same as the swept cluster-maintenance-manager); registered under category: 'tricycle-hardware' with eight scenario deep-links. Canon-lint 0/0; flow-diff 0 vs the reference; all 11 views runtime-probed (no undefined/NaN, no console errors).
  • Onboarding PM/APM Overview — story tiles collapse to a card + modal, two charts get their aspect ratio and scale fixed. Follow-up round after the Product Command redesign PR merged (#149), on flows/pm-onboarding/index.html and flows/apm-onboarding/index.html only. Story tiles (Onboarded, Active riders, Released not yet swapping, MEI pass rate, Lead→Activation cycle time, Activation revenue) no longer show their full chart/evidence/why-line/drill-down inline on Overview — each collapses to title · period control · big value · one comparison badge · a tiny unlabeled sparkline, and clicking the card body (not the toggle) opens a modal with the full labelled chart, evidence, why-line and drill-through. Five of the six keep their Day/WTD/MTD toggle on the collapsed face (it changes what the headline value itself means, so it has to be one click away, not buried in the modal) — MEI pass rate gains this toggle for the first time (it was a single fixed weekly figure with no period control at all). Tile 3 (“Released, not yet swapping”) is the deliberate exception: its date-range picker is bulkier than a 3-button pill, so it stays modal-only, never on the card face. New openStoryModal(tile)/renderSparkline() reuse the file’s existing single shared #dlg/openDlg() dialog rather than six static modals. Comparison wording is now consistent by metric type instead of picked per-tile — Day mode reads “vs avg {weekday}” for counts and money (was “vs median {weekday}” on some tiles, “vs yesterday” with no comparable wording on others), WTD reads “vs last week”, MTD reads “vs last month”; “median” is reserved for the one duration metric (Lead→Activation cycle time), which now explicitly says “vs {period}‘s median” since the skew argument that justifies median only holds for durations, not counts/revenue. Two shared-chart fixes to renderLineAreaChart (used by Pipeline’s “New riders entering pipeline” and Activation’s “Trend of daily activations”, plus Revenue’s fee-earned chart): the y-axis floor is now anchored at 0 instead of auto-scaling tightly around the data’s own min (a 255–270 range stretched to fill the chart was turning ordinary week-to-week wiggle into what read as dramatic mountains); the last x-axis label now anchors text-anchor="end" instead of "middle" (was clipping, same fix renderOvChart already had); chart height bumped 200→230. The two flagged cards additionally get max-width:760px (previously spanned the full page width against a chart designed at a ~3:1 aspect, stretching the line badly) — narrowed rather than paired into a 2-column grid, since their card heads already carry a date-range + group toggle that would crowd in half the width. Also fixed proactively: the same tight ~15px label-vs-toggle margin that caused a CI-only (Ubuntu-fallback-font) row-baseline mismatch on the old expanded tiles is now structurally impossible — .opm-story-lbl truncates with an ellipsis (title attribute carries the full text) instead of wrapping to a second line, so no card’s label can ever grow taller than its row-mates regardless of the rendering font. Re-verified: lint 0 errors (same 2 pre-existing baselined warnings), flow-diff at the same 1 known baselined gap, all 11 views runtime-probed clean in both themes at 1440×900 on both files, apm-onboarding mirror reconfirmed at exactly the 7 known substitution pairs. Fast-follow (same round): MEI pass rate’s card wasn’t opening its modal on click, so its 80%-target reference line effectively vanished (it only ever lived in the modal); renderSparkline() gains a dashedRef option so the target line now shows on the collapsed card’s sparkline too, independent of whether the modal opens, and the modal-open path itself was re-verified end to end (structurally identical to the other 5 tiles — no defect found there, but hardened regardless). Active riders’ sparkline was a near-flat cumulative-total line sitting next to 5 tiles that visibly move; renderSparkline() gains a bars mode and the tile’s data switched from raw stock levels to a net-change-per-period series (bars, each period’s own delta), giving it real shape while keeping its last bar consistent with the existing net-change badge. Second fast-follow (same round) — Onboarding funnel ribbons: FUNNEL_STATIONS/FUNNEL_CLUSTERS dropped the app’s usual multi-hue palette (green/blue/purple/amber/red) for one dark-to-light green family (Deep Pine → Dark Emerald → Classic Emerald → Medium Mint → Soft Mint, plus Pale Ice Green as a 6th step for cluster mode’s extra category), each step carrying its own designed opacity (15% for the darkest/largest-share band up to 88% for the lightest/smallest), so adjacent ribbons read as one flowing river and can never be mistaken for the app’s semantic green/amber/red status colours. “No station” keeps its own pale warm grey, deliberately outside the ramp. The harder-looking edge on the topmost (“No station”) band — never an actual stroke, traced to that band alone getting a much lower fill-opacity than every real segment, which made its boundary against the page read as a harder line — is gone now that every segment (grey or coloured) shares the same per-step-designed opacity treatment; the same fix removes an earlier anti-aliasing-seam patch (a sub-pixel overlap between adjacent ribbon paths) that’s no longer needed and was overreaching the stack’s own outer top/bottom edges. Same palette applied to the “By cluster” toggle. Third fast-follow — sparkline shadow: renderSparkline()’s line variant gains a soft gradient area-fill under the line (28%→0% opacity), matching the established PM Tricycle Hardware KPI-sparkline convention, instead of a literal box-shadow/blur filter which would smear the whole 28px-tall SVG at that size. Re-verified: lint 0/0, flow-diff at the same known gap, all 11 views probe-clean on both files, apm-onboarding mirror reconfirmed at the 7 known substitution pairs.
  • Onboarding PM / APM, Onboarding — Product Command redesign: story-tile Overview, 3-tab Pipeline, filterable Riders, story-treatment Revenue at flows/pm-onboarding/index.html and flows/apm-onboarding/index.html (Star Trek and the ported PCA screens are unchanged). Filter architecture: the global bar now carries only cluster + station — the old global date range is gone, replaced by controls local to each surface that actually needs one (Overview’s per-tile Day/WTD/MTD toggles and tile 3’s own date range, Pipeline’s per-tab as-of/date-range, Riders’ own Filter panel). Overview is rebuilt as five story tiles (chart → value + verdict → evidence → why-line → drill), each honest about what its data can say: Onboarded/conversion, Active riders and Lead→Activation cycle time carry the Day/WTD/MTD toggle; Released-not-yet-swapping gets its own date range; MEI pass rate gets a dashed 80%-target reference line. The onboarding funnel is now genuinely 9 stages (Lead captured → Activation fee paid → ⋯ → Active, matching the canonical account_status model — there is no ACTIVE status, “Active” is RETROFIT_COMPLETED+activated+enabled+swap_count>0), segments by preferred swap station (muted “No station” band for pre-assignment stages, with a hide toggle) or toggles to cluster, and its “biggest leak” callout is computed from the stage totals rather than hand-typed. The exception queue and activity strip read real counts off the Retrofit Standby / PCA queue / station-capacity data instead of static numbers. Pipeline drops the old 4 sub-tabs for 3 (Composition → Distribution → Time & Flow): Composition is a lean current snapshot (stage donut, 4 headline counts with vs-last-period deltas, the 2 data-quality flags) with an “as of” date picker; Distribution slices active riders and pipeline riders by station/cluster (by preferred swap station, not route — station is the unit the PM acts on) with trend headers on the real aggregates, adds a sortable station-capacity table (current load / max / available / utilisation) with a near-capacity alert, and keeps the real per-stage and per-station aging tables; Time & Flow gets its own date-range picker, switches the weekly-intake chart to bars + a rolling-average overlay (distinct from the glance-surface line pattern), and pairs each percentile card with a histogram alongside the plain numbers. Riders gains a filter-context strip (“Showing: …·N of M·Clear filters”), a local agent + date-range filter beside the existing status multiselect, and bulk row selection for CSV export only (reassign stays one-rider-at-a-time). The Rider Record drops the manual status-override action entirely (account_status is system-driven, so there’s nothing to override) and splits the old combined “Edit details” into Edit contact (phone/email/address) and Edit tricycle (type/plate/chassis), each reason-gated; the Activity panel is now an audit table (Field · Change · Who · When · Reason, old value struck through) instead of a one-line feed. Revenue gives Recognized/Reversed/Net the same chart+verdict+why story treatment as the Overview tiles, adds the previously-missing “Activation fee earned” trend chart and a 2-way Earned/Refunded disposition split, and the rider-payments table gains its own swap-station filter plus a Custom date range. Canon-lint 0 errors on both files (the pre-existing web-undefined-class warnings for .opm-sankey/.rdr-clear-chip are fixed and dropped from the baseline; the two remaining warnings are unrelated pre-existing drift in Agents/Star Trek, out of scope here); flow-diff unchanged at 1 known gap (the same untouched Agents table); all 11 views runtime-probed clean in both themes. Corrections pass (v1): every chart everywhere now carries a labelled axis and a hover tooltip with the exact value — no more shape-only decoration (the Overview tiles, Revenue’s three headline cards and its fee-earned chart, and the Time & Flow percentile histograms all gained real axes + data-tip-rows hover, and the histograms now plot real per-bucket rider counts instead of an illustrative shape); “typical” is replaced with “median” everywhere (percentile trio is now Median / 9-in-10-clear-by / worst case); Active riders (a cumulative stock, both on Overview and in Pipeline → Distribution) and Swaps · today drop their misleading trendlines for a net-change hero and a vs-a-normal-day comparison respectively. Corrections pass (v2): the Overview Day/WTD/MTD toggle now re-scopes a tile’s chart, x-axis, headline, comparison and evidence line together as one unit, instead of the chart silently staying on a different period than the headline; the funnel’s station segmentation now spans the whole funnel (preferred swap station is captured at lead capture, so “No station” is a small, roughly-uniform residual of ~0.6-3% at every stage — a data-quality gap, never a whole-stage default, and no longer read off the unreliable raw preferred_station_id column); and every time-series chart (Overview tiles, Pipeline’s rider-intake chart, all four Revenue charts) now groups its data adaptively — by day at ≤2 weeks, by week at ≤6 months, by month beyond that — labelling its own x-axis and a small “Grouped by …” caption to match, with a manual day/week/month override on the Pipeline chart. That chart (“New riders entering pipeline”) is also redesigned from wide bars to a single line + soft area fill with a dashed rolling-average overlay (matching the Revenue “Activation fee earned” style), on a card sized 1080×200 (a 5.4:1 ratio, tuned after review from an initial 140px pass that read too flat/wide). The Overview funnel drops its “Onboarding in progress” column (now 8 stages, not 9). The “Released, not yet swapping” tile’s cohort is corrected to retrofit_completed + activated + enabled + an assigned swap station (a new field, distinct from the preferred station captured at lead capture) + zero swaps; its aging line now shows the cold count and the past-7-days-since-retrofit subset as two honest, distinct numbers (never implying an unproven pickup/handover date); its chart’s x-axis no longer clips its last label and its date range now adaptively groups like every other chart, with its own date-range picker actually driving the data (previously fixed at a 6-point shape). Pipeline → Time & Flow’s two bottom panels are now visually and behaviourally distinct: “Stage transition times” sorts slowest-first on one shared scale and tags the worst stage; “Current backlog age” is a live worklist — per-queue rider counts, amber/red colouring as a queue’s wait crosses its own concern threshold, and every row drills into the actual riders. Both duration histograms gain median/P90 vertical markers tying the chart shape to the plain-number percentiles beside it. A one-line .mbanner data-model explainer (matching the Revenue Assurance dashboards’ convention) is added to the Overview funnel, the “Released” tile, Pipeline → Time & Flow, and Revenue, stating how each screen’s numbers are derived. Re-verified: canon-lint 0 errors, flow-diff unchanged at 1 known gap, all 11 views runtime-probed clean in both themes on both files (Star Trek’s pre-existing KPI-wrap finding is untouched, out of scope). Corrections Round 2: the Revenue sidebar item is renamed “Activation & Revenue” and gains its own sub-tabs — Activation (default: a lead-quality/readiness view — daily count+₦ vs a PM-configurable target with progress bar, a trend chart with a target reference line, a sortable per-agent activations table, all adaptively grouped) and Revenue (the existing screen, unchanged, relocated). The daily activation target is now editable in Settings → Onboarding, confirm-gated and audit-logged (old→new/who/when), and re-renders everywhere it appears (Activation tab, a new Overview activity-strip chip, a new 6th Overview story-tile “Activation revenue”). The Agents screen is reworked to a strict onboarding lens — Agent/Leads submitted/Show-up rate/MEI pass rate/Riders in book/Quality flag (no Commission anywhere), sorted worst-first by a volume-weighted quality score, row click now drilling straight into that agent’s riders instead of an intermediate agent-record page. Re-verified: lint 0 errors, flow-diff unchanged, all 11 views probe-clean in both themes on both files. The Country and Regional Rider Acquisition Managers (flows/rider-acquisition-manager/index.html, flows/regional-rider-acquisition-manager/index.html) gain the same Activation sub-tab, agent-performance emphasis — reusing each file’s own existing AGENT_DATA/range-scoping and chart function (extended backward-compatibly with an optional target-reference-line) rather than importing pm-onboarding’s infrastructure. Canon-lint 0/0, flow-diff 0 structural differences on both, all views flow-probe clean at the canonical 1440px canvas. Live-review fast-follow (same day): the activation fee corrected to ₦20,000 everywhere it’s priced or quoted across all four files (pm-onboarding, apm-onboarding, both RAM flows — was inconsistently ₦25,000 in places); only the Onboarding PM/APM can set the daily activation target — the Settings-editable/audit-logged pattern is removed from both RAM flows entirely (no pane, no confirm dialog, no log), which read the same default value read-only; the Onboarding PM/APM Activation trend chart defaulted to a single “Today” point that rendered as an invisible sliver — now defaults to “This week” and gained an MTD option; every per-agent activations table (all four files) gained a Leads created column ahead of Activations, scoped by the same range control as its chart; the Overview “Active riders” net-change card now leads with the total (was buried in trailing text after the delta); both RAM flows’ Overview “Onboarded by cluster” card defaults to by station with a station/cluster toggle (STATION_DATA already existed, just unused for this card); and the Onboarding PM/APM Overview “Released, not yet swapping” banner is removed per feedback. Re-verified at the canonical 1440px canvas: lint 0/0 and flow-diff 0 on both RAM files, all views probe-clean on all four files — a first probe pass on the RAM flows at the Browser pane’s un-resized 966px default falsely flagged clipped headers and KPI-label wraps across every view; re-running at 1440px cleared every one, confirming it was a viewport artifact rather than a defect (same lesson as Star Trek’s KPI-wrap finding earlier this session — always resize before trusting a probe failure). Second live-review pass: the Activation banner is trimmed to just the fee sentence (Activation fee is ₦20,000, paid at lead capture.) on all four files — the trailing “signals a committed rider / target / not commission” clause read as filler once the tab itself already shows the target and the count. Both RAM flows’ Activation tab gains its own local Day/This week/MTD/Custom filter (defaults to Day), fully decoupled from Clusters & Agents’ shared range — AGENT_DATA‘s per-agent rows already carried a Today figure that the shared REG_RANGE never exposed (it only ever runs This week/MTD/custom), so the fix was a parallel AR_RANGE/arVal/arAgentPrevVal/arPeriodLabel set mirroring the existing regVal/regAgentPrev/regPeriodLabel pattern, plus its own custom-date dialog (ar-date-dlg) matching the Revenue tab’s own dialog convention rather than importing pm-onboarding’s inline date inputs. Re-verified: lint 0/0, flow-diff 0, all views probe-clean on both RAM files at 1440px. Third live-review pass: the Onboarding PM/APM Activation tab’s “Daily activations vs target” Day/Week/Month toggle previously only swapped the comparison label while the headline count stayed pinned to today’s figure — switching to Week or Month showed a stale daily count next to a “this week”/“this month” claim. It now genuinely re-scopes the whole card as one unit: count, target, progress bar and ₦ amount are all summed over the selected period (1/7/days-elapsed-this-month) and the delta compares against the equivalent prior period, via new arCmpDays/arCmpSum helpers replacing the old comparison-only arComparisonDelta. Re-verified: lint 0/0, flow-diff 0, all 11 views probe-clean on both pm-onboarding and apm-onboarding at 1440px. Design-reviewer pass (all four files, before PR): an independent design-reviewer sweep of the full branch diff against canon (judgment layer, not the deterministic lint/flow-diff/probe gates) surfaced findings unique to each file, all now fixed and re-verified. pm-onboarding/apm-onboarding — Composition’s “Onboarded today” plus its two data-quality flags had regressed from a compliant .chip row (DESIGN.md:394, cross-cutting flags beside a partition) back into full .pstat peer cards; restored as chips. Pipeline → Distribution’s “Active riders” and “Swaps · today” were bare .tbl-cards with no table inside (a table-system atom used as an empty shell); converted to .pstat cards. The Station capacity table’s Utilisation bar was a hand-rolled .opm-barlist-track inline in a <td>; swapped for the canonical .hcell/.cbar-top/.cbar-track/.cbar-fill bar-in-cell pattern (new to this file, ported from facilities-regional-manager). The Day/WTD/MTD “period toggle” pill on story tiles and the Activation headline had invented a second small-.pseg variant (.opm-story-seg); renamed to the already-canonical .pseg.pseg-sm (established in pm-tricycle-hardware). Composition’s “as of” date picker silently only rescoped the donut/pipeline-total, leaving Active/Dormant/Onboarded-today on the unscoped global-filter factor; now all four share one f = gfScaleFactor()*cmpAsOfFactor(), with the two real-roster data-quality flags deliberately documented as date-invariant (live signals, not a snapshot metric). The Overview Day/WTD/MTD toggle updated a tile’s own data but never refreshed OV_PERIOD_FROM/TO, so a “View onboarded riders →” drill-through could land on a stale date range after switching tiles’ periods; ovSetPeriod now re-derives the bounds on every t1 change. “Onboarded / conversion” tile never actually showed a conversion rate; retitled to “Onboarded” rather than inventing an unpaired rate. Minor: the Rider Record timeline printed raw enum strings (LEAD_CREATED, ACTIVATED) instead of a label; the two non-clickable Revenue story-tiles (“Recognized”/“Reversed”) still carried the hover-lift affordance of a clickable card (new .pstat.static/.opm-story-tile.static modifiers zero both cursor and lift, replacing the cursor-only inline-style patch used elsewhere in this same PR); the funnel’s “Hide ‘No station’” checkbox was a bare unstyled <input> beside every other checkbox in this PR using .opm-rs-checkbox. Also caught in passing (not a reviewer finding): the “Activation & Revenue” sidebar crumb rendered the literal text &amp; on screen — CRUMB is a JS string object read via .textContent, so its value needs a real &, not an HTML entity (that mistake only shows up at runtime, never in a source read). Also applied to both Activation headline cards, matching a defect the RAM reviews caught in the same widget: proper .pstat-top label+icon structure, “of {target}” moved out of the bold .pstat-val into a .pstat-sub line (weight discipline — 700 is for the bare numeral only), and align-items:start on the 2-up row so the shorter “Fees collected” card doesn’t stretch to match its bar-carrying sibling. Country RAM — the per-agent activations table’s sort-header and delta-column arrows were raw &#9650;/&#9660; text glyphs bypassing this file’s own existing rdSortIc()/trendCell() canonical components (a new arAgentSortIc() mirrors rdSortIc(), keyed to the Activation table’s own sort state); the Activation trend chart carried no window label unlike its sibling Revenue chart’s .th-sub convention — added. Also elevated the same partial-roster defect the Regional RAM review caught: the Activations headline summed only the 6 named AGENT_DATA rows instead of the true 18-agent national total in CLUSTER_DATA; CLUSTER_DATA gained a prev baseline (derived from each cluster’s own trendPct) so the headline and its vs-prior-period delta both read the complete population. Regional RAM — same .pstat-top/weight-discipline/alignment/glyph-arrow/window-label fixes as pm-onboarding and Country RAM, plus two RAM-specific defects: (1) critical — the read-only Activation target reused the Onboarding PM’s national 20/day figure unscaled for a single-cluster (South West) persona, so the KPI could mathematically never clear even amber; ACTIVATION_TARGET_CONFIG now carries a share:7 derived from South West’s 6-of-18 agent-count proportion of the national roster, with the derivation spelled out in a comment. (2) The Overview “Onboarded by cluster” toggle offered a “Cluster” view that — in a file permanently locked to one cluster — rendered a ranking of one (a single 100%-width bar, nothing to compare it against); removed the toggle and its dead OV_SPLIT_DIM/ovSplitSetDim/renderOvSplit() plumbing, leaving the always-meaningful station view. (3) Same partial-roster headline fix as Country RAM, scoped to CLUSTER_DATA[0]. One pre-existing, out-of-diff finding (a dead “across 4 clusters” fallback string, unreachable since this file has no scope picker) was left alone per the reviewer’s own note that it predates this PR. Re-verified all four files: lint 0 errors (same baselined warnings on pm/apm-onboarding, 0/0 on both RAM files), flow-diff at the same known baselined gap (pm/apm-onboarding only; 0 on both RAM files), all views runtime-probed clean at 1440×900 on every file, apm-onboarding mirror re-generated and re-confirmed at exactly the 7 known substitution pairs.
  • Relationship Manager — retrieval approval captures the logistics handoff; status filter + pagination at flows/relationship-manager/index.html (PR #113). The RM’s Update retrieval status dialog now branches on the chosen status: selecting Approved reveals four fields the pickup team needs — why we’re retrieving, where the asset is (Swap station / Retrofit station / With the rider), which swap station (shown only when the asset is at a swap station), and whether the rider is aware — captured before the approval saves. “Arrived retrofit station” is removed from the RM’s options — marking arrival becomes the logistics team’s action (see the new Retrieval logistics flow), so the RM’s terminal choices are Approved or Retrieval exception (unchanged, reason-only). The Retrievals table gains a Filter by status dropdown in the table-card head (beside Active/Completed) and pagination. Canon-lint 0/0; flow-diff 0; both branches re-verified at runtime.
    • Production build (Atlas app): in app/(admin)/revenue-assurance/retrievals/components/update-retrieval-status-sheet.tsx drop ArrivedRetrofitStation from statusValues, and render the four new fields only when status === Approved (the swap-station select conditional on asset_location === 'SWAP_STATION'). In page.tsx add the status Select (with the @rechaj/icons Filter icon) and pass pagination to DataTable; queries/use-get-asset-retrievals.ts must take pageable + status and return a paged response (needs the backend list endpoints to accept page/size/status). Backend: new asset_retrievals columns retrieval_reason (text), asset_location (SWAP_STATION | RETROFIT_STATION | WITH_RIDER), swap_station_id (fk, nullable), rider_aware (bool) — carried on the PUT /api/v1/selene/asset-retrievals/{uid}/status payload; the swap-station dropdown is the 8 active swap stations.
  • VP Telematics & KaaG — Programme overview retired at flows/vp-product-kaag/index.html — the KaaG-only overview page (adoption band, freshness buckets, trajectory, its copy of the attention table) is removed along with its sidebar entry, tab switchers, bucket renderer and data; ?page=overview deep links fall back to the Fleet overview. Sessions now carry the who-is-using-it story and Rider impact carries adoption-vs-outcome, so the page had become a duplicate landing.
  • VP Telematics & KaaG — KaaG section rework: sessions, impact, demand at flows/vp-product-kaag/index.html — the KaaG programme group grows the surfaces the generator product actually needs. Sessions: active sessions now (rider, elapsed, live draw, energy at tariff, SOC) over a filterable history, each opening a session detail page with the energy-through-the-session chart (cumulative kWh + instantaneous draw against the 1 kW inverter, SOC-floor cut annotated) and measurement honesty (inverter-kWh vs battery-Ah divergence). Rider impact: cohort KPIs (90-day retention 93% vs 84%, swaps/week, active days, churn), a 12-week retention curve vs a matched non-KaaG cohort, efficiency paired bars, and the demand signal (212 expressed interest, 58% conversion, 34% referral share) — with the observational-not-causal note. Demand stage: Expressed interest now tops the rollout page’s five-stage demand & eligibility pipeline. Session energy is scaled to the physical product (a 5-6 h session at 380-700 W household load lands at 1.6-4.9 kWh; peaks never exceed the inverter).
  • VP Telematics & KaaG — telematics-first rebuild at flows/vp-product-kaag/index.html — the surface was designed KaaG-first with telematics as a side note; it now leads with the estate. New Telematics sidebar group: Fleet overview (348-VCU estate KPIs, last-seen buckets, 14-day uptime trend vs the 96% executive floor, commands/OTA/SIM-data rollups, estate-wide attention worklist), VCU register (filterable by state, programme, firmware; standard-fleet units join the sample alongside KaaG), and Connectivity & SIMs built on the real Onomondo API surface (GET /sims online/last_came_online_at, usage webhooks, network-auth events) with an outage-class watchlist — session flapping, online-but-zero-MQTT, blocked-at-data-cap, auth-denied, IMEI mismatch, SMS-only registration — network/RAT distribution, and per-SIM data usage. The persona gains command authority: a Send-command dialog (telemetry snapshot, battery unlock, inverter ON/OFF, reboot, OTA retry, out-of-band SMS wake through the Onomondo SIM) with a mandatory reason, audited to [radar-command-audit] and surfaced immediately in the per-VCU event timeline; the flow’s Read-only badges and “no command affordances” notes are gone accordingly. KaaG keeps its programme overview, usage & energy, inspection & rollout and the management report, scoped to KaaG units only. Fleet health is regrouped under Telematics as Uptime & health. Onomondo reality is stated in-page: no radio signal metrics exist in their API (RSSI stays VCU-sourced), and events are mirrored into RadR by webhook.
  • Revenue Assurance dashboards + scorecards — QA follow-up to #100 at flows/revenue-assurance-lead/index.html and flows/relationship-manager/index.html. A QA click-through of every interactive element turned up two classes of affordance that responded but didn’t finish the job, now fixed: (1) dashboard rows landed on a general list instead of the record — the RA-Lead Approval-inbox row now opens that specific request (openReq(uid)) and the RM not-swapped-today row opens that specific rider (openRider(id), relabelled “View rider”); (2) the RA-Lead scorecard’s accountability actions — Issue query / Log coaching note / Send recognition — were toast-only stubs, where the flow’s convention for an action that captures input is a dialog. They now open proper openDlg dialogs (title + .field/.inp textarea + Cancel/confirm, mirroring the flow’s loReject pattern) and toast on confirm. Canon-lint 0/0 under the current ruleset; a re-run QA click-through confirms every action opens/lands correctly with no console errors.
  • Onboarding PM/APM — design-canon drift from this session’s batches at flows/pm-onboarding/index.html, flows/apm-onboarding/index.html, and the shared flows/star-trek/shared.css — a /design-review pass over batches 1-4 turned up 6 real regressions, now fixed and re-verified: a missing .b-purple badge tone (the Override-status modal’s “MEI Passed” option rendered as an undefined/unstyled chip); a decorative gradient on Star Trek’s vehicle-photo placeholders (now flat var(--grey2), fixes VP/PM/APM at once since the CSS is shared); .tbl missing table-layout:fixed + primary-column width, which left narrow tables (Trend & excellence, Needs your call today) hugging the left edge with dead space on the right; a truncated Settings placeholder gear icon (rendered as a bare dot); .dlg at 480px instead of the canon 540px; and an em dash in the Rider Record’s override Activity-log entry. Five further items were flagged as pre-existing debt from before this session. Two were low-risk enough to fix now: .opm-action-link/.section-link (the latter unused) and .opm-record-back duplicated the canonical .link-add — consolidated into one real .link-add{...} definition (previously only usable inside #startrek-mount) with .opm-record-back trimmed to just its icon-gap/margin override, a pure cosmetic no-op verified via computed styles; and .pg-wrap widened from 1280px/32px to the canon 1600px/40px. Three remain as tracked debt since they touch pre-existing feature visuals more directly: Revenue fee-card border-top accent stripe, the rider-list drawer’s hand-rolled .opm-drawer-* (duplicates the canonical .drawer already used in this same file’s Area details drawer), and .pstat extended with an undocumented .opm-kpi-bar/.opm-kpi-foot.
  • Facilities — Location Acquisition Manager: multiple leases per location, stacked by layer at flows/facilities-location-scout/index.html (spec: PRD-multiple-leases.md). A project’s single lease becomes a leases set, one per physical layer of the site — land · building · roof · airspace · car_park · grid · whole_site · other — so one location can carry, for example, a ground lease, a building lease and a rooftop-solar lease at once. The project details page’s Lease & landlord card is now a Leases .ls-row stack (the location’s stack of interests): layer badge(s), landlord, term, rent and status, with the one Primary and any Essential or Master masterRef leases badged, a footer of layer/active counts and total annualised rent, and superseded leases kept read-only under a Previous agreements divider. The Lease details .dlg gains a layer multi-select (.lchip chips), Role, an .tgl Essential toggle, structured rent (amount · period), a Supersedes picker (renewal supersedes, never overwrites) and a master-agreement ref. The Primary gates Approved → Leased and headlines the Projects table (with a +N marker for extra layers); the Lease expiring KPI/chip now fire on any active lease inside 180 days (amber) / 90 (red). Seed data: Ikorodu Charge-Swap carries the full stack (building + land + roof + car park, plus a superseded roof) totalling ₦14,000,000/yr; Ota BAU shows a combined {land, building} agreement. Verified: canon lint 0 errors, flow-diff 0 structural differences, flow-probe 5/5 at 1440, and the detail render → dialog populate → save → read-back path exercised at runtime (total, expiry chips, Primary/Essential/Master/Superseded all correct), no console errors.

  • Retrieval logistics — new Atlas flow for the Cluster Operations Manager (CLOM) at flows/retrieval-logistics/index.html (PR #115), registered in site/src/data/products.ts under revenue-assurance. Inserts the missing owner between the Relationship Manager and the Retrofit team — RM → Logistics → Retrofit — so an approved retrieval has someone accountable for the physical move (today ~99 sit at APPROVED with no owner; ~6 days approval→arrival against a 48h target). Persona: Cluster Operations Manager (CLOM). Four surfaces, built verbatim on the starter-template shell (boots to the app, no login gate): Retrieval queue — a KPI strip (pending pickup / in transit / arrived / SLA breaches) over a search-, status- and location-filtered, paginated table; a full detail page on row click — the RM-approval context (reason, asset location, swap station, rider aware), the transition timeline, a live VCU-telemetry map (read-only, logistics-only, never shown to the RM), retrieval-support assignment (a company employee — field support and retrofit share the workload for now) and the rider’s read-only sales agent (who onboarded them) for contact, a retrieval-spend log with an Add-cost dialog, and Mark in transit / Mark arrived / Put on hold; a Logistics dashboard — completions, avg time-to-arrive vs the 48h target, pending & SLA counts, a hoverable trend chart, and by-retrieval-support / by-swap-station / outcomes .cbar breakdowns; and a Retrieval spend accountability tab — totals, spend by category and by retrieval support, and an expense ledger with receipts. Only defined canon atoms plus a small flow-local .rl-map / .rl-tl block (palette tokens only). Canon-lint 0/0; flow-diff 0; every page runtime-probed (filters, pagination, chart-hover tooltip, dialogs, back-nav).

    • Production build (Atlas app): new route /retrieval-logistics (queue · dashboard · spend, plus /[uid] detail), gated by a new permission canManageRetrievalLogistics mapped to a RETRIEVAL_LOGISTICS (CLOM) app-role assigned to the CLOM — wire through components/app-sidebar/menu-items.ts, lib/route-permissions.ts and lib/auth/authority-mapping.ts. Backend: add IN_TRANSIT to the retrieval status enum (between APPROVED and ARRIVED_RETROFIT_STATION); new asset_retrievals columns logistics_owner_id (fk), retrieval_support_id (fk — the assigned company employee), in_transit_time (ts); new asset_retrieval_expenses table (asset_retrieval_id, category [TRANSPORT|FUEL|SUPPORT_ALLOWANCE|SECURITY_TRACE|MISC], amount, currency, note, file_upload_id, logged_by, logged_at). Endpoints: logistics list (APPROVED + IN_TRANSIT, scoped to the owner’s cluster), status update (IN_TRANSIT / ARRIVED_RETROFIT_STATION / ON_HOLD + assign retrieval support). Logistics can pause a retrieval as On hold (ON_HOLD) with a reason and resume it — a distinct, logistics-owned status, not the RM-owned RETRIEVAL_EXCEPTION, expense create/list + spend roll-ups, and dashboard aggregates (counts by status, avg approval_time → arrival_time, SLA breaches, by-station, by-retrieval-support). The rider’s sales agent (who brought them in) is shown read-only on the detail so retrieval support can contact them for extra rider info — derived via rider_onboardings.onboarding_agent_id → agents → users, not a new column. Live map: resolve the asset’s current position via asset → vcu (batch item) → vcu_locations (lat/long + last_telemetry_timestamp); 746 assets report location today, 480 fresh in 24h. The Retrofit team’s /stations/retrieval-list is unchanged — it receives ARRIVED_RETROFIT_STATION exactly as today.
  • Post-Onboarding — Release Vehicle at flows/onboarding-agent/index.html, per the Post-Retrofit Vehicle Release — PCA Module PRD v3.0 (internally “Release Keke”; see PRD.md §13). A standalone Post-Onboarding sidebar group (below the existing Pipeline group) with one item, Release Vehicle, opening a full-pipeline riders list (search + status filter, every rider regardless of status) that drills into a release record on row click. The record’s three tabs (Rider Details / Keke Details / Wallet) are read-only visibility for any rider, but a Retrofit Completed rider additionally gets a persistent two-column layout with a Release Checklist panel — six pass/fail items with a live “X of 6 passing” counter — that stays visible across all three tabs. PCA actions flip the gating items: Assign/Remove Battery (typed serial, not a picker), Update Swap Station (a capacity-aware picker, full stations disabled — reuses the onboarding room’s Step-6 capacity convention), and Create Wallet & Virtual Accounts (an exception-path action, hidden once a wallet exists; the Wallet tab’s populated state — Available/Ledger balance + a Virtual Accounts grid — matches the live rider-wallet reference also used by the Relationship Manager’s six-tab rider profile). The Release Vehicle button is disabled until 6 of 6 pass, then releases immediately on click with no confirmation prompt, replacing the counter with a “Released on [date, time]” record and the PCA’s name; the rider’s account status is unaffected. VCU assignment stays read-only throughout — owned by another team, no PCA action ever shown for it. Built on the flow’s own table/dialog/.pseg/badge atoms plus the canonical .rdy-item activation-readiness-checklist pattern (from flows/retrofit-manager/index.html) and the .detail-2col/wallet/virtual-accounts atoms (from flows/relationship-manager/index.html). Canon-lint 0 errors; flow-probe clean across the list, all three record tabs, the read-only (non-eligible-status) record, and the empty-wallet state.

  • Facilities — Location Acquisition Manager: Site Assessment checklist on the case report at flows/facilities-location-scout/index.html. The Attach a case report dialog gains the SOP’s Site Assessment Checklist: 29 criteria across 7 categories (Spatial requirements, Logistics & access, Typology, Internal spacing, External spacing, Initial screening, Property documentation), each ticked one of Yes/No/Good/Bad/Average via a canonical .filt-select in a scrollable box, plus Required deliverables (4) and a Site-visit checklist (3) as .tgl toggles. The completed matrix stores on report.assessment and reads back on the location’s details page (#pg-report) as a Site assessment card — a summary line (“N of 29 criteria assessed”) and the ticked items grouped by category with colour-coded badges (Yes/Good green, No/Bad red, Average amber). Copy is ASCII-safe per canon (>= 1000 sqm, 1-2 plots — no em/en dashes or m²/≥ glyphs); the SOP’s two “Initial Screening” sub-tables (split only by a page break) are one category here. A probe-caught layout bug was fixed — the base .fld select{width:100%} rule was stretching each response select to full width and collapsing the criterion label, so the select is pinned narrow at id specificity (#rf-assess .assess-sel{width:116px}). Verified: canon lint 0 errors; flow-probe 5/5 at 1440 in light and dark; the render→fill→save→read-back path exercised at runtime, no console errors.

  • Facilities — Location Acquisition Manager: address field on File location, highlighted on the Overview map at flows/facilities-location-scout/index.html. File a location gains an Address field, stored on the location and shown on its details page (#pg-report, “Not recorded” when absent). On save, a Lagos address is geocoded through a small built-in Lagos gazetteer (geocodeLagos() — no live geocoder is loaded offline/CSP, so an unknown area drops near Lagos centre) and dropped as a distinct highlighted purple pin (.sp-hi) on the Overview map: the flow switches to Overview, pans to the pin and pops open its address. The map marker draw was refactored out of the once-only buildMap() into a re-drawable renderMapMarkers(highlightId) so a newly filed location appears without a reload. A non-Lagos address is stored but not mapped (the Overview is deliberately the Lagos-cluster lens), with an honest toast rather than a misplaced pin. Verified: canon lint 0 errors; flow-probe 5/5 at 1440 in light and dark; both the Lagos-highlight and non-Lagos paths exercised at runtime, no console errors.

  • Facilities — VP/PM assign a Location scout + Cluster facility manager to a cluster at flows/facilities-vp/index.html and flows/facilities-pm/index.html. Builds on the acquisition-cluster feature: each cluster now carries a Location scout (who sources locations within it) and a Cluster facility manager (who runs its live sites), either of which may be Unassigned. The Acquisition clusters table gains Scout and Facility manager columns (name, or an Unassigned b-grey badge); clicking a cluster opens its record, whose Assign people action opens a dialog (#dlg-assign) with two role pickers drawn from a shared roster (scouts: Yusuf Idris, Ngozi Afolabi, Emeka Nwosu; managers: Bukola Sanni, Ifeoma Chukwu, Kayode Adeyemi — reusing the canonical Location Acquisition Manager and Ogun-cluster Facility Manager personas). Saving updates the cluster and the table live; a cluster opened via New cluster starts unassigned. Seeded identically in both flows (Lagos fully assigned, Ogun with an open scout slot). On the VP this joins New cluster as the acquisition-cluster planning it may do — staffing a cluster hands work down to the field and still advances/approves/resolves no estate decision, so the monitor-only guarantee holds. Also fixes a regression the prior cluster commit introduced: the VP’s acquisition-cluster row opener was named openCluster, colliding with the flow’s pre-existing openCluster(name) region-details cluster drilldown (JS kept the later definition, silently breaking the drilldown — the probe missed it because #pg-region is dormant and not in flowViews()). Renamed to openAcqCluster; the region drilldown is verified working again, and every other cluster identifier was grep-audited across both flows for collisions. Verified: canon lint 0 errors; flow-probe at 1440 in light and dark — VP 6/6, PM’s clusters table + dialogs pass with no new failures (its pre-existing pg-record/pg-settings findings unchanged); create, assign/reassign, row-click record and the restored region drilldown all exercised at runtime, no console errors.

  • Facilities — VP/PM open acquisition clusters, the Location Acquisition Manager scouts within them (cross-tier) at flows/facilities-vp/index.html, flows/facilities-pm/index.html and flows/facilities-location-scout/index.html. A cluster is now a first-class scouting zone opened at the executive tier and consumed downstream. The VP (Expansion page) and PM (Projects page) each gain a New cluster action — a canon centred .dlg (#dlg-cluster: cluster name · coverage area · target facility type, with empty + duplicate guards) — and an Acquisition clusters table (Cluster · Coverage · Scouting for · Status) whose rows open a read-only record (the VP via its existing showVpDlg; the PM via #dlg-cluster-view). On the Location Acquisition Manager side, the File location cluster picker is now generated from a shared CLUSTERS registry (seeded Lagos / Ogun, copied verbatim into all three flows the same way STAGES / PROJECTS already are) rather than a hardcoded list, with a caption stating the direction — “Clusters are opened by the VP / PM · you scout locations within them.” So one cluster reads the same at every tier and the flow runs VP/PM → scout. On the VP this is the single deliberate exception to its otherwise read-only, monitor-only posture: opening a cluster is a forward planning action that hands a scouting scope down and advances / assigns / approves / resolves nothing (its design.md “read-only is enforced structurally” section is updated to say so). Verified: canon lint 0 errors on all three; flow-probe at 1440 in light and dark clean — VP 6/6, Location Acquisition Manager 5/5, and the PM’s new clusters table + dialogs pass (the PM’s pre-existing read-only detail/settings-table every row clickable findings are unchanged and were confirmed untouched by this diff); create, duplicate-guard and row-click detail exercised at runtime, no console errors.

  • Facilities — Estate Manager (renamed from Location Scout) + a new Projects surface at flows/facilities-location-scout/index.html. Rename: the persona’s remit widened from sourcing only to sourcing and development, so Location Scout is now Estate Manager across the flow (title, user pill, settings role row, topbar scope chip now “Expansion · development”), design.md, flows/README.md, site/src/data/products.ts, and the PM’s cross-references (flows/facilities-pm/PRD.md, design.md, its Settings role row) plus the VP’s activity feed. The flow slug, folder and published URL deliberately stay facilities-location-scout so existing links keep working — the slug is the stable id, the name is the label; a naming note in design.md records this. The reporting line is now stated explicitly: the Estate Manager reports to the Facilities PM and the VP of Facilities only. New Projects surface (its own “Development” sidebar group), built to the persona PRD: a location accepted by the PM or VP (FR-8) stops being a Location and is not yet a Facility, so it becomes a Project — a construction effort with a lease, a landlord, a contractor and a stage. Tracked through the PRD’s four stages Leased → Design → Construction → Handover (FR-10) on the canonical .tl-step-* state-machine timeline (DESIGN.md “Status timeline”), with its global tokens mapped onto the flow’s local :root. Stage badges follow the canon 3+1 status rule (pending amber · in-progress blue · done green · slipped red), the stage name carrying the granularity rather than a 5th colour. Lease & landlord record (FR-9): each project carries landlord, letting agent, lease start/expiry, annual rent, the signed agreement attachment and a renewal reminder date for financial planning, added and edited in a canon centred .dlg (landlord + expiry required). Lease expiry drives an amber chip inside 180 days, red inside 90, a Lease expiring KPI + filter, and a “Not recorded” badge where no lease is on file yet. KPIs for active / in construction / lease expiring / slipped handover each filter the table. Stage is read-only: the PRD gives this persona no design or process ownership and asks only to monitor the lifecycle, so the drawer offers Flag a delay / Send update / Add lease details and never advances a stage. Built to the current “Page + table structure” hard rule (PATTERNS.md) rather than the flow’s four older surfaces: no .pg-sub page subtitle, no .pseg as a table filter, a working .filt-search + one .filt-select stage dropdown inside the table card head, and the filtered count in a .tbl-foot. The flow’s non-canonical .filt-sel class was folded into the canonical .filt-select, and the bespoke .cluster-chip topbar chip into the canonical .loc-pill region indicator (“South-West region”). Also from the PRD: explicit empty states on all four tables via the canonical .empty-wrap, so a zero-result filter never reads as broken (§2.2 edge case); SOP tags on Requirements (a badge per subdivision plus SOP tag: Location · <type> in the drawer, FR-3/FR-4); and Locations’ Status column relabelled Lifecycle stage (FR-3). The persona PRD now lives in the repo at flows/facilities-location-scout/PRD.md (v1.1), fulfilling the companion-PRD reference in the Facilities PM PRD §12 and giving design.md’s FR citations something to link to. The revision resolves three open questions — the persona rename; Case Reports only for this persona (no Issues queue, no Requests surface, since Issue/Case Report is a single entity); and only the PM/VP can advance a project stage (new FR-11, making the read-only stage a requirement rather than an inference) — and fixes the document’s own defects: the truncated access-level line, FR-3 appearing in two sections with §2.3’s FR-5/FR-6 copy-pasted from §2.2 (renumbered to FR-4/FR-5, with FR-8/9/10 held stable since they are referenced downstream), a missing FR for case-note attachments (new FR-6), an empty §2.4 Edge Cases heading, §2 jumping to §4 with a §5.1 nested inside, and a Lease entity that FR-9 required but §3.1 never defined (plus a Stage entity that listed its four values as attributes). Three questions stay open and are tracked in its §4: where Alert/Notification surfaces, regulatory compliance having no requirement, and whether this persona keeps visibility of a project after handover given the lease outlives it. design.md carries the PRD traceability table. Per-surface deep-link added (?page=projects); the catalog’s stale “Sign in” frame was dropped since the flow boots to the dashboard.

  • Revenue Assurance — RA dashboard widgets + a KPI Scorecards screen, ported into the swept flows at flows/revenue-assurance-lead/index.html and flows/relationship-manager/index.html. Fills the empty-dashboard follow-up recorded in flows/revenue-assurance-lead/design.md (“The Revenue Assurance dashboard is an empty state with no widgets configured”). Built entirely on the host flows’ existing atoms — .pstat, the canonical .cbar/.cbar-track/.cbar-fill bar, .tbl-card/.tbl-card-head, .card, .badge, .pseg — plus a small additive atom set (.gauge SVG ring [stroke-dasharray, no gradient], .trend chevron chip in place of ▲▼ glyphs, .leak stacked bar, .hm compliance heatmap, .mgrade grade chip, .card-sub as display:block). No reductions or re-skins of the swept shell: the topbar chrome, role switcher and, on the RA-Lead flow, the two-hat setScope('ra'|'pm') mechanism are untouched, and the Product-Manager scope still renders.

    • RA-Lead dashboard (renderDashboard, was the empty state): daily/weekly toggle; four .pstat KPIs (Cluster SRRR with a .trend chip, Pending approvals, At risk, Unassigned); a Cluster-SRRR gauge + SRRR-by-RM .cbar bars; an Approval inbox table wired to the flow’s own REQUESTS data (cat==='PENDING'); Top no-swap reasons with an in-card mesh segmented control (All / Ifo / Honda / Metro); an EOD summary (Omni) card (AI daily/weekly digest of the RMs’ EOD_REPORTS, with a “review before acting” note); SRRR-by-mesh; RM end-of-day reports (from EOD_REPORTS); an RM accountability leaderboard (bar-in-row per web-ranking-no-bar); and no-swap log completeness.
    • RA-Lead Scorecards (new data-scope="ra" sidebar item + renderScorecards): a composite-score leaderboard, a per-RM one-pager (score ring + seven KPI bars + revenue-at-risk leak split + worst-days), and a compliance heatmap.
    • RM dashboard + My scorecard (mirror): at-risk / not-swapped / open-cases / retrievals KPIs, the RM’s own accountability score, an SRRR gauge + SRRR-by-station bars, and not-swapped / steady-decline worklists; a My scorecard screen (one-pager + EOD streak + grading scale + personal heatmap).
    • KPI rubric (ACCT_W, sums to 1.00, outcome-weighted): SRRR attainment .35, at-risk recovery .18 (recovered ÷ at-risk blended 75/25 with contact-coverage; median contact→swap days), log completeness .15, retrieval speed .10 (median days APPROVED → ARRIVED_RETROFIT_STATION, the RM-owned segment only), EOD reports .10, log quality .07, new-rider activation .05. Composite grades: On track ≥80 / Coaching ≥65 / Formal query below.
    • Backend/data dependencies for the production build (none exposed today): per-transition retrieval timestamps (approvedAt, arrivedRetrofitStationAt) or a status-history trail; a persisted Selene “Contacted” timestamp with a recovery SLA (suggest 3 days); and the EOD corpus as Omni’s input. Suggested product change: enforce a minimum length (~120 chars) on the three EOD free-text fields so the EOD/log-quality KPIs have teeth and Omni gets real signal.
    • Note — pre-existing roster drift in the host flow: CLUSTER_RMS is Itohan / Chidi / Fatima but REQUESTS.by and the activity data use Itohan / Funmi / Lawson; the scorecards are keyed to the active (Funmi/Lawson) roster to match the approval inbox. Worth reconciling separately.
    • Canon-lint 0 errors / 0 warnings on both files under the current 72-rule ruleset (26 staged), no console errors at 1440, every screen renders.
  • Facilities — Regional Facility Manager full build at flows/facilities-regional-manager/index.html — promotes the shell to the complete nine-surface flow for the region-scoped manager (South-West), who sits between the Facilities PM and the cluster-level Facility Manager. Clusters: the region’s 3 clusters, each drilling into a cluster detail (health check, its sites, escalations pending review). Facilities: all 14 region sites, filterable by cluster + type, into a read-only per-site Record (Overview health-check + Personnel / Equipment / Contractors / Issues / SOPs tabs). Facility Issues: a region queue with an escalation-review drawer (canon .drawer) carrying an immutable case-note log and the core review-then-forward-to-the-PM workflow (Forward to PM / Handle in region / Mark resolved, with live counts). Requests: review requests from clusters + departments and forward to the PM, or decline in region. Equipment and Contractors: read-only region roll-ups. SOPs & Standards: read-only PM standards with per-cluster acknowledgment and a “remind cluster managers” nudge. Settings: profile, notifications and region preferences on the canon .settings-layout. Read-only oversight throughout, no estate-level writes. Design notes: flows/facilities-regional-manager/design.md. Boots to the dashboard per current canon; per-surface deep-links (?page=…).

  • Facilities — persona grouping + VP and Regional Facility Manager shells. Grouped every Facilities persona under a dedicated Facilities tab in the /flows catalog: added facilities to FLOW_CATEGORY_ORDER in site/src/pages/flows.astro so the personas render under a “Facilities” subgroup label instead of the trailing “Other” bucket. Added two new persona shells (canon split-screen login + shell + a landing Overview + stubbed sidebar surfaces), both under the facilities category: VP of Facilities (flows/facilities-vp/) — a strictly read-only executive view one level up from the PM, landing on a portfolio Overview (estate Facility Health, high-severity issues, resolution velocity, expansion pipeline KPIs + a Regions roll-up table + an estate-wide activity feed); and Regional Facility Manager (flows/facilities-regional-manager/) — a region-scoped manager (South-West) sitting between the PM and the cluster-level Facility Manager, landing on a region Overview (Regional Health, open issues, pending requests, out-of-service equipment KPIs + a Clusters roll-up table + a cross-cluster activity feed). Both registered in site/src/data/products.ts and listed in flows/README.md; full per-persona builds to follow. Also removed the Department Requester flow (flows/facilities-requester/) from the catalog — deregistered from products.ts, dropped from the README, and the flow folder deleted (so the sync script does not re-stub it); the Facilities group now lists six personas (VP, PM, Regional Manager, Facility Manager, Station Manager, Location Scout).

  • Facilities — Location Scout full build at flows/facilities-location-scout/index.html — promotes the companion core to the complete four-surface flow. Locations replaces the core’s static panel with an interactive Leaflet map (CARTO light basemap, L.divIcon status pins for live/earmarked/surveyed/in-review) alongside the expansion KPIs and a pipeline table; clicking a pin or row opens an area drawer (status, target facility type, and the requirement checklist with met/unmet criteria), and “File report” carries the area into the report dialog. Requirements is a read-only library of the PM’s siting standards, filterable by location type, with a per-standard drawer (version, site-selection criteria, areas assessed). Case Reports are the scout’s SOP-tied findings — All/Draft/Submitted/Reviewed filter, a detail drawer (details · case notes · photo/video attachments), and a File-report dialog with area + requirement SOP selects, case notes, and photo/video capture (capture="environment") + upload, saved as a draft or submitted to the PM (drafts submit from the drawer; KPIs + sidebar counts update live). Settings carries profile, field-notification toggles and scouting preferences (default map region, distance units, attach-GPS-to-reports, auto-save drafts) on the canon .settings-layout. Design notes: flows/facilities-location-scout/design.md. Registered in site/src/data/products.ts with per-surface deep-linked frames (?page=…).

  • Overview — KAAG gate stat-row & Recruitment agent network strip at flows/pm-onboarding/index.html and flows/apm-onboarding/index.html — two new visibility-only aggregates on Overview, both marked as owned by other teams. KAAG gate · this week (below the onboarding funnel): opt-in rate, approval rate, and home-visit SLA compliance for the contract-signing + anti-theft-device (KAAG) gate at the Onboarded stage. Recruitment agent network (below Needs your call today): active field agents, recruitment velocity (leads sourced this week, feeding Lead Created), and commission liability — a rollup of the upstream Rider Acquisition Manager team, shown for visibility only since PM/APM has no access to that module’s own screens (same rationale as PCA Queue Oversight).

  • Pipeline & Riders / Revenue — custom date-range filter at flows/pm-onboarding/index.html and flows/apm-onboarding/index.html — the canon .date-filter widget (calendar button → From/To panel, reused from flows/expansion-intelligence/index.html‘s dashboard) added to Pipeline & Riders’ page actions and beside Revenue’s Today/This week/MTD/QTD preset segment, the two mutually clearing each other on Revenue. Also drops the “PM-level tier” suffix from APM’s topbar role pill and the “PCA PRD §12” citation from the Retrofit Standby sub-copy, both internal-process detail with no reason to surface in the UI.

  • Rider Record — status override & reassignment at flows/pm-onboarding/index.html and flows/apm-onboarding/index.html — the Rider Record drill-down in Pipeline & Riders gains two audit-logged actions, per the PRD’s “override rider status in exceptional cases (audit-logged); reassign a rider between PCAs/stations”: Override status (canon .dlg — current status, a new-status select, a required reason textarea) and Reassign (canon .dlg — current station/PCA, new-station and new-PCA selects). Every action appends to a new inline Activity log on the record itself (who, what, when, newest first) rather than a separate standalone audit-log screen or feature, which stays out of scope per the PRD. Other rider-record fields (identity, tricycle, swap history) remain owned by the PCA and Relationship Manager modules — the record’s footer note is updated to say so. Reuses the existing station names (Sango Ota, Iyana Ipaja, Plastic City, Toll Gate Mega, Abeokuta Hub) and PCA names (Tunde Akinyemi, Yemi Ola, Blessing Nwosu) already established by PCA Queue Oversight.

  • PCA Queue Oversight at flows/pm-onboarding/index.html and flows/apm-onboarding/index.html — fixes the previously dead “View PCA queue →” link on Overview’s DELAYED exception row. Since PM/APM has no access to the PCA’s own screens, this is a new read-only screen under PM/APM’s own module (reachable only from that link, not its own sidebar item) mirroring the structure of the PCA module’s own Onboarding Queue — All / Awaiting / In Progress / Completed tabs, rider, recruiting PCA, status, time in queue — with riders awaiting ≥5 days flagged DELAYED. Pure oversight, no rider-record writes or PCA-owned actions from here. Demo data (9 riders, 6 delayed) matches the count Overview’s exception row already cites.

  • Retrofit Standby / Release Queue at flows/pm-onboarding/index.html and flows/apm-onboarding/index.html — fixes the previously dead “View Pool →” and “View standby queue →” links on Overview’s exception queue. A drill-down screen (reachable only from those links, not its own sidebar item) listing every rider on Retrofit Standby across all stations — rider, station, days-on-standby badge (amber ≥7 / red ≥14, matching PCA’s existing thresholds), onboarding-completed date — with a per-rider “Release to retrofit queue” action plus a bulk select-and-release bar for when several riders stack against one station that just freed up capacity. Fulfils the PM/APM half of the PCA PRD §12 two-step release gate: releasing here is what unlocks the PCA’s own “Submit to retrofit queue” action on their end. Demo data (23 riders: 14 overdue, 9 aging) matches the counts already cited on Overview’s exception rows.

  • Star Trek — real embed (was a reachability-only stub). Extracted the 6 Star Trek screens (Dashboard, Recruitment Map, Opportunity Ranking, Vehicle Gallery, Survey Agent Performance, Survey Areas) out of the standalone flows/expansion-intelligence/index.html into a single shared module — flows/star-trek/shared.css + flows/star-trek/shared.js — referenced by all three host personas rather than duplicated. Content is verbatim; only the minimum changes needed to run nested inside another page’s shell: the two genuine name collisions found (renderTrendChart vs Onboarding PM’s own Revenue chart function; CLUSTERS vs VP of Onboarding’s own Zone→Cluster filter data, which would have been a hard parse error since one used const) are renamed inside the shared module; the standalone login/topbar-breadcrumb/toast/signOut code is dropped since none of it applies once nested. flows/pm-onboarding/index.html and flows/apm-onboarding/index.html mount all 6 screens with full access; flows/vp-onboarding/index.html mounts 4 of 6 (Recruitment Map and Survey Agent Performance excluded entirely) with every edit/flagging action suppressed via a window.STARTREK_READONLY flag the host sets before the shared script loads. VP’s file predates the current canon token/typeface system, so the nested section carries its own scoped canon-token and General-Sans-font compatibility block to render identically to PM/APM rather than silently inheriting VP’s legacy values. The standalone expansion-intelligence file is untouched and remains the source of truth for the 6 screens’ content.

  • Facilities — companion persona cores — core prototypes for the four personas the Facilities PM depends on, each filed under the Facilities sub-category: Facility Manager (flows/facilities-manager/) — a cluster-scoped mirror of the PM (Ogun cluster) with a cluster Overview + Facilities directory + per-site Record, no Add-facility, read-only SOPs, and requests reviewed then forwarded to the PM; Station Manager (flows/facilities-station-manager/) — a single-station Dashboard (Ijoko) with health-check, KPIs and a recent-issues table; Location Scout (flows/facilities-location-scout/) — a Locations landing with a static map of live / earmarked / surveyed areas plus an areas pipeline keyed to requirement SOPs; and Department Requester (flows/facilities-requester/) — a My Requests surface to submit and track cross-department requests to Facilities. Each ships the canon shell + split-screen login + its landing surface; the remaining sidebar surfaces stub to a “coming next” placeholder pending the full build. Registered in site/src/data/products.ts under the facilities FlowCategory.

  • APM, Onboarding new flow at flows/apm-onboarding/index.html — its own distinct persona (not an alias of Onboarding PM), duplicated from that flow’s shell and currently provisioned at the PM-level permission tier while the PM seat is vacant and APM covers full scope in the interim. Same four sections as Onboarding PM (Overview, Pipeline & Riders, Revenue, Settings), independently adjustable from PM’s own access going forward. Registered in site/src/data/products.ts under the Onboarding sub-category. Skeleton only tonight — no new business logic.

  • Star Trek (renamed from Expansion Intelligence) re-parented from a standalone top-level Onboarding tile into a nested sidebar section inside three personas’ workspaces: flows/pm-onboarding/index.html and flows/apm-onboarding/index.html (full access) and flows/vp-onboarding/index.html (read-only, view-only styling, no edit/flagging actions). Reflects the shift to persona-first sidebar architecture — features live inside the persona workspace that needs them, not as their own top-level tile. Tonight is reachability-only: each of the three gets a nav item and a placeholder section naming the 6 real screens (Dashboard, Recruitment Map, Opportunity Ranking, Vehicle Gallery, Survey Agent Performance, Survey Areas); the actual screens still live untouched at flows/expansion-intelligence/index.html (deregistered from products.ts’s top-level flow list, but not moved or altered) pending the real embed. Onboarding PM’s own topbar role label corrected from “APM · Rider Onboarding” to “PM · Rider Onboarding” to stop colliding with the newly-distinct APM persona.

  • Facilities — Facilities PM (Super Admin) new flow at flows/facilities-pm/index.html, filed under the new Facilities sidebar sub-category. Eight surfaces for the physical-estate owner: Overview (Facility Health north-star KPI — share of sites with no open high-severity issue, no out-of-service equipment and a current condition report — plus a needs-attention table and recent-activity feed); Facilities directory → per-site Record (health-check breakdown + folded-in Personnel / Equipment / Contractors / Issues / SOPs); Facility Issues (Open → In Progress → Pending Approval → Resolved → Reopened in a right-side drawer with an immutable case-note log, contextual state actions, and photo/video evidence taken or uploaded at filing); Requests (equipment + cross-department approve / deny / redirect, with approved equipment flowing into a live provisioning pipeline); Equipment (facility-grouped inventory — condition pills, an Incoming tab, Category/Sub-type classification with a category filter, a condition-history drawer, and the out-of-service-while-open-issue guard); Contractors (per-site engagement roll-up + ORPHANED flag); SOPs & Standards (authoring surface across SOPs · Design System · Material Specs · Spatial Playbooks with versioning and document attachments — PDF/DOC/image); and Settings (profile · notification toggles · role permissions · audit log). Companion personas (Facility Manager, Station Manager, Location Scout, Department Requester) are planned. Spec: flows/facilities-pm/PRD.md · design notes flows/facilities-pm/design.md. Registered in site/src/data/products.ts with the new facilities FlowCategory and per-surface deep-linked frames (?page=…).

  • Onboarding PM at flows/pm-onboarding/index.html, filed under Atlas Onboarding beside Pipeline Conversion Analyst, Rider Acquisition Manager, and VP of Onboarding. The APM (Associate Product Manager, Rider Onboarding)’s product command surface, per the Onboarding Product Command PRD v1.1 — monitoring only, no rider-record writes, no release/submit actions (those stay owned by the PCA and PM Onboarding modules). Four sidebar surfaces, one question each: Overview (north-star KPIs against target — Lead→Active conversion, onboarding completion, cycle time, MEI pass rate — the 7-stage onboarding funnel with per-stage SLA targets and an auto-surfaced biggest-leak callout, and a “Needs your call today” exception queue reusing the PCA module’s own SLA fields, deep-link/notify only); Pipeline & Riders (the 20 APM-specified rider-level metrics across four sub-tabs — pipeline snapshot, station & geography, activity & recency, trend & operational excellence — plus a read-only Rider Record drill-down matching the Relationship Manager’s openRider() in-shell page-swap pattern rather than a modal); Revenue (the activation-fee reconciliation triplet — Recognized / Held / Reversed — reused verbatim from the Rider Acquisition Manager module, an MTD trend chart, and a fee-disposition donut); Settings intentionally defers to the existing live Atlas settings surface rather than a redesign. Registered in site/src/data/products.ts under the Onboarding sub-category.

  • Expansion Intelligence at flows/expansion-intelligence/index.html, filed under Atlas Onboarding — the Sales Lead’s field-survey and recruitment-opportunity workspace, rebuilt from an uploaded prototype onto Polaris/Caesar canon. Canonical split-screen login/landing (peach left pane, KPI proof points, Google/email sign-in) gates the app; Dashboard (coverage/observations/unique-vehicle/new-area/active-agent KPIs, a possible-duplicates rollup on the .badge b-* vocabulary, a Top Survey Areas table, and a live Sightings trend chart — Daily/Weekly/Monthly citywide totals plus a custom date-range filter, with hover-value tooltips on every bar); a Leaflet Recruitment Map (spaced-out hex-density grid + zoom-gated cluster labels, formalized against screens/kaag-hermes-map.html precedent, pins clustering, address search); Opportunity Ranking with a sort/search/date-range filter and a right-side Area Details drawer (KPIs, trend chart, mini-map, vehicle gallery, recent activity, coverage history — a new drawer pattern since PATTERNS.md only documented centered .dlg for web); a Vehicle Gallery (survey-area drill-in photo grid, detected/undetected/reviewed filters, duplicate-status + date filters, and a photo-review modal on canonical .dlg with Valid/Invalid actions); Survey Agent Performance leaderboard; and Survey Areas admin (create/edit + assign-agents modals, also rebuilt on canonical .dlg, replacing the prototype’s bespoke .gal-modal-*/.dtag components). Paired with the Expansion Capture mobile flow below. Registered in site/src/data/products.ts.

  • Issue Management Dashboard (leadership) at screens/issue-management-dashboard.html — the third piece of the reset-to-basics support model: a leadership read on the in-app issue data (not an officer tool). KPI tiles (30-day volume, resolution rate, median time-to-resolve, escalation rate, open-now); a stacked-area trend of weekly volume by category; top issue types ranked bars; a category-mix donut; a station × category heatmap; resolution vs escalation with the breakdown of where escalations route (Revenue Assurance / Hardware / Payment / Inventory); officer throughput; and a feed of manager-minted issue types flagged as candidates to formalise into the standard list. Charts are hand-built SVG following the data-viz method — categorical hues assigned in a fixed CVD-validated order (never cycled), one measure per axis, a sequential single-hue heatmap, reserved status colors shipped with icon+label, direct value labels (the light-surface contrast-relief mitigation), and both light & dark selected (validator-passed in each mode). Registered in site/src/data/products.ts under the Support sub-category.

  • Support Tickets (bare-bones) at prototypes/support-tickets-basic.html — the Atlas side of the reset-to-basics WhatsApp support model (pairs with rechaj-swap-app/.../swap-support-basic.html). No per-issue config templates, no auto-populated resolution forms — just an officer queue. Tickets queue (Open / Escalated / Resolved / All tabs, KPI row) lists every ticket a manager raised from the swap app: issue · reported-by (manager & station) · for (rider if it happened during a swap, else “No rider · station issue”) · raised · status. Ticket detail shows what the issue is, who reported it, who it’s for, the manager’s photos, and a two-way thread the officer can reply in; the resolution panel is “fix it in Atlas, then update the status” — a note + Mark resolved, or Escalate to a senior team (Revenue Assurance / Hardware / Payment / Inventory / Engineering; issues with a natural owner pre-select it and show a hint). Escalated tickets can be pulled back or confirmed-resolved; the thread logs every status change as a system line. Issue types is the one shared, company-wide catalogue — area, source (Standard vs “New · from <manager>”), open + total ticket counts, and escalation tags — so manager-minted types surface for everyone to reuse and the table never sprawls into duplicates. Registered in site/src/data/products.ts under the Support sub-category.

  • KaaG persona flows brought to RADR design parity + real VCU/DU domain model — the three KaaG personas (flows/product-manager-kaag/, flows/technical-specialist-kaag/, flows/vp-product-kaag/) were reworked to the RADR — Telemetry Admin visual + behavioral canon: dense full-width tables (48px #f4f5f7 headers, 9-column fleet rosters, no horizontal scroll at 1440), the RADR cell kit everywhere (last-seen age chips on the GREEN<10m…BLACK≥24h bands — never a bare Online/Offline — SOC bars, colored SOH, 7-day uptime sparkbars, carrier+RSSI cells, MCU·VCU·BMS·DU fault chips), 82px KPI cards with tonal icon rings, last-seen honesty bucket strips, and live behavior (2s ticking decoded signals + sparklines; the Technical Specialist gets the full dark ticking raw MQTT console with gap/backfill markers and offline session-tail honesty). Content is grounded in the real codebases (rechaj-vehicle-controller / vcu-consumer / hermes-java-api): real topics (pub/<id>, sub/<id>, retained LWT will/<id>), real payload keys (mwv, mwc, mpd, trq, tp1, soc, soh, batv, inv, blk, fvr), the real command set (IMMOBILIZE/MECHOFF with typed confirm token, REACTIVATE, KAAG_ON/OFF, AUTO with the 21:00–06:00 night schedule and 77.5V cut) with SENT/QUEUED semantics and the radr.commands.enabled kill-switch honesty. Because there is no networked display unit, DU surfaces are modeled truthfully as display-link health — indicator states from MCU vehicle-lights frame 0x18F86590, SOC-push-to-display freshness, odometer — with no invented DU commands. Data-quality honesty items surfaced throughout (fault register parsed-but-not-published per RUNBOOK §4.4, pub/ vs vcu/pub/ namespace mismatch, IMEI/ICCID not captured, 90-day raw retention with 1m/1h aggregates). Persona access boundaries preserved: PM = decoded-only + inverter controls; TS = full raw + commissioning + firmware + full commands; VP = strictly read-only.

  • Technical Specialist · KaaG at flows/technical-specialist-kaag/index.html, filed under Atlas Telemetry. Merges the Hermes and KaaG PRD v1.1 Technical Officer and Embedded Systems Engineer scopes into one P0 persona across six linked surfaces plus a unit detail: technical overview, commissioning, decoded and raw telemetry, diagnostics, signed firmware rollout, and command audit. The flow connects hardware identity, wiring, SIM, GPS, firmware, and first-heartbeat validation directly to raw MQTT investigation, data-quality triage, OTA guardrails, rollback state, and audit-recorded remote controls. Rider-profile edits, Product policy decisions, and commercial eligibility approvals remain outside the role.

  • Product Manager · KaaG Operations at flows/product-manager-kaag/index.html, filed under Atlas Telemetry beside RADR Telemetry Admin and the VP Product KaaG programme view. Implements the Hermes and KaaG PRD v1.1 P0 Product Manager persona across six linked surfaces: operations overview, fleet and inverter control, sessions and energy, read-only inspection pipeline, alert centre with the shared action audit, and rider or VCU detail. Remote disable, re-enable, and Engineering-review actions use canonical centered dialogs, preserve offline-honest delivery states, and record actor, timestamp, reason, command, and outcome. Rider-profile edits, inspection edits, and raw MQTT access are intentionally excluded.

  • VP Product · KaaG Programme at flows/vp-product-kaag/index.html, filed under Atlas Telemetry beside RADR Telemetry Admin. Implements the Hermes and KaaG PRD v1.1 P1 persona as a strictly read-only executive flow: programme overview, adoption and energy, fleet health, inspection and rollout, weekly digest, and a summarised rider or VCU telemetry drill-down. Filters, search, and CSV or PDF export are present; create, edit, assignment, approval, remote-control, and raw MQTT affordances are intentionally absent. Registered with per-surface deep links in site/src/data/products.ts.

  • Procurement & Requisitions Flow Improvement — PRD + four persona flows. The draft PRD lands at docs/procurement-inventory-prd.md (original PDF in docs/attachments/): end-to-end Needed → Requested → Ordered → Shipped → Delivered → Used lifecycle across Atlas + Polaris, eliminating manual order duplication and the stock-decrement-on-receive bug. Four role surfaces built swap-style (one entry per persona under the Inventory sub-category, each seeing only their own modules): Inventory Manager (flows/inventory-manager/) — populated dashboard, low/critical alerts with in-system Request-from-Procurement trigger, labelling/UOM stewardship + ad-hoc entry review, receiving with serialized-tag scan verification, returns to stock, usage-driven reorder points; Procurement Manager (flows/procurement-manager/) — requisition queue with auto team tags + urgency notifications + cross-team conflict resolution with recorded reasoning, orders with pre-send editing and post-send amendment history, ₦0 costs, attachments, air/sea/road shipping, flexible vendor contacts + lead-time tracking, BOM Procurement Orders traced to generated vendor orders, Atlas·Polaris sync view; Production Manager (flows/production-manager/) — end-to-end request lifecycle visibility with visible partial-fulfillment reasoning (the 10-rolls-of-tape case), cross-team demand at request time, consumption logging at point of use; Retrofit Manager (flows/retrofit-manager/) — same request transparency from Retrofit’s side plus Rider Management restored per FR-22. The existing screens/inventory-management.html Inventory & Bundles surface is kept as-is; its ATP/days-of-cover, burn-rate, alert and receiving-session semantics are reused across the new persona dashboards. All four registered with per-view deep links in site/src/data/products.ts.

  • RADR — Telemetry Admin: Firmware Versions + Audit Trail — the two System sidebar stubs are now real surfaces in flows/vcu-telemetry-kaag/index.html. Firmware Versions (#firmware): signed release list with adoption bars and per-release notes (2.4.1 current / 2.4.0 superseded / 2.3.2 retired / 2.3.0 deprecated), staged-wave rollout tracker (canary → 25% → fleet → stragglers), the OTA guardrail card (updates apply only parked + SOC ≥ 40% + RSSI ≥ −95 dBm, never during a KaaG session; delta ~380 KB chunked-resumable over GSM; A/B slots with boot-check auto-rollback; ≈0.4 MB of the 500 MB monthly SIM budget), and the pending/problem table explaining each of the 7 badge units (5 stalled in dead zones with resume-at-chunk detail, 2 failed + rolled back). Audit Trail (#audit): append-only, hash-chained action log — who did what to which unit, the operator-entered reason, and the field outcome (delivered / queued-offline / expired), filterable by Commands / Firmware / Repairs / KaaG / Access & exports with search; queued-command outcome breakdown (71% delivered on reconnect, 8% expire at 72 h so stale locks never fire), actor roster including the policy engine and read-only API tokens, and an integrity card (dual device/server timestamps, nightly chain verification). Both registered as deep-linked frames in site/src/data/products.ts.

  • RADR — Telemetry Admin full rebuild at flows/vcu-telemetry-kaag/index.html (flow moved under Atlas from products/hermes-web-app/, filed under the new Telemetry sidebar sub-category). Replaces the five Hermes-era screens (Fleet Overview / Hermes Live Map / Inverter Control / Adoption Metrics / Battery Health) with an admin-first IA for the RADR team: Fleet Overview (VCUs on field 318/342, reporting-now honesty buckets, fleet uptime, per-unit 7-day uptime sparkbars, carrier + RSSI, MCU·VCU·BMS·DU fault chips, command queue with queued-while-offline states), VCU Detail (click any unit → decoded signals ticking live with sparklines + a raw MQTT console streaming radr/v1/<serial>/# JSON frames with UTC timestamps, GSM-gap and store-and-forward backfill markers; 24 h connectivity timeline; audit-logged commands that declare “instant” vs “will queue”; offline units show honest last-known state), Uptime & Reliability (90-day trend with incident annotations, worst-unit league, gap-cause breakdown — GSM dead zones 46% / keke power loss 27% / SIM data 14%, uptime by carrier incl. the dual-SIM pilot note, known dead-zone corridor table), KaaG — Deployments & Energy (kits deployed 124/140, kWh + ₦ at ₦90/kWh per unit and fleet-wide, 14-day energy trend, nightly usage curve with SoC-floor saves, holder custody table, idle-kit reassignment queue), and Repairs & Exchanges (ticket-follows-the-fault / custody-follows-the-box kanban: Reported → Diagnosed → Exchange issued → In workshop → Ready to redeploy; spare pool with forward caches; exchange log tracking rider dark-time; MTTR 2.4 d). Architecture: one shared <template data-shared> stylesheet + JS data module injected by the router in front of every screen — the per-screen CSS duplication of the old file is gone (426 KB → 128 KB). Hermes Live Map removed (the live map lives in Radar — Fleet Intelligence). Registered in site/src/data/products.ts with per-surface deep-links.

  • Lead Queue Console at prototypes/lead-queue-console.html — Sales & Retention pipeline console. PCA Lead Queue of WAITLISTED riders pending station check-in with SLA tiering (amber 48h+ / red 72h+), clickable tier stat chips, cluster/agent/date-range filters, masked phone with copy, lead detail slide-over, and a begin-check-in action that moves the lead straight into the MEI Inspection Queue (shared pipeline, no assignment step). Also covers Band D Escalation, MEI Summary dashboard, Onboarding Queue, KAAG Coordination with detail drawer, and the RM Post-Retrofit Onboarding flow. Registered in site/src/data/products.ts. The production Next.js implementation of the Lead Queue screen has begun in moc-x/atlas (branch feat/sales-retention-lead-queue).

  • Inventory Management reworked at screens/inventory-management.html to mirror the rechaj-backoffice-v2 inventory module + new in-scope features. New IA groups Catalog (Items, Item types, Categories, Bundles), Stock (Batches, Stock health) and Movements (Transfers, Requests, Receiving) under a collapsible sidebar. Repurposed Bundles as proper CRUD — named/described saved sets of items reusable from transfers and requests, with grid + inline editor. Fleshed out the previously-placeholder views: Items (full SKU table with category/type/stock-state filters), Item types (tracking semantics + per-type ATP formula, two-pane list+detail), Categories (stock-state mix bars), Batches (lot list + drill-down batch-items panel), Stock health (ATP cover, stock-outs, days-of-cover with burn rate), Transfers (outbound, sender-initiated, bundle-linked), Requests (inbound, receiver-initiated, ATP-gated fulfilment), Quarantine (per-SN with dispute linkage), Alerts (full inbox + tabs), and Audit log (movement timeline + event-type breakdown + top actors). Reuses all existing components — KPI cards, state-strip, chips, scan-progress, breakdown bars, alert rows — with only additive styles (form-grid, picker chips, tpl-card, timeline, mini-tiles, dir badges).

  • New Swap Module Dashboard at screens/swap-module-dashboard.html — the Swap business unit’s KPI view inside the Atlas backoffice. Covers session counts, revenue health, goal tracking, top stations, issues by type, the battery-conflict queue, anomaly alerts, station-to-station drift, and a paginated recent-sessions list with per-session detail drilldown. Registered as both an Atlas flow and screen in site/src/data/products.ts.

  • Swap PM Dashboard (v2 candidate) at screens/swap-pm-dashboard-v2.html — candidate redesign up for review against v1 before replacing. Swap-time-led: median as the lead KPI on a dark hero card, distribution histogram + per-phase breakdown (wait, scan, VCU connect, unlock, physical, payment). Anomaly band auto-flags week-over-week scenario movements. Friction map ranks every v3 support scenario by Ops-time-per-case so the PM sees the prioritization queue, not raw counts. Money-flow integrity card splits captured / stuck / leaked + funding-source mix (Opay / Paystack / Sterling) + recovery rates. Infrastructure card shows the VCU resolution ladder (BT direct → BT retry → internet → manual unlock) and battery operational signals. Specialist scoreboard sits alongside the manager scoreboard. Registered in site/src/data/products.ts.

  • TH-288’s budget and TH-289’s Hardware block are in the PRD, where both had shipped pointing at a flow because neither was written down. The budget was half covered already — FR-BM1 holds the bill of materials and FR-IP9 already has its foot following the filter — so section 38 adds what was missing: the plan as need times riders, a budget as the plan less stock available to promise and quantity already with a vendor, the order-by date struck from the date needed less the vendor’s lead time, grouping by item rather than by bill-of-materials line (an item on two units’ bills is one purchase, and netting its stock per line counts it twice), and the rules the tiles follow — freight is quoted on a load of whole rider kits so it is never apportioned to a filtered subset, a Budget tile exists only where one currency covers both halves, and the parts figure names the basket it could not price. Section 39 writes down the Hardware block: the VCU and battery the station sets, the SIM it only reads because attaching one is telematics bench prep, the shipped ConnectivitySim states rather than a second vocabulary, unmapped kept distinct from mapped-and-quiet, the as-of time on every row, and the SIM hanging off the VCU rather than the rider.
  • FR-IP4 forbade what two surfaces ship. It said nothing anywhere is summed across currencies, on the grounds that the system holds no rate — but the budget holds one and prints it with its as-at date under every figure that used it, and the PM Vehicle Operations PRD had already settled the same question the other way. It now forbids what it was actually protecting against: a converted figure nobody can reproduce, not conversion itself.
  • The Procurement & Inventory PRD is now Supply Chain & Parts, Vehicle Operations and Production, with its attachment renamed to match. The old name described two of the six personas in it; the document spans three units — Supply Chain & Parts buys and holds, Production and Vehicle Operations draw on that stock at their own facilities. The overview said “four persona flows” where section 3 has always listed six, and now names them by unit. Two dead links to a draft PDF that was never in the repository are cut.
  • Two requirements corrected against new tickets in the same PRD. FR-R16 — a delivery-note leg no longer needs a plate to dispatch; logistics and vehicle type stay required and the plate is optional. FR-U4 — a threshold alert reaches Inventory and Procurement both, where it named no recipient at all, and FR-R12 says so where the notifications centre lists the alert. Also FR-W2: one order may travel on several shipment methods, and the method belongs to the shipment rather than the order, so an order split across two shipments carries a method each.
  • Tricycle Hardware is Vehicle Operations across every PRD — 51 mentions in eight documents, including the page footers of the three Word attachments. The unit dissolved in October and its people merged under Vehicle Operations, and the flow catalog had already been renamed, so the documents were the last surface still sending a reader to a team that does not exist. Flow slugs keep the old word, because a slug is an address and not a name. Every rendered attachment is regenerated; the .docx are edited in place rather than re-rendered, since pandoc is not in this toolchain and a nine-word edit should not change how a document looks.
  • The conversion station dashboard takes a period (flows/retrofit-manager). Twelve tiles in three rows of four, ordered by importance, above a Today / This week / This month / Custom control. Every period measure and the seven-day spark read one daily series, so a custom range needs no second set of figures and the chart and the tile cannot report two different numbers for the same week. The five point-in-time counts take no period and their subtext says what they count rather than naming a window they do not honour. KPI rows fold to two columns and then one on a narrow window, which no row in this flow did before.
  • A Converted N days ago badge on the maintenance side, red, on the tricycle case and the tricycle work order in head-of-maintenance. The same fault reads differently on a keke converted five weeks ago. It stops at three months: past that the conversion is no longer the first thing to suspect and a badge on every case would say nothing. A battery work order carries a pack rather than a plate and takes none.
  • The runtime probe looks inside a render host (site/scripts/flow-probe.js). Its stacked sections have space between them check walked only a view’s own children, so a notice rendered into a wrapper div shipped welded to the table card below it with the check green. A bare <div> carrying only an id and holding several siblings is now flattened into the stack it really is. Re-run over 280 view-themes across 15 flows with no new failures.
  • Rider Acquisition Manager — full redesign, 6 screens down to 3 at flows/rider-acquisition-manager/index.html. The prior build restated rollups and computed scores (SRRR quality %, Good/Watch/At-risk labels, week-over-week deltas) but never let the manager see an individual rider. Dropped: Conversion funnel (standalone; duplicated stage counts now reachable via Riders), Activation revenue (fee reconciliation isn’t this role’s job), Agent performance (the SRRR-scored leaderboard and its ≥5-swaps/week covenant-withhold drill — the score is cut, not relabeled; the raw counts underneath it survive), and SLA & breaches (dropped entirely — no one is tracking SLA breaches yet, so the concept came out repo-wide on this flow, including the matching “Needs attention” breach preview that had lived on Overview and the breach-count column on Overview’s Top agents snapshot). Kept, trimmed: Overview, rebuilt around raw counts only — a Today/This week/MTD/custom date-range picker driving 4 KPIs (leads created, onboarded, active tricycles, in pipeline) and a Top agents table that now shows every agent (not just top performers), sorted by highest onboarded for the active range and cluster scope, paginated. Clusters & Agents (renamed from Regions & agents): the ranking table toggles By cluster / By swap station (a cluster’s 6 South West agents map to 3 distinct stations, so the station view isn’t just a relabel) — name, agents-assigned-or-active-riders, riders onboarded, and a week-over-week ▲/▼ trend percentage — plus a custom date-range filter beside the This week/MTD segment, both reacting live to the range toggle; the field-agent table strips SRRR quality %, the standing label, and breach count down to Agent/Cluster/Pipeline/Active riders/Commission earned, and is now searchable and paginated so a manager doesn’t have to scroll to find one agent; clicking any cluster, station, or agent row navigates straight into Riders, pre-filtered. A single canonical AGENT_DATA dataset (per-agent values keyed by range) now backs both the Overview Top-agents table and the Clusters & Agents field-agent table, so range/cluster changes stay consistent across screens. Added: Riders — the actual point of the redesign, a full, paginated, sortable roster of every rider from every agent (30-row demo dataset spanning all 6 agents, 4 clusters, and all 8 pipeline statuses, 10 rows/page via the canonical .pager). 7 stat cards (In pipeline, Inspection pending, Awaiting retrofit, Active tricycles, Never swapped, Delayed, Inactive) recompute live against whichever Cluster/Agent/Status/Swap-station filters are active — and clicking a card clears the filters, so the two never fight each other — replacing the earlier “cards always show the full unfiltered count” behavior that read as broken once dropdown filtering existed. Filters are the canon .ms multi-select component (verbatim from Polaris’s Assignees picker): each of the 4 filters is independently searchable and accepts multiple values, and the whole toolbar sits above the stat cards so it reads as screen-wide rather than table-scoped. Every column is sortable (default: Days in status, descending), a two-line Swaps (7d) / total cell (the flat “7 / 220” reading was ambiguous about which number was which), an Inactive flag for riders whose account has is_enabled = false regardless of pipeline status (previously invisible — a retrofit-completed or even an activated rider could be disabled with no way to see it), plus CSV export and a row click into a new read-only Rider Record drill-down mirroring the PCA module’s viewRecord() pattern (onboarding-agent/PRD.md §3’s “View Record” action) rather than inventing a second rider-detail component. Status vocabulary wired to RETROFIT_PENDING (not RETROFIT_QUEUED, per product direction — the latter isn’t live yet). Also fixed a real bug found in review: the .badge status pill has a fixed height, so a narrow Status column made two-word statuses like “Awaiting retrofit” wrap and spill outside the pill’s colored background — widened the column so status badges never wrap.
  • KaaG persona sidebar identity now matches the Atlas onboarding treatment across Product Manager, VP Product, and Technical Specialist: the canonical Rechaj mark and wordmark are paired with a Team KAAG sublabel, replacing the standalone RADR label. The collapsed rail retains only the Rechaj mark.
  • Sidebar logo on the Swap Module Dashboard now uses the canonical two-tone Rechaj brand mark from the new components/rechaj-logo.svg asset (documented as patterns/brand-logo.md), replacing the placeholder dark-square-with-hexagon mark that violated the DESIGN.md hard rule against redrawing the bolt.
  • Swap Module Dashboard — date-range filter is now a plain caption beside the period selector (no longer styled as a competing button). Performance vs Goals targets are read-only (backend-owned, edit affordances removed). Station-to-station drift restructured as one home station fanning out to many destinations, with each destination weighted by share of drifted riders. Top Swap Managers ranks by Opay wallet activation (the manager’s pull) or avg swap speed (toggle); swap volume is no longer the headline metric.
  • Swap-time numbers across both v1 and v2 dashboards recalibrated to operational reality: normal swap ~2 min, issues drag to 5–10 min max (not 20+). Median 2m 14s, P90 4m 38s, P95 6m 22s, hit-goal rate 48%. Manager swap-speed range tightened to 1m 48s – 2m 50s. Friction-map “Ops time” column reframed as specialist-minutes per case (2–6 min) rather than total swap drag.
  • RADR — Telemetry Admin (flows/vcu-telemetry-kaag/) — superseded by the three role-scoped KaaG personas (Product Manager, Technical Specialist, VP Product), which now carry all of its surfaces at RADR design parity: the live raw MQTT console and firmware/coverage tooling live in Technical Specialist, operational fleet control in Product Manager, and the executive reporting in VP Product. Deregistered from site/src/data/products.ts; its design language survives as flows/kaag-radr-foundation.css and the persona implementations.
  • Battery duplicate-ID queue card on the Swap Module Dashboard — surface lives on the dedicated Battery Conflicts sub-page instead.