MMAKKIDEMOLITION Full review: mock data, Fieldflo re-watch, gaps (3 Oct 2026) ←Makki DemolitionHome

The Checker — full review, 2026-10-03

Task: Omar, 2026-10-03 — "I want the mock data to be perfect, like i want it to look like real data. So do a review of everything and watch the video again and tell me what the application is missing." One grade, read-only. No worker, no rounds. Nothing under portal/, profile/, tools/ or GO_LIVE.md was edited.

Summary (15 lines)

  1. Both live URLs serve v30-admin and every portal file on disk is byte-identical to what makki-home serves; gating ALL 360 PASSED; 0 console errors on all six logins. The app is sound. The data is not.
  2. [redacted: a margin or profit figure, the owner's only]
  3. The clock is pinned to 2026-08-22 in nine files; at real today every "11 days left" ticket has expired, 63% of receivables are over 90 days, and the active-projects panel would be empty. Every dated record must move, so the data must be generated relative to a build date — the DATA SPEC (A.7) is the brief.
  4. (demo) sits inside 358 data values ("Bin hauler (demo)", "Safety officer (demo)" PIN 2468); every phone is 555; the two estimators tie at exactly 698/698 because a hash assigns them; the demo's own Start Day shows all five of Crew A blocked and Otis Brandt working four days on an expired asbestos ticket.
  5. The tools and the portal agree on every figure (same files, same clock); the three apparent mismatches are scope (Jobs tile 239 vs 578; To-invoice 18 vs 13; "6 people" vs "14 men").
  6. The old generator (portal/_build/extract.py over source_mock.xlsx) cannot run on this box — openpyxl is not installed. Regeneration needs a new seeded node generator.
  7. The video was re-watched in full: 178 old frames + 139 new cuts at every Makki-side turn = 317 frame-reads, plus the whole transcript. 90 things Fieldflo showed or said are not in the 09-26 table (B.1), among them: "Online" to the QuickBooks question, the ~$15k/yr price including QuickBooks for just under 15 users, Fieldflo's own onboarding delivered as in-product trainings, per-project hauler rate tables, an asbestos regulatory inspection checklist, a containment log with three time-in/out pairs, CSI-coded positions, and that their "any language" is a Google-Translate bar with wrong terms.
  8. The Makki side's own words rank the gaps: "Connect to QuickBooks" (8:00), "Okay. Wow." at permissions (8:52), "Oh that's great" at the hard-hat scan (14:00), "Perfect" at training (15:24), an orientation video for managers (32:09), "our current system is holding us back" (40:46), and a texting failure never resolved on the call (35:48–36:24).
  9. Re-graded against v30-admin: of 63 items, Built 18 · Part built 19 · Not built 14 · Out on rail 12. Of the 34 "Not built" on 09-26, 16 are now Built (maintenance engine, Reporting Center, Admin, Roll Call, stat tiles, equipment map, auditors, evacuation plan, abatement checklist, record depth, cert photo, CSV/QR, Company/Messages/⋯, ideas, head starts, project-inventory report) and 14 are not.
  10. Strictness on the waves: any-language = 152 chrome strings, page content stays English; weather is seeded with no live call; voice is the phone browser's own engine; equipment positions are seeds. All graded accordingly.
  11. Money is read-only. The bookkeeper cannot create an invoice, record a payment, release a holdback or write off; her pages have no buttons; the collector's 13 drafts are shown by no portal file. Fieldflo never showed an invoice either — this is Makki's edge and it is a hole.
  12. Abatement specifics a Calgary contractor must keep are thin: no containment entry log, one checklist line for air monitoring, one tick for clearance, one yes/no for the Alberta OHS notification, a WCB account field and nothing else, no FLHA, no hauler/landfill register, manifest = a number.
  13. Still Not built from Fieldflo: training, CRM, hazard library, incident wizard, warehouse loop, GEO, takeoff, document folders, min/max, approval chain, body-part chart, containment log, OHS/WCB reporting.
  14. The twelve rail rows are unchanged and are one decision for Omar — an outbound channel and who approves each send; the Makki side's own experience of Fieldflo's texts failing makes that decision the differentiator either way.
  15. Top 10 (D.1 ★): QuickBooks live (the owner) · invoicing actions (build) · the outbound channel (Omar) · training module (Omar, then build) · full-content languages (build) · containment log + air monitoring + clearance (build; the owner for wording) · Alberta OHS / WCB paperwork (build; the owner for documents) · hazard library / FLHA (build; the owner for wording) · a real CRM (the owner) · the incident side done properly (build). Mock-data regeneration (D.0) comes before all of them — it is Omar's order.

Method and baseline evidence

The grep target is the live app. Both URLs serve v30-admin, and the portal files on disk are byte-identical to what makki-home serves, so portal/*.js is a measurement of the live site (.bak_* files excluded everywhere):

$ curl -s https://makki-home.pages.dev/app/sw.js | grep -o 'CACHE *= *"[^"]*"'      → CACHE = "makki-portal-v30-admin"
$ curl -s https://makki-portal-37c739cf.pages.dev/sw.js | grep -o 'CACHE *= *"[^"]*"' → CACHE = "makki-portal-v30-admin"
app.js local=29f86714 live=29f86714 SAME · roles.js 224e9bcc SAME · certs.js 5cfd97e0 SAME
data.js b69f4a61 SAME · app-admin.js 7749d598 SAME · ops-admin.js bbcc509d SAME · app-day.js 0f270544 SAME

Tool outputs (node tools/ask.cjs outstanding|jobs|quotes|crew A|tickets|inventory, node tools/collector.cjs, node tools/tickets.cjs) were run 2026-10-03 and saved verbatim in hive/checks/2026-10-03_full-review_scratch/ask.out and collector_tickets.out. Every tool prints DEMO DATA … Dated as of 2026-08-22 (the portal's demo date). Run 2026-10-03.

The fixed demo day. portal/app.js:20 const TODAY = new Date("2026-08-22T00:00:00"); // fixed "today" for a stable demo, mirrored in certs.js:131 meta:{ demo:true, today:"2026-08-22", forms.js:23, app-ops.js:25, app-jha.js:44, app-admin.js:47, and in tools/lib/makki.cjs. Real today is 2026-10-03 — 42 days later.

Four read-only workers gathered evidence in parallel, each writing one scratch file under hive/checks/2026-10-03_full-review_scratch/; The Checker re-ran its own spot checks (checker_spot_data.out) before reading theirs, and quotes their findings only where the record id, file:line or frame is given.


PART A — Mock data realism audit

Scope. 17 data files loaded in node with a fake window (_scratch/partA_load.cjs); scans partA_jobs.cjs (1,651 lines out) and partA_ops.cjs (1,334 lines out); The Checker's own spot check checker_spot_data.out. Full per-record flaw lists are in _scratch/partA_data_audit.md (318 lines); this part keeps every count, the record ids and the exact text of the worst rows.

The one finding that matters most: portal/data.js is not generated mock data. It is a verbatim extract of a spreadsheet (meta.source: "Copy of Sales Cost - MOCK DATA.xlsx", data.js:2) whose free-text cells, weekend dates, impossible addresses and bookkeeper's margin notes all came through untouched. It cannot be patched by hand; it has to be regenerated. The generator that made it, portal/_build/extract.py over portal/_build/source_mock.xlsx (not tools/lib/ as the brief said), cannot run on this box today: python3 -c "import openpyxl" → ModuleNotFoundError: No module named 'openpyxl'.

A.1 Dataset table

File · variable Records Grade Top flaw
data.js · meta 1 Needs work source: "Copy of Sales Cost - MOCK DATA.xlsx" leaks the origin
data.js · jobs 578 Fake-looking 75 invoice fields are bookkeeper notes; 215/572 work dates (37.6%) on Sat/Sun
data.js · quotes 1,396 Fake-looking 400/1,395 (28.7%) weekend dates; 27 PO notes like raj wants 8k plus 81 per window
data.js · inventory 10 Fake-looking unit strings $69/25 PIECES, $2.07/ 24, $800/4
certs.js · types 9 Needs work every issuer is "… provider (demo)"
certs.js · crews 3 Believable leads = meta.pms = job assignees, 0 mismatches
certs.js · people 14 Needs work all phones 555-01xx; 2 men with no crew
certs.js · certs 54 Believable spread fine; but Otis Brandt works 4 days on an expired Asbestos ticket
ops.js · TIMESHEETS 51 Needs work 44/51 rows exactly 8 h; one week only
ops.js · PERMITS 12 Needs work issuers (demo); numbers good
ops.js · JOB_REQUIRES / JOB_SCOPE 9 / 9 Believable —
ops.js · WASTE · ops2.js · MANIFESTS · ops-job.js · LOADS 4 / 9 / 24 Needs work hauler/landfill "Bin hauler (demo)", "Class II landfill (demo)" on every row
ops.js · ASSETS · ops-yard.js · GEAR · ops-board.js METERS/TRIGGERS/ASSET_POS 12 / 12 / 12 / 9 / 12 Needs work make "Skid steer (demo)", serial VIN…7731, rental vendor "Equipment rental yard (demo)"
ops.js · INCIDENTS / ACTIONS / INSPECTIONS 3 / 5 / 3 Believable one week of history only
ops.js · SCHEDULE · ops-board.js ASSET_ASSIGN / JOB_CREW_NEED 31 / 31 / 6 Believable two weeks only
ops2.js · PHOTOS / COST_CODES / BID_SPLIT / CHANGE_ORDERS / TM_DAYS / TM_RATES / JOB_SPAN / SAFETY_DOCS / JOB_DOCS 10/7/8/5/3/1/9/11/9 Believable COs all round hundreds; splits 2-decimal round
forms.js · TEMPLATES / SUBMISSIONS 3 / 5 Believable all templates updated:"2026-08-01"
ops-job.js · SETUP / TEMPLATES / ANSWERS / DAILIES / CUSTOM_TABS 6 / 3 / 4 / 11 / 3 Needs work POL-DEMO-44821, WCB-DEMO-00-1187, the owner's phone [phone redacted]; DAILIES hours ≠ TIMESHEETS
ops-notify.js · NIGHT_SHIFTS / ORDERS / TALKS 2 / 7 / 62 Needs work talks on a rigid 3-topic rotation, done cycles 07:10→07:19; orders with no PO
ops-people.js · SKILL_TYPES / SKILLS / SITE_SKILLS / EMERGENCY 14 / 48 / 10 / 14 Needs work by:"Office (demo)" ×44; "Ruth Ferris (demo)"; notes hard-wired to the demo clock
ops-people2.js · RECORDS / CONDUCT / SAFETY_EVENTS / UNIONS / OFFICES / DIVISIONS / PAYROLL_GROUPS 14/5/14/3/2/4/4 Needs work "by":"Sam Reyes (demo)"; talksHeld 12 for everyone vs 62 talks seeded
ops-yard.js · STOCK / LOADOUTS / ORDERS / SCAN_LOG / MAINT 22/4/5/3/10 Believable "Yard hand (demo)"; units disagree with data.js inventory
ops-day.js · SUP_PINS / SEED_CODES / CODE_BY_TRADE 4/7/6 Believable PINs in a seed ("the owner":"1188")
ops-forms2.js · TEMPLATES / INSPECTION_SETS / SDS / ABATEMENT_STEPS 1/2/3/12 Believable names end (demo)
ops-board.js · CORRECTIVE / OT / YARD_POS 5/1/1 Believable —
ops-jha.js · AUDITORS / EVAC_ROUTE / WEATHER 12 / 6 / 4 Fake-looking auditors are job titles: "Safety officer (demo)" PIN 2468
ops-admin.js · SEATS / THREADS / EMAIL_TEMPLATES / REPORTS / PORTAL_SETTINGS / WHATS_NEW 10/4/5/18/6/9 Needs work 10 "project managers" who are on none of the 578 jobs; regions "Airdrie (demo)"
geo.js · sites 578 Believable hides the bad addresses behind plausible pins
roles.js · CLIENTS / JTYPES / ESTIMATORS 24 / 5 / 2 Needs work client and job type are hashes, not data; estimator split exactly 698/698

(demo) inside data values, count per file (grep -c '(demo)'): ops-job.js 96 · ops-people.js 118 · ops.js 29 · ops-people2.js 26 · ops-admin.js 19 · ops-jha.js 17 · ops-yard.js 16 · certs.js 9 · ops2.js 9 · ops-notify.js 9 · ops-forms2.js 7 · roles.js 2 · ops-board.js 1. The DEMO band already says it; the suffix inside names is what makes the screens look fake.

A.2 data.js · jobs (578) — the flaws, with record ids

Spreadsheet notes in the invoice field — 73 rows fail ^[0-9A-Za-z-]+$ (checker spot), 75 by the worker's wider scan. Every one, verbatim: J0000 "2155 (paid Marco $30,350, but received 65K already)" · J0002 "2301 (Received $48,470) still owes 9999" · J0005 "2881 (Sub contract is concrete scanning)" · J0011 "2951 (Received 3k, outstanding 7367)" · J0013 "2975 (Blake $122)" · J0014 "2990 A (blake $2802)" · J0017 "2990 C" · J0018 "2990 B" · J0020 "2991 (Billed only 90% and no gst yet)" · J0021 "2699-14 (90% paid)" · J0025 "Force account - rovan - $56/hour x 4" · J0028 "2699-7 (90% PAID)" · J0029 "2699-8 (90% PAID)" · J0030 "2699-9 (11 metal bins)" · J0031 "2699-11 (15 metal bins)" · J0032 "2699-12 (90% PAID)" · J0033 "2699-13 (90% paid)" · J0042 "2699-14R (90% paid)" · J0063 "2988 (Received $300 deposit)" · J0067 "26-0094 (billed only %90)" · J0070 "2924 (Invoiced 90%)" · J0077 "3009 (invoiced 90%)" · J0078 "3009-A (CO-1)" · J0129 "/" · J0141 "26-0370 3 hours each - 2 guiys, $281 for" · J0162 "26-0440 (garbage and drywall)" · J0176 "26-0443 (Received $766)" · J0195 "26-0536 (asbestos testing)" · J0198 "26-0508 (Received $3100)" · J0199 "26-0544 (Received $3864.16)" · J0201 "26-0545 (Received $2449.17)" · J0204 "26-0558 (ADD $307 mobilization)" · J0205 "26-0579 (Additional air drying/ mold test)" · J0206 "insulation removal 26-0568" · J0207 "26-0560 (air sampling floor 3-16 and wipe test)" · J0210 "26-0567 ($5200 a day air sampling, plus material plus labour)" · J0215 "26-0580 (3 samples of jip crete)" · J0218 "26-0303 ( Received 50%)" · J0226 "26-0620 - window caulking mobilization charge" · J0239 "2301 (Received $48,470) still owes 9999" · J0247 "2504 (missing invoice from gurdeep)" · J0255 "2512 (missing invoice from raj)" · J0261 "2524 A" · J0276 "0" · J0345 "2725 (Force account)" · J0361 "2754 (Force account)" · J0374 "2779 (1000 sq ft vermiculite abatement)" · J0378 "2796 (HVAC)" · J0384 "2745 (NVK)" · J0397 "2851 (owe marco two days of water truck)" · J0399 "2853 (Powergen)" · J0402 "2859 (Plumbing)" · J0403 "2860 (Framing)" · J0404 "2861 (Stairs)" · J0405 "2863 (Trenching)" · J0406 "2844-A (PO#F98479)" · J0408 "2850 (3 days not watered Blake)" · J0412 "2831 (FWD)" · J0415 "2795 (VMR)" · J0425 "v" · J0426 "2883 (FWD)" · J0433 "2916 (Paving VMR)" · J0439 "2932 (Blake $271)" · J0440 "2887 CO-235-MD" · J0442 "2906 (Blake $836)" · J0447 "2952 (Blake $99)" · J0450 "2967 (Blake $977)" · J0452 "2965 (blake $2314)" · J0453 "2981 (Blake $748)" · J0456 "testing of the 8 houses" · J0457 "Owe Blake $71" · J0458 "2996 Owe blake $950" · J0460 "2997 (BRENDA MOLD)" · J0465 "2951 (Received 8k)" · J0560 "2155 (paid Marco $25,343, but received 49K already)". Fix: invoice is a number only, one scheme YY-NNNN per year, strictly increasing by date; -CO1 suffix for change orders; the notes become a separate note field or are dropped.

Notes in the PO field — 53 rows across jobs+quotes contain "wants" (checker spot: J0003 "tyler wants 4250", J0212 "femi abatement guy wants 6676", J0316 "Peter wants 58874"; also J0353 "Tyler wants 9K", J0369 "Tyler wants 85450", J0378 "Casey wants 18423", J0393 po "tyler wants 4550" on a $1,147,949 job, J0398 "tyler wants $5000 (100 sq ft lino)", J0442 "2906 (Tyler wants 2754)"). Vendor refs typed by hand: "Torva Bins - PO80619" (J0161, J0216), "NVK - 14-446 MD" (J0179), "TRM (Kasia)" (J0126), "Gordon (Reed Developments)" (J0134, J0202, J0203), "Marleys 16 ave" (J0099), "Bridgeland build nadia" (J0011), "P.O. VMR-61-868 02.71" (J0415), "hydroseed round one" (J0397), "(20 yard Bin)" (J0409, J0422). Case duplicates: Bison/bison, Torva/TORVA, Form Studio/form studio, Vertex/Vertex Builders. PO equals the invoice number on 356 rows. There is no client column; roles.js:224–226 assigns a hashed client from 24 invented names that contradicts the PO (J0014 po=NVK → client=Windrow Developments). Fix: a real client column; PO = the client's PO number or blank; never a note.

Status / payment. 112 rows (every 2023 and 2024 row) have a blank payment cell → Unspecified (unknown) 112 jobs $4,978,360 on the owner's screen; J0129 "3066 LAKE BARKLEY DR SE" invoice /, payment /, sell 0 → "Other $0". Full/full case split on 15 rows. Fix: every row has a status; pre-2025 rows default to paid.

Dates. year is the workbook tab, not the work year: 35 rows mismatch (J0000 year=2026 demoDate=2024-06-11). 215 of 572 work dates on Sat/Sun (checker spot: same count); 11 jobs quoted after the work date (J0467 q=2024-02-03 work=2024-01-18, J0506 q=2024-06-20 work=2024-05-27 …); only 68 jobs carry a quoteDate (510 blank), so the quote→won→start chain cannot be shown on 88% of jobs; 3 not_started jobs have a past work date (J0184 2026-08-02, J0225 2026-07-13, J0230 2026-07-26); a $400 charge open since 2024-10-17 (J0002, 674 days); nothing dated after 2026-08-02 — a 9-week hole before real today. Per-year counts by tab 16/96/227/239 look like a startup curve, but 2026 runs 33.7 jobs/month vs 18.9 in 2025 with no story.

[redacted: a margin or profit figure, the owner's only]

Addresses (1,129 distinct across jobs + quotes). No quadrant on 257 distinct (89 of 578 jobs, 351 of 1,396 quotes); 15 spellings of 4 quadrants (SW 631 … Southwest 4, Sw 6, nw 2, NORTHWEST); 71 distinct civic numbers with 5–6 digits (801453 Quarry Rise Boulevard, 903487 range road 80, 362665 Ironwood Cres, 73456 645 Street NW); 19 numbered streets off the Calgary grid (987 468 Ave SW, 9366 951 Ave NW, 39497 971 ave E #426 = Q0000); floors above any Calgary tower: 533 6th Ave SW - Floor 84 (J0033), FLOOR 74 - 617 8TH AVENUE SW (Q0696), 110 7th Ave SW - Floor 67 (J0021, J0042); 124 strings with mixed dashes incl. 6865 — 766 - 3 Street SE (J0204) and 19 with non-ASCII dashes; typos 5721 59nd St SE (Tyler wants 363k) (Q0807), Tamarack Place and Place; 2 postal codes, both non-Calgary FSAs (T4X 3X1, T8X 3X7); bare person names as projects (Tom Radich Q0078, Petra Novak Q0816 — one letter from crew member Petra Nowak, Priya Vasani Q1327, Not provided ×3); abbreviations mixed freely (Ave 212 / Avenue 58 / AVE). Fix: one address renderer with the regex in the DATA SPEC.

A.3 data.js · quotes (1,396), inventory (10)

Quotes: won is derived by extract.py:180–186 (same year + same project string as any job), not from the sheet, and 122 won quotes are dated after every matching job's work date; quoteAmt 0 on 4 (Q0642 raj wants 37100); the estimator is ESTIMATORS[hashStr(q.id)%2] (roles.js:236) which alternates parity on Q0000…Q1395 → exactly 698/698 and win rates 37.4%/37.8% — an owner knows his two estimators do not tie. Quote numbering switches scheme mid-stream (2023–25 2020→3053, 2026 26-0001→26-0662) and 39 2026 jobs still carry 4-digit numbers. Inventory: unit strings in 4 formats; $1.69/16 vs $70.28/16 for two tapes; spray with no product; ops-yard.js STOCK already normalises the same items (unitCost 2.76 per suit) so the two tables disagree on screen; low-stock threshold qty < 80 is in both ask.cjs:343 and app.js:1967.

A.4 certs.js, ops seeds — the realism gaps that are not (demo) suffixes

A.5 Date audit — the fixed clock

Nine literal copies of 2026-08-22: certs.js:131 (the master — tools/lib/makki.cjs:48–55 and roles.js:31 read CD.meta.today), app.js:20 (an independent copy driving ageDays at app.js:151 and the dashboard), ops.js:20–22, ops2.js:19, forms.js:28, ops-yard.js:31, ops-notify.js:29, plus OPS.TODAY readers in app-ops.js:25, app-jha.js:44, app-admin.js:47; hard timestamps in ops-jha.js:79–100 (weather asOf), app-notify.js:88, ops-yard.js:99, ops-notify.js:38, ops-board.js:142,160. If "today" moved to the real 2026-10-03 (measured): 45 of 75 receivables change bucket → {61–90: 24, 90+: 47, no date: 4}, nothing current; expired tickets 2 → 5 (W01 respfit, W08 confined, W14 asbestos join) so Crew A has 3 of 5 men blocked; "Today's active projects" 5 → 0; schedule, timesheets, dailies and talks show an empty week; permits P-02/P-03 expired; rentals EQ-07/08/09 overdue; 10 asset inspections overdue; no quote after 2026-07-29 and no job after 2026-08-02. In short: every dated record (572 + 68 + 1,395 + 54 + ~570 ops dates) must move — which is why the data must be generated relative to a build date, not edited. Rule: one BUILD_DATE emitted by the generator into certs.js meta.today; every other file reads root.MAKKI_CERTS.meta.today; the six literal constants and app.js:20 go. The DEMO band stays.

A.6 Reconciliation — tools vs portal

[redacted: a margin or profit figure, the owner's only]

A.7 DATA SPEC — rules for the regenerator (brief for The Builder)

All ranges are derived from the current mock's own distribution; nothing here is a Makki fact. The DEMO band and meta.note stay. Full text with the address regex: _scratch/partA_data_audit.md §DATA SPEC.

  1. Generator: one seeded node script portal/_build/gen_mock.cjs --seed <n> --build-date <YYYY-MM-DD> writing every MAKKI_* file with today's keys unchanged (roles.js and app*.js untouched), then make_geo.cjs; retire extract.py + source_mock.xlsx. One command regenerates and verifies: generator → make_geo.cjs → portal/_qa/gating_assert.cjs → portal/_build/verify_mock.cjs (the partA_jobs.cjs / partA_ops.cjs scans, copied in) must print zero flaws, and ask.cjs / collector.cjs / tickets.cjs totals must equal the portal's owner sums.
  2. Clock: BUILD_DATE → certs.js meta.today; all dates are offsets from it; demo week = Mon–Sat containing it.
  3. Cadence: ~580 jobs / ~1,400 quotes over 36 months; monthly weights Jan .6 Feb .6 Mar .8 Apr 1.0 May 1.2 Jun 1.3 Jul 1.3 Aug 1.3 Sep 1.2 Oct 1.1 Nov .8 Dec .5; +35 %/yr growth; business days only (≤3 % Saturdays, 0 Sundays); quote 1–45 days before its job (median 16, p90 73), never after; work ≤ BUILD_DATE−1 except not_started (+1…+21) and open (started within 30 days).
  4. Status mix: paid 78 %, outstanding 8 %, holdback 3 %, open 2.5 %, not_started 1 %, court 0.3 %; no Unspecified/Other; status follows age (older than 120 d → paid or court); invoicedFlag true for paid/outstanding/holdback/court; owed = total for outstanding/court/open, 10 % × total for holdback; invoice 3–10 business days after work; holdback release 45–60 days; court 300–800 days old and ≥ $10k.
  5. [redacted: a margin or profit figure, the owner's only]
  6. Identifiers: invoice YY-NNNN strictly increasing by date; -CO1 for change orders; quote Q-YY-NNNN; PO blank 35 %, PO-nnnnn / AB-nnnn-nn otherwise; asserted ^[A-Z0-9-]+$ — no parentheses, %, $ or words.
  7. Names: keep the 14 crew, 3 leads, Priya Nair, Ray Colwell, Nadia Frost; drop Petra Novak and 8 of the 10 SEATS; a client column from ~40 invented names in three classes (GCs/developers, institutions, homeowners); haulers Chinook Bins Ltd., Bow River Hazmat Transport; public facilities and bodies may be named (City of Calgary landfills, Alberta OHS, City of Calgary Planning & Development); issuers Prairie Safety Training Ltd., Bow Valley Occupational Health; no (demo) inside any value.
  8. Addresses: {unit?} {number} {street} {type} {NW|NE|SW|SE} on 92 %, named sites 8 %; numbers residential 1–9,999, downtown 100–999, industrial ≤12,000, never ≥20,000; numbered Ave ≤200 / St ≤120 with correct ordinals; floors ≤55 downtown only; out-of-town ≤5 % (Cochrane, Airdrie, Okotoks, Chestermere, Strathmore, Range/Township roads ≤300); postal codes T2x/T3x matching quadrant; ASCII hyphen, no double spaces, no city suffix; asserted by regex; community column from make_geo.cjs COMM so the pin matches.
  9. Estimators: a real column, Ray 58 % / Nadia 42 %, win rates 40 % / 34 %.
  10. Phones / emails: 403- 60 %, 587- 30 %, 825- 10 % with the fictional 555-01nn exchange; emails on a demo domain unless Omar confirms makkidemolition.ca (app.js:96).
  11. Certs: terms as today; at BUILD_DATE 1–2 expired (never a man on this week's abatement sheet), 2–3 within 30 d, 2–3 within 60 d; 1 superseded per 25; no clock-relative prose in notes.
  12. Ops seeds: 6 weeks of history ending on the build week; hours in 0.25 steps from start/finish−break (7.5–10.5), 8–12 % absences; DAILIES.hours = Σ timesheet hours; talks random topic from 6, done 06:50–07:40, men from timesheets, talksHeld computed; incidents ~1 per 3 weeks over 6 months; permits 10–30 days before start, 60–180 days long; rentals due ≥ job end; assets with make/model/year/serial/plate; orders with PO-nnnn; auditors as {name, role}; weather asOf = BUILD_DATE 06:45; SEATS 2–3.
  13. [redacted: a margin or profit figure, the owner's only]

PART B — The video, re-watched

Method. Two readers split the 43:24 recording at 21:40. Both read the prior Part 1 table (207 rows) and the full 512-line transcript first, then opened every one of the 178 existing frames with the image reader (99 frames ≤ 21:40, 79 after) and cut new frames with _venv/bin/ffmpeg-full at every second where the transcript shows a Makki-side (@m:ss - the owner) turn not already in _times.txt, +5 s after each to catch what Dan showed in reply, plus the closing minutes: 46 new frames a_MMSS.jpg and 93 new b_MMSS.jpg in hive/checks/2026-10-03_full-review_frames/ (ls a_*.jpg | wc -l → 46; ls b_*.jpg | wc -l → 93). 317 frame-reads in total, 0 unreadable; a sorted diff of each reader's frame log against disk is empty. Rule "any 20-second window with no frame" added nothing: the 09-26 grid already has a frame every 20 s. The Checker then opened b_2250, b_3110, f_3520 and f_3000 itself and found them as described. Frame logs: _scratch/partB1_video.md and partB2_video.md.

Who is "the owner". The transcript's Makki-side speaker is The owner (54 turns); the demo employee Mark created to receive the SMS is named The owner Makki (b_3110.jpg 31:10, containment log row 1; transcript L221–L231). The 09-26 grade wrote "Owner:" against those quotes. This report says "the Makki side" and does not assert the two are one person.

B.1 New — shown or said, and not in the prior Part 1 table (90 items; 45 per half)

0:00–21:40 (frame or line cited; full wording in partB1_video.md §b)

  1. Claims: ~9 years, "hundreds of… abatement, demolition contractors", "some with 50 offices" (L26); built for field supervisors first (L28); Fieldflo trains the crews itself (L153–154); roadmap partner-driven, "zero ego" (L141–143).
  2. Tenant URL carries the company slug (portal.fieldflo.com/demo-sales/…); the public cert page is addressed by a plain sequential employee id /public/employee/1563 — not a token (f_0000, f_1351, f_1420).
  3. Top utility strip of ~11 icons with red count badges, a settings gear, an in-app support chat bubble on every page (f_0000, f_1220, a_1237).
  4. The "any language" UI is the browser's Google-Translate bar, with wrong terms on screen: "Nearing Bid Hours" → "SE ACERCA EL HORARIO DE SUBASTAS" (auction hours), "Certification" → "Proceso de dar un título" (f_0306 03:06).
  5. Dashboard: "Employee's Nearing Over Time" carries a rolling date window and an empty state; "New Projects" has a gear and EXPAND; T&M-CO-Needed lists project id + name + date (f_0000).
  6. Job Sites map shows employee clock-in locations as the employee's photo pin (f_0620, L78).
  7. Safety dashboard: "Incidents · Near Misses · Stop Works by Supervisor" widget; "Yes & Reportable" filters; an OSHA STATS widget; a forms-count widget (f_0630, f_0640).
  8. Corrective-actions widget filter by employee; the demo tenant is stale (actions open 923–1420 days, inspections overdue since 2018) (f_0640, f_0720).
  9. OSHA 300 case card fields incl. days away / on restriction (f_0710).
  10. Equipment: Open Orders 9; maintenance triggers in miles or hours; "Equipment Overdue" filter; Inspections Log window "5 days" (f_0720); rentals show negative days left in red (f_0735).
  11. CRM leads list already visible at 08:00 with Sort: Due date and board/list/grid toggles (f_0800).
  12. QuickBooks: Dan asks "desktop or online?" → Makki side "Online" (L97–101); "Are we putting employees in QuickBooks?" → "Yes, we are" (L169–172); QB import brings name/number only, each employee then completed by hand (L176, L180).
  13. Dan asks "who's doing your payroll?" (L104); role guidance "daily labor… nothing selected; supervisor… view projects, add forms, take pictures" (L121).
  14. Role groups seen: 19, not 14 (adds CRM, Clients, Employees, Messages, Production Tasks, Other) (a_0924, a_0938).
  15. Named switches not in the table: Can Override GEO Fence · Can validate anything with PIN · Can Access Sync Portal · Waste Portal Admin · Can Add/Delete Bill · Can View Contract Values Dashboard · Re-Open Closed Projects · Restore Deleted Forms · Can Delete Mandatory Forms · Labor Hours Dashboard · Job Costing Export · Scope Templates · Can Approve Payroll / Send SMS · Can Edit Times · Warehouse Fulfillment · Quick Transfer · Scheduling Mobile Access · Offline Files · Advanced Roles · CRM Approver · Proposal Templates · View Only Assigned Leads · Clients (f_0920, f_0940, a_0924, a_0938).
  16. Employee flag "FloTime Access Enabled" and a FLOTIME column (f_0840, f_1240); "System User" accounts distinct from field employees (f_1700).
  17. The full daily-digest list (28 named switches) incl. Employees Without Regulated Break · Geo Location Data Missing · Roles have been Changed · Project time has been adjusted · Prevailing Wage Jobs · CRM Reach Out / Job Walk / Proposal Due · Rental Renewal Reminder · Upcoming Inspections; Instant: Incidents · Warehouse Requests · Disciplinary Actions · Daily Set Overtime Exceeded (f_1100, f_1130).
  18. The notification email is a per-employee cert ledger with "View Cert" per line; the cert catalogue is US (AHERA 32/40 h, NC Asbestos Worker License, 10 Hour OSHA, Hazcom, PFT Physical, Audiogram) (f_1200).
  19. Employees list columns and search scope (ID, email, phone, PIN Y/N, status, FloTime; search by city, phone, union); bulk select (f_1240).
  20. Public QR landing has two sub-pages (certificates, trainings-needed) (f_1420, f_1440, f_1500); required certs are starred, expired ones show negative Days Left, "No Expiration" allowed (f_1420); cert files served through a viewer URL (f_1400).
  21. Fieldflo's own onboarding is delivered as trainings in the product ("FIELDFLO ADMIN TRAINING", "FIELDFLO UNIVERSITY - SUPERVISOR / FOREMAN ENGLISH") (f_1500) — this answers the orientation-video question the Makki side asks at @32:09.
  22. Training statuses "Deployed - Email / Deployed - SMS / Enrolled", quiz "Pending / Waiting", deployed-by stamp (f_1500, f_1520); GotSafety content embedded verbatim, ≥5-question quiz (f_1531, f_1540).
  23. Employee "typical cost code" list includes equipment-ownership and travel codes (Depreciation, Fuel, Insurance, Drive Time, Drive Time - Passenger, Double-time hourly) (f_1600).
  24. Employee fields: Employee Tag, union apprentice level ("Apprentice - Carpenter 20% 200HR"), Referral, Date Hired, photo rotate, Notes (f_1600, a_1635).
  25. Skills include work authorization (Green Card / US Citizen / Work permit), Can Drive-Passed MVR, Class E Operator, Spanish Only, Competent Person Crystalline Silica (f_1620, a_1635).
  26. Dan's dispatch example is "Suncor orientation… Suncor job" — Alberta framing from the vendor's side (L58, L209).
  27. Certificates page: a "Report" button, a TYPE column, colour pills, ⋯ Settings · Cert Names (f_1720, f_1740).
  28. The PDF cert pack generates its own certificate pages (logo, valid-from/expires, "CERTIFIED BY" + signature) for certs with no scan (f_1834, a_1839).
  29. Inventory list: Link column, Min/Max "2/100", unit of measure, categories incl. "Heavy Equipment Rented", "Current Location: Multi Projects" (f_1920).
  30. Item drawer tabs (Details · Cost/Rates · Inspections · Warehouse Request Log · Documents · Item Form Tagging · Maintenance & Repair); "Hide in warehouse request form" (f_1940).
  31. Rate rule "Daily rate up to 3 Days then charge weekly Rate" (f_2000).
  32. Warehouse request type "Transfer To: "; Returning Items block with Approved Qty per line (f_2040, f_2100).
  33. Project Inventory Report nets Ordered − Returned and can go negative (f_2126, a_2125).
  34. Project header: per-project Timezone, "Project Permits 1" / "Warehouse Pending 1" pills, mandays gauge filter by labor type (f_2140, a_0502).
  35. Said: project book holds "night shift, crews list, projected work days" (L270); "Is stuff… walking off the project?" (L253). 36–45. Smaller details recorded in partB1_video.md §b items 5, 7, 11, 15, 19, 25, 27, 28, 36, 38.

21:40–43:24 (full wording in partB2_video.md §b) 46. Project ⋯ menu: Job Costing Estimates · Export Job Costing Estimates · Documents · Employees Certs · Time Sheet Adjuster · Forms Settings · Phases · Positions · Production Tracking · Billing · Close Project (f_2320 23:20). 47. Project gauges with numbers: Schedule 74 % / 429 days left; Labor Mandays bid 279.36 · actual 84.03; Waste Loads bid 18 · actual 1; Injuries 3; T&M-COs needed 4 (f_2320, b_2407). 48. Permits: "+ Add Permit", a named permit with expiry ("Commercial Demolition Permit · 11/15/2024") (b_2210). 49. Certificate/Licenses library of hundreds of names (10/30 Hour OSHA, 32/40 Hour AHERA, 40 Hour Hazwopper) (f_2220). 50. Positions carry CSI-style cost codes (Demolition Labor 02 41 13, Asbestos Supervisor 02 82 10), union codes, and non-labour timesheet positions (Double-time, Drive Time, Drive Time - Passenger, Bonus, Commission, Contingency) (f_2230). 51. Waste Management per project: Landfill records (county/state/ZIP, + Another Landfill), Hauler with a per-haul-type rate table (20 Yd Roll Off 250.00, 40 Yard Roll Off 300.00, Fixed | Hourly), "Set project level rates", Material (b_2250 22:50 — Checker-verified). 52. Emergency Info: nearest hospital full address + Evacuation Plan image upload shown as a thumbnail strip on the project (b_2310, f_2320). 53. Job costing: Contract Value; CO type "Additional"; "End Day – Project % Complete Setting"; labour estimate rows with labor type and total position cost (765 h · $22,950); separate Per Diem estimate (f_2330, f_2340). 54. Document Management columns (Name · Shared/Gallery/Offline · Role · Created · Size); folders incl. "Xactimate Folder" (b_2350). 55. Start Day failed first click (ERR_CONNECTION_RESET), worked on retry (b_2510, f_2520). 56. Start Day created six forms (Timesheet, PSI/JHA/SPA, two Inspections, two Daily Field Reports); "End Day" appears only after Start Day; per-row translate/edit/send/download/trash (f_2520, f_2540). 57. Timesheet header: live Geo Fencing / Geo Tagging dots; Auto Save; ⋯ Same As Previous Day · Timesheet Adjuster · Pull from Scheduling · Export PDF · Form Settings; Union Skill Level column; "Total Employees: N" (b_2610, f_2630). 58. Clock states START → STOP → VERIFY; "SMS SENT" badge the instant START is pressed; supervisor-side gold "Verify"; "SEND TEXT MESSAGE?" confirm (f_2640, b_2750, b_3150). 59. JHA "Same as previous" picker warns it removes saved data; "Bring Employees In Form: Timesheet / Form" (b_2810). 60. JHA General: Task Location*, Muster / Meeting Point*; PIN becomes a green "VERIFY" stamp with name and time; "+ Auditor (max 10)" (f_2820, f_2830). 61. JHA Review adds "Other" free text, a Personal Limitations / Hazards group (8) and a PPE Requirements group of 16 (Respirator with Full Face sub-option, Tyvek, 4 Gas Monitor…) (b_2850, L328). 62. Task library: "+ Add Custom" vs "+ Add Tasks"; "Filter Tasks" with abatement tasks (glove-bag removal, regulated-area/decon set-up, scissor/boom lift, Mobilize, Load Out, Demo Drywall); numeric Risk Rating per task (f_2900, b_2910). 63. Weather adds humidity and "I have reviewed the road conditions with the crew?"; Heat Index 88 / 98 (f_2920). 64. Signature acknowledgement text still carries a COVID-19 clause and an injury-free-arrival attestation (f_2930). 65. Inspections Form demo content is an asbestos regulatory checklist: PM credentials, Air Monitoring Specialist, project design thresholds (>1,000 LF / >3,000 SF; >3 LF / >3 SF in schools), variance, "−0.02" H2O on manometer", airflow outside→inside, self-closing flaps, shower leakage, 2-stage waste load-out, supervisor state-certified, design on site and signed — each line OK/NO/N/A + Upload Photo(s) (b_2950, f_3000 30:00 — Checker-verified). 66. Daily Field Report extras: Scope block (Scope Received, Scope Date, Structure); Incident "Reportable" flag + type; "Notes related to Environmental testing"; Estimated Completion Date, Days Remaining (incl. Demobilization); "RRP and/or Abatement Procedures" cleaning-verification block (3 work-area locations, # of cleaning cloths) (f_3020, b_3030, f_3040). 67. Containment Log via "+ Add Form"; "Transferred from Daily Timesheet. Not saved yet."; per person Name/Custom, Respirator Type, Task Performed, Signature-or-PIN, three Time In/Out pairs, + Add Row, Images (f_3100, b_3110 — Checker-verified). 68. Employee verify modal computes Start/End/duration/Break and warns "Once you hit submit you cannot reverse an injury" (f_3200); delete-forms confirm; crew size 2→0 on stop (b_3130, b_3230). 69. Marketing site "Industries We Serve": Demolition · Asbestos Abatement · Environmental Remediation · Masonry · Concrete; "AI-powered estimating"; 1:48 overview video; gated whitepaper "The State of Estimating in Demolition & Abatement" (b_3305, b_3310, f_3300, f_3320). 70. Named clients on the site (PMG, Quality Environmental, ARC Abatement, Titan, Alpine, Pinnacle Environmental…); said: Northstar (~40 offices), "8 of the top 10 on the ENR list", "over 20,000 supervisors log in a day" (f_3320–b_3350, L355–357). 71. Equipment Inspection: Inspection Date and Next Inspection Date, "Equipment Non-Inventory" free text, Odometer, Hours, "Select All", Powered-Off rows (Brakes, Digging Assembly, Lights/Strobes, Undercarriage, Fluids) (f_3400, b_3410). 72. CRM list: lead numbers, client, red overdue clock, "Proposal sent / In progress" pills, sort by Due (f_3440); lead record tabs Basics (progress ring) · Job Walk · Details · Sources · Estimates (6) · Proposals (1) · Reach-outs · Files · All activity (f_3447). 73. New estimate: nine Work Types (Asbestos Abatement, Hazardous Materials Removal, Industrial Decommissioning, Interior Demolition, Lead Abatement, Mold Remediation, Soil & Groundwater Remediation, Structural Demolition, General Contracting); "Manual entry" vs "Let FLO cook!" (b_3450). 74. Estimate setup: internal due date, start/end, template vs "No template (manual pricing)", Light commercial / Institutional, Condition "Federal funded"; "Select files for FLO to auto-detect tasks and SoW. No need for drawings here." (f_3500). 75. [redacted: a margin or profit figure, the owner's only] 76. Weekly Scheduling: Week · Open · Type · Office · Set Day · Reset All; "Use Project Start/End Times"; Crew Projected vs Crew Scheduled per project (red until filled, green when met); "Active" + "Mark as Scheduled" toggles; faces tagged 8 h / 40 h; S-M-T-W-T-F-S bubbles; Scheduled Hours per man; envelope icon when sent; a Groups tab (f_3540, b_3548, b_3550). 77. Gantt: All Projects filter, 4-week span, bars show Crew Size, named crew and "Assets: N"; fourWeekView=1 (f_3720–f_3740). 78. Payroll Approval: demo week empty ("No Employees For Selected Week") so Dan switched weeks; detail columns Note · Phase · Injured · Start/End Break · Approved By/On; weekly table Employee · Time · SMS Send · Verified · Verify Status (b_3810, f_3820, b_3830). 79. Top bar badge counts; Dan runs Google Workspace tabs (b_2210). 80. Said: the location SMS is optional for the labourer (L312). 81. Said: onboarding = "your own human who's been in the industry… we hold your hand"; no orientation video (L345–349). 82. Said: takeoff/estimating is a separately "just released" module, "not in the market for upselling" (L361–370). 83. Said: the SMS verification links failed for the Makki side ("not connected to the Fieldflo app and the link is not valid"); unresolved on the call (L376–397). 84. Said: pricing — tiered by supervisors/foremen-and-above who log in; daily labour free; Makki side "just under 15" users → "around 15,000 for the year for Fieldflo with a QuickBooks integration" (L409–441; Checker re-read L404–445). 85. Said: no demo or trial login — "blank platform would have no data… I wish we did have that trial" (L461–468). 86. Said: next steps — pitch to the VP (budget already approved), Friday team run-through, Dan to send the recording (L451, L486–494). 87–90. Smaller details in partB2_video.md §b items 10, 23, 24, 37.

B.2 What the Makki side said, by time (the reactions that rank Part D)

@ Makki side Dan showed Weight
2:01 "we have tried a couple programs… hard for our workers and our managers to use on site… some people were using it, some weren't… five companies that we have" languages, white-label, roles the buying problem: field adoption; multi-company
4:26 "Some stuff for abatements is a little more detailed and job specific" job templates, form builder abatement-specific paperwork
8:00 "Connect to QuickBooks." · 8:09 "Online." · 12:47 "Yes, we are" (employees in QB) CRM tab; QB import the loudest ask in the call
8:14 "accountant doing payroll… give them access to just payroll" · 8:52 "Okay. Wow." Employee Roles, role profiles permissions
10:37 "Very, very user friendly from what I can see." notifications —
14:00 "Oh that's great." (hard-hat scan) public cert page —
15:24 "Perfect." (training + quiz + certificate) · 15:45 "let you know that's been close to expiring" training module training
17:17 gives a 403 cell number for the SMS demo — Alberta number on record
18:54 "I haven't seen anybody else incorporate that into their program" (archived certs) archives —
21:20 "That's great." (Project Inventory Report) report —
24:07 "Honestly, great. It seems like a perfect fit… nothing I could think of that we would need added." project overview; HQ dashboard claim —
32:09 "Do you guys have an orientation video… that we can share with managers?" no video; hand-held onboarding manager adoption
33:05 "I love how it's tailored to demolition and abatement." website stated buying reason
34:36 "I know our estimators aren't fans, but it'd be cool to see." (takeoff) CRM → estimate → proposal low interest
35:48–36:24 SMS links "not connected… link is not valid" — unresolved failure
39:11–40:36 "Pricing?" · "10 project managers… close to 80 employees" · "just under 15" · "I think it's a great fit for us." ~$15k/yr incl. QuickBooks price accepted
40:46 "pitch it to our VP… they have approved to spend money… our current system is holding us back" — budget exists
41:06 "Is there a demo login or a trial login?" no trial —
42:49 Friday team meeting; recording to be sent — next step
Never said by either side in 43 minutes: invoice, holdback, GST, Alberta, OHS, WCB, manifest, clearance, air monitoring (Dan showed an Air Monitoring Specialist field and folder; nobody discussed it).

PART C — The gaps, re-graded against v30-admin

Method. The 09-26 grade's Part 3 ranked 51 gaps (34 Not built, 17 Part built) plus 12 rail rows A1–A12 = 63 items. For each: a grep of portal/*.js portal/index.html (no .bak_), and the live site driven with Playwright (skills/visual-qa/.venv) as all six logins — ali, priya, ray, sam, dale and the new theo/crews — with every tab opened, 80 PNGs and per-tab text dumps in _scratch/partC_shots/. Wave claims were driven, not read: Roll Call went 0 → 5 after Sam's Start Day; an equipment inspection with one NO opened corrective #4 and moved the next-inspection date; supervisor PIN 4821 signed the JHA and auditor PIN 2468 read "1 of 10 auditors signed", a wrong PIN was refused; the ?day= link opened with no login and a tampered link was refused; the language switch flipped 27/28 nav labels to French and set dir=rtl for Arabic. The Checker re-ran the gating suite and nine of the greps itself (same output) and opened t_ali_equipment_map.png and t_sam_jha_signed.png.

Baseline lines (re-run by The Checker): node portal/_qa/gating_assert.cjs → ALL 360 PASSED. Console errors: ali 0 · priya 0 · ray 0 · sam 0 · dale 0 · theo 0. Tabs now: ali 21 (was 16: + messages · ideas · reporting · company · admin), priya 4, ray 5, sam 12 (+ daylinks), dale 5, theo 6 (new project-manager seat). No _qa/verify_*.cjs drives pages.dev (the live verifier is inside outbox/publish.cjs, not run — it publishes).

Score: of 63 items — Built 18 · Part built 19 · Not built 14 · Out on rail 12 · NOT MEASURED 0. Of the 34 "Not built" on 09-26: 16 are Built, 4 Part built, 14 still Not built. Of the 17 "Part built": 2 now Built (#46, #51), 15 still Part built. All 12 rail rows unchanged — they are Omar's one decision, not builds. Two 09-26 misses corrected: the no-login asset-scan inspection has been in app-yard.js since 09-20 (#15), and the Project Book already had insurance/WCB, owner and building panes in app-job.js V75 (#23).

C.1 The 63 rows (full evidence cells in _scratch/partC_regrade.md)

# Gap 09-26 Now Evidence (code · live) Still missing
1 Training system end to end Not built Not built grep -niE 'quiz|deploy a training' → nothing (quiz 0, Checker re-run) deploy, PIN, video, quiz, issued certificate
2 Any language Not built Part built — chrome only lang.js 152 keys × fr/es/ar; translate("Nearing maintenance","es") returns English · ali .langsel fr → 27/28 nav labels, page content still English; ar sets dir=rtl (t_ali_lang_ar.png) page content, forms, data labels; the globe is Forms-only
3 Takeoff & estimating Not built Not built takeoff 0 all
4 OHS / WCB statutory reporting Not built Not built ops-job.js:215 "Is the Alberta OHS abatement notification filed?" (one yes/no), app-job.js:166 fld("WCB account") · reporting has Incident/Injury CSVs the notice itself, WCB report, classification
5 Full incident claim wizard Not built Not built witness|employee statement|needs review 0 · one form (ali_18_safety.png) multi-step, % complete, review queue
6 Equipment maintenance & inspection engine Not built Built roles.js:3098 maintenanceDue · :3108 inspectionsDue · :3122 inspectionForm · :3141 fileInspection; ops-board.js:136 OK/NO/N/A · ali/equipment "Negative air machine #1 … 40 hours over · Service due now"; EQ-10 form ODOMETER (KM) + HOURS; one NO → "1 corrective action opened… next inspection date moved" (t_ali_inspection_filed.png) readings are seeds
7 Real CRM front end Not built Not built reach ?out|job ?walk|lead record → prose only; ops-admin.js:61 CRM report = client CSV lead record, source, due, reach-outs, Clients, calendar
8 Hazard / control / risk library Not built Not built task step|risk rating|hazard librar 0; talk = topic + 6 tick items (t_sam_jha_signed.png) ~40 hazards, controls, risk rating, auto-fill
9 GEO fencing / tagging Not built Not built geo.?fenc 0 (Checker re-run) all
10 Voice into the daily Not built Built — browser engine app-jha.js:203 window.SpeechRecognition||window.webkitSpeechRecognition (Checker re-run) · dale/endofday "Talk" enabled, 6 languages (t_dale_eod.png) depends on the phone browser; no server transcription
11 Live weather + heat index Not built Part built — seeded ops-jha.js:80 current:{ tempC:24 …humidex:29 } (Checker re-run); fetch( only in sw.js · "Seeded demo reading… Live: Environment Canada… once Omar switches it on"; "reviewed with the crew · Sam Reyes at 04:38" the live call (Omar's switch)
12 Warehouse request / fulfil loop Not built Not built warehouse (request|approv)|rapid qr 0 all
13 Reporting Center Not built Built roles.js:3374 REPORT_ROLES (Checker re-run), app-admin.js:100 · ali/reporting 18 reports, Open → "Asset report — 12 rows" (t_ali_report_open.png) CSV only
14 Admin section Not built Built (email draft-only) app-admin.js:124 ADM_TABS 8 tabs (Checker re-run) · all 8 render send is rail A6
15 Asset QR → no-login inspection / SDS Not built Built (09-26 miss) app-yard.js "Log an inspection" since 09-20; roles.js:593 sds · ?asset=EQ-07 no login: SDS block + machine checklist (t_scan_EQ-07.png) seed links no SDS file
16 Equipment location map Not built Built — seeded positions app-board.js:334 Equipment map, roles.js:2878 assetPositions — seeded, no GPS · 12 pins, Rentals 3 · Heavy 4 · Vehicles 1 (t_ali_equipment_map.png, Checker-viewed) real positions need GPS
17 Body-part / 12-month chart Not built Not built body part|12.month → none both
18 Abatement checklist on the daily Not built Built ops-forms2.js:116–129 12 steps + cleaning verification · sam/startday "0 of 12 steps" wording invented
19 Containment entry log Not built Not built app-forms2.js:25 (The containment log itself is GL-017 and is not here.) respirator, time in/out, signature
20 Employee record depth Not built Built roles.js:2325 Employee no · Office · Division · Default cost code · Union · Payroll group · Temp labour; write-ups owner-only · ali → Otis Brandt record (t_ali_man_file.png) values are seeds
21 Cert photo on file Not built Built app-people2.js:202, real file field app.js:1426, scan page app.js:1653 · viewer "Asbestos Worker Otis Brandt · ASB-829605" (t_ali_cert_photo.png) demo button draws an image; device store
22 Roll Call Not built Built app-board.js:102 rollCallPanel (Checker re-run) · 0 → 5 clocked in after Start Day; Late/Sick/Excused/No-show (t_ali_rollcall_modal.png) "clocked in" = foreman's row
23 Project Book depth Not built Part built (09-26 miss) app-job.js:11 V75 insurance, :166 WCB account, :124–146 owner/building; lien|consultant|air monitoring specialist|prevailing wage → prose only lien, designer, consultant, air-monitoring specialist, payroll info, custom tabs, phases
24 Waste registers Not built Part built ops-job.js:51 TRUCK_TYPES, :308 WASTE_MATERIALS; hauler/landfill are free text app-job.js:223–224 hauler/landfill lists with rates
25 Document folders Not built Not built folder 0 folders, roles, upload
26 Min/max reorder Not built Not built min.?max|reorder 0 both
27 PM approval chain Not built Not built approval chain → comment only; TABS.manager has no payroll chain + history
28 Stat tiles Not built Built roles.js:3071 statTiles · "CONTRACTS IN PROGRESS $466,508 · DAYS WITHOUT INJURY 3 · USERS 20 · CLIENTS 24" —
29 Auditors on the JHA Not built Built app-jha.js:135,168; 12 seeded auditors · PIN 2468 → "1 of 10 auditors signed", wrong PIN refused (t_sam_jha_signed.png, Checker-viewed) auditors are job titles (Part A)
30 Feature idea / what's new Not built Built app-admin.js:298,307 · idea saved on device; What's new v30-admin device-only
31 Evacuation plan Not built Built app-jha.js:69–71 · "MUSTER POINT Rear lot … EVACUATION ROUTE Down the east stair" —
32 HQ across branches Not built Not built branch|HQ prose only; GL-037 closed by Omar roll-up
33 CSV export + bulk QR Not built Built app-people2.js:410,414 · "14 men · 19 columns", "14 hard-hat codes on one printable page" downloads not re-driven (wave 1 PASS)
34 Company · Messages · ⋯ Not built Built app-admin.js:253,270,55 · Company "OFFICE ADDRESS — not on file — The owner fills this in"; Messages 4 mock threads; ⋯ = columns/order/density (t_ali_threedots.png) messages in-app only
35 QuickBooks Part built Part built — rail #7 app-ops.js:582 toast("Needs the owner's QuickBooks Online login … Nothing connects") the call
36 Dashboard widgets Part built Part built app-board.js:138 Employees nearing overtime, :144 New projects · 19 h3s CRM/Safety/Equipment tabs, T&M-CO queue, Messages widget
37 Scheduling board Part built Part built app-board.js:188 Crew projected / Crew scheduled / Coverage · "1 double-booking · 6 under-crewed slots"; Equipment on the schedule hours per man on the board
38 Inspection engine Part built Part built row 6; site sets app-forms2.js:16 are a read list on Start Day site sets per line + photo per line
39 Project gauges Part built Part built manday|days left → label only mandays, days-left, stats split
40 Project-level settings Part built Part built timezone|overtime trigger|multiple timesheets 0; app-job.js:87 Shift window multiple sheets/JHAs, phases, OT trigger
41 Job cost estimate Part built Part built % complete|labour estimate 0 % complete log, estimate rows
42 Proposal editor Part built Part built markup|line item → CSS only line items, markup, blocks, terms
43 Certificates page depth Part built Part built row 21 Built; labour type 0 six-field filter
44 Forms lifecycle Part built Part built closed|deleted|zip|\.pdf in app-forms.js → none Active/Closed/Deleted, pdf/zip, red-until-right
45 EOD for a man who never logs in Part built Part built app-admin.js:357 ?day=<token> · no-login day page reads hours + tickets; "This link stops working at 2026-10-04"; tampered → "not valid" (t_daylink_nologin.png) he can read, not verify hours/breaks/injured
46 Timesheet head starts Part built Built app-day.js:9 V86, :208–210 · "from the board (5 men · 8 h)" · "same as Fri 21 Aug" · "8 h each" —
47 Inventory depth Part built Part built app-forms2.js:114 Next inspection; aisle|asset tag|quick transfer|weekly rate 0 aisle, tag/class, transfer, rates
48 4-week look ahead Part built Part built look.?ahead|four.week 0 the view
49 Payroll filters Part built Part built verify status|approval status|project type 0 in app-ops.js filters
50 Role profiles Part built Part built role profile|preset 0; roles.js:190 manager role, :3405 managerSeats · team "6 people", PM roster 10 seats saved presets
51 Project Inventory Report Part built Built ops-admin.js:60 projinv · Open · Export CSV —
A1–A11 SMS/email sends (verify time, safety talk, location, payroll verify, broadcast, digest email, cert-override email, proposal Send, schedule to phone, Send Forms, notify assignee) rail Out on rail — unchanged app-admin.js:20 nothing is texted; app-ops.js:654 Draft — The owner sends. (Checker re-run); no twilio|smtp|sendgrid anywhere; dale/endofday now asks meal/break + injured in-app one decision: an outbound channel, and who approves each send
A12 Live QuickBooks rail #7 Out on rail — unchanged app-ops.js:582 Nothing connects in the demo. The owner's login

C.2 Money and abatement — what the code does not have (greps over portal/*.js portal/index.html, no .bak_; full table in partC_regrade.md Task 2)

Term Hits What it is
invoice / invoicing app.js 50, roles.js 12 (+3,2xx in data.js values) read-only tables — Outstanding (app.js:1112), To Invoice (:1129), Payments (:1143); no function creates an invoice, marks one paid, records a payment or writes off (markPaid|recordPayment|createInvoice → 0, Checker re-run)
holdback 66 a status bucket and a KPI; no release date, no release action
progress bill / claim · statutory declaration · Prompt Payment · lien 0 / 0 / 0 / 0 absent
GST app.js 12 a column and "+ GST (5%)"; Company page GST NUMBER — not on file
outbox/invoices/ (the collector's drafts) 0 portal references (Checker re-run; 13 files on disk) the portal never shows them
air monitoring · air sampling · clearance 4 · 5 · 21 one checklist line + an auditor role · one free-text question · one tick step "Clearance — visual, then the clearance air sample"; no air-monitoring results, no clearance letter record
waste manifest · manifest · landfill ticket · weigh scale 2 (prose) · 41 · 2 · 0 Manifest is a number column per load (app-job.js:200–212); no document, no hauler/landfill register
hazmat assessment · asbestos survey · designated substance 0 · 0 · 0 one template yes/no "hazardous-materials survey received and read?"
Alberta OHS · notice of project · notification of asbestos 1 · 0 · 0 one yes/no question (ops-job.js:215); no notice record, no dates, no file
WCB · Workers' Compensation · COR 10 · 0 · 0 WCB account field only (app-job.js:166, ops-admin.js:143); no incident report to WCB
FLHA / field level hazard / hazard assessment 0 / 0 / 0 absent (the talk has 6 tick items)
respirator 10 a ticket type + a fit record; no respirator program/log
Type 1/2/3 asbestos template pick-one Alberta uses low / moderate / high-risk wording
SDS · negative air · decon · toolbox talk · change order · T&M · per diem · equipment rental · payroll · timesheet · overtime · photo · signature · export · offline 70 · 31 · 35 · 16 · 59 · 28 · 19 · 731 · 136 · 110 · 28 · 240 · 48 · 52 · 24 real features
email · SMS · notification/push · GPS · geofence · Sage/Jonas/Procore · LOA drafts only · prose · in-app only (pushManager 0) · prose · 0 · 0 · 0 no outbound, no push, no GPS

What the bookkeeper can do today: read, filter, CSV-import. Buttons on outstanding [], toinvoice []; payments has only the import panel; a row click opens nothing (app.js:1121 plain <tr>). What the owner can do about money: nothing on Collections or Jobs; Payroll has Approve/Export; QuickBooks Connect is a toast. The only "write off" in the portal is gear written off on a loadout (app-yard.js:151).


PART D — What the application is missing (for Omar)

Two lists. The first is the mock data (Part A) — Omar's actual order. The second is features, ranked by minutes on Fieldflo's screen, how the Makki side reacted, and what a demolition / abatement contractor needs that Fieldflo never showed. Each line: what · why · Build (a worker can do it on seeds) / Decision (Omar) / Blocked on the owner.

D.0 Mock-data fixes — the data has to be regenerated, not patched

D.1 Feature gaps, ranked — top 10 marked ★

  1. ★ QuickBooks Online, connected for real. The Makki side said it unprompted at 8:00, answered "Online" at 8:09, confirmed employees live in QB at 12:47, and the $15k/yr price they accepted at 40:36 included the QB integration (B.2). Makki's page is a settings screen with a toast (app-ops.js:582). Blocked on the owner — his QBO login (GL-046/047/064). Nothing else moves real money into the portal until this does.
  2. ★ Invoicing that does something. Fieldflo never showed an invoice in 43 minutes (B.2 last line), so this is Makki's edge, and today it is a hole: the bookkeeper cannot create an invoice, record a payment, release a holdback or write anything off — her three pages have no buttons and no row click (C.2); the collector's 13 drafts in outbox/invoices/ are shown by no portal file. Build (on seeds) — create/mark-paid/record-payment/holdback-release actions, the drafts surfaced on To Invoice; Decision on whether invoices leave the portal (rail #1).
  3. ★ The outbound channel — one decision, twelve rows. Every "no login" trick Fieldflo sold (time verify by text, safety-talk verify by text, location text, schedule to phone, digest email, proposal Send) is rail A1–A11 and unchanged (C.1). The Makki side's own texts from Fieldflo failed on the call (35:48–36:24, unresolved) — so a working line is a differentiator either way. Decision for Omar: does the hive get a texting line and who approves each send (GL-039, GL-067, GL-105–109).
  4. ★ Training module — deploy a course to a man's phone behind a PIN, video + quiz, passing issues a certificate that is then tracked. ~2 min of the demo, the Makki side said "Perfect." (15:24); Fieldflo even delivers its own admin onboarding this way (B.1 #21), which answers the Makki side's 32:09 question about an orientation video for managers. quiz → 0 hits. Decision then Build (GL-024, GL-076).
  5. ★ Any language for the page content, not just the chrome. Dan opened the demo with it (2:37) because the Makki side's stated problem is that workers and managers would not use the last two systems (2:01). Makki translates 152 nav/button strings into three languages and leaves every page body, form and data label in English (C.1 #2). Fieldflo's own version is a Google-Translate bar that mistranslates "Bid Hours" as "auction hours" (B.1 #4) — a full string pack beats it. Build.
  6. ★ Abatement records a Calgary abatement contractor must keep: containment entry log, air-monitoring results, clearance letter. Fieldflo showed the containment log (31:40, three time-in/out pairs, respirator type — b_3110) and an Air Monitoring Specialist field/folder; Makki has no containment log (app-forms2.js:25 says so), one checklist line for air monitoring, one tick for clearance (C.2). Build on seeds now; Blocked on the owner for his wording (GL-017).
  7. ★ Alberta OHS and WCB paperwork. Fieldflo's OSHA 300/300A/301 logs (7:45) are US; Makki has one yes/no "Is the Alberta OHS abatement notification filed?" and a WCB account field — no notice-of-project record with dates and file, no WCB incident report, no OHS stats (C.2). The forms are public; Build on seeds, Blocked on the owner for his real documents (GL-026, GL-056, GL-063).
  8. ★ Hazard / control / risk library behind the JHA (an FLHA). 29:00–30:00, Dan: "This is cool"; the supervisor picks the task and the paperwork fills itself, ~40 hazards in 5 groups plus PPE requirements and personal limitations (B.1 #61–62). Makki's talk is a topic plus six tick boxes; hazard assessment\|FLHA → 0 (C.2). Build on seeds; Blocked on the owner for his task wording (GL-011).
  9. ★ A real CRM — leads with source and due date, reach-outs, job walks, a Clients tab, a calendar (7:55–8:20 and 34:40–34:47). Makki has a quote pipeline and a client CSV (C.1 #7). Blocked on the owner (GL-033: does he want leads tracked at all) then Build.
  10. ★ The incident side done properly — the 11-step claim with % complete and a review queue, the "Reportable" flag, injuries by body part and a 12-month chart (7:00–7:45, 30:40). Makki has one incident form (C.1 #5, #17). Build.
  11. Waste registers with rate tables — per-project landfill and hauler with a per-haul-type rate (b_2250: 20 Yd Roll Off 250, 40 Yd 300, Fixed | Hourly) and a manifest document per load. Makki: free-text hauler/landfill and a manifest number (C.1 #24). Build on seeds; Blocked on the owner for his haulers (GL-018).
  12. Proposal editor — line items with qty/unit/markup, misc-expense lines, drag-in text/image/PDF/signature, built-in acceptance terms, expiry, Web and PDF (35:10, f_3520). Makki generates a document from a quote (C.1 #42). Blocked on the owner for his bid items (GL-010), then Build.
  13. Payroll approval chain — PM-by-PM with a trailing history (38:40). Makki: owner-only, no chain (C.1 #27). Blocked on the owner — who besides him approves (GL-040).
  14. Project Book depth — lien information, consultant, air-monitoring specialist, project designer, payroll info, phases, custom tabs (22:00–23:30). Insurance/WCB/owner/building are in (C.1 #23). Build.
  15. Warehouse request → approve → fulfil → return loop with RAPID QR (20:30; transfers project-to-project, B.1 #32). Build.
  16. Forms lifecycle — Active / Closed / Deleted, PDF and ZIP download, red-until-answered (25:20). Build.
  17. Document folders with upload and a role per folder on the job (24:00); Makki lists titles only (C.1 #25). Build.
  18. Live weather call — the panel is built and seeded; the Environment Canada / Open-Meteo call waits on Omar's switch (C.1 #11). Decision.
  19. GEO fencing / tagging and GPS clock-in (22:00, 26:30). geo.?fenc → 0. Decision (GL-019: a phone-location policy for the crew).
  20. Min/max reorder levels on inventory (19:01). Build.
  21. Equipment: hours per man on the board, "Mark as Scheduled", Groups tab, 4-week look-ahead, payroll filters, role-profile presets (35:20–38:20; C.1 #37, #48, #49, #50). Build, small.
  22. Takeoff & estimating from drawings (34:00). Makki side: "our estimators aren't fans" (34:36); Dan himself deferred it. Decision (GL-038), low priority.
  23. Multi-company / HQ roll-up. Omar closed it 09-15 (GL-037), but the Makki side said "five companies that we have" at 2:01 and 10 PMs / ~80 employees at 39:47. Decision — re-ask Omar with that quote in front of him.
  24. An orientation video for managers — asked for directly at 32:09; Fieldflo had none. GL-076 waits on Omar. Decision.
  25. Push notifications / the bell outside the app — pushManager 0; in-app only. Decision (same channel question as #3).

D.2 Where this report could not verify