diff --git a/skills/recoup-internal-dev-issue-tracker/SKILL.md b/skills/recoup-internal-dev-issue-tracker/SKILL.md index 95e3079..f846a45 100644 --- a/skills/recoup-internal-dev-issue-tracker/SKILL.md +++ b/skills/recoup-internal-dev-issue-tracker/SKILL.md @@ -11,9 +11,7 @@ Most substantial work gets a **tracking issue**: a long-lived issue that coordin ## Issues live in a repository -Every issue belongs to one repo (`gh issue create --repo recoupable/`). There is no org-level issue — cross-repo work lives in one "home" repo's tracking issue that *links out* to PRs/issues in the others. - -**File every issue in `recoupable/chat`** — even when the actual code lands in `api`, `database`, or `docs`. One home repo means devs have a single place to find open work. Do **not** pick the repo by "where the diff lands"; link out to sibling-repo PRs/files by full ref instead (e.g. the chat cutover tracker lives in `chat` even though most commits were in `api`). If an issue gets opened in the wrong repo, move it: `gh issue transfer recoupable/chat --repo ` (preserves body/comments, leaves a redirect). +**File every issue in `recoupable/chat`**, even when the code lands in `api`, `database`, or `docs` — one home repo means one place to find open work. Never pick the repo by "where the diff lands"; link out to sibling-repo PRs/files by full ref instead (the chat cutover tracker lives in `chat` though most commits were in `api`). Wrong repo? `gh issue transfer recoupable/chat --repo ` preserves body/comments and leaves a redirect. ## Anatomy of a tracking issue @@ -21,13 +19,36 @@ Use these sections in this order. Drop sections that don't apply; never reorder 1. **Lead paragraph (no heading).** One or two sentences: what this issue tracks, the current prod/live status, and a link to the parent or sibling issue. Example: *"Tracking issue for cleanup that follows the X→Y cutover ([chat#1747](url), shipped to prod 2026-06-01). The cutover is fully live; this issue captures the remaining items."* 2. **## Goal.** The end state in concrete terms — what "done" means at the macro level, and the downstream consequences. Name the files, endpoints, and tables involved. -3. **## What shipped (context)** *(optional).* Hard numbers that ground the reader: commit/PR counts, rows migrated, latency measured. *"api/main has 23 commits / 13 PRs … 17,991 sessions with correct artist_id; 0 stragglers remaining."* -4. **## Done.** Completed items as a checked list — see the Done-item format below. -5. **## Open — .** Remaining work as unchecked items. Bucket by theme or priority (`Open — cleanup + follow-ups`, `Open — next up (in merge order)`, `Open — pre-existing docs gaps (low priority)`). See the Open-item format below. -6. **## Open — Phase N (LAST, only after …).** Sequenced/gated work. State the gate explicitly in the heading and the body — *"only after the cutover bundle is stable on `main` for some time."* -7. **## Architecture decisions.** Durable decisions with rationale, so they don't get re-litigated. Bold the decision, then explain. *"**chatId source of truth is api.** createSessionHandler mints chat.id; the client uses it as …"* -8. **## Accepted regressions / tradeoffs** *(optional).* What you knowingly gave up and may re-add later. Makes the cost explicit instead of silent. -9. **## Inherited gaps / Source references** *(optional).* Cross-links to other trackers, the originating PRs, key files (with paths), and prior art. +3. **## PRs.** The fleet table — see the PRs-matrix section below. +4. **## What shipped (context)** *(optional).* Hard numbers that ground the reader: commit/PR counts, rows migrated, latency measured. *"api/main has 23 commits / 13 PRs … 17,991 sessions with correct artist_id; 0 stragglers remaining."* +5. **## Done.** Completed items as a checked list — see the Done-item format below. +6. **## Open — .** Remaining work as unchecked items. Bucket by theme or priority (`Open — cleanup + follow-ups`, `Open — next up (in merge order)`, `Open — pre-existing docs gaps (low priority)`). See the Open-item format below. +7. **## Open — Phase N (LAST, only after …).** Sequenced/gated work. State the gate explicitly in the heading and the body — *"only after the cutover bundle is stable on `main` for some time."* +8. **## Architecture decisions.** Durable decisions with rationale, so they don't get re-litigated. Bold the decision, then explain. *"**chatId source of truth is api.** createSessionHandler mints chat.id; the client uses it as …"* +9. **## Accepted regressions / tradeoffs** *(optional).* What you knowingly gave up and may re-add later. Makes the cost explicit instead of silent. +10. **## Inherited gaps / Source references** *(optional).* Cross-links to other trackers, the originating PRs, key files (with paths), and prior art. + +## The PRs matrix (required for any multi-PR tracker) + +Any tracker coordinating more than one PR carries this table **directly under `## Goal`** — the one place a reader (or a cold agent) sees the whole fleet and its state without scanning prose. + +Heading is `## PRs (updated )` so staleness is visible. Columns: + +``` +## PRs (updated 2026-06-25) + +| PR | Item | State | +|----|------|-------| +| [docs#251](url) | `POST /api/emails` send-email contract (OpenAPI + types + nav) | ✅ merged 2026-06-25 — see Done | +| [api#708](url) | `POST /api/emails` endpoint + auth fix | 🔄 open — preview-verified end-to-end | +| [api#TBD](#) | rate-limit the send path | ⏳ not started | +``` + +- **PR** — full cross-repo ref, linked; one row per PR, sibling repos included. A tracker written before implementation lists planned PRs as `repo#TBD` rows so the fleet is visible up front. (All PRs target `main`; there is no base-branch column.) +- **Item** — one-line what-it-does, worded to match the Done/Open item it backs. +- **State** — `⏳ not started`, `🔄 open — `, or `✅ merged — see Done` (the row stays; the closure note lives under `## Done`). + +**Update a row in the same session its PR changes state.** Replace `#TBD` with the live ref the moment the PR opens — never batch for "when they're all open"; an open PR whose row still says `#TBD` is drift of the same class as a merged PR without a closure note (caught in practice on chat#1841). Follow the table with a merge-sequencing blockquote when order matters (see below); when everything is one state, say so (*"all seven merged and on prod"*). ## The Open → Done lifecycle (the most important rule) @@ -35,13 +56,13 @@ Items are **not** closed by flipping `- [ ]` to `- [x]`. When an item ships, **r ``` - [x] **chat[#1765](url) — drop legacy useChatTransport branch + delete app/chat/[roomId]/page.tsx.** - ✅ Shipped 2026-06-03 (merged to `test`, then `test`→`main`; both synced). + ✅ Shipped 2026-06-03 (squash-merged to `main`). . Verified end-to-end on preview: new chat → session-scoped URL, transport POSTs /api/chat/workflow with sessionId+chatId+bearer, assistant streams, legacy route 404s. ``` -Every Done item carries: **bold lead-in + PR link**, **✅ + ISO ship date**, **merge path** (which branches, synced?), **what changed**, and a **Verified** clause stating *how* you confirmed it and *on what* (preview/prod, what you clicked, what the response showed). If a hypothesis turned out wrong, say so and link the evidence — see how #1767 documents the "3 sessions per click" item turning out to already be fixed, with the `isLoading`→`isPending` root cause and a link to the source line range. +Every Done item carries: **bold lead-in + PR link**, **✅ + ISO ship date + merge commit**, **what changed**, and a **Verified** clause stating *how* you confirmed it and *on what* (preview/prod, what you clicked, what the response showed). If a hypothesis turned out wrong, say so and link the evidence — see how #1767 documents the "3 sessions per click" item turning out to already be fixed, with the `isLoading`→`isPending` root cause and a link to the source line range. ## Open-item format @@ -76,7 +97,7 @@ We follow **documentation-driven development**: the docs/contract is written and - When you finish a unit of work, **update the issue in the same session** — move the item to Done with its closure note. Don't let the issue drift from reality. - Keep the lead paragraph's status line current ("fully live on prod"). - **Keep the title current too.** The title is maintained state, not a fixed label — when scope changes, edit it. (#1777's title carried `+ bring-your-own-key` after that path was dropped; it had to be re-edited to match.) -- Comment for time-stamped updates or test results; edit the body for the canonical current state. (Manual test results generally go in PR comments, not the issue body.) +- Comment for time-stamped updates or test results; edit the body for the canonical current state (`gh issue edit --body-file` — a file keeps the markdown intact). Manual test results generally go in PR comments, not the issue body. - Close the issue only when **every** item is in Done or has been explicitly moved to a follow-up tracker (link it). ### Decision changes & reversals (supersede, don't erase) @@ -84,7 +105,7 @@ We follow **documentation-driven development**: the docs/contract is written and When the plan reverses (e.g. #1777 pivoted from "keep Chartmetric behind a BYO-key router" to "delete all Chartmetric code, SongStats-only" on a YAGNI call), record the change so the *old* reasoning stays auditable — don't silently rewrite history: - **Add a dated decision callout near the top** (a `>` blockquote under the lead): what changed, **who decided + when**, and the one-line rationale. Attribution + ISO date matter most for decisions that came from a discussion, not from code. -- **Supersede, don't delete.** Strike through (`~~…~~`) or annotate the now-dead item with *"Dropped — …"* / *"Supersedes the earlier X plan."* rather than removing it. A reader (or a cold agent) should see the prior plan and why it was abandoned, so it isn't re-proposed. +- **The dated callout is the tombstone — delete the dead items.** Remove superseded Open items/plans from the body; the callout alone carries what was dropped and why, so it isn't re-proposed. No strikethrough tombstones scattered through the sections. - **Update every downstream section**: Goal, the affected Open items, Architecture decisions (mark the reversed one *"supersedes the earlier …"*), the title, and Source references (link the decision thread). - **Re-anchor in-flight PRs to the new plan.** If an open PR was built for the old approach, say what now has to change before it can merge (e.g. #1777 flags that api#635's Chartmetric branch must be stripped pre-merge, and that verification must re-run after). @@ -102,27 +123,11 @@ An issue tracks the **work to be done**, not the business goal that consumes it. The smell: domain terms from a *different* layer (e.g. a business metric in an API/docs issue) showing up in the Goal, the steps, and the acceptance criteria. State the cross-layer context once, then stay in your layer. -## gh quick reference - -```bash -# Create (body from a file keeps markdown intact — preferred for long issues) -gh issue create --repo recoupable/chat --title "Post-cutover cleanup + follow-up items" --body-file issue.md - -# Edit the canonical body as work progresses -gh issue edit --repo recoupable/chat --body-file issue.md - -# Time-stamped update or test result -gh issue comment --repo recoupable/chat --body "Verified on prod 2026-06-03: …" - -# Inspect (see the two reference trackers) -gh issue view 1747 --repo recoupable/chat -gh issue view 1767 --repo recoupable/chat -``` - ## Checklist before you post / update The non-negotiables — structure/format is covered by the sections above; these are the things most often gotten wrong: +- [ ] Multi-PR tracker has a **`## PRs` matrix under `## Goal`** (PR | Item | State), `updated ` heading, every row current as of this session. - [ ] Shipped items are **closure notes under `## Done`** (PR link, ✅ ISO date, merge path, what changed, **Verified**) — never a bare `[x]`. - [ ] Every claim is **linked** (PR/SHA/file:line); numbers are **hard**, dates **ISO**; **no secrets** (env-var name, never a value). - [ ] **Title + lead reflect current reality** (scope + live status); reversals superseded, not erased.