mirror of
https://github.com/prdlk/leetcode.git
synced 2026-09-16 23:16:26 +00:00
docs(repo): add repository guidelines documentation
This commit is contained in:
@@ -0,0 +1,80 @@
|
|||||||
|
# Repository Guidelines
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
LeetCode interview-prep campaign (8 weeks, 2026-08-17 → Oct 11) run as a repo: solution files under `work/`, a Blume docs site under `docs/`, and GitHub Actions automation that reconciles issues, publishes docs, and drives a spaced-repetition system (SRS). Issues model the curriculum: ~24 `topic` issues own ~161 `problem` sub-issues (`set:core|optional|deferred`, `diff:*`); milestones are phases; a user-level GitHub Project ("Interview Prep", #2) mirrors review state.
|
||||||
|
|
||||||
|
## Architecture & Data Flow
|
||||||
|
|
||||||
|
Two subsystems, one direction of truth:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
work[work/ solutions] -->|bun run sync| docs[docs/solutions/*.mdx]
|
||||||
|
work -->|close-solved.yml| PI[problem issues]
|
||||||
|
PI -->|close-topics.yml| TI[topic issues]
|
||||||
|
SRS[.github/srs/srs.json] -->|srs-scheduler| Today[📋 Today issue]
|
||||||
|
Today -->|/done comments| Logger[srs-logger] --> SRS
|
||||||
|
SRS -->|mirror, best-effort| Proj[GitHub Project fields]
|
||||||
|
SRS -->|gate.yml| Gate[weekly gate issue + docs/gate-log.md]
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Reconcile, don't react.** `close-solved.ts`, `close-topics.ts`, and the SRS scripts recompute desired state from scratch each run: re-runs are no-ops, backfills need no special casing, closing is one-directional (nothing ever reopens).
|
||||||
|
- **`.github/srs/srs.json` is the single source of truth.** Project fields (`Target Date`, `SRS Stage`, `First Attempt`) are a best-effort mirror via `scripts/srs-project.ts`: every GraphQL failure becomes a warning, never an error — an srs.json update must never be lost to a mirror failure. Topic rows' `Target Date` is never written (problem rows only).
|
||||||
|
- **Determinism = idempotency.** Drill/gate sampling uses a seeded PRNG (`rng()` in `srs.ts`, FNV-1a → mulberry32, seed = date / ISO week), so running a workflow twice picks identical problems.
|
||||||
|
- **Chained workflows:** `GITHUB_TOKEN`-driven issue closes fire no `issues` events, so `close-topics.yml` chains off `workflow_run` of Close Solved instead.
|
||||||
|
|
||||||
|
## Key Directories
|
||||||
|
|
||||||
|
| Path | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `work/<Difficulty>/<Category>/<num>.<slug>.{js,py}` | Solutions, e.g. `work/Easy/Array/1.two-sum.py`. Machine-parsed header comment (title / `Difficulty:` / URL / `─` rule / statement) — preserve its exact shape |
|
||||||
|
| `scripts/` | Flat Bun TS: automation entries (shebang + top-level await) and libraries (no shebang, side-effect-free on import) |
|
||||||
|
| `docs/` | Blume site. `docs/solutions/(<category>)/<num>-<slug>.mdx` generated by sync; `(algorithms)/`, `(data-structures)/` hand-written explainers |
|
||||||
|
| `.github/srs/` | Machine state: `srs.json` (bot-committed), `schedule.json` (day → topic issue, human-edited), `badge.json` (shields endpoint) |
|
||||||
|
| `.github/workflows/` | deploy, close-solved, close-topics, srs-scheduler, srs-logger, gate, srs-setup |
|
||||||
|
|
||||||
|
## Development Commands
|
||||||
|
|
||||||
|
```sh
|
||||||
|
bun run pick # scaffold a solution via leetcode-cli (fuzzy picker)
|
||||||
|
bun run test # run ONE solution against LeetCode's judge (not a test suite)
|
||||||
|
bun run sync # work/ → docs/solutions/ pages
|
||||||
|
bun run dev|build # Blume docs site
|
||||||
|
bun run close-solved -- --dry-run # issue reconcilers (also DRY_RUN=1)
|
||||||
|
bun run close-topics -- --dry-run
|
||||||
|
SRS_DRY=1 SRS_TODAY=2026-08-30 bun scripts/srs-scheduler.ts # preview a brief
|
||||||
|
bun scripts/srs-logger.ts --issue N --author prdlk --body "/done 704 pass"
|
||||||
|
bun scripts/srs-gate.ts create|close --issue N
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code Conventions & Common Patterns
|
||||||
|
|
||||||
|
- **Scripts are either entries or libraries.** Entries (`close-*.ts`, `srs-scheduler|logger|gate|setup.ts`) use shebang + top-level `await` and run their pipeline linearly. Libraries (`github.ts`, `report.ts`, `srs.ts`, `srs-project.ts`) must stay side-effect-free on import — nothing touches network/credentials until a factory (`github()`, `projectMirror()`) is awaited.
|
||||||
|
- **Shared plumbing:** `github()` gives `repo`, `api()` (throws `METHOD path -> status body`), `list()` (paginating async generator), `closeIssue()` (comment **first**, then close — a failed PATCH still leaves a trace). `report.ts` gives `printTable`/`markdownTable`/`writeStepSummary`.
|
||||||
|
- **Narrow API payloads with guards**, not inline casts: `if (!("number" in value) || typeof value.number !== "number") return;` (see `readProblemIssue` in `close-solved.ts`). Named-const casts only with a reason.
|
||||||
|
- **Dry-run everything:** reconcilers take `--dry-run`/`DRY_RUN=1`; SRS takes `SRS_DRY=1` plus overrides `SRS_TODAY`, `SRS_STATE`, `SRS_SCHEDULE`, `SRS_GATE_LOG`, `SRS_BADGE` — point `SRS_STATE` at a scratch copy to exercise logic safely.
|
||||||
|
- **Dates:** always ET calendar strings (`YYYY-MM-DD`), arithmetic anchored at noon UTC (`atNoon` in `srs.ts`) to dodge DST. Never `new Date()` math directly.
|
||||||
|
- **Style:** section-divider comments (`// ── name ───`), file-top doc comments explaining the *why* and invariants, 2-space JSON with trailing newline, `Map` for dynamic keys / `Record` for static tables, no tiny one-expression wrapper functions.
|
||||||
|
- **Known intentional duplication:** `close-solved.ts` re-implements header stripping instead of importing from `sync.ts` because `sync.ts` runs its pipeline on import. Don't "deduplicate" it.
|
||||||
|
|
||||||
|
## Important Files
|
||||||
|
|
||||||
|
- `scripts/srs.ts` — SRS domain: ladder (`new → +2 → +5 → +10 → retired`; fail resets to `+2`), `fetchCatalog()` (walks topic sub-issues, parses `LC <n> · <name> · <diff> · <set>` titles), campaign math (`CAMPAIGN_START`).
|
||||||
|
- `scripts/sync.ts` — work→docs contract: only `## Solution` onward is script-owned on existing pages; human prose is never touched; never hand-write solution pages or edit inside `## Solution`.
|
||||||
|
- `.github/srs/srs.json`, `docs/gate-log.md`, `.github/srs/badge.json` — **bot-committed** (`github-actions[bot]`, `[skip ci]`). Don't hand-edit; fix via scripts.
|
||||||
|
- `blume.config.ts` — site base `/leetcode`; `README.md` campaign table doubles as topic-map input to `sync.ts` (`readmeTopics()`, `TOPIC_ALIASES`).
|
||||||
|
- Workflows share concurrency group `srs-state` (never race on srs.json); `PROJECT_PAT` secret is required for user-Project GraphQL (default `GITHUB_TOKEN` cannot), used by srs-scheduler/logger/setup only.
|
||||||
|
|
||||||
|
## Runtime/Tooling Preferences
|
||||||
|
|
||||||
|
- **Bun only**: run scripts with `bun scripts/<name>.ts`, install with `bun install --frozen-lockfile`; `bun.lock` is the sole lockfile. Node 22 appears only in `deploy.yml` because Blume requires it.
|
||||||
|
- **No tsconfig, no ESLint, no Prettier** — match surrounding style by hand. `@types/bun` is the only type dependency.
|
||||||
|
- Automation workflows skip `bun install` (scripts use Bun builtins + `fetch` only) — keep new automation dependency-free.
|
||||||
|
- Local GitHub auth falls back to `gh auth token`; scripts run fine outside Actions.
|
||||||
|
|
||||||
|
## Testing & QA
|
||||||
|
|
||||||
|
- **No test framework, no `*.test.*` files** — `bun run test` submits one solution to LeetCode's judge.
|
||||||
|
- QA is dry-runs + scratch state: verify schedulers/reconcilers with `--dry-run`/`SRS_DRY=1` and a copied `SRS_STATE` before live runs; idempotency check = run twice, `cmp` output.
|
||||||
|
- Docs changes: `bunx blume build --isolated` must pass with no new warnings (then `rm -rf .blume-verify`); after sync, review only *created* pages (prose transforms are heuristic).
|
||||||
Reference in New Issue
Block a user