--- 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. - **Title:** `LC · ` — 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. - `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 \ --title "LC 42 · Trapping Rain Water" \ --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 - **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. - **`-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`).