Session log addendum: time-tracking finding + syncro skill rewrite

Mike's 4/30 audit (surfaced via /sync) flagged that 31 closed tickets had
00:00:00 in Syncro time tracking — bare add_line_item bypasses time entries
and breaks reporting. I had just done the same on today's 3 tickets; Winter
retroactively added time entries. Rewrote the syncro skill (commit ec98c6c)
to make timer_entry -> charge_timer_entry the default and demote bare
add_line_item to a fallback for non-time items only. Disabled the
now-redundant scheduled agent (trig_01CAfvwoQ4nLcKEqbU4UQmSa).
This commit is contained in:
2026-05-01 20:08:27 -07:00
parent a18fa5f93a
commit 1280f50ff8

View File

@@ -147,3 +147,53 @@ $ ls -la "/c/Users/Howard/AppData/Local/Temp/comment_payload.json"
- Cascades client folder: `clients/cascades-tucson/` - Cascades client folder: `clients/cascades-tucson/`
- Cascades project state: `clients/cascades-tucson/PROJECT_STATE.md` - Cascades project state: `clients/cascades-tucson/PROJECT_STATE.md`
- New memory: `.claude/memory/feedback_tmp_path_windows.md` - New memory: `.claude/memory/feedback_tmp_path_windows.md`
---
## Update: 20:07 PDT — Time-tracking workflow finding + skill rewrite
After the billing work above, ran `/sync` and pulled in 5 commits from Mike. Mike's 4/30 session log contained a `## Note for Howard` flagging that **all 31 closed tickets he audited had 00:00:00 in Syncro's time-tracking system** — invoices were created with bare `add_line_item` calls and hours were typed into description text. This bypasses Syncro's time-entries table entirely and breaks reporting (hours per client, technician productivity, average resolution time, prepay burn rate).
The required workflow per Mike: `timer_entry → charge_timer_entry → invoice`. Bare `add_line_item` is only acceptable for non-time items (hardware, flat-fee services with zero labor). Even warranty/free work needs a time entry (`billable: false`); only cancelled tickets are exempt.
I had just done exactly the wrong thing on three tickets earlier in this session. Winter retroactively added time entries to fix #32225, #32229, and #32214.
### Actions taken on this finding
1. **Saved feedback memory** at `.claude/memory/feedback_syncro_timer_first.md` documenting the rule, the rationale, and the two-day repeat-incident timeline (Mike caught 31 tickets 4/30; I repeated on 3 more 5/01).
2. **Saved a separate feedback memory** at `.claude/memory/feedback_syncro_cascades_contact.md` for an unrelated rule Howard surfaced mid-session: never set `contact_id` on Cascades tickets — leaving it blank lets Syncro route to the correct email distribution; setting it (Meredith Kuhn has been the recurring incorrect default) overrides and breaks the distribution.
3. **Delegated a syncro skill rewrite** to the Coding Agent. Result committed as `ec98c6c` and pushed:
- Promoted `timer_entry → charge_timer_entry` to the documented default `/syncro bill` flow (was 13 steps using `add_line_item`; now 16 steps using the timer path).
- Demoted bare `add_line_item` to a clearly-labeled fallback section for non-time items only. Example payload there is now a hardware item, not labor.
- Added two new Hard Rules at the top of the skill: timer-entry-first rule (with warranty exception) and heredoc-payload rule (no `/tmp/*.json` files).
- Replaced every `/tmp/*.json` write+curl pattern with `--data-binary @- <<'JSON' ... JSON` heredocs. Quoting strategy: `<<'JSON'` (literal) for static payloads, `<<JSON` (interpolating) for payloads that need shell variables like `${TIMER_ID}`.
- Updated Ollama drafting block to use `$CLAUDETOOLS_ROOT/.claude/tmp/ollama_prompt.txt` (workspace path both Write and Bash agree on) instead of `/tmp/ollama_prompt.txt`.
- Updated `/syncro bill <number>` arg list to include `warranty` as a labor type.
- Preserved emergency-billing prepaid branching (product 26184 vs 26118 × 1.5), per-user attribution rules, comment-shape warnings, rate tables, endpoint reference tables, and Cascades contact rule references — all untouched.
4. **Disabled scheduled remote agent** `trig_01CAfvwoQ4nLcKEqbU4UQmSa` (was set to fire 2026-05-02 08:00 PDT to do the heredoc-only fix). Its scope was a strict subset of the larger rewrite that just shipped, so leaving it enabled would have been a no-op at best. Updated to `enabled: false` via RemoteTrigger.
### Files changed in the second half of session
- `.claude/commands/syncro.md` — major rewrite (timer-first + heredoc throughout)
- `.claude/memory/MEMORY.md` — index entries for the two new memories
- `.claude/memory/feedback_syncro_timer_first.md` (new)
- `.claude/memory/feedback_syncro_cascades_contact.md` (new)
### Repo state at end of session
- HEAD: `ec98c6c syncro skill: timer-entry-first workflow + heredoc payloads`
- Local + origin/main in sync
- Three Howard-authored commits today: session log + sync auto-commit + skill rewrite
- Three new feedback memories landed today (tmp-path, Cascades-contact, syncro-timer-first)
- One disabled remote routine (no longer needed)
### Pattern to apply going forward
Every Syncro billing operation in future sessions must be:
1. POST `/tickets/{id}/timer_entry` (with `start_at`, `end_at`, `billable`, `product_id`, `notes`) → record time
2. POST `/tickets/{id}/charge_timer_entry` (with `{"timer_entry_id": N}`) → auto-generate line item
3. Verify line item came in with correct `price_retail`; PUT-patch via `update_line_item` if it landed at $0
4. POST `/invoices` → roll line item onto invoice
5. PUT ticket status to `Invoiced`
The skill now reflects this. The memory now reinforces it. If a future session reverts to bare `add_line_item` for time-bearing work, it's a regression — call it out and use the timer path.