design
Retrofit Station Manager — design notes
Section titled “Retrofit Station Manager — design notes”Persona surface for the Supply Chain & Parts, Vehicle Operations and Production — Product Specification. Web flow, canonical Atlas shell (1440). Appears as “Retrofit Station Manager” (e.g. Kelechi Nwosu, Sango facility) in facility team rosters. “Sango facility” is this retrofit site; the central inventory warehouse it draws from is a separate entity, “Sango warehouse”.
Persona
Section titled “Persona”The Retrofit Station Manager requests the materials retrofit work needs and runs the retrofit stations. Structurally the same request pains as Production — shared demand for the same consumables with no visible resolution — seen from the other side of the tape split. Also needs Rider Management to plan bays and reach riders whose kekes are scheduled into the station.
Problems being solved
Section titled “Problems being solved”- Same as Production: no end-to-end request visibility, no shown reasoning on partial fulfilment, cross-team demand invisible at request time.
- Rider Management was not reachable from this role’s navigation; it is now a normal working module scoped to the station’s retrofit pipeline.
- No consumption logging at point of use, so reorder points were guesswork. Now represented: step draws and usage logged on the floor take stock out of the shared pool (each a movement on the Ledger) and feed a reorder-point signal on My Inventory.
Navigation
Section titled “Navigation”Sidebar (per PRD §3.4): the same items, grouped under .sb-group section headers — Overview (Dashboard), Inventory (My Inventory), Retrofit floor (Work Orders, Assembly Procedures), Facility (My Facility, Category approvals), Rider management (Rider). No nav items added or rewired; only regrouped. Dashboard is the landing view. Rider is a plain nav item — no badge, no annotation. Breadcrumbs on every view; rich records (a work order, an assembly procedure) open as a full inner detail page (view-wo-detail · view-proc-detail, reached on row click, with a canonical .pg-back text button that re-activates the parent sidebar item and record identity in the breadcrumb), while compact create/edit/confirm records stay in a centred .dlg — never a side drawer. Filters in each .tbl-card-head; dates on every row. Every .tbl carries a canonical .tbl-foot pager (.lbl “Showing X of Y” + a .pager ‹ Prev · 1 · 2 · Next ›, every button wired). The Work Orders page-head no longer carries a redundant ellipsis/More button. Mirrors the Production Manager flow so the two personas stay consistent.
| Slug | What it does |
|---|---|
dashboard |
Rescoped to retrofit-floor health: twelve floor signals as .pstat KPIs across three rows of four, in importance order — row 1 did the work get out and did it hold up (Conversions completed · Behind schedule · 3-month breakdown rate · First-pass yield), row 2 the work in hand (Active conversion WOs · Conversions queued · Rework rate · Open defects), row 3 what explains the two above (On-time completion · Units closed · Material fill rate · Kits to decide). A .dash-period strip above them switches Today / This week / This month / Custom, and every period measure plus the seven-day spark reads one daily series, so no two numbers for the same week can disagree; the five point-in-time counts take no period and their subtext says what they count instead of naming one. First-pass yield replaces the old QA-pass-rate card (a stricter quality signal: units passing QA with zero rework loops); the old Ready for pickup card is dropped since My Inventory already carries an Awaiting pickup KPI (#kpi-pickup) and the header has an Accept receipt action. Each carries a .trend delta on the value’s own line; a worsening-when-up metric (Behind schedule, Open defects) that rises reads red (.trend-down) with an up chevron matching the delta sign, and green .trend-up is reserved for genuinely-good movement (including a good-when-down metric like Rework rate falling, shown green with a down chevron). Below the KPIs a .chart-row pairs a Units closed · last 7 days .spark column chart with an Active retrofit WOs by stage .cbar breakdown (In progress + Open sum to the active total). Quick-links route into Work orders / My Inventory. |
inventory |
Mirrors the Forge app’s shared pool. A .pseg strip swaps Stock / Ledger / Requests / Outgoing / Incoming / Item requests. The page head carries two actions, Return to warehouse and Request items. A My-Inventory summary row of four .pstat KPIs sits above the tabs: Items in pool (#kpi-skus, distinct lines), Low stock (#kpi-low, lines at or below their low threshold, from refreshHealth; opens Stock filtered to Low), Short for active WOs (#kpi-short, BOM lines the pool cannot cover) and Incoming (#kpi-pickup, fulfilled requests to receive; opens Incoming). Stock (#inv-stock-tbl) — the pool’s lines: Item (28px .it-thumb beside the name, category beneath) · Tracking (Serialised / Consumable, a serialised line’s first serial + +N beneath) · On hand · Usable · Incoming (each with its unit) · Health (Healthy / Low / Critical against the line’s threshold: Low at or below it, Critical under 60% of it, refreshHealth) · Last movement (the line’s newest Ledger movement, with its date and who) · Request. Search, one filter (All items / Low stock / Serialised / Consumables) and Export CSV. Row-click opens the item detail, whose primary action is Request item (requestItem). Units are the canonical lowercase-singular set pcs · each · roll · metre · litre. Ledger (#inv-ledger, #lg-tbl) — the pool’s append-only movement history, newest first; a row opens the item it moved (openLedgerItem): When · Movement · Item (serials beneath, first + +N) · Qty (signed) · On hand after · By · Reference (request, work order and unit, step, return reference, reason; usage logged with no job reads No work order). Movements are Received, Used on unit (drawn for a step), Used (logged on the floor, Forge FR-FS11 to FR-FS13), Returned to warehouse, Count adjusted and Reversed. Filters: search, Movement, Item, By, Work order (with No work order) and a When date range; Export CSV carries the filters. On hand after is walked back from each line’s current on-hand (prepLedger), so the Ledger and Stock always agree. The item detail shows lot / expiry for consumables (LOT, #it-lot-row) with an In date / Expiring soon / Expired badge (lotStatus vs the flow’s reference date); shelf-life items (adhesives, oils) carry an expiry, hardware consumables are lot-only. Floor signal: every SKU still carries a reorder point tracked internally for the item detail, but it no longer surfaces as a dashboard KPI (reorder is a warehouse concern, not the facility’s); the Inventory KPI is Short for active WOs (#kpi-short) — the count of BOM lines below need across the manager’s assigned work orders (shortForActiveWOs), derived from the per-unit BOM scaled by WO size. Consumables are seeded at/below reorder (Loctite 243 Critical, Differential oil and Insulation tape Low) so shortfalls are visible. A Unit column carries the weight/length dimension; continuous consumables (Loctite 243 in litre, Differential oil in litre, Power cable 6mm in metre) deplete in their measured unit so a partial pour never falsely reads 0, and the item detail flags them as continuous. Requests — one status-tracking list of every request this facility has raised, the manager’s own and the team’s alike: .pstat KPIs (With the inventory manager, Open, Accepted, Rejected) with Pending — a subset of Open — as a .chip beneath the row, status/date/search filters, a table (request + WO link · requested by · items · status badge · requested · updated · view) and a row-click detail carrying requested-by, reason / purpose, date required, approved-by, the requested lines (requested qty in unit · available · fulfilled), the linked WO or General request, a status timeline, and the split or rejection reasoning. The approval gate is not here. A team member’s request goes to the pool’s Retrofit Station Inventory Manager (Bukola Ajayi), who approves it onward to the warehouse or rejects it with a reason; this console reads the outcome and never decides it. Such a request sits at With inventory (badge b-amber) until the gate moves it, and the detail’s timeline names the inventory manager as the pending approver. A request the manager raises directly is unchanged and starts at Requested. The Request items dialog is WO-BOM-driven (the single-item add-line picker is gone): a From your work orders section renders one card per assigned WO (renderReqWOCards) with a Have/Need BOM table — have = on-hand, need = per-unit BOM × the WO’s unit count — where a fully-covered WO reads “You already have all the BOM items” and a short WO offers “Add N missing item(s) to request” that raises one single-item request per shortfall line (requestWOShortfall, each linked to the WO) so they land as separate rows on the request table, fulfillable per item; a per-WO dedup disables re-requesting while an open request is linked (reopening only on Rejected / Partially fulfilled / Declined). An Other items → Browse all items path (openCatalog) is the only free-form route — a searchable catalog with a qty per item, required Reason / purpose and required Date required (submit blocked with inline errors until both are filled). Outgoing — returns sent back to the warehouse (sent to · destination · items · status · date created · view), its status/destination/created-date filters in one Filters .dlg with an active-count badge, search inline. Return to warehouse (#dlg-push) returns only what the pool actually holds: the item picker lists on-hand lines and addPushLine caps the quantity at on-hand. Each return captures a Condition (Unused · Refurbished · Used · Faulty), a Faulty return captures the serial of each faulty serialised unit (renderFaultySerials), and a Note is required (#ps-note-err). Returns land in Inventory’s returns lane, where deciding quarantine is the Inventory Manager’s job. Incoming — deliveries from the Central warehouse, each Ready for pickup until accepted; the whole row is clickable to an items-received detail. Accept draws the delivered items into My Inventory on-hand (adjustStock → refreshReorder), flips the row to Delivered, turns the row action into a clickable View (opens the items-received detail — never a dead “Delivered” label), and toasts “Items received into my inventory”. Accept captures a received quantity per item vs what was requested (#ac-qty table: Item · Requested · Received input, defaulting to the delivered qty) — the received amount is what populates on-hand. Serialized items require a serial per received unit (renderAcceptSerials regenerates one input per received unit as the qty changes; accept is blocked until all are keyed). The receipt then reconciles against the linked original request (fulfilRequestOnReceipt reads the Fulfils REQ-#### ref off the row): a full receipt closes it Accepted, a short receipt marks it Partially fulfilled (each line’s fulfilled = what was received, shortfall reason recorded) — status, lines, timeline, and the Requests table row all update. The receipt also captures lot + expiry for each consumable (renderAcceptLots → LOT, persisted onto the item). Accepted deliveries leave the incoming queue (the queue only holds what’s still awaiting pickup) — the record now lives on the linked request and in stock. A Partially fulfilled request detail shows the outstanding balance per line and a Request the balance action (requestBalance) that raises a follow-up request (backorder) for the shortfall. A fifth .pseg sub-panel, Item requests (#inv-itemreqs, #itemreq-tbl), holds requests for items the catalog does not carry: Request · Item · Category · Unit · Qty · Location · Requested · Status, with search plus status and location .filt-selects (filterItemReq). Raising or reading one is a page, not a dialog — #view-newitem (openNewItemReq), an inner page whose .pg-back returns to this tab, laid out as .nit-grid: the form on the left, the approval line on the right. That line is the flow’s own .tl-item timeline — Requested (the manager and the date) → Line manager approval (Head of Retrofit) → Procurement (the request reference once raised) → Inventory issues it — each step done, pending, or warn where the request was rejected. The item name is composed, never free-typed: the nir- prefixed name composer ported from the Inventory Manager gives an Item type combobox over the controlled ITEM_TYPES list (searchable by alias), plus Describe it, Key specs and an optional Version + How it differs, forming the name live as [Describe] [Type] [Version] (Key specs, How it differs). Its duplicate guardrail checks the composed name against this facility’s own stock (_catalogNames reads #inv-stock-tbl): an exact match turns the preview red and blocks Send for approval, offering Open existing (which jumps to the stock tab filtered to that item); a similar name warns amber but allows it. The rest of the form is Quantity needed · Category · Unit · Why it is needed · Industry standard or spec · Location · Need by · Urgency · Photo, with .f-err inline validation, and the requester and date are captured automatically. Sending appends the request as Pending approval and returns to the tab. Opening an existing record renders the same page read-only with no submit action. |
facility |
A .pseg strip swaps Overview / Team. Overview — Sango facility summary card beside a team-composition card. Team — the Sango facility roster (Kelechi Nwosu as Retrofit Station Manager + the retrofit crew; Olugbenga Jibowo as facility Inventory Manager) (name + email + role + status), role/status filters, search, Add team member dialog. |
workorders |
Retrofit-floor work orders. Five .pstat KPIs (active WOs, units closed today, behind schedule, open defects, QA pass) reconciled to the dashboard’s retrofit-floor numbers so the two surfaces agree — 18 active of 30 · 14 units closed today · 3 behind schedule (= the past-pace rows) · 2 open defects · 96% QA pass; the old “+13248h” slip is gone. Each row is led by a unique WO-90xx reference (.td-title.sn, item as the sub-line), then status · progress · declined · team — the number of people assigned (“N assigned”, “0 assigned” when none, never a bare “No team”) · due date + pace · started. On the WO detail the Team meta counts the distinct people across the WO’s steps. Status, team and start-date filters (3) collapse into a single Filters .dlg (Reset / Apply, active-count badge); search stays inline. Only the retrofit persona’s own create action is kept — a single primary “New retrofit WO” (the generic “New work order” button is intentionally not present here); a WO can be created on either Atlas or Forge and populates both systems (Forge owns the downstream execution actions); plus Plan day / Export. A row opens the WO detail inner page (view-wo-detail, below). |
view-wo-detail |
Inner record page for one work order (row click). Canonical detail-page head — a .pg-back text button back to Work orders → .pg-head › .pg-title-row (WO title + status .badge inline) over a .pg-sub metaline (facility · pace), with .pg-actions holding only the Park/Live toggle, Archive and the actions menu (assignees · export). A .pstat KPI row (Closed units · In progress · Defects · QA pass, each woKpiTo-jumping to the matching Units filter) sits before the .pseg, which swaps Overview / Units. Overview — a single brand-green linear progress track (.wo-prog-track #01E46F fill over a --grey2 remainder, “X / N closed · P%”) with per-state .badge legend chips (Closed / Awaiting QA / In progress / Rework / Queued — replaces the old segmented .seg-prog bar), a .kv-grid meta strip (Family · Type · Started · Elapsed (a live run-timer from when the first unit started — #wo-elapsed/woElapsedMin) · Due · Team · SOP steps · QA pass · Avg cycle) — Park WO ↔ Set live pauses/resumes the WO, banking the elapsed minutes and freezing the clock (“· paused”) via togglePark — a shared Atlas + Forge action, so parking the same WO from either surface pauses the line on both, the procedure shape as full-width .shape-cards that mirror the assembly procedure tied to this WO — step names, checklist, BOM, minimum-people and SOP image all come from the matched procedure’s meta (woShapeFor pulls meta[i].checklist/meta[i].bom etc.), and per-step assignees seed from the procedure too (ensureWOAssignees reads the procedure’s meta[i].assignees, falling back to WO crew), so editing the procedure — or assigning assemblers on it — changes what the WO run shows (and editing procedure assignees applies to already-open WOs: saveAssignees in proc mode clears their cached stepAssignees so they re-seed from the procedure) (each card: a BUILD/QA badge b-blue/b-purple, a roster multi-select of assignees rendered as “N / min assigned · names” with an amber shortfall signal (.shape-short, “needs X more”) when the step is under its minimum, BOM lines, the acceptance checks as a stacked wrapping .shape-checks list (not inline pills), an SOP reference-image slot); a Manage assignees link sits at the top of the step list (openAssignees · per-step checkbox list over the retrofit roster · saveAssignees). The minimum-people count is a hard gate on the run, not just advisory: while any step is understaffed (woStaffingGap), the Overview shows an amber “N steps understaffed” banner and completing the batch is blocked (Close-all-remaining toasts “assign the minimum people first”). Per-step QA photo capture is intentionally not here — capturing a photo against the actual step being worked lives on the Forge app (floor execution), not this back-office view. An activity feed (.tl-item) closes the panel. Units — a per-unit table (WO-ref · Unit N · serial · BMS ID (battery builds only — any “rept”/“battery” item, isBatteryOutput; column toggled by .show-bms, input on the last + QA step on Forge) · state · current step · Step assignee · QA · time) with a state .pseg filter (data-canon="allow-pseg-filter"), a step-assignee filter and a serial search; a row opens the Assembly record .dlg. Assignees live on the steps, so a unit has different assemblers across its steps: the Step assignee column shows whoever is on the unit’s current step (unitStepAssignees), displayed compactly as one name with a “+N” chip (fmtAsn) rather than a comma list, the assignee filter matches on that, and the dropdown lists the union of everyone assigned across the WO’s steps (“All assignees”). The Assembly-record dialog carries a Step assignees breakdown (#rc-steps) listing every step with its assignee(s) and a badge marking which step the unit is On this step / Done / Queued. Step completion, QA, close and the serial come from the Forge floor app, so the unit record is read-only (no manual QA/close, no serial confirmation): every output is serialized and the serial is auto-generated when the unit passes QA (MOC-X-SAN-…, shown on #rc-serial once passed, “Issued when the unit passes QA” before). Battery builds (any “rept”/“battery” item, isBatteryOutput) also carry a BMS ID (input on the last + QA step on Forge) — a BMS ID column on the Units table and a BMS detail on the record. The record carries the serial, BMS, a Step assignees breakdown and QA gates (no “Components scanned” list). Closing is automatic on QA pass; a manager Close all remaining units override mints the balance into Inventory (confirmCloseWO) and — because it is a force-close that bypasses Forge’s QA-pass serial issuance — asks the manager whether to generate serials (#cw-gen-serial, off by default: checked mints each serial, unchecked closes without serials so they can issue later if the units clear QA). A Close all remaining units action mints the balance (the WO’s components were committed when it was created: confirmNewWO → consumeWOCreation draws the per-unit BOM × qty from on-hand at creation, the reserve/allocate-at-release model, so stock reflects the commitment up front rather than at close). The per-unit BOM is the single source of truth: perUnitBom(kit) aggregates the tied procedure’s per-step BOM (sum of every step’s lines), falling back to the static BOM_PER_UNIT only for a kit with no authored procedure BOM — both the request have/need and the WO commitment derive from what’s authored on the steps. (Editing a procedure’s steps preserves each surviving step’s authored BOM/checklist/assignees/min/SOP by name+kind.) Archive (required reason) is gated on not-started only (woStarted); Park/Live toggle and an actions menu (assignees, export) round out the header. |
procedures |
Versioned assembly playbook per item. Table (item + item type as muted plain text, not a badge · version · status · assembly type · steps · active WOs · last edited). Status / type / last-edited filters. A row opens the procedure detail inner page (view-proc-detail, below). A shared create/edit .dlg (searchable item picker · version · Bench / Line selectable .pick-tile cards · build-steps and QA-steps textareas, one step per line (shown as a persistent .f-hint, not just placeholder text) — each line parses into a real BUILD or QA step, so the row’s N build · M QA count and the detail step cards match what was typed. A step’s minimum people is set afterward with the Min. people dropdown on its step card (see view-proc-detail), not via typed syntax): New procedure drafts a new Draft row, Edit procedure opens it prefilled and Save updates both the record and the table row. A Deprecate action (procedure detail actions menu, deprecateProc) marks a version Deprecated (b-grey) in both the record and the list row and surfaces it under the Deprecated status filter; the primary button flips to Reactivate this version (same readiness gate), and new work orders only offer Active procedures (openNewWO excludes Deprecated and Draft). |
view-proc-detail |
Inner record page for one procedure (row click). Canonical detail-page head — a .pg-back text button back to Assembly procedures → .pg-head › .pg-title-row (item + version with the status + assembly-type .badges inline) over a .pg-sub metaline (family · version · editor); .pg-actions holds the actions menu + Activate this version. Steps render as a vertical list of full-width .step-cards (.step-row is a column, not a 216px horizontal scroller — real SOP step text is too long for narrow cards): a BUILD/QA badge b-blue/b-purple, “N / min assigned · N BOM · N checklist” counts, the step’s Bill of materials as .shape-bom pills and its Checklist (the step’s acceptance items, meta[i].checklist — an authored array, not a generic pool) as a stacked, wrapping .shape-checks list, an SOP reference-image slot (add or replace — sopSlot renders a working file input in every state, .sc-sop-replace), and an insert-step affordance. Each step is fully authored on its card: a .sc-edit footer gives Assignees (openAssignees('proc')), Edit BOM (#dlg-step-bom, an item+qty catalog picker writing meta[i].bom) and Edit checklist (#dlg-step-checklist, one item per line writing meta[i].checklist). Each card carries its assignee names (.sc-who) plus a Min. people select (.sc-min-sel, a 1–6 dropdown · floor of 1 · setStepMinTo — a dropdown rather than typed syntax so authoring is unambiguous) that sets how many people the step needs, with a “needs X more” / “met” signal, and a Manage assignees action (openAssignees('proc')) opening the same per-step roster multi-select. An Activation readiness checklist gates the Activate / Reactivate this version primary (Draft or Deprecated → Active): every step must meet its minimum-people count (n ≥ min, “ |
rider · Kit reassignment |
The record of where a kit or bundle taken off a keke goes next, replacing the spreadsheet the station was keeping. The third tab on Rider management, beside Riders and Kit retrieval, because a keke arriving and the kit coming off it are one chain rather than two pages. Four clickable .pstat KPIs (Retrieved · Reassigned · Not yet decided · Sent to inventory) filter the table. #retr-tbl columns: Serial · Item · Came off, which carries the plate, the rider and the date it was taken, because they are one event · Condition · Outcome, which carries the badge and where it went. Six headers used to sit over eight cells, so every header after Came off described the column to its left., with search plus outcome and condition .filt-selects (filterRetr). The item is a catalog item — Retrofit Kit (v1), Telemetry Bundle, Main Retrofit Harness (Bundle) — and the serial is the unit’s own. Nothing is logged by hand. A record is minted when a retrieval is marked completed on the retrieval list, not when its arrival is confirmed: the register is asked which unit is fitted to that plate, and that unit opens as Not yet decided against the retrieval it came from. A plate the register holds no unit against mints nothing, and a unit that already has an open record is not opened twice. The keke a kit goes to is a searchable picker over the station’s waiting queue (RETR_QUEUE), the same input-plus-datalist atom the push and BOM pickers use, validated with a .f-err on a plate the queue does not hold — so a reassignment can never name a keke that is not waiting. The serials the register holds in service are RETR_SERIALS, serial to the item it is and the keke it is fitted to, which is what the mint reads to find the unit standing against a plate. Dispatching keeps the register true: reassigning moves the serial to its new plate, returning it to inventory takes it off the fleet, and reopening an awaiting record puts it back so the keke can be set. A Faulty kit cannot be reassigned — choosing it flips the decision to Return to inventory. A reassignment names the keke it goes to: the destination is picked from the station’s waiting queue and a plate the queue does not hold is refused on the field, so the record flips to Reassigned and stamps the date at the moment it is taken. There is no awaiting-decision state — the decision is always taken on the form. A return mints the retrieval reference (BND-####) that the Inventory Manager receives it under. The record leads with the whole kit. Most kits come off one keke and go straight onto the next, so the decision is taken once for the kit: its condition, and where it goes next — reassign the whole kit to another keke, return the whole kit to inventory, or split it by item when the components genuinely differ, which is what opens the per-item table. The keke it goes to is a searchable picker over the waiting queue with a .f-err on a plate the queue does not hold, never a dropdown of plates, because the queue grows. A row opens #dlg-retr with the whole chain plus, where the same serial has been through before, its earlier lives (RETR_HISTORY) — so a kit retrieved twice reads as two events on one unit rather than a contradiction. |
A kit comes off a keke as a kit and goes back out as parts. Treating a retrieval as one thing with one condition and one destination is not what happens on the floor: the controller is fine and goes onto the next keke waiting, the BMS is faulty and is held for repair, the harness goes back to the warehouse. The record therefore opens into the items the kit is built from (RETR_KIT, the same composition the warehouse issues it as), each carrying its own serial (a component’s serial reads off the kit’s own, so the same kit always opens with the same units under it), its own condition, and its own destination. A good component goes onto one of the kekes waiting at the station or back to inventory; a Faulty one swaps those for a disposition — hold for repair here or send back to inventory. Recording the outcomes settles each component on its own and the record follows what its parts did, so one kit can leave in three directions. A settled retrieval reads back as a record, not a form. |
| rider | Rider Management scoped to retrofit — rider, keke id, retrofit stage, battery assigned, station, scheduled date; row detail with contact and retrofit history. Its three filters (retrofit stage, station, scheduled-date range) collapse into a single Filters .dlg (Reset / Apply, active-count badge) inside the .tbl-card-head; search stays inline. Kept from the original flow. |
| rider · Kit retrieval | The riders whose kekes are being retrieved, as a .pseg tab beside Riders on the same page, because riders and the retrievals raised against them are two readings of the same people. Three .pstat KPIs (To confirm · Awaiting completion · Completed). #rl-tbl columns: Rider (phone under it) · Plate number · Status · Sent with the retrieval logistics person who dispatched it under it · 4-week efficiency (a 0 to 1 ratio, shown as a percentage — rlEff() multiplies by 100, and the threshold in the trigger copy is written in the same unit through rlEffFloor(), so a rider at 0.1 reads as 10.0% against “under 90%” rather than as “0.1%” against “under 0.9”) · Last update (the status, its date and who moved it) · Actions, over search, a status .filt-select, a sent-date range, a reset that appears only once something is filtered, and an export. A retrieval is approved and sent here by retrieval logistics, who mark it arrived; arrived is that person’s claim, so the station manager confirms the keke is actually standing here before anything else can happen to it, and only a confirmed retrieval can be marked retrieval completed. The row menu offers only the step the record can take next. The record (#dlg-rl-confirm) carries the retrieval, who sent it, the trigger, and a status trail built from the stamps themselves (generated, sent for retrieval, marked arrived, confirmed, completed) so the trail and the record cannot drift apart. |
| reports | Early breakdowns in full, and the one question the register cannot answer. Three .pstat cards that read the filtered list, not the register behind it — early breakdowns in the filter, median days to failure (median, not mean: one failure at 88 days should not move the number that says how soon these go wrong), and how many are waiting on a cause, split into ready to review and still in the bay. Below them the register with search, a cause filter and export, then a group-by card over the same filtered rows: by component, step, technician, batch or vendor, drawn as .cbar bars. |
| earlybd | Inner record page for one early breakdown (row click from the dashboard or Reports). .pg-back to Reports, plate as the title, the cause or the state as the badge beside it. Vehicle card, then a .chart-row holding the conversion and breakdown timeline (each step with who did it and when, QA, collection, then the failure) beside the serials fitted at conversion. Then the maintenance record as the bay closed it: short facts as .kv rows, and complaint, diagnosis and work done as full-width prose, because a .kv value is right-aligned and two sentences of diagnosis come out ragged down the left. Last, parts removed and fitted, where a serial the bay took off that this station fitted is spelled out on the line (Fitted at conversion 1 Jun 2026, removed at Ikorodu bay 25 Jun 2026) and marked This station or Not ours. The only thing the page writes is the cause. |
| cat-approvals | Dual sign-off with the Production Manager on new inventory categories; reject requires a reason — the reject .dlg uses the canonical .fld block with a label.req required marker, never a hand-rolled required star. |
Deep-linkable via ?scenario=<slug>.
Send feedback
Section titled “Send feedback”Every persona console carries the same Send feedback action: a topbar .icon-action (message icon) opens #dlg-feedback — Type (Bug / Improvement) · Impact (Blocking / Slows me down / Minor) · Where (this persona’s own pages, preselected to the page it was raised from) · Details · optional Screenshot. sendFeedback() validates the required fields and confirms with a toast. Submissions land on the Product Manager · Tricycle Hardware console’s Tech feedback queue, which triages them by type, impact and area.
Requirement coverage
Section titled “Requirement coverage”FR-11 (shared-demand reasoning visible), FR-12 (dashboard), FR-13/FR-25 (accept receipt = consumption), FR-14 (transfers in/out), FR-15 (urgency), FR-20 (auto team tag), FR-22 (Rider Management in navigation, presented as an ordinary module), FR-30 (request note), FR-35 (filters + dates). Conventions: NFR-6/7/8/9.
Cross-links
Section titled “Cross-links”Links to the Procurement Manager flow for an end-to-end demo.
Candidate future personas
Section titled “Candidate future personas”Per PRD §11/FR-29 — a Line Manager with team-request visibility is the natural role above this surface.
Canon sweep (2026-08-03)
Section titled “Canon sweep (2026-08-03)”Swept on top of PR #91’s Work Orders + Assembly Procedures enrichment. What changed:
- Topbar —
renderCrumbs()already built Parent / Current fromTRAIL, which is the canonical shape, so the only drift was the hardcoded product segment in front of every page; that is gone. Added the.loc-pill(“Retrofit station”) and replaced the bare.user-pillwith the full.acct-wrap(Switch role via#role-dlg, Settings, Logout). The reference role list had no Retrofit entry, so one was added and marked current. - Notifications and Settings did not exist. The bell only raised a toast. Notifications
is now the canonical
.ntf-rowlist under.ntf-secday headings, built from this flow’s own events, each row routing to the page that owns it; Settings is the two-pane.settings-layoutpage. Both getTRAILentries with a clickable Dashboard parent. - Tab strips stay
.pseg.#inv-seg,#fac-segand#wo-segswap whole sections, and#req-segand#unit-segcarrydata-canon="allow-pseg-filter". Only#ca-seghid table rows, and it became a.filt-selectkeeping its id. - Filters — the floating
.filt-bars folded into the.tbl-card-head..filt-selectreplaced.filt-seland.filt-datereplaced.filt-range; heads with three or more controls collapsed behind one Filter button and the shared#dlg-filtersmodal. - Card heads carry controls, not prose: order is title · spacer · search · filters ·
actions, two prose labels removed, and the one head CTA moved into
.pg-actions. - Guidance panels are dismissible — each gained a
.panel-x;dismissPanel()removes the node so the gap closes with it. - Atoms — four
<td>selector hooks becamedata-*attributes (they were hooks, not styling): removed.in-stat, removed.dec-prod, removed.dec-celland removed.act-cell..f-hinthad markup but no rule, so the DS rule was lifted..link-greyneeded a real definition and is now the muted twin of.link-add— same shape, muted colour, so a Decline reads as the secondary of a green Approve. - Stacked containers get their gap from one rule rather than an inline margin on some.
Lint: 0 errors / 0 warnings, baseline entry removed (zero tolerance).
Rev 7 — configurable serial capture + WO-create BOM (2026-08-06)
Section titled “Rev 7 — configurable serial capture + WO-create BOM (2026-08-06)”Mirrors the Production Manager Rev 7 exactly (this flow shares the assembly-procedure + work-order engine):
- Per-BOM-component Capture serial toggle on the Edit BOM dialog (
#dlg-step-bom→capSerial), generalizing the old hard-coded BMS ID; the Units Captured serial column + assembly record are driven bycaptureSerialComps. - If any build step captures a serial, the QA step confirms it (Serial confirmation block on the QA step card).
- New work order lists the components needed (
renderNwoBom) after the procedure is picked; the Team field was removed from work-order creation.
Rev 8 — Rider management, facility record, WO created-by (2026-08-07)
Section titled “Rev 8 — Rider management, facility record, WO created-by (2026-08-07)”- Rider view rebuilt to read-only rider management (matches the live rider-management surface): KPI row (Total riders / Active riders / Pending retrofits), a
#rider-bodytable (Rider · License plate · Status · Onboarded by · Enabled · Date onboarded) with an inline All status.filt-select+ name/phone search. Row opens a read-only detail (#dlg-rider, close only) — no create/edit. The old retrofit-pipeline table + filter modal were removed. - My Facility is the editable facility record (not read-only):
.psegtabs Overview / Batteries / Users (switchFac), Overview adds Physical address / Country / Coordinates, with Edit (#dlg-fac-edit) and Deactivate (#dlg-fac-deact,.btn-danger-out) actions. Batteries is a seeded table; Users is the former Team roster. - Dashboard — removed the “Retrofit station readiness” card; the dashboard stays floor-health only.
- Work Orders — added a Created by column (
injectWOCreator,WO_CREATORmap over the manager default) tracking the user who created each WO. WO-create button keeps its name; only the form title reads “New Forge work order”. Inventory issuance-window copy mirrors the Production Manager’s. - Assembly-procedure steps gained Instruction + Acceptance criteria (2026-08-10, mirrors Production Manager):
ensureProcMetaseedsinstruction+acceptanceper step (blank on drafts); the step card shows both as.sc-parasections above Bill of materials; the edit row leads with Edit instructions (#dlg-step-instructions,openStepInstructions/saveStepInstructions— Step name · Instruction · Acceptance criteria), same per-aspect dialog pattern as Edit BOM / Edit checklist.
Investigations (view-investigations)
Section titled “Investigations (view-investigations)”The Product Manager (Tricycle Hardware) raises investigations off their own analysis and assigns each one to a named owner. This console is where the assignee works it. Assigned to me lists ref, subject, who raised it, severity, how long it has been running (flagged red once it passes the limit the PM set) and status. A row opens the record: scope, the full activity log naming who did what and when, and the actions Start work, Add finding and Close investigation - which will not resolve without both a root cause and the action taken. Findings and the closure are what the PM reads back. Nothing on this page operates a work order.
Goals (dashboard)
Section titled “Goals (dashboard)”The delivery target is set by the Product Manager, not here: 5,000 conversions by 31 Aug. The dashboard carries the same figures the PM sees, so both sides read one number: progress with a marker for where we should be by now, delivered against what is left, the rate we are running at, the rate needed from here to land it, where the current pace finishes, and the split by bay so it is clear where the output is coming from.
Several goals can run at once, so this page renders one card per goal the PM has running for this unit, each with its own target, deadline, delivery owner and state - not started, on track, behind pace, met or missed. A met or missed goal keeps its card (delivered against target, how far over or short, the average a day, the window) until the PM closes it; closed goals drop off this page. Goals are set and closed on the PM console, not here - the delivery owner reads them and delivers against them.
The table carries the full filter set - search, status, severity, a from/to date on when it was raised, and a clear - and its summary cards (active, not started, in progress, running long) sit clear of it. The owner can export a findings pack from here, not only from the PM console. When the PM raises one and assigns it, an assignment notification lands in this console’s own notifications - naming the ref, who raised it and what it is - so a flagged investigation is not missed among the personas who share it.
A goal leaves the live list the moment it finishes, so the dashboard shows only what is
still running. Finished goals sits underneath as a table — reference, target, delivered,
result, window and, for a goal the PM voided, the reason they gave. pgDone decides which
list a goal belongs to and pgResult states how it ended: met — +12, 190 short, or
voided. Nothing is overwritten and nothing disappears; a voided goal keeps its record and
its reason on this side too, so the person delivering it sees why it stopped.
The strip and the page do different jobs
Section titled “The strip and the page do different jobs”On the dashboard, one line. Whether anything is behind pace, and which goal is
furthest behind — 5,000 conversions · 432 behind. The whole strip is the click
target. The goal cards are no longer on the dashboard.
On the page, the work. A roll-up across the live goals (running, delivered, still to go, met), the live goal cards, and the finished-goal history. A finished-goal row opens that goal, including the reason the PM voided it.
One name: Targets
Section titled “One name: Targets”A delivery push and a standing service level are both the thing you are held to, so a persona does not have to learn two words for it. The nav item, the page, the strip and the page copy read Targets on every console that carries either. What each console measures is unchanged: Production and Retrofit still track delivery against pace, and a finished one still moves to Finished targets with its result and, where the PM voided it, the reason.
The tables
Section titled “The tables”Two things came out of driving the runtime probe to zero on this console.
Wide tables fold, they do not shrink. A qualifying field goes under the field it
qualifies as a .td-sub: the category under the item it classifies, the serial under the
tracking mode that produced it, the location under the person at it, the date a return
was actioned under the outcome. Nothing was dropped to make the count.
A table whose rows have nothing behind them says so. A breakdown by line, a log of
what changed, the line items on one note, an admin list whose rows carry their own Edit
and Disable links — none of those has a record to open, and demanding a row handler
would only produce one that goes nowhere. Those tables carry
data-canon="allow-static-rows" with the reason written beside them. Where a record
did exist, the row opens it instead.
The page spaces its own sections. Each section used to carry whatever margin its own
atom happened to have, which left the summary strip 4px from the section under it here
and 0px on the head consoles. #goals-page now zeroes its
children’s bottom margin and put a single 20px between them, so the gap does not
depend on which atom comes next. The two tables also stopped declaring an inline
margin-top, which would have won against the page rule.
The card says what moves the number
Section titled “The card says what moves the number”Each target names the work item it delivers, drawn from what this console records rather
than free text, and states the record set its progress is counted from — Counted from retrofit orders closed at QA. The finished-target detail repeats it, so a closed target
can still be checked against its source.
The new-item request says what it is for
Section titled “The new-item request says what it is for”The form enforced both of its rules and stated neither. An exact catalog match already
put the name preview into its exact state, disabled Send for approval, and
submitNewItemReq refused even when called directly — but a requester only discovered
that by tripping the warning, and only learned who approves by reading to the Approval
line card at the bottom. A line above the form now says it: this is for an item not
already in the catalog, an existing one blocks the request and offers the existing item
instead, and a new one goes to the named line manager before Procurement can buy it.
A reassigned kit writes its own trail
Section titled “A reassigned kit writes its own trail”Settling a retrieval updated the record and RETR_SERIALS but never wrote to
RETR_HISTORY — so the This serial section of the detail was frozen seeded data and a
reassignment left no trace on the unit. Every outcome now appends to that serial’s trail
through retrLog, reassigned, sent to inventory, or split into its items, so the kit carries
the list of kekes it has been fitted to. retrWho names the keke and its rider together, on the trail entry and on
the Reassigned to row, because a rider is never identified by one or the other alone.
Progress is counted, not typed
Section titled “Progress is counted, not typed”done was a seeded number, so nothing about it answered to the window, the model, or any
work actually recorded. DELIVLOG is now an output log of closed work orders — 678
records — each carrying what it delivered, for which model, on what date and how many
units. delivDone sums the records matching a target’s deliverable, its model and its
window up to TODAY_ISO; delivElapsed derives the days elapsed from the same dates. So
narrowing a window drops the figure (G-114 goes 321 to 132 when its start moves to
1 August), switching the model changes it, and Any model sums both.
The segments make the unit ramp across the year, which is why the same deliverable pays out differently in different windows — and it is why a target that was authored to look on pace can come out behind once the number is actually counted.
Voiding a request, and who did it
Section titled “Voiding a request, and who did it”A request can be withdrawn only while it is still waiting on a decision. pending offers
Void request; created and rejected offer nothing, because the decision stands. The
confirm names the request, the quantity, who was waiting on it and when it was raised, and
says plainly that the item is never created and it cannot be undone. On confirm the record
goes to voided, the list row and its badge follow so the filter and the counts agree, and
the approval line reads Withdrawn before approval against the person who did it.
The retrieval trail names the signed-in user the same way: retrActor reads the topbar
rather than having a name written into the logger, so it follows a role switch and records
the role alongside the name.
The confirm dialog first shipped with .dlg-footer and .btn-danger, neither defined in
this file — the half-transplant web-undefined-class exists to catch. It uses the local
.dlg-foot atom, and the canonical .btn-danger rule was copied in beside the outline
variant rather than invented.
The request page had no page gutter
Section titled “The request page had no page gutter”Every view in this console sits inside .pg-wrap, which carries the canonical
padding: 28px 40px 64px. The new-item request section had been placed as a direct
child of .main, before the wrap even opens — the only view in the file outside it. So
it lost the 40px side gutter: its content started at 248px, flush against the sidebar,
and ran to 1265px, where every other page stops at 288 and 1225. Moving the section
inside the wrap was the whole fix.
The approval line no longer leaves an empty column. It was a 337px card in a 320px
column beside a 1023px form, so two thirds of that column was dead space. Sticky is not
available here: the console sets body{overflow:hidden auto} while the HTML element is
what actually scrolls, which makes body the sticky scrollport — and body never moves, so
a sticky item can never engage. The card sits below the form as a full-width section
instead. The form gets the whole 937px, and the page reads in order: name the item, say
what is needed, then see who has to approve it.
The approver is chosen, and the approval line stays beside the form
Section titled “The approver is chosen, and the approval line stays beside the form”Back to two columns. The approval line sits beside the form again. The sticky
experiment is not repeated: this console sets body{overflow:hidden auto} while the HTML
element is the real scroller, which makes body the sticky scrollport, and body never
moves — so a sticky item cannot engage here. The rule was removed rather than left
looking as though it worked.
Who approves is a decision, not a label. It was hardcoded, so every request went to
the same person and the Line manager approval step was decoration. NIR_APPROVERS lists
the people who can sign for this unit and the step renders a .filt-select over them
while the request is being written. The choice is stored on the record as by, so a
submitted request shows the person it actually went to and the select is gone. The line
under the page title names whoever is selected and follows the picker; on a submitted
record it is hidden altogether, because guidance for writing a request is wrong when you
are reading one. The void confirm and its toast name the same person.
The gutter check across the consoles. Only these two had a view outside .pg-wrap.
Measured across every view of all seven consoles: the PM and Head of Maintenance consoles run 32/32,
the five persona consoles 40/40, each internally consistent.
The approval chain is derived, not chosen
Section titled “The approval chain is derived, not chosen”The approval line renders one step per level the policy requires, naming the role and the
person from the org chart — Head of Retrofit · Ifeoma Chukwu, then VP, Tricycle Hardware · Osita, then CEO. There is no picker: the requester cannot route around their line
manager. The line above the form states the depth and the chain before they start, and the
submitted record keeps the chain it went through.
A kit that is split stops being a kit
Section titled “A kit that is split stops being a kit”A kit or bundle that comes off a keke whole is still a kit, so it can go straight onto the next one, and Reassign the whole kit to another keke stays exactly as it was.
Splitting it by item ends that. The parts are loose stock the moment they are separated, so each
one goes back to the warehouse as its own single return, under its own condition, never as a
kit or bundle retrieval. Fitting a loose part to another keke is not offered: a split item goes
Return to inventory or Hold for repair here (retrDests), and settling a split with
nothing held closes the retrieval as sent, awaiting acceptance whatever mix of conditions the
items carry.
A part on the bench holds the kit. Holding one item for repair — or the whole kit, which is its own option on the decision — stops the settle: the record goes to Held for repair and nothing leaves, because a kit half-sent around a component still being worked on is a kit the warehouse cannot reassemble and a keke that can never be fitted. The record names what is held, the whole kit or the items by name, and offers one action, Mark repaired. That puts the kit back on the floor whole, claims the repaired parts as Refurbished, and returns the record to the decision it came from, so the kit leaves reassigned onto another keke or sent to inventory, as one kit. Both the hold and the repair append to the serial’s own trail.
The warehouse sees each one as a single return naming the kit it came out of, which is where the history of a split kit lives once the kit itself no longer exists.
Claimed in the words the warehouse stocks by, and not returned until it says so
Section titled “Claimed in the words the warehouse stocks by, and not returned until it says so”A retrieval is claimed in the four conditions stock is actually held in, Unused, Refurbished,
Used and Faulty (RETR_BUCKETS), rather than a good-or-faulty pair the warehouse cannot restock
against. A retrieval nobody has ruled on carries no condition at all: Not yet decided means
the condition and the outcome are both unset, and the table says Not set rather than inventing one.
Sending is not returning. A kit or an item that has left the station reads Sent to inventory and states Awaiting acceptance until the warehouse takes it, and only then Accepted by inventory. For exactly that long the claimed condition stays editable, per item on a split and on the kit itself where it went whole, because the claim is the station’s and the decision is the warehouse’s.
The kit reassignment is minted when the keke is received, on completing the retrieval, not when its arrival is confirmed. Nothing is typed twice: the unit the system holds against that plate opens on the Kit reassignment tab with nothing decided.
Serial capture is the receiving desk’s
Section titled “Serial capture is the receiving desk’s”A serialised line is captured in one field, not one field per unit: it takes a scan, a typed serial on Enter, or a pasted list, with Upload CSV for the packing list, removable chips and a running N of M captured. Accepting is refused until the count matches the quantity received. This is the Inventory Manager’s receiving pattern; it used to be a separate input per unit here, so twenty units meant twenty boxes and the two surfaces collected the same fact two different ways.
No lot number is asked for either. Accepting used to require one for every consumable, with an expiry beside it. The estate captures no such thing: the record of a production run is the warehouse’s batch, not a number a floor console keys at receipt, so the field, the refusal it raised and the expiry badge it drove are gone.
The approval gate moved
Section titled “The approval gate moved”Team requests used to stop here: this console carried a Team approvals segment, a history log of every decision, and inline Approve / Decline on the pending rows. All three are gone. The gate belongs to the steward of the shared team pool — see Retrofit Station Inventory Manager — because that person is the one who knows whether the pool already holds the part, and because a request should pass one gate, not two.
What stays is the reading. The With the inventory manager KPI counts what is still at the gate, the status filter offers With inventory as a value the data can hold, and the request detail names who it is waiting on. A manager blocked by a slow decision can still see it; they just cannot make it.
The figure is still editable while the request waits
Section titled “The figure is still editable while the request waits”The quantity is editable while a request is pending, with Save quantity beside Void request; every other field stays locked, and a decided record is read-only. The duplicate check reads the queue as well as the catalogue, so a name already waiting on a decision cannot be sent a second time.
A unit held before QA, and how far into the conversion a keke is
Section titled “A unit held before QA, and how far into the conversion a keke is”A unit stopped at chassis validation is not in progress, not in rework and not queued: it waits on somebody outside the station to say which tricycle came in. Folded into any state the board already had it looks like work somebody is doing, and nobody chases it. So On hold is its own state, carrying the number found beside the number on file and how long it has sat, and it filters like the rest.
The one move the station has is Send back to inspection pending, for when onboarding confirms the wrong tricycle arrived. The reason is required because the rider and the next technician read it. The manager is notified when a held unit record moves, since the thing that unblocks it happens elsewhere.
The register says how far into the conversion each keke is. Status says where a rider sits in the lifecycle; it does not answer the question the station is asked all day. The rungs are the retrofit client own, with one added: On hold amber beside Conversion in progress, naming its reason. A corrected file reads Conversion in progress with a Re-check chassis label, because work resumed.
A conversion stage only shows where a conversion has started. A rider still awaiting inspection has none, rather than being shown part-way through one. A rider sent back from step 4 sits at Inspection pending with the defect that sent them there on their record.
The rider detail answers whether the keke can talk
Section titled “The rider detail answers whether the keke can talk”The detail carries a Hardware block under the rider’s own fields: the VCU, the SIM attached to it, and the battery pack. All three labels sit on the same line and the SIM names what it belongs to, VCU SIM, rather than being indented under it, which left the labels ragged.
The SIM hangs off the VCU and not off the rider, which is what it does physically: assign a VCU and its SIM comes with it, take the VCU off and the SIM row goes too, and the remove confirmation says so. Keyed to the rider instead, a rider would keep a SIM after losing the device it was attached to. A keke with no VCU has no SIM row at all rather than an empty one.
The VCU and the battery pack carry their actions: Assign where nothing is fitted, picking from the serials this station holds free so the list cannot offer a unit already on someone else’s tricycle, and Remove where one is, behind a confirm, because the trail records it and the keke stops reporting the moment the VCU comes off.
The words are the shipped contract’s (riderSim). ConnectivitySim in
views/kaag-live/contracts.ts already models every part of this, and the row
reads it rather than inventing a second vocabulary for one fact: mapped is a
SIM carrying this VCU’s serial, and the state is the contract’s own
DATA_ATTACHED, SMS_ONLY, OFFLINE and CAP_BLOCKED, shown as Online, SMS
only, Offline and Cap blocked.
Unmapped is a different problem from mapped-and-quiet, so they do not share a
badge. A VCU with no SIM against it reads No SIM mapped with with Telematics · bench prep, because it is a bench job that was never done. A mapped SIM that
has stopped talking reads its state and how long since it last did.
The whole thing is a synced snapshot, so every row carries its as-of time.
ConnectivitySummary.asOf is MAX(synced_at) over the Onomondo read model and the
contract marks it nullable, so the row says as of today 09:12, or that nothing
has ever synced. Online with no as-of claims the SIM is talking when it means it
was talking when Onomondo was last read. The masked ICCID shows, because the
contract offers iccidMasked and a station does not need the full number to raise
a ticket.
The station reads this and does not set it. Attaching a SIM is bench prep in the telematics lifecycle, serial then SIM then firmware then ping, done before the device reaches a station, so there is no Attach button here. What the station gets is the fact and who it sits with.
The measure is the failure rate, not its complement
Section titled “The measure is the failure rate, not its complement”A station’s own quality signal is a keke it converted coming back with a fault in what the conversion touched. The first cut of this read three months breakdown-free, and that is the wrong way round: 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 vehicles coming back. The tile counts the failures.
The denominator is vehicles whose three months have elapsed. One converted last week has not had its chance to fail and would only dilute the rate. The ones still inside their window are not hidden by that: the register’s own line says how many of its rows are still inside theirs, so the six it lists and the five the rate counts reconcile on the page rather than in the reader’s head.
The clock starts when the rider collects, and at Ready for pickup where no collection was recorded, because a keke standing at the station is not in service and cannot break down in one.
Only what the conversion touched counts — motor, harness, VCU, battery wiring. A snapped brake lever on the same keke rides the record for context and never the rate.
A pattern is named only when there is one. The amber line above the register appears at three or more of the same component and says nothing otherwise, because the same fault twice over is a coincidence a manager should not be asked to act on.
The cause is set once the bay has closed the case, and until then the record offers no action and says Maintenance in progress. The four causes are Workmanship, Component, Rider use and Not conversion-related.
The register tells one story
Section titled “The register tells one story”The flag on the riders register — Broke down 23 days after conversion — first landed on riders sitting at Inspection pending and at Re-check chassis, because the conversion history and the live pipeline had been seeded with the same plates. A row cannot be awaiting its first inspection and also have broken down twenty-three days after its conversion. The history now has its own plates and the riders who actually collected a converted keke sit in the register at Collected, which is the only rung the flag appears on. It rides the Conversion cell rather than a column of its own: it is true of almost no row, and an eighth column would cost every row to say so.
A render host is not a section
Section titled “A render host is not a section”The pattern line shipped welded to the table card under it. .view > .tbl-card
and its siblings space the page’s stack, and the moment anything is rendered into
a wrapper div that selector stops at the wrapper and never reaches the children.
The host now carries the same spacing its children would have had as direct
children — and site/scripts/flow-probe.js was taught to look inside a bare
wrapper, because its stacked sections have space between them check walked only
the view’s own children and so reported a clean pass on exactly this defect.
A keke still inside its first three months, on the maintenance side
Section titled “A keke still inside its first three months, on the maintenance side”The Head of Maintenance console and the Argo Maintenance Supervisor both carry a Converted N days ago badge on the case, amber, beside the status. 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.