2026-08-27 15:46:34 -04:00
---
name : campaign-issues
description : Create GitHub issues for this LeetCode campaign — individual problem issues and the topic issues that own them — using the repo's exact title, label, milestone, body, and sub-issue conventions. Use when asked to add/create an issue for a LeetCode problem or a topic, attach a problem to its topic, or backfill the issue catalog.
---
# Campaign issues
The GitHub issue tracker **is the campaign catalog** : ~24 `topic` issues each own a
set of `problem` sub-issues. The Worker reconciles this catalog into D1 nightly
(`/admin/reconcile` ), so a correctly-labelled issue is all that's needed — the SRS,
digest, charts, and Project mirror pick it up automatically. Get the labels/body shape
right; everything downstream is reconciliation.
All commands use `gh` against `prdlk/leetcode` and fall back to `gh auth token` .
## Problem issue
One issue per LeetCode problem, attached as a sub-issue of its topic.
2026-08-27 16:04:18 -04:00
- **Title:** `LC <num> · <Title>` — the LC number and the problem's name, nothing
else. Separator is a middle dot `·` (U+00B7) with single spaces. Difficulty and
set are **labels only** ; never repeat them in the title (they used to be a `·
Hard · core` suffix — that is gone, and `catalog.ts` no longer parses it).
- **Labels** (four, all required — these are what the Worker reads):
- `problem` — marks the sub-issue as curriculum; without it the reconcile skips it.
- `diff:easy` | `diff:medium` | `diff:hard` — LeetCode's own rating, do not invent.
- `set:core` | `set:optional` | `set:deferred` — see set semantics below.
2026-08-27 15:46:34 -04:00
- `phase:N` — the **topic's** phase (same phase label the topic issue carries).
- **Milestone:**
- `core` / `optional` → the topic's phase milestone.
- `deferred` → `Review — Transfer & Mocks` (deferred Hards are parked until week 8).
- Pass the milestone **title** , not its number, to `--milestone` .
- **Body** (exact shape; `<slug>` is the LeetCode URL slug, `<topic-issue>` the owning topic's number):
```
https://leetcode.com/problems/<slug>/
- **Topic:** #<topic-issue>
- **Set:** <core|optional|deferred>
- **Language:** Python
### Close-out (paste before closing this issue)
- Time: O(?)
- Space: O(?)
- Edge case traced:
- First attempt passed: yes / no
- Miss note:
` ``
Create it:
` ``sh
gh issue create --repo prdlk/leetcode \
2026-08-27 16:04:18 -04:00
--title "LC 42 · Trapping Rain Water" \
2026-08-27 15:46:34 -04:00
--label problem --label set:core --label diff:hard --label phase:1 \
--milestone "Phase I — Linear Structures" \
--body "https://leetcode.com/problems/trapping-rain-water/
- **Topic:** #9
- **Set:** core
- **Language:** Python
### Close-out (paste before closing this issue)
- Time: O(?)
- Space: O(?)
- Edge case traced:
- First attempt passed: yes / no
- Miss note:"
` ``
Then **attach it as a sub-issue of the topic** (this is a separate API call — creating
the issue does not link it). The sub-issues API wants the child's internal **id**, not
its issue number, and the field is integer-typed, so use ` -F` (not ` -f`):
` ``sh
child_id=$(gh api repos/prdlk/leetcode/issues/211 --jq '.id')
gh api --method POST repos/prdlk/leetcode/issues/9/sub_issues -F sub_issue_id=$child_id
# verify
gh api repos/prdlk/leetcode/issues/9/sub_issues --jq '.[] | "\(.number) \(.title)"'
` ``
## Topic issue
One issue per curriculum topic; owns the problem sub-issues.
- **Title:** ` Topic NN — <Name>` (zero-padded number, em dash, e.g. ` Topic 07 — Monotonic Stack`).
- **Labels:** ` topic`, ` phase:N`.
- **Milestone:** that phase's milestone (title, not number).
- **Body:**
` ``
**Scheduled:** <Weekday Mon DD, YYYY>
**Phase:** <Roman> — <Phase name> (Week N)
**Builds on:** Topic <n>
### Trigger
TODO
### Invariant
TODO
### Trap
TODO
### Close-out ritual
Before every submit, out loud:
1. State time and space complexity.
2. Trace one edge case.
### Day rules
- 90-minute coding cap. Stop at the cap, even mid-problem.
- Core problems first. Optional only if the core is done.
- Finished early? Do this topic's optional set. Do not start tomorrow.
` ``
` Scheduled` should come from the calendar of record — ` apps/api/data/schedule.json`
(day → topic issue) — not guessed.
## Reference tables
Set semantics (from the label descriptions):
| set | meaning | milestone |
|---|---|---|
| ` core` | must solve on the topic day | topic's phase milestone |
| ` optional` | solve only if the clock allows | topic's phase milestone |
| ` deferred` | a Hard, parked until week 8 | ` Review — Transfer & Mocks` |
Milestones (` --milestone` takes the **title**):
| # | title |
|---|---|
| 1 | Phase I — Linear Structures |
| 2 | Phase II — Nodal & Grid |
| 3 | Phase III — Hierarchical |
| 4 | Phase IV — Relational |
| 5 | Phase V — Decision Space |
| 6 | Review — Transfer & Mocks |
Find a topic issue and confirm its phase before creating problems under it:
` ``sh
gh issue list --repo prdlk/leetcode --label topic --state all --limit 30 \
--json number,title,labels,milestone
` ``
## Gotchas
2026-08-27 16:04:18 -04:00
- **Check the LC number is not already in the curriculum BEFORE creating.** D1 keys
` problems` on ` lc_number` (` ON CONFLICT(lc_number)`), so two issues for one LC number
silently fight over a single row — whichever the reconcile walks last wins, and the
loser's issue number ends up orphaned in D1. A problem can legitimately move topic or
set; that is a relabel/re-parent of the *existing* issue, never a second issue:
` ``sh
gh issue list --repo prdlk/leetcode --label problem --state all --limit 300 \
--search "LC 42" --json number,title,labels,state
` ``
If a row already exists, change the existing issue instead: swap its ` set:*` label,
move the sub-issue to the new topic, and fix its milestone. Then reconcile the board
(` project-fields` skill). If a duplicate did get created and one is deleted, the
surviving issue number and set only reach D1 on the next catalog reconcile — SRS
columns (` stage`, ` next_review`) are preserved, since they are the real attempt history.
2026-08-27 15:46:34 -04:00
- **` -F` vs ` -f`:** ` sub_issue_id` must be an integer; ` -f` sends a string and the API
rejects it with ` is not of type integer`.
- **id, not number:** the sub-issue payload wants the child's ` .id` (a large opaque
integer), never its display ` #number `.
- **` --milestone` wants the title string**, not the numeric id (` '1' not found` otherwise).
- **Reconcile, don't react:** don't edit D1 or the Project by hand — a correct issue is
reconciled into SRS state on the nightly cron. Solutions landing in ` work/` are what
close problem issues (via ` close-solved.yml`), which then roll up to close topics.
- **Difficulty is LeetCode's**, ` set` is our scheduling choice — they're independent. A
Hard can be ` core` if we deliberately schedule it (vs the usual ` deferred`).