chore(memory): consolidate scattered feedback/project/reference files
Compressed memory store 104 -> 71 files via four passes: - Syncro: 19 scattered feedback_syncro_* files merged into 3 rule files (api/billing/workflow) + an on-demand feedback_syncro_history.md for incident detail, quotes, and tech/product ID tables. - Four near-duplicate merges: Howard paste-safety, Pluto build server, Howard backend deferral, IX server access (ssh+tailscale). - Per-cluster rule/state/history split applied to GuruConnect (2->1), Dataforth (3->2), Cascades (7->3), GuruRMM (13->3). - New reference_resource_map.md: single auto-loaded cheatsheet for "do I have access to X and how do I connect from this machine?" - MEMORY.md rewritten to match the new layout. Health: broken backlinks 8->7, overlap clusters 12->5, orphans 17->0.
This commit is contained in:
@@ -1,16 +1,104 @@
|
||||
---
|
||||
name: Syncro - preview all comments before posting
|
||||
description: Every Syncro comment must be previewed and confirmed before posting, no exceptions
|
||||
type: feedback
|
||||
originSessionId: 4ccedc24-2f39-497e-9a89-ca09aba03982
|
||||
name: Syncro billing rules — products, rates, taxes, attribution, emergency, warranty
|
||||
description: How to bill a Syncro ticket correctly — fetch live rates, use real product names, pick the right labor type for the delivery channel, set taxable=false on labor (AZ), warranty product 1049360, emergency ×1.5 (branch by prepay_hours), preserve original tech's user_id on corrections, estimate hardware uses product 32252.
|
||||
metadata:
|
||||
type: feedback
|
||||
---
|
||||
**Rule:** ALWAYS show the full comment text to Mike and wait for explicit confirmation before posting ANY comment to a Syncro ticket. No exceptions — not for billing comments, not for resolution notes, not for client-facing messages, not for internal notes.
|
||||
|
||||
**Why:** Mike has called this out multiple times. Comments posted without preview have had wrong tone, missing context, or incorrect content. Once posted they can't be deleted via API and require manual GUI cleanup.
|
||||
Rules only. Incident detail, verbatim Mike quotes, ticket numbers, dates, the tech user_id table, and the labor-product table all live in [[feedback_syncro_history]] — read on-demand when judging an edge case. API mechanics: [[feedback_syncro_api]]. Workflow: [[feedback_syncro_workflow]].
|
||||
|
||||
**How to apply:**
|
||||
- Draft the comment, show it in chat as a formatted block
|
||||
- Say "Good to post?" or similar and wait for a yes
|
||||
- Only then call POST /tickets/{id}/comment
|
||||
- This applies to every single comment regardless of how routine it seems
|
||||
- Also always ask for minutes + labor type before logging any time entry — never assume a default
|
||||
`.claude/commands/syncro.md` is the authoritative live product table.
|
||||
|
||||
---
|
||||
|
||||
## 1. Bill with `add_line_item` directly — never the timer workflow
|
||||
|
||||
`POST /tickets/{id}/add_line_item` is the billing path for ALL work (labor, warranty, internal, hardware). The timer workflow (`timer_entry → charge_timer_entry`) is **not used**.
|
||||
|
||||
**Payload:** `product_id`, `quantity` (decimal hours), `price_retail` (fetched live), `name` (the product's REAL name — see §3), `description` (free-text work narrative), `taxable: false` for labor.
|
||||
|
||||
---
|
||||
|
||||
## 2. ALWAYS fetch the rate live
|
||||
|
||||
Fetch `price_retail` from `GET /products/<id>` → `.product.price_retail` before billing. The product-ID table in `.claude/commands/syncro.md` is valid for IDs but **not** dollar amounts — rates vary by contract and change.
|
||||
|
||||
```bash
|
||||
RATE=$(curl -s "$BASE/products/$PRODUCT_ID?api_key=$API_KEY" | jq -r '.product.price_retail')
|
||||
```
|
||||
|
||||
Use `$RATE` for drafts, the user preview, and the `price_retail` field.
|
||||
|
||||
---
|
||||
|
||||
## 3. NEVER invent or rename labor line items
|
||||
|
||||
Every labor line MUST be an existing Syncro product, billed under its **REAL name** (from `GET /products/<id>` → `.product.name`, verbatim). Work-specific narrative goes in `description`, never the `name`.
|
||||
|
||||
**Why:** invented names break the Syncro → QuickBooks sync. QB maps each labor line to an existing item; a fabricated name has no QB match and messes up the accounting. If no existing product fits, **STOP and ask Mike** — never invent one.
|
||||
|
||||
Product table lives in [[feedback_syncro_history]] (and `.claude/commands/syncro.md`).
|
||||
|
||||
---
|
||||
|
||||
## 4. Labor type must match delivery channel — never "Prepaid project labor"
|
||||
|
||||
Pick the labor product matching how work was delivered: **remote** (most common), **onsite**, **in-shop**, or **web**. Resolve `product_id` via `GET /products?search=remote+labor` etc.
|
||||
|
||||
**Never default to "Prepaid project labor"** — it is **exempt** and does NOT consume hours from a customer's prepaid block. Block accounting silently drifts.
|
||||
|
||||
**Verify:** after billing a prepay-block customer, confirm the block balance dropped by the expected hours. If it didn't, the labor type was wrong.
|
||||
|
||||
---
|
||||
|
||||
## 5. Labor is NEVER taxable in Arizona
|
||||
|
||||
Pass `"taxable": false` explicitly on every labor line. The product config has `taxable: false`, but `add_line_item` does **not** inherit it — posts as `taxable: true` regardless. Applies to remote, onsite, in-shop, emergency, warranty, prepaid.
|
||||
|
||||
---
|
||||
|
||||
## 6. Warranty / no-charge → product `1049360`, never patch the price
|
||||
|
||||
Warranty work uses `product_id: 1049360` ("Labor- Warranty work", $0/hr, non-taxable). The line generates at $0 from `price_retail × quantity` — no need to flag or patch anything.
|
||||
|
||||
**Do NOT** pick a regular labor product and try to neutralize it with `billable: false` or by patching `price_retail` to `0`. **Prices are set by selecting the correct product.** If you reach for `update_line_item` to drop a price, that's the signal to back up and pick a different `product_id`.
|
||||
|
||||
The only legitimate `update_line_item price_retail` use is the Syncro auto-gen-zero recovery case (auto-line came in at $0 instead of the product's rate).
|
||||
|
||||
---
|
||||
|
||||
## 7. Emergency / after-hours — ×1.5 applied ONCE; branch by `prepay_hours`
|
||||
|
||||
`GET /customers/<id>` and read `prepay_hours` BEFORE adding any emergency line. Emergency = **time-and-a-half, applied ONCE**. Never bill a separate regular line + emergency line for the same hours.
|
||||
|
||||
**No prepaid block (`prepay_hours == 0`):**
|
||||
- product `26184`, quantity = **actual hours** (do NOT also ×1.5 the quantity)
|
||||
- `price_retail` by delivery channel (the 1.5× lives in the dollars):
|
||||
- Onsite emergency = `$262.50` (175 × 1.5; 26184's default).
|
||||
- Remote / In-Shop emergency = `$225` (150 × 1.5) → override `price_retail` to `225`.
|
||||
|
||||
**Prepaid block (`prepay_hours > 0`):**
|
||||
- product `26184`, quantity = **actual hours × 1.5** (premium goes in the QUANTITY)
|
||||
- Delivery channel / dollar rate is irrelevant; prepaid blocks debit by quantity. Invoice nets to $0; block debits hrs×1.5.
|
||||
- e.g. 1.5 emergency hrs → `26184` @ `2.25`.
|
||||
|
||||
Always set `price_retail` explicitly — the rate doesn't auto-populate and the line posts $0 if omitted. Verify after: `.invoice.total` (non-prepaid) or block decrement (prepaid).
|
||||
|
||||
---
|
||||
|
||||
## 8. Corrections preserve the ORIGINAL tech's attribution; ticket ownership is sticky
|
||||
|
||||
**Labor lines:** when fixing a wrong line, preserve the **original tech's** `user_id` so their commission isn't lost.
|
||||
- **Prefer `update_line_item` in place** — it preserves `user_id`.
|
||||
- **If you must remove + re-add:** the new line defaults to the **API-key owner's** `user_id`. Explicitly set `user_id` to the original tech on `add_line_item`, or PUT-fix it afterward.
|
||||
- Determine the original tech from `.ticket.user_id` and the line's `.user_id` BEFORE correcting; verify after.
|
||||
|
||||
**Ticket ownership:** adding notes or labor does **NOT** change `.ticket.user_id`. Multiple techs routinely work the same ticket. Only change ticket ownership when explicitly asked. Status PUTs send only `status`; line edits use `update_line_item`; neither touches `user_id`.
|
||||
|
||||
Tech user_id table → [[feedback_syncro_history]].
|
||||
|
||||
---
|
||||
|
||||
## 9. Estimate hardware → product `32252`
|
||||
|
||||
All hardware on estimates uses one generic product: `product_id: 32252` ("Hardware", `price_retail: 0.0`). Differentiate via `name` ("Dell OptiPlex 7010") and `price_retail` (actual cost). Hardware is typically `taxable: true`. Never look up individual hardware product IDs — there's only one.
|
||||
|
||||
Reference in New Issue
Block a user