From 5b1b5be4d6328323da1f6d0f5d99ea8f05a7d383 Mon Sep 17 00:00:00 2001 From: John Menke Date: Thu, 10 Sep 2026 19:24:30 -0400 Subject: [PATCH] Lock dogfood slash commands to the shipped Kasana I1/I2 templates. Cloud Agents execute .cursor/commands/, not templates/cursor/. Resync code and review via the install-time path rewrite and fail CI if they drift beyond that allowlist. Co-authored-by: Cursor --- .cursor/commands/sdlc-spdd-code.md | 13 ++++-- .cursor/commands/sdlc-spdd-review.md | 24 ++++++++-- README.md | 2 +- TESTING.md | 4 ++ docs/contributing-command-specs.md | 22 +++++++++ docs/research/kasana-agent-harness-2-0.md | 2 +- docs/research/uberorchbot-via-sdlc-spdd.md | 6 +-- tests/test-command-specs.sh | 53 ++++++++++++++++++++++ 8 files changed, 114 insertions(+), 12 deletions(-) diff --git a/.cursor/commands/sdlc-spdd-code.md b/.cursor/commands/sdlc-spdd-code.md index f6d16195..aa9ba1b9 100644 --- a/.cursor/commands/sdlc-spdd-code.md +++ b/.cursor/commands/sdlc-spdd-code.md @@ -31,14 +31,19 @@ Your job is to implement exactly one approved operation from a REASONS Canvas. 13. Update task status in the canvas and stage progress evidence via `./sdlc-spdd/scripts/sdlc.sh capture` (session record). 14. If the requested behavior conflicts with the canvas, stop and recommend `/sdlc-spdd-prompt-update` before changing code. 15. If no task is selected, ask which approved operation to implement before changing code. -16. Run Validation commands named on the selected canvas operation. If none, +16. Optional DIF check (never required). If `$DIF_HOME/scripts/dif-fold.sh` or a + sibling `../embabel-dif/scripts/dif-fold.sh` exists, run + `architect --quiet --canvas` on this Work ID. Exit 1: STOP and recommend + `/sdlc-spdd-architect` — do not implement. If the script is missing, continue + — that is not an error. Do not start a JVM from `sdlc.sh next` or `sdlc.sh gate`. +17. Run Validation commands named on the selected canvas operation. If none, discover the project's documented test/lint/typecheck commands when they exist. -17. On failure: do not mark the T## complete. Return the command output AND +18. On failure: do not mark the T## complete. Return the command output AND the Norm/Safeguard it maps to. Host may retry in-session. -18. If the same verify command fails twice with the same error, STOP. +19. If the same verify command fails twice with the same error, STOP. Recommend `/sdlc-spdd-prompt-update` or shelf. Do not loop forever. -19. After edits: `git diff --name-only` must stay within the active T## +20. After edits: `git diff --name-only` must stay within the active T## `Files:` plus test paths. Extra paths: do not mark complete. ## Context Backend (runtime-resolved) diff --git a/.cursor/commands/sdlc-spdd-review.md b/.cursor/commands/sdlc-spdd-review.md index 0c4983c6..6887bb05 100644 --- a/.cursor/commands/sdlc-spdd-review.md +++ b/.cursor/commands/sdlc-spdd-review.md @@ -39,11 +39,29 @@ Do not make code changes unless explicitly asked. `readiness:`) to **Reviewed** (or **Complete** if Final Status is also Complete). 20. Recommend `/sdlc-spdd-prompt-update` for behavior or requirement changes before additional code changes. 21. Recommend `/sdlc-spdd-sync` for accepted non-behavioral refactors after review. -22. Run the operation-diff-scope machine check: +22. Optional DIF check (never required). If `$DIF_HOME/scripts/dif-fold.sh` or a + sibling `../embabel-dif/scripts/dif-fold.sh` exists **and** snapshot files + `sdlc-spdd/spdd/snapshots/-before.json` and `sdlc-spdd/spdd/snapshots/-after.json` + exist, run `review --quiet --before … --after … --canvas sdlc-spdd/spdd/canvas/.md`. + Exit 1: do not set Reviewed / Approved; cite the one-line `dif=blocked` (and + `.gate.json` / VerificationResult). If the CLI or either snapshot is missing, + continue — that is not an error. Do not use login fixtures. Do not start a + JVM from `sdlc.sh next` or `sdlc.sh gate`. +23. Run the operation-diff-scope machine check: `./scripts/check-operation-diff-scope.sh --work-id ` (orchestrator: `./scripts/check-operation-diff-scope.sh`; installed - projects: `./sdlc-spdd/scripts/check-operation-diff-scope.sh`). - Exit 1: do not set Result to Approved or Approved With Notes. + projects: `./sdlc-spdd/scripts/check-operation-diff-scope.sh` or + `python -m sdlc_engine.canvas --work-id `). Optional + `--base ` adds `git diff --name-only ...HEAD`. Optional + `--ops T01,T02` limits Files: to those operations; default is + selected/completed T## (or all T## if none selected). Changed paths + must be a subset of those Files: plus allowed test paths + (`tests/**`, `engine/tests_unit/**`, `engine/tests_integration/**`, + `engine/tests_e2e/**`, or basename `test_*.py` / `*_test.py` / + `*.spec.md`). Exit 1 (extra production paths or `..` traversal): + do not set Result to Approved or Approved With Notes — use Changes + Requested or Blocked and list the extra paths. Hunk-level C-DRIFT + inside an allowed file remains a human finding. ## Context Backend (runtime-resolved) diff --git a/README.md b/README.md index 71b36c2b..23e4562e 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ Program detail: [Storage v3](docs/storage-v3.md) ## Current focus -**On main after [#264](https://github.com/jmjava/sdlc-spdd-orchestrator/pull/264)–[#269](https://github.com/jmjava/sdlc-spdd-orchestrator/pull/269):** Kasana I1–I3 on `/sdlc-spdd-code` and `/sdlc-spdd-review`, a copy-only `pre-commit.sample`, and this repo’s Cloud Agent `.cursor/environment.json`. Details: [Maintaining your project](docs/maintaining-your-project.md) · [Kasana overlay](docs/research/kasana-agent-harness-2-0.md). +**On main after [#264](https://github.com/jmjava/sdlc-spdd-orchestrator/pull/264)–[#270](https://github.com/jmjava/sdlc-spdd-orchestrator/pull/270):** Kasana I1–I3 on `/sdlc-spdd-code` and `/sdlc-spdd-review`, a copy-only `pre-commit.sample`, this repo’s Cloud Agent `.cursor/environment.json`, and the README sync for those contracts. Details: [Maintaining your project](docs/maintaining-your-project.md) · [Kasana overlay](docs/research/kasana-agent-harness-2-0.md). **Product:** ADF template library + Vue3 ops console (unchanged). diff --git a/TESTING.md b/TESTING.md index b1377ee7..bf297701 100644 --- a/TESTING.md +++ b/TESTING.md @@ -247,6 +247,10 @@ real upgrade. CI: `.github/workflows/test-upgrade-consolidate.yml`. `./tests/test-command-spec-generation.sh` asserts adapters match `spec/commands/*.spec.md`, that `--check` detects drift, and parity validation still passes (FEAT-002). +`./tests/test-command-specs.sh` also locks dogfood `.cursor/commands/sdlc-spdd-code.md` +and `sdlc-spdd-review.md` to the shipped Cursor templates after +`framework_rewrite_adapter_paths` (Cloud Agents execute dogfood, not `templates/cursor/`). + `./tests/test-commit-message-command.sh` asserts `/sdlc-spdd-commit-message` adapters exist with generate-only (no-commit) language, Python engine delegation (`sdlc.sh commit-message`), and that generator `--check` plus adapter validation diff --git a/docs/contributing-command-specs.md b/docs/contributing-command-specs.md index 79d70ee7..97fc1fb0 100644 --- a/docs/contributing-command-specs.md +++ b/docs/contributing-command-specs.md @@ -27,6 +27,19 @@ canonical spec per command. This removes hand-maintained three-way drift. ``` 4. Commit **both** the spec and generated template files. +5. If you changed `lifecycle-code` or `lifecycle-review`, resync this repo's + dogfood Cursor hosts (Cloud Agents execute `.cursor/commands/`, not + `templates/cursor/`). Use the same rewrite `install-cursor-commands.sh` + applies when `sdlc-spdd/` exists — do not copy templates blindly: + + ```bash + # surgical: copy the two templates, then framework_rewrite_adapter_paths + # (see scripts/lib/framework-install.sh). Or: + ./scripts/install-cursor-commands.sh --target . --force + ``` + + `--force` rewrites **all** Cursor commands. Prefer the surgical copy+rewrite + when only code/review changed. CI runs `generate-command-adapters.sh --check`, `validate-command-adapters.sh`, and `tests/test-command-specs.sh` — stale adapters or missing semantic contracts fail the build. @@ -115,6 +128,15 @@ If templates were edited by hand (avoid — prefer spec edits), refresh specs: - **No posture language** in generated adapters (`make it work/right/fast` stays in orchestrator planning docs only). Enforced by `check-posture-boundary.sh`. - **No new commands** under FEAT-002 — change existing commands only unless a new Work ID adds them. - Parity contract is encoded in `validate-command-adapters.sh` — read it when adding sections. +- **Dogfood Cursor code/review must match shipped templates** except the + explicit path substitutions in `framework_rewrite_adapter_paths` + (`scripts/sdlc-spdd/` → `sdlc-spdd/scripts/`, `./scripts/sdlc.sh` → + `./sdlc-spdd/scripts/sdlc.sh`, `spdd/` → `sdlc-spdd/spdd/`, and the other + rewrite rules in that function). Do not add substitutions. Orchestrator-root + `./scripts/` parentheticals the rewrite leaves alone + (`./scripts/resolve-context-backend.sh`, + `./scripts/check-operation-diff-scope.sh`) must stay. Locked by + `tests/test-command-specs.sh`. --- diff --git a/docs/research/kasana-agent-harness-2-0.md b/docs/research/kasana-agent-harness-2-0.md index 07a27be2..e5e4ea2b 100644 --- a/docs/research/kasana-agent-harness-2-0.md +++ b/docs/research/kasana-agent-harness-2-0.md @@ -209,7 +209,7 @@ I0 this note (done) Uberorchbot does not replace I1–I3. Cursor Automations (or a human) start Cloud Agents that run them; the Uberorchbot plugin is opt-in behavior inside the VM: see [Uberorchbot via SDLC-SPDD](uberorchbot-via-sdlc-spdd.md) (U0–U5). The platform is Cursor Environments + Cloud Agents, not a second farm. Native Automation self-chaining is out of scope. ``` -I1–I3 landed without promoting `LOCAL-001-kasana-harness-research`. The I3 copy-only leftover is done (#268). U2 (repo-managed `.cursor/environment.json`) is done in this repo. Next leftover is U3 in Uberorchbot. Do not invent a DOC/FEAT. +I1–I3 landed without promoting `LOCAL-001-kasana-harness-research`. The I3 copy-only leftover is done (#268). U2 (repo-managed `.cursor/environment.json`) is done in this repo. U3 (`sdlc-session` skill) is done in Uberorchbot (#16). Next leftover is U4 (live Automation save) in Uberorchbot — do not start it from this repo. Do not invent a DOC/FEAT. ### Out of plan (still not doing) diff --git a/docs/research/uberorchbot-via-sdlc-spdd.md b/docs/research/uberorchbot-via-sdlc-spdd.md index 04bfe66d..49cb0ead 100644 --- a/docs/research/uberorchbot-via-sdlc-spdd.md +++ b/docs/research/uberorchbot-via-sdlc-spdd.md @@ -135,11 +135,11 @@ Do **not**: | **U0** | Cloud Agents + Environments are the platform | this file (done) | | **U1** | Read Uberorchbot; correct dispatcher assumptions | this file (done in the U1 amendment) | | **U2** | Repo-managed `.cursor/environment.json`: `install` has `sdlc-engine`; builds enabled | this orchestrator (done) | -| **U3** | Opt-in `sdlc-session` skill: existing Work ID, gate, Resume Prompt, one phase, capture | Uberorchbot plugin | -| **U4** | Document and configure **separate** event-triggered Automations; re-check `gate` every run; shelf after repeat failure | Uberorchbot docs + Cursor Automations UI | +| **U3** | Opt-in `sdlc-session` skill: existing Work ID, gate, Resume Prompt, one phase, capture | Uberorchbot plugin (done — [Uberorchbot #16](https://github.com/jmjava/Uberorchbot/pull/16)) | +| **U4** | Document and configure **separate** event-triggered Automations; re-check `gate` every run; shelf after repeat failure | Uberorchbot docs + Cursor Automations UI (not started) | | **U5** | Reuse regenerated `/sdlc-spdd-code` (I1); do not duplicate the four bullets in the plugin | this repo I1, then U3 | -U2 is done in this repo (committed `.cursor/environment.json` + `.cursor/install.sh`). U3–U4 are plugin + Automation configuration, not a new control plane. +U2 is done in this repo (committed `.cursor/environment.json` + `.cursor/install.sh`). U3 is done in Uberorchbot (#16). U4 is live Automation save — not started. Do not invent a DOC/FEAT. ## Claims allowed diff --git a/tests/test-command-specs.sh b/tests/test-command-specs.sh index 30ac1b11..312e82bf 100755 --- a/tests/test-command-specs.sh +++ b/tests/test-command-specs.sh @@ -198,6 +198,59 @@ for adapter_file in \ "fail-closed approval in ${adapter_file#${REPO_ROOT}/templates/}" done +# --------------------------------------------------------------------------- +echo "== Dogfood .cursor/commands parity (code / review) ==" +# Cloud Agents and live-consumer in this checkout execute .cursor/commands/, +# not templates/cursor/. Allowlist vs shipped templates: only the substitutions +# in scripts/lib/framework-install.sh framework_rewrite_adapter_paths (the same +# rewrite install-cursor-commands.sh applies when sdlc-spdd/ exists). +# Orchestrator-root ./scripts/ parentheticals the rewrite leaves alone must stay. +# shellcheck source=../scripts/lib/framework-install.sh +source "${REPO_ROOT}/scripts/lib/framework-install.sh" + +assert_dogfood_matches_rewritten_template() { + local slug="$1" + local expected + expected="$(mktemp)" + cp "${REPO_ROOT}/templates/cursor/${slug}.md" "${expected}" + framework_rewrite_adapter_paths "${expected}" + if diff -q "${expected}" "${REPO_ROOT}/.cursor/commands/${slug}.md" >/dev/null 2>&1; then + ok "dogfood ${slug} matches rewritten template" + else + bad "dogfood ${slug} drifted from templates/cursor/${slug}.md beyond rewrite allowlist" + diff -u "${expected}" "${REPO_ROOT}/.cursor/commands/${slug}.md" | head -40 >&2 || true + fi + rm -f "${expected}" +} + +assert_dogfood_matches_rewritten_template sdlc-spdd-code +assert_dogfood_matches_rewritten_template sdlc-spdd-review +assert_contains "${REPO_ROOT}/.cursor/commands/sdlc-spdd-code.md" "Optional DIF check" \ + "dogfood code has Optional DIF" +assert_contains "${REPO_ROOT}/.cursor/commands/sdlc-spdd-review.md" "Optional DIF check" \ + "dogfood review has Optional DIF" +assert_contains "${REPO_ROOT}/.cursor/commands/sdlc-spdd-review.md" "python -m sdlc_engine.canvas" \ + "dogfood review has full I2 check-operation-diff-scope text" +assert_contains "${REPO_ROOT}/.cursor/commands/sdlc-spdd-code.md" "./scripts/resolve-context-backend.sh" \ + "dogfood code keeps orchestrator-root resolve-context-backend path" +assert_contains "${REPO_ROOT}/.cursor/commands/sdlc-spdd-review.md" "./scripts/check-operation-diff-scope.sh" \ + "dogfood review keeps orchestrator-root check-operation-diff-scope path" + +dog_code="${REPO_ROOT}/.cursor/commands/sdlc-spdd-code.md" +dog_bak="$(mktemp)" +cp "${dog_code}" "${dog_bak}" +printf '\n# dogfood-only drift\n' >> "${dog_code}" +expected="$(mktemp)" +cp "${REPO_ROOT}/templates/cursor/sdlc-spdd-code.md" "${expected}" +framework_rewrite_adapter_paths "${expected}" +if diff -q "${expected}" "${dog_code}" >/dev/null 2>&1; then + bad "dogfood parity compare missed injected drift" +else + ok "dogfood parity compare detects injected drift" +fi +cp "${dog_bak}" "${dog_code}" +rm -f "${dog_bak}" "${expected}" + # --------------------------------------------------------------------------- echo "== Generator staleness check ==" expect_pass "generate --check clean tree" "${GEN}" --check