Files
claudetools/.claude/memory/feedback_syncro_history.md
Mike Swanson 0c000109dc 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.
2026-06-01 16:25:45 -07:00

12 KiB
Raw Blame History

name, description, metadata
name description metadata
Syncro lessons — incidents, quotes, and the events behind the rules Detail and incident archive backing the Syncro feedback rules. Read this when you need to judge an edge case, verify a rule is still right, or understand WHY a rule exists. Tickets, dates, verbatim quotes, and tech user_id table live here so the main rule files can stay terse. Companion to feedback_syncro_api / billing / workflow.
type
feedback

This file is the incident archive behind feedback_syncro_api, feedback_syncro_billing, and feedback_syncro_workflow. Those three files state the rules; this one preserves the events, quotes, and specifics so you can judge edge cases and verify a rule still applies. Read on-demand, not at session start.


Tech user_id table

Used by feedback_syncro_billing Section "Corrections preserve attribution".

Tech user_id
Mike 1735
Howard 1750
Winter 1737
Rob 1760

Labor / hardware product IDs (verify rates live)

Used by feedback_syncro_billing. Rates change — always GET /products/<id> for .product.price_retail. The product IDs are stable; the table in .claude/commands/syncro.md is authoritative for the live list.

product_id name role typical rate
1190473 Labor - Remote Business remote (most common) $150
26118 Labor - Onsite Business onsite $175
573881 Labor - In-Shop Business in-shop (check live)
26184 Labor - Emergency or After Hours Business emergency/after-hours $262.50
1049360 Labor- Warranty work warranty / no-charge $0
32252 Hardware generic estimate hardware $0 base

Incidents — by ticket / date

#32333 (2026-05-28) — Content-Type missing

  • Posted a comment without -H "Content-Type: application/json". Syncro returned a 400 HTML error page twice before the fix. The HTML response looks like a hard failure but it's just a missing header.
  • Lessonfeedback_syncro_api Section "Content-Type required".

#32332 (Cascades — Chris Knight new-user setup, 2026-05-27) — multi-lesson

This one ticket informed several rules at once:

  1. Fabricated labor names. Product 26118 ("Labor - Onsite Business") was billed on two lines as "Emergency Call Setup" and "Onsite Computer Setup" — both invented. Breaks the Syncro → QuickBooks sync because QB maps each labor line to an existing item.

    • Mike's exact words: "You CANNOT make up labor items. You MUST use existing items only for all labor items… the labor item must use the ones that already exist in syncro (otherwise it messes things up in Quickbooks)."
    • Lessonfeedback_syncro_billing "Never invent labor names".
  2. Prepaid emergency billed as a split made-up onsite/emergency. 1.5 hours of emergency on a prepaid customer (Cascades has 27h block). Howard had split it into fabricated onsite + emergency lines. Correct shape: ONE line on 26184 at quantity 2.25 (hrs×1.5).

    • This also confirmed the 2026-05-27 update: prepaid emergency now uses 26184 at ×1.5 quantity, REPLACING the older "prepaid → onsite 26118 at ×1.5" rule. 26184 labels the line correctly as emergency and maps right in QuickBooks.
    • Lessonfeedback_syncro_billing "Emergency labor".
  3. Correction via Mike's API key would have stolen Howard's commission. The original line was Howard's (user_id=1750). Correcting via update_line_item preserved user_id=1750. A remove + re-add would have defaulted the new line to Mike's 1735 (the API-key owner).

  4. Ticket ownership is sticky. Mike confirmed (also 2026-05-27): adding notes or labor to a ticket does NOT change the ticket owner. Multiple techs routinely work the same ticket. Only change ticket ownership when explicitly asked.

#32312 (Winter, 2026-05-21) — wrong day of week

  • "Saturday" was computed as May 24, which is actually a Sunday. The appointment landed on the wrong day and didn't appear where Winter expected it on the calendar.
  • Lessonfeedback_syncro_workflow "Verify appointment day-of-week". Always display Day YYYY-MM-DD (e.g., "Saturday 2026-05-23") in the preview, never the numeric date alone.

2026-05-21 (Mike) — timer workflow superseded

  • Mike confirmed the timer workflow (timer_entry → charge_timer_entry) is not used. The previous rule requiring timers was wrong and caused repeated billing failures (wrong product on the timer, product_id silently ignored by charge_timer_entry).
  • Lessonfeedback_syncro_billing "Bill with add_line_item directly". The timer-response-shape rule in feedback_syncro_api is now historical / reference-only.

#32304 (Cascades, 2026-05-20) — hardcoded rates wrong

  • Hardcoded rate table in the skill had Labor - Remote Business at $150/hr. The correct rate was $175/hr. Rates vary by contract and change over time.
  • Lessonfeedback_syncro_billing "Fetch rates live".

Kittle Design #32263 (Howard, 2026-05-08) — appointment owner

  • Howard created an 11:30 AM onsite to set up Joshua. I auto-added Howard's user_id to the appointment's user_ids array without confirming whether Howard was the owner or just an attendee.
  • Howard's direction: "when setting up an appointment confirm the appointment owner — don't just add additional attendees."
  • Lessonfeedback_syncro_workflow "Ask the appointment owner explicitly".

#32225 (Sombra Residential, 2026-05-06) — warranty hack

  • Picked product 1190473 (Labor - Remote Business, $150/hr) for a warranty cleanup, set billable: false on the (then-used) timer, and assumed the timer flag would zero the line. Syncro silently overrode billable: false and the line came in at $75. I patched price_retail to $0 to "fix" it.
  • Howard caught it: warranty has its own product in the dropdown, and patching dollar amounts is never how this is solved. Use 1049360.
  • The earlier guidance in .claude/commands/syncro.md ("Warranty → use closest labor product with billable=false") was wrong; warranty has its own product like Onsite, Remote, Emergency.
  • Lessonfeedback_syncro_billing "Warranty → product 1049360, never patch the price".

#32253 (Cascades, 2026-05-05) — duplicate timers from wrong jq path (HISTORICAL)

  • The skill doc used TIMER_ID=$(jq -r '.timer.id // .timer_entry.id') on a flat response → resolved to null. A null TIMER_ID broke charge_timer_entry ("Not found"). The script retried and created a duplicate timer.
  • Created two 0.5hr duplicate timers; deleted one via delete_timer_entry.
  • Lessonfeedback_syncro_api timer section. Timers are no longer the workflow (see 2026-05-21), so this is reference-only.

2026-05-04 (Winter) — wrong labor type default, blank-contact rule generalized

Two adjacent lessons:

  1. Tickets I created used "Prepaid project labor" as the auto-selected labor type. That product is exempt and does NOT consume hours from a customer's prepaid block. Block-hour accounting silently drifted. Winter is fixing them retroactively.
  2. Winter generalized the prior Cascades-only blank-contact rule to "most customers" — blank contact_id lets Syncro apply company-level email defaults, which route to the right people. Setting a specific contact overrides that.

#32203 (Desert Auto Tech, 2026-04-23) — emergency was additive

  • Billed "1h onsite + 1h emergency" as two additive lines = $437.50. The correct shape is ONE emergency line at time-and-a-half — 1 actual hour of emergency should bill at $262.50 (or $225 remote).
  • Lessonfeedback_syncro_billing "Emergency = ×1.5 applied once".

#32142 (2026-04-23) — comment dup from wrapper-key error

  • POST to /comment returned {"comment": {...}}. The script parsed .id (returning null), saw an error, and retried — creating a duplicate.
  • Lessonfeedback_syncro_api "Response wrappers". POST /comment response is {"comment": {...}} — use .comment.id. Also: when GETting to verify, check ALL comments not just [-3:] — the new comment may not be the most recent if other activity occurred.

2026-04-22 — ticket dup from retry

  • A POST /tickets response looked wrong (null fields, jq error). The response wrapper is {"ticket": {...}}.ticket.id not .id. Retried the POST, creating a duplicate ticket.
  • Lessonfeedback_syncro_api "No idempotency — GET before retry" applies to ticket creation, not just comments.

#32185 — comment dup from shell-quoting error

  • Subject contained an em-dash () → shell interpolation issue → the POST appeared to fail but actually succeeded. Retry created a duplicate comment. Comments cannot be deleted via API.
  • Lessonfeedback_syncro_api "No idempotency". Hardening: write comment payloads to a temp file (e.g. tmp/syncro_comment.json) before posting — avoids shell quoting/encoding failures that produce misleading errors on requests that actually succeeded.

HTML formatting incident — <ul>/<li> rendered as one line

  • Posted a comment with <ul><li> items; Syncro's renderer collapsed them into a single line with no spacing. Had to post a corrected duplicate.
  • Lessonfeedback_syncro_api "HTML formatting". Use <br> inside a <p> wrapper for bulleted lists.

Cascades — Meredith Kuhn keeps being the wrong default

  • At Cascades of Tucson (customer_id 20149445), Syncro's contact picker repeatedly pre-selects Meredith Kuhn (Assistant Manager, ASSISTMAN-PC). She's the wrong contact — assigning her overrides distribution emails and routes notifications only to her.
  • Howard surfaced the pattern; Mike confirmed the global blank-contact rule on 2026-05-24.
  • Lessonfeedback_syncro_workflow "Cascades-specific guard".

Superseded rules — kept for context

Rule (old) Replaced by Date
All time billing through timer_entry → charge_timer_entry Bill with add_line_item directly 2026-05-21
Prepaid emergency → onsite 26118 at ×1.5 Prepaid emergency → emergency 26184 at qty ×1.5 2026-05-27
Blank contact only at Cascades Blank contact for ALL customers by default 2026-05-04
Warranty → closest labor product with billable=false Warranty → product 1049360 (its own product) 2026-05-06

  • Skill doc: .claude/commands/syncro.md — current labor product table, billing workflow, examples.
  • API docs: api-docs.syncromsp.com (Swagger spec).
  • Tenant attribution rule (cross-product): per-user-key attribution; see /syncro Attribution rule and [[feedback_psa_default_syncro]].