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,52 +0,0 @@
|
||||
---
|
||||
name: Syncro — timer_entry response is FLAT, not wrapped
|
||||
description: POST /tickets/{id}/timer_entry returns a flat object {"id": N, "ticket_id": ..., "product_id": ..., ...}, NOT wrapped in {"timer": {...}} or {"timer_entry": {...}}. Parse as `.id`, never `.timer.id` — using the wrapped pattern silently returns null and creates duplicate timers when the script "retries".
|
||||
type: feedback
|
||||
---
|
||||
|
||||
> **SUPERSEDED / HISTORICAL — 2026-05-21.** Timers are no longer part of the ACG Syncro
|
||||
> billing workflow; billing uses `add_line_item` directly. See [[Syncro — use add_line_item for billing, not timers]] (`feedback_syncro_timer_first.md`). Keep this note ONLY as reference
|
||||
> for the rare case a timer is created manually — do not treat it as current workflow.
|
||||
|
||||
**Rule:** When parsing the response from `POST /tickets/{id}/timer_entry`, use `.id` directly — the response is a FLAT object. Do NOT use `.timer.id // .timer_entry.id`.
|
||||
|
||||
**Verified response shape (2026-05-05, ticket #32253):**
|
||||
```json
|
||||
{
|
||||
"id": 39031258,
|
||||
"ticket_id": 109895882,
|
||||
"user_id": 1750,
|
||||
"start_time": "2026-05-05T09:00:00.000-07:00",
|
||||
"end_time": "2026-05-05T09:30:00.000-07:00",
|
||||
"recorded": false,
|
||||
"billable": true,
|
||||
"notes": "...",
|
||||
"product_id": 26118,
|
||||
"comment_id": null,
|
||||
"ticket_line_item_id": null,
|
||||
"active_duration": 1800,
|
||||
"billable_time": 1800
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
**Why:** The skill doc at `.claude/commands/syncro.md` shows
|
||||
```bash
|
||||
TIMER_ID=$(echo "$TIMER_RESP" | jq -r '.timer.id // .timer_entry.id')
|
||||
```
|
||||
That fallback resolves to `null` because neither key exists on the flat response. A `null` TIMER_ID then breaks `charge_timer_entry` ("Not found"). If the script retries the timer_entry POST after the perceived failure, it creates a duplicate — Syncro has no idempotency. Hit this on ticket #32253 (Cascades) on 2026-05-05; created two duplicate 0.5hr timers and had to delete one via `delete_timer_entry` before charging.
|
||||
|
||||
**How to apply:**
|
||||
|
||||
- **Parsing:** Always `jq -r '.id'` on the timer_entry response.
|
||||
- **After ANY ambiguous timer_entry response** (null `.id`, jq error, network blip): GET the ticket and inspect `.ticket.ticket_timers[]` BEFORE retrying. Filter for `recorded: false` entries with the start/end times you just sent.
|
||||
- **Cleanup if duplicates exist:** `POST /tickets/{id}/delete_timer_entry` with `{"timer_entry_id": N}` for the older duplicate(s). Returns `{"success": true}`.
|
||||
- **Verifying the timer is on the ticket:** `GET /tickets/{id}` → `.ticket.ticket_timers` is the authoritative list. The standalone `/ticket_timers?ticket_id=N` query parameter does NOT filter by ticket — returns the entire global timer history.
|
||||
|
||||
**Charge timer response is also flat:**
|
||||
```json
|
||||
{"id": 39031258, "recorded": true, "ticket_line_item_id": 42313052, ...}
|
||||
```
|
||||
Parse as `.ticket_line_item_id` to get the auto-generated line. Do not look for a wrapper.
|
||||
|
||||
**Where this lands in skill code:** `.claude/commands/syncro.md` example block needs `.id` not `.timer.id // .timer_entry.id`. Until the skill is patched, override the example pattern when running.
|
||||
Reference in New Issue
Block a user