diff --git a/.claude/commands/syncro.md b/.claude/commands/syncro.md index e47d0a64..8edac1f2 100644 --- a/.claude/commands/syncro.md +++ b/.claude/commands/syncro.md @@ -55,6 +55,10 @@ Create, update, close, comment on, and bill tickets in Syncro PSA. **Always pass `"taxable": false` explicitly on labor line items.** Labor products are configured with `taxable: false` in Syncro, but `add_line_item` via API does not inherit the product's taxable setting — it posts the line item as `taxable: true` regardless. Always include `"taxable": false` in the payload to match the product's configured value. +**`product_category` is a CONTROLLED VOCABULARY — never invent one, never invoice a line blank.** Syncro categories are an admin-defined set; the CATEGORY column on every invoice line drives QuickBooks item mapping and revenue reporting. A blank category = an uncategorized line that breaks both. Two hard rules: +- **Never make up a category string.** Use ONLY a value that already exists in the tenant. To see the live set, enumerate distinct `product_category` across products (do NOT hardcode — it changes): `for p in $(seq 1 N); do curl -s "${BASE}/products?per_page=100&page=$p&api_key=${API_KEY}"; done | jq -r '.products[].product_category' | sort -u`. Known good values include `Labor`, `Software`, `Hardware`, `Product`, `Service`/`Services`, `Subscriptions`, `Contract`, `Discount`, `Exempt Labor`, `Prepay Hours`, `Other`, `Deposit`, `Default`. If none clearly fits, **ASK — do not guess**. +- **Never invoice a line whose product has `product_category: null`.** Before billing, `GET /products/` and check `.product.product_category`. If it is `null`/blank, the product is mis-configured — STOP and flag it (a Windows/OS/software item → `Software`; a physical item → `Hardware`). Do not silently push the line out uncategorized. (Incident 2026-06-30, Cascades #32466/#32474 invoices 67887/67890: "Windows Pro Upgrade" product 23571919 has `product_category: null`, so every billed line showed a blank CATEGORY column. Winter corrected the records; the rule is here so the skill catches it next time.) + **`DELETE /schedules/{id}` destroys the recurring invoice template immediately — no confirmation, no undo.** Past generated invoices are unaffected but future billing stops. The schedule must be recreated manually with all line items if deleted accidentally. NEVER run destructive HTTP method probes against a live customer schedule — use ACG internal account (customer_id 15353550) for any testing. Incident: Russo Law Firm schedule 224454 deleted during API research 2026-05-26; recreated as 509659. **Test articles — always prefix the subject/name with `[TEST]`.** Any ticket, estimate, appointment, or schedule created for testing or API research MUST have its subject or name prefixed with `[TEST]` (e.g. `[TEST] Schedule API research`, `[TEST] Estimate - hardware pricing`). This applies regardless of which customer account is used (including the ACG internal test account, customer_id 15353550). Test records must be instantly distinguishable from real customer work at a glance. If a test article was created without the prefix, PUT the subject to add it before continuing. @@ -670,6 +674,8 @@ JSON - `price_retail` — **must be set explicitly**; Syncro does NOT auto-populate from product rate via API - `taxable` — **must be set explicitly**; always `false` for labor; `true` for taxable hardware +**Pre-flight every line item's category.** `GET /products/` and confirm `.product.product_category` is non-null and is a real existing category (see the controlled-vocabulary rule above). A `null` category means the line will invoice with a blank CATEGORY column — STOP and flag the product instead of billing it. Never substitute an invented category. + **Do NOT remove line items after invoicing.** Leave them on the ticket. **Labor product IDs** — always fetch `price_retail` live, never hardcode: diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md index ba1ad9a8..ce791afb 100644 --- a/.claude/memory/MEMORY.md +++ b/.claude/memory/MEMORY.md @@ -41,6 +41,7 @@ - [INKY outbound breaks DMARC](reference_inky_outbound_breaks_dmarc.md) — Reverse-resolve DMARC rua failing IPs before blaming a sender: ipw-outbound.inkyphishfence.com / us.cloud-sec-av.com = INKY re-injection breaking DKIM+SPF. INKY is in-M365 (connectors+transport rules) per enrolled tenant, but hosting-level (IX/cPanel website) outbound also routes through it independent of M365 enrollment. Fix is INKY-side (outbound DKIM/SPF/ARC), not cPanel DNS. - [Syncro prepay: full-GET only](feedback_syncro_prepay_full_get_only.md) — read prepay_hours ONLY from GET /customers/{id}; the customer search/list endpoint returns null/stale prepay. Never assert "no block" in a billing preview from search data. - [Syncro priority/type format](feedback_syncro_priority_type_format.md) — every ticket create needs a number-prefixed priority ("2 Normal", not bare "Normal" which renders blank) AND a valid problem_type. Winter flagged #32193/#32194. Use the syncro skill's create flow. +- [Syncro line-item category](feedback_syncro_line_item_category.md) — product_category is a controlled vocab: never invent one, never invoice a line whose product has product_category:null (blank CATEGORY breaks QB mapping). Pre-flight GET /products/. Winter fixed Cascades 67887/67890 "Windows Pro Upgrade". - [RMM drive-map Explorer refresh](reference_rmm_drive_map_explorer_refresh.md) — drive mapped via RMM user_session works but the user's running Explorer won't show it until SHChangeNotify(DRIVEADD); also UNC \\ gets eaten in heredoc+jq, build it from [char]92. - [Verify live before acting](feedback_verify_live_before_acting.md) — pull LIVE data (OMSA/iDRAC/live API) before acting on a hardware/infra flag; wiki/logs go stale. Cascades CS-SERVER "degraded RAID" was 9-day-stale (mirror self-recovered, SSDs bought needlessly). Windows can't see RAID member health. - [Windows Pro upgrade billing](feedback_windows_pro_upgrade_billing.md) — ACG MAK key (vault infrastructure/windows-pro-mak, Mike's ACG key) for Home->Pro upgrades; RULE: invoice $99 PER machine activated, name the machine on the line item, bill after success. Each use consumes a MAK count. diff --git a/.claude/memory/feedback_syncro_line_item_category.md b/.claude/memory/feedback_syncro_line_item_category.md new file mode 100644 index 00000000..f1f926d9 --- /dev/null +++ b/.claude/memory/feedback_syncro_line_item_category.md @@ -0,0 +1,15 @@ +--- +name: feedback_syncro_line_item_category +description: Syncro product_category is a controlled vocabulary — never invent one, never invoice a blank-category line +metadata: + type: feedback +--- + +When billing in Syncro, every invoice/ticket line item carries a CATEGORY (`product_category`) that is a **controlled, admin-defined vocabulary** and drives QuickBooks item mapping + revenue reporting. Two hard rules: + +1. **Never make up a category.** Use only values that already exist in the tenant (e.g. `Labor`, `Software`, `Hardware`, `Product`, `Service`/`Services`, `Subscriptions`, `Contract`, `Discount`, `Exempt Labor`, `Prepay Hours`, `Other`, `Deposit`, `Default`). Enumerate the live set from `GET /products` rather than hardcoding. If none fits, ASK — do not guess. +2. **Never invoice a line whose product has `product_category: null`.** Pre-flight with `GET /products/`; a blank category = an uncategorized line. Flag/fix the product (Windows/OS/software → `Software`, physical → `Hardware`) before billing. + +**Why:** A blank or invented category silently breaks downstream accounting and makes humans clean up records. Incident 2026-06-30: Cascades "Windows Pro Upgrade" (product 23571919, `product_category: null`) invoiced on #32466/#32474 (invoices 67887/67890) with blank CATEGORY columns; Winter had to correct them. This keeps recurring as a skill-following gap. + +**How to apply:** In the `/syncro` flow, before `add_line_item`/invoicing, GET the product and verify `product_category` is a real existing value. Rule lives in `.claude/commands/syncro.md` (taxable-rule block + add_line_item pre-flight). Related: [[feedback_syncro_billing]], [[feedback_syncro_preview_mandatory]], [[feedback_syncro_workflow]]. diff --git a/clients/cascades-tucson/docs/migration/share-group-roster-proposed-2026-06-25.md b/clients/cascades-tucson/docs/migration/share-group-roster-proposed-2026-06-25.md index 2dfd4d58..64ec0c37 100644 --- a/clients/cascades-tucson/docs/migration/share-group-roster-proposed-2026-06-25.md +++ b/clients/cascades-tucson/docs/migration/share-group-roster-proposed-2026-06-25.md @@ -28,21 +28,21 @@ ### `SG-Management-RW` → `\\CS-SERVER\Management` **RW:** Meredith Kuhn, Ashley Jensen, Lauren Hasselman, Allison Reibschied, Megan Hiatt, -Crystal Rodriguez, Veronica Feller, Shelby Trozzi, Christina DuPras · ~~Tamra Matthews~~ *(leaving)* +Crystal Rodriguez, Veronica Feller, Shelby Trozzi, Christina DuPras · ~~Tamra Matthews~~ *(OFFBOARDED 2026-06-30)* **RO (read-only):** Lois Lane, Christine Nyanzunda **[OPEN]**, Susan Hicks **[OPEN]**, John Trozzi, Lupe Sanchez **[OPEN]** > No `SG-Management-RO` group exists — RO members need either a new RO group or a direct NTFS read ACL. **Decision needed.** ### `SG-Sales-RW` → `\\CS-SERVER\Sales` / `SalesDept` -**RW:** Meredith Kuhn, Ashley Jensen, Lauren Hasselman, Megan Hiatt, Crystal Rodriguez · ~~Tamra Matthews~~ *(leaving)* +**RW:** Meredith Kuhn, Ashley Jensen, Lauren Hasselman, Megan Hiatt, Crystal Rodriguez · ~~Tamra Matthews~~ *(OFFBOARDED 2026-06-30)* **RO (`SG-Sales-RO`):** Shelby Trozzi > **Two shares exist — `Sales` and `SalesDept`.** SalesDept holds the real history (2014–2026 reports, marketing). Confirm which the group maps to (or both), and what `Sales` is for. ### `SG-ALdocs-RW` → `\\CS-SERVER\ALdocs` *(share + group NOT created yet)* -**RW:** Lois Lane, Karen Rossini, Meredith Kuhn, Ashley Jensen, Megan Hiatt, Crystal Rodriguez · ~~Tamra Matthews~~ *(leaving)* +**RW:** Lois Lane, Karen Rossini, Meredith Kuhn, Ashley Jensen, Megan Hiatt, Crystal Rodriguez · ~~Tamra Matthews~~ *(OFFBOARDED 2026-06-30)* > Must create the share + `SG-ALdocs-RW` group before assigning. Nurses (Lois/Karen) + Exec tier + Sales team. ### `SG-WebDocs-RW` → `\\CS-SERVER\WebDocs` *(share + group NOT created yet)* -**RW:** Megan Hiatt, Crystal Rodriguez, Meredith Kuhn, Ashley Jensen · ~~Tamra Matthews~~ *(leaving)* +**RW:** Megan Hiatt, Crystal Rodriguez, Meredith Kuhn, Ashley Jensen · ~~Tamra Matthews~~ *(OFFBOARDED 2026-06-30)* > Must create the share + `SG-WebDocs-RW` group. Distinct from the retired DSM `web` station. ### `SG-Server-RW` → `\\CS-SERVER\Server` diff --git a/clients/cascades-tucson/docs/printer-gpo-map.md b/clients/cascades-tucson/docs/printer-gpo-map.md new file mode 100644 index 00000000..958d31b3 --- /dev/null +++ b/clients/cascades-tucson/docs/printer-gpo-map.md @@ -0,0 +1,43 @@ +# Cascades — Printer / VLAN 20 Migration Map (GPO planning) + +Living reference for the printer migration onto Staff VLAN 20 (10.0.20.0/24) and the +eventual **printer GPO** build. Update as machines/printers migrate. Started 2026-06-30 (Howard). + +## How the GPO needs to be built (two layers) + +1. **Point-and-Print policy (computer GPO, fleet-wide)** — REQUIRED prerequisite or any + GPO-pushed printer fails (PrintService event 513 / error 0xBCB) for standard users. + Set on `HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Printers`: + `RestrictDriverInstallationToAdministrators=0`; subkey `PointAndPrint`: + `Restricted=1, TrustedServers=1, ServerList=CS-SERVER, InForest=0,` + `NoWarningNoElevationOnInstall=1, UpdatePromptSettings=2` (scopes silent driver install + to CS-SERVER only). Caregiver machines already have this — that's why their printer GPO + works. Set manually 2026-06-30 on DESKTOP-ROK7VNM + DESKTOP-DLTAGOI; needs to be a GPO. +2. **Printer deployment** — GPP Printers / Deployed Printers mapping `\\CS-SERVER\` + to the right users/OU/room. Existing GPO `CSC - Life Enrichment Printers` likely still + points at OLD share names — repoint. `CSC - Printer Deployment` is disabled/empty (do not use). + +**Driver trap:** Canon MF741/743 are **UFR II only** — PCL6 produces Error #822 (spools, never +prints). Any GPO/share for those Canons MUST use `Canon Generic Plus UFR II V250` (INF cnlb0ma64.inf). + +## Printer / machine map + +| Printer (share / name) | Model | IP (VLAN20) | Driver | Machine | User(s) | Domain? | Status / GPO action | +|---|---|---|---|---|---|---|---| +| `\\CS-SERVER\FrontDesk` | Epson ET-5800 | 10.0.20.221 | EPSON ET-5800 Series | RECEPTIONIST-PC (frontdesk box, S/N MJ0KQHNP) | frontdesk | Domain (cascades.local) | DONE — share repointed, mapped, default. Add to GPO. | +| `\\CS-SERVER\LifeEnrichment` | Canon MF741CDW | 10.0.20.94 | Canon Generic Plus UFR II V250 | DESKTOP-DLTAGOI; DESKTOP-ROK7VNM | sharon.edwards; susan.hicks | Domain | DONE — UFR II driver fixed, mapped (not default). **Repoint `CSC - Life Enrichment Printers` GPO from old `1F-132-RecRoom-Canon` to `LifeEnrichment`.** | +| Dining Room Manager - Canon MF743CDW | Canon MF743CDW (MF741C/743C) | 10.0.20.228 | Canon Generic Plus UFR II V250 | DESKTOP-MD6UQI3 | dining manager (Alyssa) | **WORKGROUP — not domain-joined yet** | DONE as direct-IP (local) printer, default. **TODO: when DESKTOP-MD6UQI3 is domain-joined, add this printer to the GPO and map it to Alyssa's domain account.** | +| Chef Office - Brother MFC-9330CDW | Brother MFC-9330CDW | 10.0.20.236 | Brother MFC-9330CDW Printer | CHEF-PC | chef (all users) | **WORKGROUP — not domain-joined** | DONE as direct-IP (machine-wide / all users), default. **TODO: add to GPO + map to chef's domain account once CHEF-PC is domain-joined.** This is the Chef's printer in the Chef's office (distinct from the kitchen printer with the chefs). | +| Memory Care Front Desk - Epson ET-5800 (`\\CS-SERVER\MCReception`) | Epson ET-5800 | 10.0.20.78 | EPSON ET-5800 Series | MEMRECEPT-PC | memfrtdesk (+ other MemCare front-desk staff) | **WORKGROUP — not domain-joined** | Already shared on CS-SERVER as `MCReception`. Machine currently has the Epson via OLD vendor/WSD ports (`EP833571:ET-5800 SERIES` + WSD), NOT the static .78 — needs direct-IP to 10.0.20.78. **Mark for GPO: MemCare front-desk users (mostly the memfrtdesk machine). TODO: add to GPO + map to domain accounts once domain-joined.** | +| Memory Care MedTech - Brother MFC-L8900CDW (`\\CS-SERVER\MCMedTech`) | Brother MFC-L8900CDW | 10.0.20.74 | Brother MFC-L8900CDW series | RECEPTIONIST-PC (memcare box → **rename to MEMCARE-***); DESKTOP-LPOPV30 | memory care; karen rossini | **WORKGROUP** | DONE direct-IP machine-wide on both; old 192.168.2.53 + WSD connections removed; LPOPV30 default = new printer (was the old one); memcare box default unchanged (iR-ADV). MedTech room in Memory Care. **TODO: GPO + domain accounts once joined.** | +| `\\CS-SERVER\Kitchen` | Canon MF743CDW | 192.168.3.232 (pre-migration) | (verify) | (kitchen) | chefs | — | Kitchen printer (with the chefs). Not yet migrated to VLAN20 this round. | + +## Machine rename TODO +- **RECEPTIONIST-PC** (the Memory Care box, "memory care" user, S/N MJ0KQH4R, agent 57f19e17) shares its hostname with the front-desk RECEPTIONIST-PC box — too hard to tell apart in the agent list. **Rename to a unique `MEMCARE-*` name** (pending Howard's chosen name + reboot). The OTHER RECEPTIONIST-PC (frontdesk user, S/N MJ0KQHNP) is the actual front desk. + +## Notes +- Workgroup machines (DESKTOP-MD6UQI3, CHEF-PC) get **direct-IP local printers** for now + (no domain auth / no point-and-print needed). Once domain-joined, switch them to the + GPO-deployed `\\CS-SERVER\` model and map to the domain account. +- Detailed how-to + pfSense routing fix: `.claude/memory/project_cascades_vlan20_migration_routing.md` + and session log `clients/cascades-tucson/session-logs/2026-06/2026-06-30-howard-vlan20-printer-migration.md`. diff --git a/clients/cascades-tucson/docs/security/offboarding-2026-06-30-tamra-matthews.md b/clients/cascades-tucson/docs/security/offboarding-2026-06-30-tamra-matthews.md new file mode 100644 index 00000000..3f0bee2c --- /dev/null +++ b/clients/cascades-tucson/docs/security/offboarding-2026-06-30-tamra-matthews.md @@ -0,0 +1,66 @@ +# Offboarding Record — Tamra Matthews + +**Date:** 2026-06-30 · **Performed by:** Howard Enos (ClaudeTools session) · **Authorized by:** Howard Enos +**Separation type:** Voluntary (left Cascades, June 2026) · **Role:** Move-In Coordinator (Marketing / Sales) +**Runbook:** `docs/security/termination-procedures.md` + +## Identities handled +- **M365 (cloud-only):** `tamra.matthews@cascadestucson.com` — id `2d9cf0d1-2b0b-424e-9cd1-91eaac408837` + (`onPremisesSyncEnabled=null` — cloud-mastered object, NOT Entra-synced) +- **On-prem AD:** `Tamra.Matthews` (was `OU=Marketing,OU=Departments,DC=cascades,DC=local` — separate + object, NOT Entra-synced; renamed from Tamra.Johnson 2026-04-13) +- **ALIS:** Not handled this session — Move-In Coordinator role; confirm/disable ALIS staff profile if + she had clinical/ALIS access (open follow-up below). + +## Actions completed (M365) +| # | Action | Result | +|---|---|---| +| 1 | Revoke active sign-in sessions | HTTP 200 | +| 2 | Block sign-in (`accountEnabled=false`) | confirmed false | +| 3 | Reset password (random, vaulted) | OK — no elevation needed (holds no admin role, **no PAA stranding**) | +| 4 | Convert mailbox → **SharedMailbox** | confirmed (`RecipientTypeDetails=SharedMailbox`) | +| 5 | Grant **FullAccess** to Crystal Rodriguez, Megan Hiatt, Meredith Kuhn, Ashley Jensen | all 4 confirmed FullAccess | +| 6 | Hide from GAL (`HiddenFromAddressListsEnabled=true`) | confirmed | +| 7 | Remove **O365 Business Standard** license (`f245ecc8…`) | confirmed 0 licenses — **frees 1 seat** | +| 8 | Remove from groups `Sales`, `All Cascades`, `SG-SSPR-Eligible` | HTTP 204 ×3 | + +### AutoMapping caveat (delegate auto-attach) +- **Crystal Rodriguez + Ashley Jensen** — added with `AutoMapping:$true`; the shared mailbox + **auto-attaches** in their Outlook. +- **Megan Hiatt + Meredith Kuhn** — `AutoMapping:$true` would not persist via the ComputerGuru + Exchange Operator app: the cmdlet echoed success but the grant rolled back (a failed + `msExchDelegateListLink` write aborts the whole `Add-MailboxPermission` transaction). Re-added with + `AutoMapping:$false`, which **persisted**. They have full access but the box does **not** + auto-attach — one-time manual add in Outlook (File → Open & Export → Other User's Folder, or add + `tamra.matthews@cascadestucson.com` as an additional mailbox), **or** flip auto-mapping from an + interactive EXO PowerShell session later (`Add-MailboxPermission … -AutoMapping $true`). + +## Actions completed (on-prem AD, CS-SERVER) +- `Set-ADAccountPassword -Reset` (random, vaulted) +- `Disable-ADAccount Tamra.Matthews` → Enabled=False +- Group memberships: already 0 (no explicit groups) — nothing to strip +- `Move-ADObject` → `CN=Tamra Matthews,OU=Excluded-From-Sync,DC=cascades,DC=local` + +## Retention / compliance +- **No Litigation Hold applied.** Decision (Howard, 2026-06-30): although Move-In Coordinator is a + resident-intake / PHI-adjacent role, Howard authorized the same posture as the Alma Montt + offboarding — **shared-mailbox conversion + zero-deletion** (no mailbox deleted), license removed to + free the seat. Mailbox is preserved under default MRM retention; revisit if her PHI-access + determination or a legal hold changes. Litigation Hold remains available later (tenant has Business + Premium / Exchange Plan 2) if the determination changes. +- Passwords stored for emergency recovery/audit only: vault `clients/cascades-tucson/tamra-matthews` + (`m365_password`, `ad_password`). **Do NOT re-enable without authorization.** + +## Open follow-ups +- [ ] **ALIS staff profile** — confirm whether Tamra had ALIS access; if so, disable the staff record + (audit record stays). Her M365 SSO tie is already severed by the sign-in block. +- [ ] **AutoMapping for Megan Hiatt + Meredith Kuhn** — either they add the shared mailbox manually, + or flip `-AutoMapping $true` from an interactive EXO session (the app-based REST path won't + persist it for these two). Crystal + Ashley already auto-attach. +- [ ] **Reconcile** Tamra out of forward-looking plans/rosters. Share roster + `docs/migration/share-group-roster-proposed-2026-06-25.md` already shows her struck-through + *(leaving)*; `docs/servers/active-directory.md` OU=Marketing row updated to disabled + + Excluded-From-Sync. April/May questionnaires, CSVs, and the staff roster + `reports/cascades-staff-2026-04-22.csv` left as historical record. +- [ ] **Note (separate):** Megan Hiatt's M365 account carries a `CREDENTIAL_STUFFING_ACTIVE` flag in + the April tenant inventory — unrelated to this offboarding, but worth a breach check. diff --git a/clients/cascades-tucson/docs/servers/active-directory.md b/clients/cascades-tucson/docs/servers/active-directory.md index 8b2b8643..bea797b3 100644 --- a/clients/cascades-tucson/docs/servers/active-directory.md +++ b/clients/cascades-tucson/docs/servers/active-directory.md @@ -75,7 +75,7 @@ |---------------|------|----------|-------| | Megan.Hiatt | Megan Hiatt | Sales Director | M365: Sales@ | | Crystal.Rodriguez | Crystal Rodriguez | Sales Associate | PC: CRYSTAL-PC. M365: Sales@ | -| Tamra.Matthews | Tamra Matthews | Move-In Coordinator | Renamed from Tamra.Johnson (2026-04-13) | +| ~~Tamra.Matthews~~ | ~~Tamra Matthews~~ | ~~Move-In Coordinator~~ | **OFFBOARDED 2026-06-30** — disabled, moved to `OU=Excluded-From-Sync`. See `docs/security/offboarding-2026-06-30-tamra-matthews.md` | **OU=Resident Services** | SamAccountName | Name | Position | Notes | diff --git a/errorlog.md b/errorlog.md index c43808d4..04cc5a7d 100644 --- a/errorlog.md +++ b/errorlog.md @@ -17,6 +17,10 @@ Categories (the `[type]` tag): _(none)_ = skill/command execution failure · +2026-06-30 | Howard-Home | remediation-tool/exchange-op | [friction] Add-MailboxPermission -AutoMapping $true silently rolled back the FullAccess grant for 2 of 4 delegates (cmdlet echoed [FullAccess] success but Get-MailboxPermission showed NONE); a failed msExchDelegateListLink write aborts the whole Add transaction. Fix: re-add with -AutoMapping $false (FullAccess then persists); set automapping separately/interactively if auto-attach is required. [ctx: tenant=cascadestucson.com mailbox=tamra.matthews app=ComputerGuru-Exchange-Operator] + +2026-06-30 | Howard-Home | /syncro | [correction] invoiced 'Windows Pro Upgrade' line items (Cascades 67887/67890) with blank CATEGORY; product_category was null and I billed it anyway — correct is to pre-flight GET /products/, never invoice a null/blank category, and never invent one (use existing set e.g. Software) [ctx: ref=feedback_syncro_line_item_category invoices=67887,67890 product=23571919] + 2026-06-30 | Howard-Home | rmm/printer-map | [friction] Add-Printer -ConnectionName in user_session = HRESULT 0x800702e4 ELEVATION_REQUIRED (Point-and-Print); agent watchdog times out on the interactive UAC prompt. Use WScript.Network.AddWindowsPrinterConnection + have a user at console approve, or pre-stage driver/connection as SYSTEM 2026-06-30 | Howard-Home | rmm/powershell | [friction] literal UNC backslashes (hostshare) in a jq-built PS payload got mangled to a single backslash -> Add-Printer 'invalid name'; fix: build UNC with [char]92 instead of literal backslashes [ctx: ref=feedback_windows_quote_stripping host=RECEPTIONIST-PC]