Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 36 additions & 31 deletions skills/recoup-internal-dev-issue-tracker/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,58 @@ 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/<repo>`). 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 <n> recoupable/chat --repo <wrong-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 <n> recoupable/chat --repo <wrong-repo>` preserves body/comments and leaves a redirect.

## Anatomy of a tracking issue

Use these sections in this order. Drop sections that don't apply; never reorder the ones you keep.

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 — <bucket>.** 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 — <bucket>.** 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 <ISO date>)` 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 |
```
Comment on lines +37 to +45

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Tag the example fence as Markdown.

This snippet will trip MD040 as written. Add a markdown fence tag so the docs lint stays clean.

Suggested edit
-```
+```markdown
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```
## 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 |
```
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 39-39: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@skills/recoup-internal-dev-issue-tracker/SKILL.md` around lines 39 - 47, The
example fence in the PR list section is missing a language tag and is triggering
MD040. Update the fenced block in the PRs table example to use a
Markdown-labeled fence, keeping the rest of the snippet unchanged so the docs
lint passes cleanly.

Source: Linters/SAST tools


- **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 — <verification status>`, or `✅ merged <ISO> — 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)

Items are **not** closed by flipping `- [ ]` to `- [x]`. When an item ships, **rewrite it into a closure note** and move it under `## Done`:

```
- [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`).
<what actually changed, technically — 2-4 sentences>.
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

Expand Down Expand Up @@ -76,15 +97,15 @@ 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)

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).

Expand All @@ -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 <number> --repo recoupable/chat --body-file issue.md

# Time-stamped update or test result
gh issue comment <number> --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 <ISO>` 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.
Expand Down
Loading