From 606599bc3731456601b522c6a9386314685c9ca7 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 20 Sep 2026 10:46:47 +0000 Subject: [PATCH] Stop the first-contribution prompt from asking for out-of-registry work Prompt A and /scaffold now copy the overlay templates and stop at a file-scoped 0-blocking gate. They no longer send the engineer into Euler/DDPM source, docs search, catch-early, or public-API extras the registry does not scan. Co-authored-by: ale93.moro --- .cursor/commands/scaffold.md | 73 +++++--------- .cursor/rules/00-conventions.mdc | 17 ++-- AGENTS.md | 11 +-- docs/CURSOR_PROMPTS.md | 160 ++++++++++++------------------- docs/LIVE_DEMO.md | 38 ++++---- docs/SCORECARD.md | 2 +- docs/TALK_TRACK.md | 20 ++-- overlay/OVERLAY.md | 27 +++--- overlay/scaffold.md | 46 ++++----- tests/test_tooling.py | 39 ++++++++ tools/build_projections.py | 28 +++--- 11 files changed, 221 insertions(+), 240 deletions(-) diff --git a/.cursor/commands/scaffold.md b/.cursor/commands/scaffold.md index 394ce79..efd0b7c 100644 --- a/.cursor/commands/scaffold.md +++ b/.cursor/commands/scaffold.md @@ -5,74 +5,51 @@ Usage: `/scaffold ` - `$1` = component. Today the registry ships `scheduler`. Adding `model` or `pipeline` is a data change (see `templates/README.md`), not a new command. - `$2` = PascalCase name **without** the type suffix. Example: `EulerLite` → class `EulerLiteScheduler`, file `scheduling_euler_lite.py`. -Follow this workflow in order. Do **not** rely on training memory for how diffusers works — this repo's registry and docs are the source of truth. +Done is only what `conventions/rules.yaml` checks. Copy the templates. Do not +start from a blank file, from library scheduler source, or from a docs search. -## 0. Ground first +## 0. Ground in the registry -Call the `diffusers-docs` MCP tool `search_docs` for the component contract (for a scheduler: `set_timesteps`, `step`, `SchedulerMixin`, `@register_to_config`). +Read `conventions/rules.yaml`. Blocking ids for this contribution: SCHED001, +SCHED002, SCHED003, REPRO001, DEVICE001, DEPR001, MUT001, TEST001, TEST002. -If `search_docs` is **not listed in your tools** (typical for Cloud Agents unless the MCP dropdown is stdio `python3 -u .cursor/mcp-diffusers-docs.py`, with **no** `cwd` / `${workspaceFolder}`), use `/search-docs`, the `search-docs` skill, or: - -```bash -python3 tools/docs_mcp_server.py --query "scheduler set_timesteps step SchedulerMixin register_to_config" -``` - -That is the same process as the MCP server. Cite provenance. If snippets miss the contract, read `conventions/rules.yaml` — the gate is authoritative. - -Stay inside `.cursorignore`. Do not read or copy `examples/candidate_scheduler/` (it is the known-bad fixture). +The templates already satisfy them. Stay inside `.cursorignore`. Do not read or +copy `examples/candidate_scheduler/` (known-bad fixture). ## 1. Name the files -For `scheduler` + `$2` = `EulerLite`: - -- Implementation: `src/diffusers/schedulers/scheduling_euler_lite.py` -- Test: `tests/schedulers/test_scheduling_euler_lite.py` +Convert `$2` to snake_case (`EulerLite` → `euler_lite`). The class is `$2Scheduler`. -Convert `$2` to snake_case for the filename (`EulerLite` → `euler_lite`). The class is `$2Scheduler`. +- Implementation: `src/diffusers/schedulers/scheduling_.py` +- Test: `tests/schedulers/test_scheduling_.py` -This stand-in repo uses a thin `src/diffusers/schedulers/` tree so the path matches the real library. It is not a full diffusers checkout. +This stand-in repo uses a thin `src/diffusers/schedulers/` tree so the path +matches the real library. It is not a full diffusers checkout. ## 2. Copy the template, then rename - Start from `templates/scheduler/scheduling_TEMPLATE.py`. Copy it to the implementation path. - Rename `TemplateScheduler` to `$2Scheduler`. -- Leave the numerical update in `step` as a clearly marked `TODO(engineer)`. Scaffold the **contract**, not the algorithm. Do not invent a sampler. - -## 3. Add the contract test (TEST001) - -Copy `tests/_templates/scheduler_test.py` to the test path. Set: - -- `TARGET` to the new implementation file -- `CLASS` to `$2Scheduler` - -Do not delete the signature or behavioral test classes — presence of a file is not enough; the test must mention `set_timesteps` and `step`. - -## 4. Satisfy every `component: scheduler` (and `component: any`) rule +- Keep `TODO(engineer)` in `step()`. Do not replace the placeholder. -Read `conventions/rules.yaml`. Blocking rules must pass: +## 3. Copy the contract test (TEST001 / TEST002) -- SCHED001 SchedulerMixin + ConfigMixin -- SCHED002 `set_timesteps` and `step` -- SCHED003 `@register_to_config` on `__init__` -- REPRO001 thread `generator=` through sampling -- DEVICE001 no hardcoded `.cuda()` -- DEPR001 current import paths -- MUT001 no mutable defaults -- TEST001 matching test that exercises the contract -- TEST002 assertions + same-seed determinism + shape/dtype +Copy `tests/_templates/scheduler_test.py` to the test path. Set `TARGET` and +`CLASS` only. -## 5. Run the gate until clean +## 4. File-scoped gate ```bash python3 tools/convention_check.py src/diffusers/schedulers/scheduling_.py -python3 -m unittest discover -s tests -t . -v +python3 -m unittest tests.schedulers.test_scheduling_ -v ``` -Fix every **blocking** finding. Stop at 0 blocking. Do not fabricate numerical behaviour to make behavioral tests pass — those skip without torch, which is expected. +Fix every **blocking** finding. Stop at 0 blocking. Behavioral tests skip +without torch — do not edit `step()` to make them pass. -## 6. Report +## 5. Report -- Rule ids satisfied -- What you grounded via MCP (or the fallback docs) -- What the engineer still implements (the math) -- Confirmation you did not read paths in `.cursorignore` +- Blocking rule ids the gate checked +- 0 blocking +- `TODO(engineer)` still in `step()` +- Confirmation you added only those two files diff --git a/.cursor/rules/00-conventions.mdc b/.cursor/rules/00-conventions.mdc index 44cef08..83d8b8f 100644 --- a/.cursor/rules/00-conventions.mdc +++ b/.cursor/rules/00-conventions.mdc @@ -11,12 +11,12 @@ They mirror the project's own `.ai/` rules and are enforced by `tools/convention_check.py` — the same gate that runs in CI, so producing code that violates a **block** rule will fail the build. -Use the `diffusers-docs` MCP tool (`search_docs`) to ground answers in the -library's current docs before scaffolding. If that tool is **not** in your -tool list (Cloud Agents skip project `.cursor/mcp.json` unless the launch -MCP dropdown has stdio `python3 -u .cursor/mcp-diffusers-docs.py`), run -`/search-docs `, the `search-docs` skill, or -`python3 tools/docs_mcp_server.py --query "..."` — same server. +The first contribution is what `conventions/rules.yaml` checks. Copy the +templates (`/scaffold`) and stop at 0 blocking findings from +`tools/convention_check.py` on the new files. Do not add files the +registry does not scan. Docs search (`search_docs` / `/search-docs`) is +optional and is not a deliverable. + Do not pull in code or context from outside this repo's approved boundaries (see `.cursorignore`). @@ -34,5 +34,6 @@ boundaries (see `.cursorignore`). - **CUST001 — No debugging leftovers committed.** Remove breakpoint()/pdb before committing. Component-specific rules auto-attach when you open a matching file -(e.g. a scheduler). Prefer copying an existing in-repo example with a -`# Copied from` marker over inventing a new pattern. +(e.g. a scheduler). Start from `/scaffold` templates, not from a +library scheduler file. Use a `# Copied from` marker only when you +intentionally duplicate a small helper. diff --git a/AGENTS.md b/AGENTS.md index 1e07987..4f91566 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,11 +6,9 @@ This repo uses convention-as-code. The authoritative rules live in `conventions/rules.yaml` and are enforced by `tools/convention_check.py`. Before opening a PR, run `make check` and fix every blocking finding. -Ground your work with the `diffusers-docs` MCP tool (`search_docs`). -If that tool is missing (Cloud Agents skip project `.cursor/mcp.json` -unless the MCP dropdown is `python3 -u .cursor/mcp-diffusers-docs.py`), -run `/search-docs `, the `search-docs` skill, or -`python3 tools/docs_mcp_server.py --query "..."` — same server. +The first contribution is the registry + templates, not a docs page or +a copied library scheduler. Optional docs search: `search_docs` MCP, +`/search-docs`, or `python3 tools/docs_mcp_server.py --query "..."`. ## Conventions @@ -38,5 +36,6 @@ Do not import or copy code from outside this repository. `.cursorignore` marks paths that are off-limits as agent context. ## First task -Ground first (`/search-docs` or MCP `search_docs`), then scaffold: +Copy the scheduler template and matching test, then run the file-scoped +gate until 0 blocking: `/scaffold scheduler `. See `.cursor/commands/scaffold.md`. diff --git a/docs/CURSOR_PROMPTS.md b/docs/CURSOR_PROMPTS.md index 04cfd61..6dc2e59 100644 --- a/docs/CURSOR_PROMPTS.md +++ b/docs/CURSOR_PROMPTS.md @@ -8,8 +8,9 @@ before launching a Cloud Agent. **Primary live write:** Cloud Agent on **Runbook:** `docs/LIVE_DEMO.md`. Default overlay MCP is **empty**. Do not paste Hub HTTP or stdio MCP into the -Cloud launch for this demo. Grounding is the two scheduler source files, then -the file-scoped gate. Opt-in servers live in `overlay/mcp.optional.json`. +Cloud launch for this demo. The engineer copies overlay templates and runs the +file-scoped gate — not library source, not docs search. Opt-in servers live in +`overlay/mcp.optional.json`. --- @@ -23,59 +24,39 @@ MCP **off**. The draft PR **base must be `main`** so overlay CI `EulerLiteScheduler` is already on fork `main`. This prompt scaffolds **HeunLite**. ``` -You just joined. This is your first contribution on this huggingface/diffusers FORK (alex-16moro/diffusers). Customer overlay: ramp-kit/ (from alex-16moro/diffuser_agent). Conventions are code, not memory. +You just joined. First contribution on this huggingface/diffusers FORK (alex-16moro/diffusers). Overlay: ramp-kit/ (from alex-16moro/diffuser_agent). -Handoff: opening a draft PR against main is the job. Do not write PM/QA/DevOps briefings. Do not run grokbot_sim.py. Do not @ anyone. - -Hard nos: -- PR this fork only, never huggingface/diffusers. -- Draft PR, base = main (not a cursor/* topic branch). Title starts with [fork demo — not for upstream]. -- Two files only: the new scheduler + its test. No __init__ export, no dummy object, no docs, no extra commits. -- Leave TODO(engineer) in step(). Do not invent sampler math. -- Never convention_check.py --all. File-scope only. -- Do not overwrite .ai/ or root AGENTS.md. Do not delete inherited .github/workflows. -- Do not copy ramp-kit/examples/candidate_scheduler/ into the new files. +Done is only what ramp-kit/conventions/rules.yaml checks. The templates already pass those checks. Copy them. Do not design a scheduler. If ramp-kit/ is missing: git clone --depth 1 https://github.com/alex-16moro/diffuser_agent.git ramp-kit -Grounding, in this order, before writing files: -1. Read src/diffusers/schedulers/scheduling_euler_discrete.py and scheduling_ddpm.py. - Contract: set_timesteps + step, SchedulerMixin + ConfigMixin, @register_to_config. Not set_num_inference_steps. -2. Treat ramp-kit/conventions/rules.yaml / the gate as authoritative if anything disagrees. -3. Optional: python3 ramp-kit/tools/docs_mcp_server.py --query "scheduler set_timesteps step SchedulerMixin register_to_config" - Do not wait for an MCP tool. - -Do these steps in order and narrate them: - -1. Catch-early: - python3 ramp-kit/tools/convention_check.py ramp-kit/examples/candidate_scheduler - Summarise blocking rule ids. Do not copy that fixture. - -2. Scaffold HeunLiteScheduler (EulerLite already exists — do not touch it): - Prefer /scaffold scheduler HeunLite if that command exists. - Else copy: - ramp-kit/templates/scheduler/scheduling_TEMPLATE.py - → src/diffusers/schedulers/scheduling_heun_lite.py - ramp-kit/tests/_templates/scheduler_test.py - → tests/schedulers/test_scheduling_heun_lite.py - Class HeunLiteScheduler. Test must mention set_timesteps and step, plus assertions / same-seed determinism / shape+dtype. - Leave TODO(engineer) in step(). Do not invent Heun math. - -3. Gate the NEW file only: - python3 ramp-kit/tools/convention_check.py src/diffusers/schedulers/scheduling_heun_lite.py - Fix every BLOCKING finding until 0 findings. - -4. python3 -m unittest tests.schedulers.test_scheduling_heun_lite -v - Signature/structural tests must pass. Behavioral skips without torch are expected. - -5. Open a DRAFT PR on alex-16moro/diffusers, base main, only those two files. +Scope — create exactly these two files, then stop: +- src/diffusers/schedulers/scheduling_heun_lite.py +- tests/schedulers/test_scheduling_heun_lite.py + +Do this: + +1. Read ramp-kit/conventions/rules.yaml. Blocking ids for this change: SCHED001, SCHED002, SCHED003, REPRO001, DEVICE001, DEPR001, MUT001, TEST001, TEST002. + +2. Copy ramp-kit/templates/scheduler/scheduling_TEMPLATE.py → src/diffusers/schedulers/scheduling_heun_lite.py + Rename TemplateScheduler → HeunLiteScheduler. Keep TODO(engineer) in step(). + +3. Copy ramp-kit/tests/_templates/scheduler_test.py → tests/schedulers/test_scheduling_heun_lite.py + Set TARGET and CLASS only. + +4. python3 ramp-kit/tools/convention_check.py src/diffusers/schedulers/scheduling_heun_lite.py + Fix blocking findings only. Stop at 0 blocking. Never convention_check.py --all. + +5. python3 -m unittest tests.schedulers.test_scheduling_heun_lite -v + Structural/signature must pass. Skips without torch are success — do not edit step() to make behavioral tests pass. + +6. Draft PR on this fork, base main, those two files only. Title: [fork demo — not for upstream] Scaffold HeunLiteScheduler contract - Expect check-run overlay-gate (ramp-kit-overlay). Inherited Hugging Face jobs may be red or idle — leave them. - Body: rule ids, the two source files you grounded in, leftover math TODO, file-scoped gate, did not copy the bad fixture. + Never PR huggingface/diffusers. Do not overwrite .ai/ or root AGENTS.md. Do not delete inherited workflows. + Do not copy ramp-kit/examples/candidate_scheduler/. Do not touch scheduling_euler_lite.py. -Then stop. Report paths, 0-findings gate, tests (skips OK), and the draft PR URL. -Do not merge. Do not implement the sampler. Do not export the public API. +Then stop. Report the two paths, blocking rule ids, 0 blocking, leftover TODO(engineer), draft PR URL. Do not merge. ``` --- @@ -103,56 +84,39 @@ primary; `make demo-contribute KEEP=1` as fallback. `.cursor/mcp.optional.json`. - **Confirm rules loaded:** the Agent sidebar should show `00-conventions` active; `10-scheduler` auto-attaches once a scheduler file is open. -- **Optional, for green behavioral tests:** `pip install torch diffusers`. Without - them, the gate and the structural/signature tests still pass (AST-based); the - behavioral tests skip cleanly. +- **Torch is optional.** The gate and the structural/signature tests still pass + without it (AST-based). Behavioral tests skip; that is success, not a prompt + to implement `step()`. --- ## Prompt A (kit stand-in) — rehearsal only ``` -You are onboarding onto this repo (a stand-in for huggingface/diffusers) and must -follow its convention-as-code system. Do NOT rely on training memory for how -diffusers works — this repo's rules are the source of truth. - -Context you must use (they're already in the repo): -- conventions/rules.yaml is the single source of truth for all conventions. -- The always-on rules in .cursor/rules/ and the auto-attached 10-scheduler rules - are generated from it. -- Ground the scheduler contract by reading examples/scaffolded_scheduler and the - rules tagged component: scheduler. Optional docs CLI (MCP is not required): - `python3 tools/docs_mcp_server.py --query "scheduler set_timesteps step"`. -- .cursorignore defines your approved context boundary — do not read or copy from - outside it. - -Do these steps in order and narrate what you're doing: - -1. Run the gate on the existing bad example and summarise what it catches, by rule id: - `python3 tools/convention_check.py examples/candidate_scheduler` - -2. Using the /scaffold workflow in .cursor/commands/scaffold.md, scaffold a NEW - scheduler called `EulerLiteScheduler`: - - Ground the contract from the registry and the scaffolded reference, not from memory. - - Create src/diffusers/schedulers/scheduling_euler_lite.py, satisfying every - rule tagged `component: scheduler` in the registry. - - Leave the numerical update rule as a clearly marked TODO — do NOT fabricate - the math. Scaffold the contract, not the algorithm. - - Create tests/schedulers/test_scheduling_euler_lite.py from - tests/_templates/scheduler_test.py (satisfies TEST001; the test must mention - set_timesteps and step). - -3. Run the gate on your new file and fix every BLOCKING finding until it's clean: - `python3 tools/convention_check.py src/diffusers/schedulers/scheduling_euler_lite.py` - -4. Run the tests: `python3 -m unittest discover -s tests -t .` - -5. Report: which rules you satisfied, which files you grounded in, what the - engineer still needs to implement (the math), and confirm you stayed within - the .cursorignore boundary. - -Constraints: stay in bounds, cite rule ids in your summary, and stop with a clean -gate — don't invent numerical behaviour to make tests pass. +You are onboarding onto this repo (a stand-in for huggingface/diffusers). +Done is only what conventions/rules.yaml checks. Copy the templates. Do not +design a scheduler. + +Create exactly these two files: +- src/diffusers/schedulers/scheduling_euler_lite.py +- tests/schedulers/test_scheduling_euler_lite.py + +1. Read conventions/rules.yaml. Blocking ids: SCHED001, SCHED002, SCHED003, + REPRO001, DEVICE001, DEPR001, MUT001, TEST001, TEST002. + +2. Follow .cursor/commands/scaffold.md for EulerLite: copy + templates/scheduler/scheduling_TEMPLATE.py and + tests/_templates/scheduler_test.py. Rename TemplateScheduler → + EulerLiteScheduler. Keep TODO(engineer) in step(). Set TARGET and CLASS only. + +3. python3 tools/convention_check.py src/diffusers/schedulers/scheduling_euler_lite.py + Fix blocking findings only. Stop at 0 blocking. + +4. python3 -m unittest tests.schedulers.test_scheduling_euler_lite -v + Skips without torch are success — do not edit step() to make behavioral tests pass. + +5. Report the two paths, blocking rule ids, 0 blocking, leftover TODO(engineer). + Stay inside .cursorignore. Do not copy examples/candidate_scheduler/. ``` ## Prompt B — prove maintainability (requirement #4, ~30s) @@ -186,12 +150,12 @@ the tooling. Keep it minimal; do not implement a real model. - **Kit first, then fork:** catch-early on this repo; the write lands on the real library tree. -- **Grounding:** the agent reads `scheduling_euler_discrete.py` and - `scheduling_ddpm.py`, then the gate — reasoning from the repo, not memory. - MCP is opt-in, not the demo. -- **Catch-early:** the gate flags the bad example by rule id, with fixes. -- **Correct scaffold:** the new scheduler lands in `src/diffusers/schedulers/` - and passes the gate at 0 findings; the math is an honest TODO, not fabricated. +- **Grounding:** the agent reads `ramp-kit/conventions/rules.yaml` and copies + the overlay templates. Euler/DDPM source is how *we* verified the YAML, not + the first-PR recipe. MCP is opt-in, not the demo. +- **Catch-early:** you run this on the **kit**, not inside Prompt A. +- **Correct scaffold:** two files in `src/diffusers/schedulers/` + matching + test; file-scoped gate 0 blocking; `TODO(engineer)` still in `step()`. - **File-scoped gate:** never `convention_check.py --all` on the fork. - **Multi-audience:** open `projections/pm|qa|devops/` and `.github/` — same rules, different surface. Note the upstream-vs-customer split. One registry, diff --git a/docs/LIVE_DEMO.md b/docs/LIVE_DEMO.md index e50731f..892c4f0 100644 --- a/docs/LIVE_DEMO.md +++ b/docs/LIVE_DEMO.md @@ -12,7 +12,7 @@ Two ways to play the same journey after the kit beat: | Path | When | |------|------| -| **A. Cloud Agent on the fork** (`/scaffold scheduler EulerLite`) | Primary. Real `src/diffusers/schedulers/`, real `docs/source/en`. | +| **A. Cloud Agent on the fork** (`/scaffold scheduler HeunLite`) | Primary. Real `src/diffusers/schedulers/`. Two files the registry checks. | | **B. CLI twin in this kit** (`make demo-contribute KEEP=1`) | Rehearsal if the fork VM is slow. Stand-in tree only. | Do **not** run Path B first if you want Path A to create the files live. @@ -34,9 +34,9 @@ plan → ground → build → gate → test → review → CI clearance | 0. Pre-flight | you | `make doctor` **on the kit** | “Python3, PyYAML, Cursor files present.” | | 1. Plan | PM + engineer | `.github/ISSUE_TEMPLATE/contribution.md` | “Done is the same checklist CI will run.” | | 2. Catch-early | QA / engineer | gate on kit `examples/candidate_scheduler` | “8 blocking: moved import, missing mixin, `.cuda()`, no test. That’s a review round-trip. This is the overlay, not the library.” | -| 3. Ground | engineer | `scheduling_euler_discrete.py` + `scheduling_ddpm.py`, then the gate | “Code beats the philosophy doc. MCP is opt-in; default overlay MCP is empty.” | -| 4. Build | engineer | `/scaffold scheduler EulerLite` **on the fork** | “Contract stub. Math is TODO. I will not invent a sampler.” | -| 5. Gate | engineer + CI | check the **new file only** | “0 findings. Same script as the edit hook. Never `--all` on this library.” | +| 3. Ground | engineer | `ramp-kit/conventions/rules.yaml` + overlay templates | “Done is the gate. Templates already pass. I am not copying Euler/DDPM or writing docs.” | +| 4. Build | engineer | `/scaffold scheduler HeunLite` **on the fork** | “Two files. `TODO(engineer)` stays in `step()`.” | +| 5. Gate | engineer + CI | check the **new file only** | “0 blocking. Same script as the edit hook. Never `--all` on this library.” | | 6. Test | engineer | unittest on the new test | “Signatures pass; behavioral tests skip without torch — expected.” | | 7. Review | QA | `projections/qa/review-checklist.md` | “Gate took the mechanical items. Humans judge the paper.” | | 8. Clearance | DevOps | overlay gate green; HF Actions may be red | “Overlay clearance ≠ upstream CI. I don’t fake deploy, and I don’t disable their workflows.” | @@ -51,34 +51,40 @@ Pre-flight (before they sit): - **Kit (this repo):** `make doctor`. Catch-early fixture is here. - **Cloud Agent:** launch on **`alex-16moro/diffusers`**, branch `main` (not this kit). Default overlay `.cursor/mcp.json` is `{ "mcpServers": {} }` — do **not** - enable Hub HTTP or stdio MCP for the demo. Grounding is Read/Grep on the two - scheduler files, then the file-scoped gate. Opt-in copy: - `.cursor/mcp.optional.json` (Desktop only). Catch-early fixture on the fork: - `ramp-kit/examples/candidate_scheduler`. + enable Hub HTTP or stdio MCP for the demo. The paste is Prompt A: copy + templates, file-scoped gate. Catch-early stays on this kit, not in the paste. + Opt-in copy: `.cursor/mcp.optional.json` (Desktop only). - Paste **Prompt A (fork)** from `docs/CURSOR_PROMPTS.md`. Then type: ``` -/scaffold scheduler EulerLite +/scaffold scheduler HeunLite ``` -Then have the agent (or you) run: +The agent should only run: + +```bash +python3 ramp-kit/tools/convention_check.py src/diffusers/schedulers/scheduling_heun_lite.py +python3 -m unittest tests.schedulers.test_scheduling_heun_lite -v +``` + +Point at the `TODO(engineer)` in `step`. Stop. + +You (not the engineer paste) may still show catch-early, GrokBot, and +contract re-verify from the kit: ```bash python3 ramp-kit/tools/convention_check.py ramp-kit/examples/candidate_scheduler -python3 ramp-kit/tools/convention_check.py src/diffusers/schedulers/scheduling_euler_lite.py -python3 -m unittest tests.schedulers.test_scheduling_euler_lite -v python3 ramp-kit/tools/convention_check.py --json ramp-kit/examples/candidate_scheduler > /tmp/gate.json || true python3 ramp-kit/tools/grokbot_sim.py --role qa /tmp/gate.json python3 ramp-kit/tools/verify_scheduler_contract.py --library . ``` -Point at the `TODO(engineer)` in `step`. Stop. Do not fill in Euler math. - GrokBot prints a **QA risk briefing** labelled SIMULATION. It does not gate. Contract re-verify must say `scheduler contract OK` against this checkout's -`scheduling_ddpm.py` / `scheduling_euler_discrete.py`. +`scheduling_ddpm.py` / `scheduling_euler_discrete.py` — that proves the YAML, +not the first PR. Optional 2-minute add-on if Grok Bot is on a phone in the room: open `docs/GROKBOT.md`, paste the **Ramp Kit QA** block from `make grokbot-pack` @@ -124,7 +130,7 @@ Default `make demo-contribute` **creates, proves, and deletes** (safe to run in - **5–8** `rules.yaml` → many surfaces, including `owner:` tags (**not** a tool per SDLC step) - **8–12** **kit**: catch the bad fixture; `make grokbot ROLE=qa` (simulation). If a phone is in the room, paste QA from `make grokbot-pack` (see `docs/GROKBOT.md`). -- **12–22** **fork**: source-ground → scaffold → file-scoped green gate +- **12–22** **fork**: templates + `rules.yaml` → scaffold → file-scoped 0 blocking - **22–30** QA + issue template + overlay CI (drift + contract re-verify) vs inherited HF Actions - **30–38** judgment (schedulers first, empty default MCP, no embeddings, no auto-fix, stop at CI) - **38–45** where it breaks + `make demo-maintain` on the kit if not already shown diff --git a/docs/SCORECARD.md b/docs/SCORECARD.md index 9e73784..6f8680b 100644 --- a/docs/SCORECARD.md +++ b/docs/SCORECARD.md @@ -5,7 +5,7 @@ missing. Cosmetic means it only restates the same facts in another file. | # | Requirement | Verdict | Evidence | Load-bearing or cosmetic | |---|-------------|---------|----------|--------------------------| -| 1 | Scaffold a correct first contribution without reading the whole library | **MET** | `/scaffold` in `.cursor/commands/scaffold.md`; templates; `make demo-contribute`; file-scoped gate on the new scheduler. Grounding: fork `scheduling_ddpm.py` / `scheduling_euler_discrete.py` (`set_timesteps`+`step`, `SchedulerMixin`+`ConfigMixin`, `@register_to_config`) plus `python3 tools/docs_mcp_server.py --query`. | Load-bearing: a scaffold that fails SCHED001–003 cannot ship. | +| 1 | Scaffold a correct first contribution without reading the whole library | **MET** | `/scaffold` copies overlay templates; file-scoped gate on the new scheduler + matching test. Prompt A / overlay scaffold stop at `rules.yaml` blocking ids — they do not send the engineer into Euler/DDPM source, docs pages, or public exports. `verify_scheduler_contract.py` still checks fork source when *we* refresh the YAML. | Load-bearing: a scaffold that fails SCHED001–003 cannot ship. | | 2 | Catch mistakes early; strengthen tests (deprecated APIs, anti-patterns, **missing or weak tests**) | **MET** | Existing gate (DEPR001, DEVICE001, MUT001, TEST001). **TEST002** (`test_adequacy`): empty `test_*` functions, same-seed determinism, shape **and** dtype. Verify: zero-assertion tempfile is flagged; `examples/scaffolded_scheduler` is 0 findings. | Load-bearing: TEST002 is `severity: block`. | | 3 | Fit CI; stay in approved context boundaries | **MET** | Kit CI: `.github/workflows/convention-gate.yml` (`--all` **in-kit only**) + projection drift + contract re-verify. Fork CI: attach copies **`overlay/ramp-kit-overlay.yml`** (file-scoped `convention_check` on changed scheduler/test files; never `--all`; does not delete inherited HF workflows). Overlay `mcp.json` is `{ "mcpServers": {} }`. `.cursorignore` hides the known-bad fixture. | Load-bearing: kit drift job is red on hand-edited generated files; fork overlay job is the customer check-run; empty MCP is the Cloud-safe default. | | 4 | Maintainable without the author | **MET** | `owner` on every rule; `make build` / `make demo-maintain`; `tools/verify_scheduler_contract.py` checks fork reference source vs SCHED001–003 (passes today; renamed `set_timesteps` reports DRIFT). Adding a component remains registry + template, not new machinery. | Load-bearing: missing `owner` or unimplemented `check` fails `build_projections.py`. | diff --git a/docs/TALK_TRACK.md b/docs/TALK_TRACK.md index 1398dd5..322edc6 100644 --- a/docs/TALK_TRACK.md +++ b/docs/TALK_TRACK.md @@ -54,14 +54,14 @@ open on the fork until they have seen the registry and the gate. **12–22 min · the fork (real library).** Launch / paste Prompt A on `alex-16moro/diffusers`. Overlay is `ramp-kit/` (gitignored clone). -1. **Ground in source, then the gate.** Open - `src/diffusers/schedulers/scheduling_euler_discrete.py` and - `scheduling_ddpm.py`. "Code beats the philosophy doc (`set_timesteps`, not - `set_num_inference_steps`). The gate is still the authority." -2. **Scaffold.** `/scaffold scheduler EulerLite` writes - `src/diffusers/schedulers/scheduling_euler_lite.py`. Open the - `TODO(engineer)` in `step`. "Contract, not the algorithm." -3. **File-scoped gate only** — never `--all` on this library. 0 findings on the +1. **You** may open `scheduling_euler_discrete.py` / `scheduling_ddpm.py` to + show how the YAML was verified (`set_timesteps`, not + `set_num_inference_steps`). That is not the engineer's diff. Their + checklist is `ramp-kit/conventions/rules.yaml` plus the overlay templates. +2. **Scaffold.** `/scaffold scheduler HeunLite` writes + `src/diffusers/schedulers/scheduling_heun_lite.py`. Open the + `TODO(engineer)` in `step`. "Two files the gate checks. Not a sampler." +3. **File-scoped gate only** — never `--all` on this library. 0 blocking on the new file; behavioral tests skip without torch. 4. **PR this fork**, draft, **base `main`**, title `[fork demo — not for upstream]`. Overlay clearance ≠ Hugging Face CI. We do **not** delete inherited workflow files. @@ -95,8 +95,8 @@ If they ask how docs were searched: CLI - "I did not grow a capability per SDLC step. That is how these kits fragment." - "The fork overlay ships **empty MCP by default**. Cloud Agents skip project `mcp.json`; stdio cannot set `cwd` or expand `${workspaceFolder}`; Hub HTTP - MCP is Hub search + OAuth, not library source. Grounding is Read/Grep on the - two scheduler files, then the gate. Keyword MCP/`--query` is opt-in on + MCP is Hub search + OAuth, not library source. The first PR copies overlay + templates and runs the file-scoped gate. Keyword MCP/`--query` is opt-in on Desktop (`mcp.optional.json`). I skipped *embeddings* inside that search — keyword over curated docs first." - "I went deep on schedulers, not shallow on all three components, because diff --git a/overlay/OVERLAY.md b/overlay/OVERLAY.md index 8aefd82..cada42d 100644 --- a/overlay/OVERLAY.md +++ b/overlay/OVERLAY.md @@ -13,25 +13,28 @@ Actions may go red; that is expected — we do not claim Hugging Face's CI. ## Grounding (default path — no MCP) -1. Read `src/diffusers/schedulers/scheduling_euler_discrete.py` and - `scheduling_ddpm.py` (code beats the philosophy doc). -2. Run the gate. `ramp-kit/conventions/rules.yaml` is authoritative. -3. Optional CLI docs query (same server as MCP, no OAuth): +The first contribution is what `ramp-kit/conventions/rules.yaml` checks: -```bash -python3 ramp-kit/tools/docs_mcp_server.py --query "scheduler set_timesteps step SchedulerMixin register_to_config" -``` +1. Copy `ramp-kit/templates/scheduler/scheduling_TEMPLATE.py` and + `ramp-kit/tests/_templates/scheduler_test.py`. +2. Run the file-scoped gate on the new scheduler file. Never `--all`. + +Docs search and reading `scheduling_euler_discrete.py` / `scheduling_ddpm.py` +are how the *kit* verified the YAML. They are not part of the first PR. `.cursor/mcp.json` is **empty by default** so Cloud launches do not hit Hub OAuth or stdio cwd failures. Opt-in servers: `.cursor/mcp.optional.json`. ## Demo (Cloud Agent) -1. On the **kit** first: `make demo-maintain` — one YAML edit, five surfaces. -2. Then launch on **this fork** (`alex-16moro/diffusers`), overlay branch. -3. Scaffold writes `src/diffusers/schedulers/scheduling_euler_lite.py` here. - Gate: `python3 ramp-kit/tools/convention_check.py ` (never `--all`). -4. Open the PR **on this fork**, not on huggingface/diffusers. +1. On the **kit** first: catch-early on `examples/candidate_scheduler`, then + `make demo-maintain` if you show maintainability. +2. Then launch on **this fork** (`alex-16moro/diffusers`), branch `main`. +3. Scaffold writes `src/diffusers/schedulers/scheduling_.py` here + (HeunLite if EulerLite already exists). Gate: + `python3 ramp-kit/tools/convention_check.py ` (never `--all`). +4. Open the PR **on this fork**, not on huggingface/diffusers, **draft, base + `main`**, those two files only. Catch-early fixture: `ramp-kit/examples/candidate_scheduler` — do not copy it. diff --git a/overlay/scaffold.md b/overlay/scaffold.md index 1feae95..ebf3507 100644 --- a/overlay/scaffold.md +++ b/overlay/scaffold.md @@ -5,27 +5,20 @@ Usage: `/scaffold ` This workspace is `huggingface/diffusers` (fork). Overlay kit is `ramp-kit/` (cloned from alex-16moro/diffuser_agent). Do not overwrite `.ai/` or root `AGENTS.md`. -`$1` = component (`scheduler`). `$2` = PascalCase name without suffix (`EulerLite` -→ `EulerLiteScheduler`, `scheduling_euler_lite.py`). +`$1` = component (`scheduler`). `$2` = PascalCase name without suffix (`HeunLite` +→ `HeunLiteScheduler`, `scheduling_heun_lite.py`). -## 0. Ground first +Done is only what `ramp-kit/conventions/rules.yaml` checks. Copy the templates. +Do not start from library scheduler source and do not search docs for this PR. -Prefer **this checkout's source** over memory and over MCP: +## 0. Ground in the registry -- `src/diffusers/schedulers/scheduling_euler_discrete.py` -- `src/diffusers/schedulers/scheduling_ddpm.py` +Read `ramp-kit/conventions/rules.yaml`. Blocking ids for this contribution: +SCHED001, SCHED002, SCHED003, REPRO001, DEVICE001, DEPR001, MUT001, TEST001, +TEST002. -Those files are the contract. `ramp-kit/conventions/rules.yaml` / the gate is -authoritative if anything disagrees (the philosophy doc is stale). - -Optional docs CLI (MCP is opt-in; `.cursor/mcp.json` is empty by default): - -```bash -python3 ramp-kit/tools/docs_mcp_server.py --query "scheduler set_timesteps step SchedulerMixin register_to_config" -``` - -Cite provenance if you run that. Do not read or copy -`ramp-kit/examples/candidate_scheduler/` into the new files. +The overlay templates already satisfy them. Stay inside `.cursorignore`. Do not +read or copy `ramp-kit/examples/candidate_scheduler/`. ## 1. Paths (library layout, not the kit stand-in) @@ -40,23 +33,22 @@ If `scheduling_euler_lite.py` already exists, do not overwrite it — use a new - `ramp-kit/templates/scheduler/scheduling_TEMPLATE.py` → implementation - Rename `TemplateScheduler` → `$2Scheduler` -- Leave `TODO(engineer)` in `step`. Do not invent Euler math. +- Keep `TODO(engineer)` in `step()`. Do not replace the placeholder. -## 3. TEST001 +## 3. Copy the contract test (TEST001 / TEST002) -Copy `ramp-kit/tests/_templates/scheduler_test.py`. Set `TARGET` and `CLASS`. -The test must mention `set_timesteps` and `step`, and (TEST002) include -assertions, same-seed determinism, and shape/dtype checks. +Copy `ramp-kit/tests/_templates/scheduler_test.py`. Set `TARGET` and `CLASS` +only. Do not add files or tests the template does not already contain. ## 4. Gate (file-scoped — do not `--all` this library) ```bash -python3 ramp-kit/tools/convention_check.py ramp-kit/examples/candidate_scheduler python3 ramp-kit/tools/convention_check.py src/diffusers/schedulers/scheduling_.py python3 -m unittest tests.schedulers.test_scheduling_ -v ``` -Catch-early uses the kit fixture path. Stop at 0 blocking. Do not fabricate numerics. -Do not open a PR against huggingface/diffusers — PR this fork, **draft, base `main`** -(so `.github/workflows/ramp-kit-overlay.yml` runs). Two files only: scheduler + test. -No public-API export, no docs, no sampler math. +Fix every **blocking** finding. Stop at 0 blocking. Behavioral skips without +torch are success — do not edit `step()` to make them pass. + +Do not open a PR against huggingface/diffusers — PR this fork, **draft, base +`main`**, those two files only. diff --git a/tests/test_tooling.py b/tests/test_tooling.py index 94a2463..24d2a7b 100644 --- a/tests/test_tooling.py +++ b/tests/test_tooling.py @@ -567,6 +567,11 @@ def test_attach_writes_empty_mcp_servers(self): self.assertNotIn("convention_check.py --all", wf) self.assertIn("Never convention_check --all", wf) self.assertTrue((fake / ".github" / "scripts" / "overlay_pr_gate.py").is_file()) + scaffold = (fake / ".cursor" / "commands" / "scaffold.md").read_text() + self.assertIn("rules.yaml", scaffold) + self.assertIn("scheduling_TEMPLATE.py", scaffold) + self.assertNotIn("docs_mcp_server.py", scaffold) + self.assertNotIn("Those files are the contract", scaffold) def test_attach_does_not_delete_inherited_workflows(self): with tempfile.TemporaryDirectory() as td: @@ -589,6 +594,40 @@ def test_attach_does_not_delete_inherited_workflows(self): self.assertTrue((fake / ".github" / "workflows" / "ramp-kit-overlay.yml").is_file()) +class TestEngineerPromptScope(unittest.TestCase): + """Prompt A must not send the engineer into work the registry does not check.""" + + def _fork_prompt_a_paste(self) -> str: + text = (ROOT / "docs" / "CURSOR_PROMPTS.md").read_text() + start = text.index("## Prompt A — first contribution") + rest = text[start:] + fence = rest.index("```\n") + 4 + end = rest.index("\n```", fence) + return rest[fence:end] + + def test_prompt_a_stays_inside_registry_checked_files(self): + paste = self._fork_prompt_a_paste() + self.assertIn("conventions/rules.yaml", paste) + self.assertIn("scheduling_heun_lite.py", paste) + self.assertIn("test_scheduling_heun_lite.py", paste) + self.assertIn("TODO(engineer)", paste) + self.assertIn("scheduling_TEMPLATE.py", paste) + self.assertNotIn("scheduling_euler_discrete.py", paste) + self.assertNotIn("scheduling_ddpm.py", paste) + self.assertNotIn("docs_mcp_server.py", paste) + self.assertNotIn("docs/source", paste) + self.assertNotIn("search_docs", paste) + self.assertNotIn("grokbot_sim", paste) + + def test_overlay_scaffold_copies_templates_not_library_source(self): + text = (ROOT / "overlay" / "scaffold.md").read_text() + self.assertIn("rules.yaml", text) + self.assertIn("scheduling_TEMPLATE.py", text) + self.assertNotIn("Those files are the contract", text) + self.assertNotIn("docs_mcp_server.py", text) + self.assertNotIn("scheduling_euler_discrete.py", text) + + class TestOverlayPrGate(unittest.TestCase): def test_skips_when_no_relevant_files(self): env = {**os.environ, "OVERLAY_GATE_FILES": "README.md", "OVERLAY_KIT": str(ROOT)} diff --git a/tools/build_projections.py b/tools/build_projections.py index 18b4037..89a50d6 100644 --- a/tools/build_projections.py +++ b/tools/build_projections.py @@ -281,12 +281,12 @@ def build_cursor_core(): "`tools/convention_check.py` — the same gate that runs in CI, so producing", "code that violates a **block** rule will fail the build.", "", - "Use the `diffusers-docs` MCP tool (`search_docs`) to ground answers in the", - "library's current docs before scaffolding. If that tool is **not** in your", - "tool list (Cloud Agents skip project `.cursor/mcp.json` unless the launch", - "MCP dropdown has stdio `python3 -u .cursor/mcp-diffusers-docs.py`), run", - "`/search-docs `, the `search-docs` skill, or", - "`python3 tools/docs_mcp_server.py --query \"...\"` — same server.", + "The first contribution is what `conventions/rules.yaml` checks. Copy the", + "templates (`/scaffold`) and stop at 0 blocking findings from", + "`tools/convention_check.py` on the new files. Do not add files the", + "registry does not scan. Docs search (`search_docs` / `/search-docs`) is", + "optional and is not a deliverable.", + "", "Do not pull in code or context from outside this repo's approved", "boundaries (see `.cursorignore`).", "", @@ -300,8 +300,9 @@ def build_cursor_core(): lines.append(f"- **{r['id']} — {r['title']}.** {r['agent_hint']}") lines.append("") lines.append("Component-specific rules auto-attach when you open a matching file") - lines.append("(e.g. a scheduler). Prefer copying an existing in-repo example with a") - lines.append("`# Copied from` marker over inventing a new pattern.") + lines.append("(e.g. a scheduler). Start from `/scaffold` templates, not from a") + lines.append("library scheduler file. Use a `# Copied from` marker only when you") + lines.append("intentionally duplicate a small helper.") lines.append("") write(ROOT / ".cursor" / "rules" / "00-conventions.mdc", "\n".join(lines)) @@ -347,11 +348,9 @@ def build_agents_md(): "This repo uses convention-as-code. The authoritative rules live in", "`conventions/rules.yaml` and are enforced by `tools/convention_check.py`.", "Before opening a PR, run `make check` and fix every blocking finding.", - "Ground your work with the `diffusers-docs` MCP tool (`search_docs`).", - "If that tool is missing (Cloud Agents skip project `.cursor/mcp.json`", - "unless the MCP dropdown is `python3 -u .cursor/mcp-diffusers-docs.py`),", - "run `/search-docs `, the `search-docs` skill, or", - "`python3 tools/docs_mcp_server.py --query \"...\"` — same server.", + "The first contribution is the registry + templates, not a docs page or", + "a copied library scheduler. Optional docs search: `search_docs` MCP,", + "`/search-docs`, or `python3 tools/docs_mcp_server.py --query \"...\"`.", "", "## Conventions", ] @@ -379,7 +378,8 @@ def build_agents_md(): "marks paths that are off-limits as agent context.", "", "## First task", - "Ground first (`/search-docs` or MCP `search_docs`), then scaffold:", + "Copy the scheduler template and matching test, then run the file-scoped", + "gate until 0 blocking:", f"{comp_list}. See `.cursor/commands/scaffold.md`.", "", ])