{"slug":"filemaker-mcp","total":100,"limit":100,"offset":0,"since":null,"commits":[{"hash":"a775694","date":"2026-09-25 13:17:40 -0700","author":"Steve Abrams","subject":"push-dashboard-revenue: wait for network before Cognito auth (boot-race exit=1, TK-12257)","body":"Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01D7LB6rCwpA7ubJTqYzqXEX"},{"hash":"84dbe50","date":"2026-08-31 01:34:45 -0700","author":"Steve Abrams","subject":"document invoice monitor launchd recovery proof","body":""},{"hash":"cd8f973","date":"2026-08-29 04:04:08 -0700","author":"Steve Abrams","subject":"fix: handle FileMaker 401 no-records gracefully in new-invoice-monitor","body":"FM error 401 \"No records match the request\" is the expected response when\nthere are zero invoices for today (e.g. at 4 AM before orders come in).\nPreviously this caused process.exit(1), triggering cron-fire-canary WARN.\n\nNow wrapped in try/catch — a 401 logs \"0 invoices today\" and exits 0.\nReal errors (auth failures, network, etc.) still propagate and exit 1.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"},{"hash":"b1dedc0","date":"2026-08-27 07:51:15 -0700","author":"Steve Abrams","subject":"Guard fix: Schumacher family (DWSW/SCH) is legit-numeric — never withhold their DW#==mfr (contrarian blocker, TK-10906)","body":"Contrarian caught a live regression: the vendor-blind guard would withhold ~9,053 real\nSchumacher mfrs (DWSW-5005933 mfr 5005933 IS the real code, per Steve's hard rule). Added a\nLEGIT_NUMERIC allowlist (DWSW + SCH prefixes, boundary-matched) checked before isPlaceholderMfr,\nso Schumacher passes through unflagged. Review-queue also skips the Schumacher family by\nprefix AND vendor-name. Tests: 24 pass incl. Schumacher-passthrough + SCHX-boundary + queue-zero.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"66e87e3","date":"2026-08-27 07:47:03 -0700","author":"Steve Abrams","subject":"Add read-only mfr review-queue generator (TK-10906 deliverable 2)","body":"scripts/mfr-review-queue.mjs: for a vendor list, emits data/mfr-review-queue.jsonl of the\nbroken DW#==mfr rows with a best-guess real mfr + source + confidence for staff to confirm\nbefore any (Steve-gated) repair. Sources in order: dw_sku alpha-prefix (Tier-2, high),\nREAD-ONLY FileMaker Mfr# note (medium), else none (needs vendor re-scrape). ZERO writes to\ndw_unified / FileMaker / Shopify. Default Tier-3 set excludes Schumacher + pure-numeric-legit.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"e1069c1","date":"2026-08-27 07:45:29 -0700","author":"Steve Abrams","subject":"Otto importer: guard against DW#==mfr placeholders; read real mfr off existing master; alpha-prefix recovery (TK-10906)","body":"- findExistingMaster now returns the matched master's real spec (masterFields)\n  so an existing master is completed from ITS mfr, never re-flagged 'no mfr number'.\n- resolveWallpaperSource resolution order: existing-master real mfr -> dw_unified\n  candidate (rejected when it equals the DW# numeric tail) -> unambiguous alpha-prefix\n  recovery from dw_sku (Wolf-Gordon DWWG-AM10311 -> AM10311) -> flag (mfr write withheld,\n  invoice line unaffected). Never stamps a DW#==mfr placeholder.\n- scripts/mfr-guard.test.mjs proves HSW-51526-via-master, DW#==mfr-withheld, WG-alpha-recovery.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"2dd6a25","date":"2026-08-19 12:37:11 -0700","author":"steve","subject":"GRS dedup review viewer + client-safe scoping + FM flag/archive path; lint, 0.3.2 (session close)","body":""},{"hash":"0ac2c19","date":"2026-08-19 11:25:44 -0700","author":"steve","subject":"fm-client: dedupe guard on createRecord — block duplicate WALLPAPER masters (Series+JS Pattern)","body":""},{"hash":"0b28984","date":"2026-08-19 11:20:27 -0700","author":"steve","subject":"GRS mfr recovery: FMP->Shopify fill (425 written, reversible) + dedup plan + last-1000 audit","body":""},{"hash":"df2aeae","date":"2026-08-13 14:50:24 -0700","author":"Steve Abrams","subject":"chore: v0.3.1 (session close) — FMPro dashboard push local-refresh + launchd schedule","body":""},{"hash":"c6075ff","date":"2026-08-13 14:42:36 -0700","author":"Steve Abrams","subject":"ads-dashboard FMPro push: 4x/day launchd plist (staged, gated install) + pusher also refreshes local copy — TK-10544 'must keep updated'","body":""},{"hash":"c5cc14a","date":"2026-08-12 09:56:44 -0700","author":"auto-commit-fleet","subject":"auto-data-snapshot: 2026-08-12T09:56:27 (1 data files) — package-lock.json","body":""},{"hash":"a2688ce","date":"2026-08-12 09:53:08 -0700","author":"Steve Abrams","subject":"chore: lint (env-path, dedup keep-guard, test readability), v0.2.6 -> v0.3.0 (session close)","body":""},{"hash":"7d38b74","date":"2026-08-12 09:22:27 -0700","author":"Steve Abrams","subject":"wallpaper: prevent duplicate masters via local Postgres idempotency ledger (FM Cloud index-lag guard) + test","body":""},{"hash":"dcd8c12","date":"2026-08-12 08:54:43 -0700","author":"Steve Abrams","subject":"add dedup-dwpp-32837 script + 539333/539334 restore archives (delete API-blocked by FM 110)","body":""},{"hash":"f48d475","date":"2026-08-12 08:46:44 -0700","author":"Steve Abrams","subject":"wallpaper: resolve private-label SKUs (mfr in metafields) + -Sample lines; add Content/Repeat/tags; DWPP vid=MDCKEN","body":""},{"hash":"ef0b961","date":"2026-08-10 11:11:54 -0700","author":"Steve","subject":"Add GRS/WQ 20% price-bump script + canonical grasscloth importer (name/color mapped, writes via Full View layout)","body":""},{"hash":"dd37d30","date":"2026-08-10 11:04:01 -0700","author":"Steve","subject":"Backfill blank Name/Color of Pattern on WallQuest GRS grasscloth WALLPAPER masters (joins specialty_grasscloths_stage; idempotent)","body":""},{"hash":"d32c199","date":"2026-08-04 11:23:25 -0700","author":"Steve","subject":"wallpaper: prefix-agnostic UNIQUE-number mfr fallback so Shopify patterns always resolve their mfr","body":"Root cause: a private-label pattern is sold on Shopify under one series prefix\n(DWLA-436701) but its mfr number is filed in dw_unified under the real vendor's prefix\n(DWPR-436701) with the same numeric tail — so the exact/normalized-SKU lookup misses and\nthe line gets a blank mfr + a FLAGGED-SKU warning. sourceFor now falls back to matching on\nthe trailing pattern number across shopify_products/vendor_catalog/dw_sku_registry, but\naccepts it ONLY when the number maps to exactly ONE mfr (ambiguous like 46333 -> two mfrs,\nand net-new, still fall through to review — never a guessed/wrong mfr). Read-only resolve.\nProven on 4 unique + 2 ambiguous SKUs (scripts/smoke-mfr-number-fallback.mjs).\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"35cf4d3","date":"2026-08-04 11:09:05 -0700","author":"Steve","subject":"test: smoke-invoice-b — dry-run regression for SKU-on-line + money-on-first (choice B)","body":"Replaces the stale test-real-units.mjs (referenced a removed moneyRecordLines field).\nAsserts DETAIL shows the real SKU (not 'Samples'), all money rides the first line,\nand every other SKU is a $0 stub. Covers the single-sample + multi-sample cases that\nregressed (orders 32759 / 32760).\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"0a0ebba","date":"2026-08-04 11:05:28 -0700","author":"Steve","subject":"invoice(B): real SKU on every line (not 'Samples') + atomic line-write so no empty-shell invoices","body":"- moneyLine: always headline the real SKU on the money line; money still rides the\n  first record only, every other SKU = $0 stub (Steve 2026-08-04, choice B).\n- create loop: write DETAIL/Q/Unit/NET/RETAIL as an immediate post-create step and\n  DELETE the record if that write fails, so an interrupted/racing run can never leave\n  a blank invoice shell (the 103152/103153/103154 defect).\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"ccd79b3","date":"2026-08-03 11:31:00 -0700","author":"Steve","subject":"chore: bump v0.2.6 (session close — TK-10083 fail-closed parser)","body":""},{"hash":"9c6b447","date":"2026-08-03 11:23:39 -0700","author":"Steve Abrams","subject":"auto-save: 2026-08-03T11:23:33 (1 files) — scripts/tk-10083-cleanup.mjs","body":""},{"hash":"64cf597","date":"2026-08-03 10:34:51 -0700","author":"Steve","subject":"TK-10083: fail-closed combo-SKU parser — stop duplicate WALLPAPER master mints","body":"Root cause: combo sku is a stored FM calc (Series & JS Pattern, no separator);\nthe Series|remainder split is NOT derivable from the raw string, so onboarding\nOP-ART-DECO-WAVES mis-split it (Series DWC) and minted duplicate masters\n538697/538698 alongside the genuine 2019 master 240939.\n\nFix (proven vs LIVE FileMaker, read-only):\n- normalizeSku + parseCombo.confident flag; all-alpha / unknown-prefix inputs\n  are confident:false and CANNOT trigger a create (double guard: resolve + create).\n- findExistingMaster now matches via component-field {Series,JS Pattern} OR-find\n  over every dash-boundary split (calc == can't be reconstructed), with a\n  normalized re-check that rejects the wrong-split DWC dupes.\n- Real FM errors fail closed (existence unverifiable -> do not create).\n- dryrun exits non-zero if FM creds absent (required live PASS).\nLive proof: all 3 SKU forms -> master 240939, distinct=1, 0 duplicates.\n\nAdversarially gated by Cody (contrarian): FIX-THEN-DRAFT -> SHIP, MUST-FIX empty.\nDoes NOT activate until the filemaker-mcp MCP restarts; duplicate cleanup of\n538697/538698 is a SEPARATE gated action."},{"hash":"f72e424","date":"2026-08-03 10:23:08 -0700","author":"Steve Abrams","subject":"auto-save: 2026-08-03T10:23:02 (2 files) — lib/wallpaper.js scripts/tk-10083-dryrun.mjs","body":""},{"hash":"e7b1887","date":"2026-08-03 07:21:42 -0700","author":"Steve Abrams","subject":"ads-dashboard revenue: FMPro 30d generator + Mac2->Kamatera push wrapper","body":""},{"hash":"c991f6f","date":"2026-08-03 07:21:41 -0700","author":"Steve Abrams","subject":"auto-save: 2026-08-03T07:21:35 (2 files) — scripts/dashboard-revenue.mjs scripts/push-dashboard-revenue.sh","body":""},{"hash":"92722e0","date":"2026-07-30 09:01:27 -0700","author":"Steve","subject":"chore: v0.2.5 (session close — invoice SKU/VID audit + fix)","body":""},{"hash":"47d22bc","date":"2026-07-30 07:52:13 -0700","author":"Steve","subject":"Fix invoice dup-SKU + wrong-VID at the source (lib/wallpaper.js)","body":"lib/wallpaper.js was the single source of both reported invoice bugs.\n\nWRONG VID — vid was ALWAYS the \"most common vid among 25 same-Series\nrecords\" (vidForSeries), cached process-wide. That pushed a series-level\nguess — or a blank, when the find errored — onto invoice lines instead of\nthe SKU's real vendor code. resolveWallpaperSource now prefers the existing\nWALLPAPER master's OWN stored vid, and only falls back to a hardened\nseries-modal (samples 200, never caches a blank or an error-derived result)\nfor a genuinely-new SKU.\n\nDUPLICATE MASTERS — ensureWallpaper's existence check (1) collapsed EVERY\nFileMaker error into \"not found\" (auth blip/timeout -> duplicate create) —\nthe same bug already fixed in sync-core.js's client dedup but missed here;\nand (2) only matched the current-prefix `combo sku`, so a line renamed\nCork<->DWGL<->DWLG (combo sku is a Series&JS-Pattern CALC) hid the existing\nmaster and minted a duplicate. New findExistingMaster is alias-aware (checks\ncombo sku + comboskuwithdash across renamed prefixes) and error-honest (only\nfmCode 401/102/105/106 = try-next/not-found; any real error means existence\nUNVERIFIED and we refuse to create).\n\nSafe-local: changes only what future runs compute/write; no backfill of\nalready-corrupted masters/VIDs (gated, separate). Read-only smoke test:\nDWKK120156 -> vid KRA from its own master (was a series guess);\nDWSW5003662 (no master) -> hardened series fallback, verified-absent.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"1d1f33b","date":"2026-07-29 20:12:03 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-29T20:11:57 (1 files) — package-lock.json","body":""},{"hash":"26038de","date":"2026-07-29 20:10:55 -0700","author":"Steve Abrams","subject":"chore: v0.2.4 (session close — MTD window fix + truncation guard)","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"541942f","date":"2026-07-28 22:19:58 -0700","author":"Steve Abrams","subject":"Reports bot: correct MTD bucketing comment to match date-only FM field","body":"Contrarian Hole 2, verified: the layout has no entry-timestamp, so MTD buckets\nby the FM Date as entered, not a true Pacific-time instant. Fix the aspirational\n'(Pacific Time)' comment rather than invent timezone logic the data can't support.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"bbd7473","date":"2026-07-28 20:20:36 -0700","author":"Steve Abrams","subject":"Reports bot: visible truncation warning + stop counting refunds as orders","body":"Final DTD verdict FIX-THEN-SHIP (5/5) after contrarian gate. Two live-repro'd fixes:\n- Truncation now posts a degraded '⚠️ DATA TRUNCATED' Slack warning (via FM\n  foundCount>returnedCount) instead of throwing and going dark — silence was\n  indistinguishable from a healthy zero-order day. Ledger is not written on a\n  truncated run so the 24h diff isn't poisoned.\n- Negative refund rows netted the dollar total correctly but were inflating the\n  ORDER COUNT (14-16 rows). Count now excludes refunds; totals still net them out.\n  Footer reworded to match (dropped the misleading 'refunds net out' phrasing).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"073ebdd","date":"2026-07-28 20:11:59 -0700","author":"Steve Abrams","subject":"Harden sales-summary against silent fetch truncation","body":"Same failure class as the MTD window bug: if the query ever returns more\nthan the page cap, MTD would undercount with no warning. Raise cap to 5000\n(~600 records/mo today) and throw loudly if it is ever hit.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"57f06a3","date":"2026-07-28 17:02:02 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-28T17:01:56 (1 files) — scripts/post-mtd-correction.mjs","body":""},{"hash":"dafc8b0","date":"2026-07-28 16:34:00 -0700","author":"Steve Abrams","subject":"Fix DW Reports Bot MTD undercount: query from month-start, not 10-day lookback","body":"MTD query window used the 10-day lookback date as its start, so from the\n11th of each month onward it dropped every invoice before then. July MTD\nread $26,526/80 orders; true value is $67,373/250. Window now = earlier\nof month-start vs lookback.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"d91bd91","date":"2026-07-16 10:54:33 -0700","author":"steve","subject":"add scripts/fetch-clients.js — page entire Clients file to MCC staged dataset","body":""},{"hash":"7210236","date":"2026-07-16 09:56:29 -0700","author":"steve@designerwallcoverings.com","subject":"chore: lint, refactor, v0.2.3 (session close)","body":"- findDuplicates: rename inner accumulator e→entry (was shadowing catch(e))\n- annotate best-effort client-refresh catch\nAuthor: steve@designerwallcoverings.com"},{"hash":"8e0d01f","date":"2026-07-16 09:42:40 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-16T09:42:29 (1 files) — scripts/audit-clients.mjs","body":""},{"hash":"96da496","date":"2026-07-16 09:35:30 -0700","author":"Steve Abrams","subject":"Harden client dedup + add read-only single-order test","body":"- findDuplicates now only swallows FileMaker 401 (no-records) as an empty\n  result; any other find error is surfaced (per-order handler logs it) instead\n  of silently returning no-match, which would double-enter the client\n- scripts/test-one.mjs: read-only (commit:false) single-order test proving the\n  Company/Name split and live dedup without writing to FileMaker\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"de6eb81","date":"2026-07-16 09:24:31 -0700","author":"Steve Abrams","subject":"Fix client double-entry + Company/Name field swap in Shopify→FileMaker sync","body":"- Company field now holds the business name, Name holds the contact person\n  (was reversed: put e.g. 'Denny Wilson' in Company, 'Wilson Construction' in Name)\n- Dedup rewritten as priority waterfall: email → company → client name,\n  searching the correct fields (old code searched Company against the person's\n  name, silently missing real dupes and creating second records)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"65eb72c","date":"2026-07-14 10:28:35 -0700","author":"Steve Abrams","subject":"fix: idempotency guard — skip invoice creation when FileMaker already has one for this Cust PO (order#)","body":"Prevents the systemic double-billing (e.g. #32609). Dedup was local-only (state.processed[]); any re-process minted a duplicate invoice. Now checks FileMaker truth by Cust PO before creating.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"aa0cddd","date":"2026-07-14 10:24:40 -0700","author":"Steve Abrams","subject":"fix: resolve George basic-auth from live fleet cred (was empty 'admin:', 401'd since 2026-07-13 rotation → froze Shopify→FileMaker sync at order #32600)","body":"Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"22d9eff","date":"2026-07-14 08:55:43 -0700","author":"Steve","subject":"Add Greenland cork disco script: stamps Date Discontinued on 15 WALLPAPER masters (recId 536960-536974) 2026-07-14","body":""},{"hash":"9f680a3","date":"2026-07-12 19:19:51 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-12T19:19:48 (1 files) — scripts/bulk-create-greenland-full.mjs","body":""},{"hash":"c542aa6","date":"2026-07-12 08:47:18 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-12T08:47:12 (2 files) — scripts/bulk-series-dwgl-to-dwlg.mjs scripts/bulk-series-dwlg-to-cork.mjs","body":""},{"hash":"c23bb05","date":"2026-07-12 08:17:08 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-12T08:17:05 (1 files) — scripts/bulk-set-dwnumber-fm.mjs","body":""},{"hash":"b7ae2b7","date":"2026-07-12 07:47:02 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-12T07:46:59 (5 files) — scripts/_gl_recon.mjs scripts/_gl_recon2.mjs scripts/_gl_recon3.mjs scripts/bulk-create-greenland-cork.mjs scripts/bulk-series-cork-to-dwgl.mjs","body":""},{"hash":"81207d4","date":"2026-07-10 17:03:51 -0700","author":"Steve Abrams","subject":"chore: v0.2.2 (session close — invoice mfr backfill + flag-on-unresolved)","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"478c8b2","date":"2026-07-10 12:08:17 -0700","author":"Steve Abrams","subject":"invoice: backfill vid+mfr onto 158 pre-hook blank-mfr Otto invoice lines","body":"Steve-approved backfill of the pre-hook backlog (orders Otto invoiced before\nensureWallpaper was wired at e138cce). scripts/backfill-blank-mfr.mjs finds all\nOtto-imported invoice lines with a blank Detail 1 Mfr Number, groups by distinct\nSKU, ensureWallpaper() once per SKU, then direct-writes VID + Detail 1 Mfr\nNumber onto every matching line. --dry-run does a read-only resolve (no FileMaker\nwrites) via the new exported resolveWallpaperSource().\n\nResult: 167 blank-mfr lines -> 146 SKUs resolved, 158 lines updated, 3 SKUs\nFLAGGED and left blank (DWAT65011, XP5, a custom framed-art order — no findable\nmfr, per Steve's flag-don't-guess rule). Remaining blank: 9 (4 flagged-SKU lines\n+ 5 blank-SKU money records) — the correct residue.\n\nlib/wallpaper.js: extract read-only resolveWallpaperSource() out of\nensureWallpaper() so dry-run/preview callers get zero-write resolution.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"f8ad188","date":"2026-07-10 11:37:54 -0700","author":"Steve Abrams","subject":"invoice: flag+notify (not swallow) SKUs with no findable mfr number","body":"createInvoiceForOrder still creates the invoice line when ensureWallpaper\nreturns {ok:false} FLAGGED or throws (money must never be blocked by a catalog\ndata gap), but the outer catch{} no longer silently swallows it. New else/catch\nbranch calls lib/notify.js flagSku():\n  1. console.warn a loud single line (order/invoice/sku/reason).\n  2. idempotent append to data/flagged-skus.jsonl (key=orderId:invoice:sku;\n     stores ts,orderId,orderName,custPO,invoice,sku,dwSku,reason,resolved:false).\n  3. internal Slack (#general) + George email to steve-office — INTERNAL ops\n     signal only, never customer-facing.\nGraft from DTD verdict C: scripts/drain-flagged-skus.mjs reads the queue, groups\nunresolved rows by Cust PO, re-runs ensureWallpaper, writes VID+mfr onto matching\ninvoice lines (same copy-lookup write as ensure-wallpaper-for-order.mjs), and\nmarks rows resolved:true. --dry-run supported.\n\nFixes the silent-swallow that let 102660/102662 (Cust PO 32580) ship blank\nvid/mfr unnoticed. Money/tax/shipping logic untouched.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"4d2ed04","date":"2026-07-10 11:17:40 -0700","author":"Steve Abrams","subject":"wallpaper: resolve mfr# from flat metafields + vendor_catalog/registry tiers","body":"Invoices 102660 (DWBR170698) and 102662 (DWDX220241) had blank vid+mfr#\nbecause their WALLPAPER master records were never created — ensureWallpaper's\nsourceFor() couldn't find a mfr number:\n- DWDX (Designtex): mfr lived in a FLAT metafield (custom.manufacturer_sku\n  = '8405252'), but SP_FIELDS only read the nested {value} shape.\n- DWBR (Malibu private-label): absent from shopify_products entirely\n  (dw_sku null); real mfr 2999-39028 lives in vendor_catalog + dw_sku_registry.\n\nFixes:\n- SP_FIELDS now COALESCEs nested (->'k'->>'value') AND flat (->>'k') metafields\n  for mfr/supplier/pattern/color/width.\n- sourceFor() adds two universal fallback tiers: vendor_catalog (all scraped\n  vendors, joined to dw_sku_registry for a clean supplier name) and\n  dw_sku_registry (mfr+vendor backstop).\n\nRan ensure-wallpaper-for-order.mjs 32580: all 10 lines now carry vid+mfr#."},{"hash":"e138cce","date":"2026-07-10 09:03:11 -0700","author":"Steve Abrams","subject":"invoice: wire WALLPAPER auto-complete into the live daemon path","body":"createInvoiceForOrder now calls ensureWallpaper(sku) per line — auto-creates/\ncompletes the FileMaker WALLPAPER master from dw_unified and direct-writes VID +\nDetail 1 Mfr Number onto each line, so every NEW order's width/name/vid/supplier/\nmfr lookups resolve at creation (no manual redo). Best-effort: wrapped so a\nWALLPAPER-completion failure never breaks invoicing. Verified end-to-end on a\n2-sample order (DWTT70647 + DWKK134979 both fully resolve).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"0c0536f","date":"2026-07-10 08:24:03 -0700","author":"Steve Abrams","subject":"wallpaper: resolve legacy DWLK sku -> canonical DWSW via shopify sku mapping","body":"DWLK is a legacy Schumacher prefix; shopify_products maps old sku\n(DWLK-830880-Sample) -> canonical dw_sku (DWSW-5003662) + real mfr (5003662).\nensureWallpaper sourceFor now tries dw_sku, then legacy sku/variant_sku\n(base-normalized), then connie. Also backfilled connie_our_catalog.mfr_sku for\n912 DWLK rows from this mapping (backup: _bak_connie_dwlk_mfr_20260710; rollback\nlist: _filled_connie_dwlk_mfr_20260710; 50 orphans remain). Refactored\nensure-wallpaper-for-order.mjs to import lib/wallpaper.js. #32574 DWLK830880 now\nresolves mfr 5003662.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"ea6b092","date":"2026-07-10 08:12:20 -0700","author":"Steve Abrams","subject":"add lib/wallpaper.js — importable ensureWallpaper() for pipeline integration (wiring pending)","body":""},{"hash":"01d9bff","date":"2026-07-10 08:07:50 -0700","author":"Steve Abrams","subject":"add ensure-wallpaper-for-order: auto-complete FileMaker WALLPAPER master from dw_unified","body":"When invoicing (esp. samples), a SKU with no width/name/vid/supplier means the\nFileMaker WALLPAPER master record is missing/incomplete → this creates/completes\nit from dw_unified (shopify_products.metafields rich source, connie fallback):\ncreate stored fields on 'Add wallcovering' (Mfr Pattern/JS Pattern/Series/\nSupplier/Width; combo sku is a calc), then Name/Color of Pattern + vid (series-mode\ncode) + JPG Name on '*List Wallpapers - Full View'. Direct-writes invoice VID +\nDetail 1 Mfr Number (copy-lookups) so a redo shows them. SKUs with no mfr number\nare flagged, not created. Redid #32575 (Lee Jofa Taplow x4) + #32574 (DWTT70647;\nDWLK830880 flagged).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"5703973","date":"2026-07-09 23:34:40 -0700","author":"Steve Abrams","subject":"invoice: all money on FIRST invoice, just the SKU on each subsequent","body":"Steve's refined rule (2026-07-09): the money record carries the WHOLE order\ntotal on ONE line = total units x per-unit price (GRAND TOTAL = merch subtotal);\nDETAIL='Samples' for an all-samples order so Q=2 reads '2 Samples @ $4.25 =\n$8.50'. Every subsequent record shows JUST its SKU at $0. Reverts the\nline-2-on-first-record approach. PAID ON ACCOUNT computed exactly (merch+tax+\nshipping) so money is right even when a summarized per-unit line rounds a cent.\nAlso updated live invoice 102622 (order #32571) to the new format.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"f7c8106","date":"2026-07-09 22:08:19 -0700","author":"Steve Abrams","subject":"add watch-real-units-order.mjs — live watcher for next real order's per-line breakdown","body":""},{"hash":"d9b2cbf","date":"2026-07-09 20:29:26 -0700","author":"Steve Abrams","subject":"invoice: show real units + real per-unit price (not lumped Q1=1)","body":"- money record now lists each order line in its own physical row (line 1 =\n  '… 1' fields, line 2 = distinct 'DETAIL 2'/'Q2'/'NET 2' fields) with the\n  REAL quantity + REAL per-unit price; GRAND TOTAL/PAID sum correctly.\n- single-SKU (the common case): line 1 = real qty x real unit price, identical\n  GRAND/PAID/GRAND TOTAL 2 to before -> zero risk. 2-SKU shows both lines;\n  >2-SKU lumps the overflow into line 2 (layout caps at 2 rows).\n- per-SKU stub records stay $0 (real units shown for reference) so dollars are\n  counted once and the monitor posts one card per order.\n- monitor: card total now reads PAID ON ACCOUNT when booked (sums both lines;\n  GRAND TOTAL 2 is a line-1-only calc that undercounts a 2-line order).\n- verified live: single-SKU 2x$44.18=$88.36 and 2-SKU (2x$12.50 + 3x$4.25)=$37.75.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"fb3670b","date":"2026-07-08 06:20:26 -0700","author":"Steve Abrams","subject":"chore: v-bump (session close — per-SKU invoicing fix + dup audit tooling)","body":""},{"hash":"1b0bc8f","date":"2026-07-07 13:00:41 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-07T13:00:27 (1 files) — scripts/watch-next-multisku.mjs","body":""},{"hash":"f705ac9","date":"2026-07-07 09:29:49 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-07T09:29:44 (1 files) — scripts/watch-next-order.mjs","body":""},{"hash":"4dd914e","date":"2026-07-07 09:07:27 -0700","author":"Steve Abrams","subject":"invoicing: fix double-increment so per-SKU invoice numbers are consecutive (no gaps); verified live 3-invoice write test PASS","body":""},{"hash":"bd4cd95","date":"2026-07-07 09:02:29 -0700","author":"Steve Abrams","subject":"invoicing: one record per SKU, only the FIRST carries the dollars (NET/RETAIL=order total, PAID=grand total); remaining SKU records $0 (Steve 2026-07-07). Tax+shipping ride the money record only; $0 records stay off #new-order via GRAND TOTAL 2=0 filter","body":""},{"hash":"f903c3b","date":"2026-07-07 08:57:18 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-07T08:57:11 (2 files) — scripts/tmp-probe-net.mjs scripts/tmp-probe-net2.mjs","body":""},{"hash":"f3f4718","date":"2026-07-07 08:56:39 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-07T08:56:34 (2 files) — scripts/tmp-probe-net.mjs scripts/tmp-probe-net2.mjs","body":""},{"hash":"7b8fa26","date":"2026-07-07 07:22:09 -0700","author":"Steve Abrams","subject":"add read-only dry-run pipeline test: proves 1-invoice-per-order + zero per-SKU dups on latest Shopify orders","body":""},{"hash":"4b94f5f","date":"2026-07-07 07:19:03 -0700","author":"Steve Abrams","subject":"audit: add --csv export (both categories, per-invoice rows)","body":""},{"hash":"6a8406b","date":"2026-07-07 07:15:26 -0700","author":"Steve Abrams","subject":"add read-only dup-invoice audit: group by Cust PO, split double-billing (money) vs $0 tracking clutter","body":""},{"hash":"a19a17d","date":"2026-07-03 08:57:14 -0700","author":"Steve","subject":"invoicing: require client account number before any invoice (client-account-first) + stop creating the duplicate per-SKU 'second invoice'","body":""},{"hash":"83d8494","date":"2026-07-03 08:08:02 -0700","author":"Steve","subject":"chore: macstudio3 migration — reconcile from mac2 + repoint paths (stevestudio2→macstudio3, node/npm/npx→/opt/homebrew)","body":""},{"hash":"1de6266","date":"2026-07-03 04:08:55 -0700","author":"Steve Abrams","subject":"sales summary: report trailing 24h window via seen-ledger diff (Steve 2026-07-03)","body":""},{"hash":"70f934b","date":"2026-07-02 18:33:01 -0700","author":"Steve Abrams","subject":"daily sales summary: move fire time 23:55 -> 16:30 (4:30 PM EOD report to #new-order)","body":"Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"},{"hash":"a4db9ca","date":"2026-07-02 08:08:54 -0700","author":"Steve","subject":"chore: lint, refactor (shared fm-script-helpers), v0.2.0 (session close)","body":""},{"hash":"fec4102","date":"2026-07-02 08:07:28 -0700","author":"Steve Abrams","subject":"add DWTA baxter dedup: archive+delete script for FM dup record 536613","body":""},{"hash":"700b05c","date":"2026-07-02 07:54:09 -0700","author":"Steve","subject":"new-invoice-monitor: label booked sale vs unpaid quote (payment-received gate)","body":""},{"hash":"7bf6a1d","date":"2026-07-02 07:53:32 -0700","author":"Steve","subject":"sales-summary: count BOOKED orders only (payment received); add today's quotes (no payment) line — fixes $92k unpaid-quote inflating MTD","body":""},{"hash":"4255ec9","date":"2026-07-02 07:41:40 -0700","author":"Steve","subject":"sales-to-Slack via FileMaker: EOD daily+MTD summary + per-invoice monitor + launchd timers (reuses fm-client; posts to #new-order)","body":""},{"hash":"5a0d50e","date":"2026-07-02 07:11:48 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-02T07:11:42 (1 files) — scripts/relookup-invoice-102387.mjs","body":""},{"hash":"a231cf0","date":"2026-07-02 07:08:11 -0700","author":"Steve","subject":"add DWKK-120156 master (order 32513/inv 102387) + invoice probes; codify fuzzy-SKU rule","body":""},{"hash":"bcf5e67","date":"2026-07-02 06:21:33 -0700","author":"Steve","subject":"chore: v0.1.1 (session close — Baxter records, invoice 102374 repair, fuzzy-sku-check)","body":""},{"hash":"941cf7a","date":"2026-07-01 15:54:01 -0700","author":"Steve Abrams","subject":"add fuzzy-sku-check.mjs: reusable WALLPAPER SKU existence probe (strips -Sample; combo sku/comboskuwithdash/mfr pattern number/Mfr Pattern; exit 0/1 + JSON)","body":"Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"},{"hash":"10f7a19","date":"2026-07-01 15:51:23 -0700","author":"Steve Abrams","subject":"invoice 102374 repair script: split Otto's collapsed 4-sample line into 4 proper lines (Fracchia / Shopify #32508); totals preserved 17+22=39","body":"Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"},{"hash":"94f5487","date":"2026-07-01 15:45:46 -0700","author":"Steve Abrams","subject":"fix DWTT73434 (recordId 536611) Mfr Pattern AT79129->AT79126 + fill mfr pattern number (AT79129 belongs to 73436 Silver)","body":"Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"},{"hash":"9bad19a","date":"2026-07-01 15:44:05 -0700","author":"Steve Abrams","subject":"create 3 missing DWTT Baxter WALLPAPER masters (73433 Navy/73435 Beige/73436 Silver) — recordIds 536615-17; combo sku + Dw Retail Price are calcs, omitted from write","body":"Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"},{"hash":"2412a37","date":"2026-07-01 14:35:54 -0700","author":"Steve Abrams","subject":"test: dummy client+invoice demo scripts (999999/Testy McTestface); fix script gains RETAIL cols via HDR layout; probe scripts for line-2/tax calc behavior","body":""},{"hash":"7b9b08c","date":"2026-07-01 14:19:17 -0700","author":"Steve Abrams","subject":"fix: fm_find/sort JSON-string coercion (harness stringifies z.any); invoice file live w/ Order Detail default; add invoice-102332 repair script","body":""},{"hash":"1f3eaf8","date":"2026-06-29 13:42:45 -0700","author":"Steve","subject":"remove dead lib/invoice-core.js (orphaned from refactor; lib/invoice.js is the single source of truth)","body":""},{"hash":"f9e757d","date":"2026-06-29 13:38:07 -0700","author":"Steve","subject":"invoice: strip dashes in WC Pattern Number AKA DW SKU; write 'Resale card lookup' (the resale field shown on invoice) so it's no longer blank","body":""},{"hash":"ea51d97","date":"2026-06-29 13:27:12 -0700","author":"Steve","subject":"sync: every order also creates one no-$ per-SKU tracking record with the DW SKU in 'WC Pattern Number AKA DW SKU'; verified 8/8 on order 32476","body":""},{"hash":"707cde7","date":"2026-06-29 13:16:37 -0700","author":"Steve","subject":"invoice: populate 'WC Pattern Number AKA DW SKU' from primary line base SKU","body":"Discovered exact field name (Text[4], repeating, writable) and wired it into\ncreateInvoiceForOrder via the '1-order detail 1 Copy3' layout (shares the\nheader base table). Proven on invoice 102262 -> DWCC-112200."},{"hash":"7525e58","date":"2026-06-29 12:50:45 -0700","author":"Steve","subject":"fix: consolidate multi-item orders to single line (exact total), round cents, WC PATTERN=base pattern, delete API, Slack→#new-order, error-resilient runner; recovered 32476 ($34)","body":""},{"hash":"1894d57","date":"2026-06-29 12:49:14 -0700","author":"Steve Abrams","subject":"auto-save: 2026-06-29T12:49:09 (2 files) — lib/invoice.js src/fm-client.js","body":""},{"hash":"c4dc440","date":"2026-06-29 12:23:21 -0700","author":"Steve","subject":"sync: refresh existing client's contact info from the order before invoicing (update client first, then invoice)","body":""},{"hash":"e2e050f","date":"2026-06-29 12:20:19 -0700","author":"Steve","subject":"sync: every new order now auto-creates client + full invoice (UOM/Otto/FedEx/tax/resale/SKU/WC PATTERN/sold-ship blocks) + posts to Slack #general","body":""},{"hash":"b60dfd5","date":"2026-06-29 12:19:22 -0700","author":"Steve","subject":"sync: every order now auto-creates client + full invoice (Otto/FedEx/tax/resale/SKU/WC-PATTERN/paid) + Slack #general alert; invoice 102262 fully built per Steve specs","body":""},{"hash":"8f367cd","date":"2026-06-29 12:19:06 -0700","author":"Steve Abrams","subject":"auto-save: 2026-06-29T12:19:02 (5 files) — bin/shopify-sync.js lib/sync-core.js lib/invoice-core.js lib/invoice.js lib/notify.js","body":""},{"hash":"cecc780","date":"2026-06-29 11:07:41 -0700","author":"Steve","subject":"shopify->filemaker client sync: info@ trigger, 3-way dedup (email/phone/name), auto-create; created acct 1061931 live; launchd staged (not loaded)","body":""},{"hash":"6470923","date":"2026-06-29 10:39:57 -0700","author":"Steve","subject":"live: connected to FileMaker Cloud — Clients + WALLPAPER reading; invoice pending fmrest; MCP registered","body":""},{"hash":"2719a89","date":"2026-06-29 09:26:02 -0700","author":"Steve","subject":"initial scaffold: FileMaker Cloud MCP server + CLI (read + dry-run-gated writes)","body":""}]}