From d53afa099c0e506999036b8f68c03d56f7fa2f2b Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Thu, 25 Jun 2026 13:10:55 -0500 Subject: [PATCH 1/3] recoup-internal-dev-issue-tracker: make the PRs matrix a required section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PRs matrix (PR | Item | Base | State, directly under Goal) is one of the most important parts of a tracker, but it was never listed in the Anatomy section, had no format spec, and wasn't in the checklist — so it got omitted from follow-up trackers (e.g. chat#1815) that linked several PRs only in prose. - Add `## PRs` to the Anatomy list (item 3, directly under Goal). - Add a "The PRs matrix (required for any multi-PR tracker)" section: heading with `(updated )`, the four columns, per-column rules, and the merge-sequencing follow-up. - Add a checklist gate so it can't be skipped again. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../SKILL.md | 39 +++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/skills/recoup-internal-dev-issue-tracker/SKILL.md b/skills/recoup-internal-dev-issue-tracker/SKILL.md index 95e3079..0e89fa6 100644 --- a/skills/recoup-internal-dev-issue-tracker/SKILL.md +++ b/skills/recoup-internal-dev-issue-tracker/SKILL.md @@ -21,13 +21,37 @@ 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 at-a-glance table of every PR the issue coordinates — **required for any multi-PR tracker** (see the PRs-matrix format below). Goes directly under Goal. +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) + +Every tracking issue that coordinates more than one PR carries a **PRs table directly under `## Goal`** — it's the one place a reader (or a cold agent) sees the whole PR fleet and its state at a glance, without scanning prose. This is one of the most important parts of a tracker; **never skip it.** If a follow-up tracker links several PRs and has no matrix, that's a bug — add it. + +Heading is `## PRs (updated )` so staleness is visible. Four columns, in order: + +``` +## PRs (updated 2026-06-25) + +| PR | Item | Base | State | +|----|------|------|-------| +| [docs#251](url) | `POST /api/emails` send-email contract (OpenAPI + types + nav) | `main` | 🔄 open — preview-verified; merge first | +| [api#708](url) | `POST /api/emails` endpoint + route ephemeral key to `RECOUP_API_KEY` (auth fix) | `test` | 🔄 open — preview-verified end-to-end | +| [tasks#153](url) | retire dead `run-sandbox-command` task (OpenClaw Phase 2 cleanup) | `main` | 🔄 open — 355 tests pass, grep clean | +``` + +- **PR** — full cross-repo ref, linked (`[api#708](url)`). One row per PR; sibling-repo PRs included. +- **Item** — one-line what-it-does, terse. Match the wording to the Done/Open item it backs so they cross-reference. +- **Base** — the target branch (`main`, or `test` for `api`/`chat`), because merge/promote path matters here. +- **State** — `✅ merged — see Done` once shipped (the row stays; the closure note lives under `## Done`), or `🔄 open — ` while in flight. Keep it current as PRs land. + +Follow the table with a short **merge-sequencing blockquote** when order matters (`docs → database → api → tasks`, contract-first; see Merge sequencing below). When everything is one state, say so explicitly (*"All four open and preview-verified; none merged yet"* / *"All seven merged and on prod"*) so the reader isn't left inferring. ## The Open → Done lifecycle (the most important rule) @@ -123,6 +147,7 @@ gh issue view 1767 --repo recoupable/chat 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 | Base | State), `updated ` heading, kept current — never omitted just because the PRs are also named in prose. - [ ] 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. From b03bcec9d57b1ac677535381e152c464acb4e0de Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Fri, 3 Jul 2026 11:11:44 -0500 Subject: [PATCH 2/3] issue-tracker: planned #TBD rows + same-session PR-open matrix update rule A tracker written before implementation may carry repo#TBD placeholder rows; each must be replaced with the live PR ref + verification status in the same session the PR opens, never batched. Gap caught on recoupable/chat#1841 (four PRs open before any row updated). Co-Authored-By: Claude Fable 5 --- skills/recoup-internal-dev-issue-tracker/SKILL.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/skills/recoup-internal-dev-issue-tracker/SKILL.md b/skills/recoup-internal-dev-issue-tracker/SKILL.md index 0e89fa6..f45f2d4 100644 --- a/skills/recoup-internal-dev-issue-tracker/SKILL.md +++ b/skills/recoup-internal-dev-issue-tracker/SKILL.md @@ -51,6 +51,8 @@ Heading is `## PRs (updated )` so staleness is visible. Four columns, - **Base** — the target branch (`main`, or `test` for `api`/`chat`), because merge/promote path matters here. - **State** — `✅ merged — see Done` once shipped (the row stays; the closure note lives under `## Done`), or `🔄 open — ` while in flight. Keep it current as PRs land. +**Planned rows and the PR-open rule.** A tracker written before implementation lists its planned fleet as placeholder rows — `repo#TBD | | | ⏳ not started` — so the whole effort is visible up front. The moment a PR opens, **replace its `#TBD` placeholder with the live ref + verification status in the same session** — never batch this for "when they're all open." An open PR whose matrix row still says `#TBD` is drift of the same class as a merged PR without a closure note. (Caught in practice on chat#1841: four PRs were open before any row was updated.) + Follow the table with a short **merge-sequencing blockquote** when order matters (`docs → database → api → tasks`, contract-first; see Merge sequencing below). When everything is one state, say so explicitly (*"All four open and preview-verified; none merged yet"* / *"All seven merged and on prod"*) so the reader isn't left inferring. ## The Open → Done lifecycle (the most important rule) From 3c036a92cbd02489f6903d4994c48e49bc504908 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Fri, 3 Jul 2026 15:17:32 -0500 Subject: [PATCH 3/3] =?UTF-8?q?issue-tracker:=20KISS=20pass=20=E2=80=94=20?= =?UTF-8?q?cut=20stale=20+=20duplicated=20guidance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Net vs main: matrix spec added while the skill shrinks. Removed: the Base column (all PRs target main now — the column carried no information), the retired test→main merge-path example, the gh quick reference (table-stakes gh usage; --body-file tip moved inline), the strikethrough-tombstone rule (superseded plans are deleted; the dated decision callout carries the why), and triple-stated matrix-placement guidance. Co-Authored-By: Claude Fable 5 --- .../SKILL.md | 58 ++++++------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/skills/recoup-internal-dev-issue-tracker/SKILL.md b/skills/recoup-internal-dev-issue-tracker/SKILL.md index f45f2d4..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,7 +19,7 @@ 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. **## PRs.** The at-a-glance table of every PR the issue coordinates — **required for any multi-PR tracker** (see the PRs-matrix format below). Goes directly under Goal. +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. @@ -32,28 +30,25 @@ Use these sections in this order. Drop sections that don't apply; never reorder ## The PRs matrix (required for any multi-PR tracker) -Every tracking issue that coordinates more than one PR carries a **PRs table directly under `## Goal`** — it's the one place a reader (or a cold agent) sees the whole PR fleet and its state at a glance, without scanning prose. This is one of the most important parts of a tracker; **never skip it.** If a follow-up tracker links several PRs and has no matrix, that's a bug — add it. +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. Four columns, in order: +Heading is `## PRs (updated )` so staleness is visible. Columns: ``` ## PRs (updated 2026-06-25) -| PR | Item | Base | State | -|----|------|------|-------| -| [docs#251](url) | `POST /api/emails` send-email contract (OpenAPI + types + nav) | `main` | 🔄 open — preview-verified; merge first | -| [api#708](url) | `POST /api/emails` endpoint + route ephemeral key to `RECOUP_API_KEY` (auth fix) | `test` | 🔄 open — preview-verified end-to-end | -| [tasks#153](url) | retire dead `run-sandbox-command` task (OpenClaw Phase 2 cleanup) | `main` | 🔄 open — 355 tests pass, grep clean | +| 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 (`[api#708](url)`). One row per PR; sibling-repo PRs included. -- **Item** — one-line what-it-does, terse. Match the wording to the Done/Open item it backs so they cross-reference. -- **Base** — the target branch (`main`, or `test` for `api`/`chat`), because merge/promote path matters here. -- **State** — `✅ merged — see Done` once shipped (the row stays; the closure note lives under `## Done`), or `🔄 open — ` while in flight. Keep it current as PRs land. - -**Planned rows and the PR-open rule.** A tracker written before implementation lists its planned fleet as placeholder rows — `repo#TBD | | | ⏳ not started` — so the whole effort is visible up front. The moment a PR opens, **replace its `#TBD` placeholder with the live ref + verification status in the same session** — never batch this for "when they're all open." An open PR whose matrix row still says `#TBD` is drift of the same class as a merged PR without a closure note. (Caught in practice on chat#1841: four PRs were open before any row was updated.) +- **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`). -Follow the table with a short **merge-sequencing blockquote** when order matters (`docs → database → api → tasks`, contract-first; see Merge sequencing below). When everything is one state, say so explicitly (*"All four open and preview-verified; none merged yet"* / *"All seven merged and on prod"*) so the reader isn't left inferring. +**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) @@ -61,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 @@ -102,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) @@ -110,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). @@ -128,28 +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 | Base | State), `updated ` heading, kept current — never omitted just because the PRs are also named in prose. +- [ ] 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.