What:PLAN、ANALYZE、DELIVER、MAINTAIN、REPO 五個目錄頁改由 wiki-repo CONTENTS 解析並透過 wiki-contents.sh upsert 寫入,內容頁仍各走自己的型別。MAINTAIN 只有 目錄頁,整個型別都在專用存取庫。 Why:目錄頁與內容頁不再同庫,跨庫沒有 wiki 連結語法可用,一律改 wiki-url 的絕對 網址。原本四處取網址都沒有退出碼分流,5 被讀成空字串就寫出空連結,7 被讀成 4 就 把活著的頁當成沒寫成。 How:plan 與 analyze 會上階段鎖,而寫入閘門只看鎖不看路徑,所以流程要產的列檔與 暫存檔會被自己的閘門擋掉。兩支的限制段明寫這些檔一律用 heredoc 或 mktemp 產出。 wp-gate.sh 讀的是分析內容頁,維持走 ANALYZE,原地註明不得改成 CONTENTS。 Who:jsc-sdlc
76 lines
12 KiB
Markdown
76 lines
12 KiB
Markdown
---
|
|
name: plan
|
|
description: SDLC planning stage. Gate on capability tags enforced in code by sdlc-gate (plan requires reasoning-max, verified against the transcript's actual model id), pick or create a plan from PLAN_CONTENTS, which sits in the separate CONTENTS wiki repo, then run a decision tree until goal, scope, and feasibility reach consensus. Produce user stories into wiki page PLAN_{HASH} in the PLAN wiki repo, upsert the directory row through jsc-gitea/tools/wiki-contents.sh with an absolute wiki-url link, then close with tools/stage-report.sh - model tag verdict, worklog link, every wiki link written. Logic only - never write code or modify files. Use when the user wants to start or refine a plan; not for analysis or implementation.
|
|
---
|
|
|
|
# plan
|
|
|
|
Goal: create or extend the wiki plan page `PLAN_{HASH}`.
|
|
This skill is a **logic-only** stage: never output code, and **never modify any file**.
|
|
|
|
`{HASH}` = the shared wiki hash for `{owner}/{repo}` used to build the `PLAN_{HASH}` page name, computed by `jsc-gitea/tools/hash-id` (see `jsc-gitea:wiki`). It prints the **full 40-character uppercase SHA-1** of its input — no truncation to 8 characters, no prefix rewrite. Never shorten it by hand: a shortened name points at a page nobody else writes to.
|
|
|
|
**The two pages this stage touches live in two different wiki repos.** The content page `PLAN_{HASH}` sits in the repo `jsc-gitea/tools/gitea.sh wiki-repo PLAN` resolves. The directory page `PLAN_CONTENTS` sits in the repo `gitea.sh wiki-repo CONTENTS` resolves — `JSC_WIKI_REPO_CONTENTS` first, `JSC_WIKI_REPO` second, exit 3 when neither is set; it **never** falls back to `JSC_WIKI_REPO_PLAN`. Because the two pages sit in different wikis, the directory row links the plan page by the absolute URL from `gitea.sh wiki-url {PLAN repo} PLAN_{HASH}`: `[[...]]` resolves only inside one wiki and would dead-link from the directory.
|
|
|
|
All wiki reads and writes go through `jsc-gitea:wiki`. **A failed wiki read or write stops this stage**: report which page and which operation failed, never carry on against a page you could not read, and never report a page as saved when the write failed. Step 8 still runs after such a stop.
|
|
|
|
## Steps
|
|
|
|
1. **Model gate and stage lock** — run `jsc-cli/tools/model-tags.sh sync`, then `jsc-hooks/hooks/sdlc-gate.sh lock plan`. This stage requires the `reasoning-max` capability tag. Rules: `references/model-gate.md`. Completion condition: the script exited 0, and you have reported the stage, the required tag, the actual model id it read from the transcript, and the verdict.
|
|
2. Read `PLAN_CONTENTS` via `jsc-gitea:wiki`, out of the CONTENTS wiki repo (`gitea.sh wiki-repo CONTENTS`, never the PLAN one), and list the plans whose status is the literal 「未分析」 (not analyzed), with names and HASH. Completion condition: you have listed every 未分析 plan with its name and HASH, or reported that none exists.
|
|
3. Let the user choose per `jsc-ask:ask` rules: **extend an existing plan** (list the not-analyzed plans as options) or **create a new plan**. State the impact scope on every option. Completion condition: the user has picked one option explicitly, and you have named the `PLAN_{HASH}` page this run writes to.
|
|
4. **Keep questioning until consensus** — rules in `references/consensus.md`, which is the single authority for both planning and analysis. Cover all three items:
|
|
- Goal: the problem to solve and the criteria for success.
|
|
- Scope: what is included, what is excluded, which repositories are involved.
|
|
- Feasibility: whether the system architecture and data sources support the goal.
|
|
|
|
**One round is never enough**: every answer must produce the next question, derived from what that answer just exposed. Never fill a gap with your own assumption, and never move on to user stories while any item is still open.
|
|
|
|
Completion condition: all three items are settled under both conditions of `references/consensus.md` — no remaining unknown that would change the output, **and** the user's explicit confirmation of the summary you read back.
|
|
5. Turn the consensus into **user stories** (the zh-TW pattern 「身為⋯⋯我想要⋯⋯以便⋯⋯」), one per line. Completion condition: every consensus item is covered by at least one user story in that pattern, and no user story rests on an unanswered question.
|
|
6. Apply `templates/plan-page.md` to create or update the plan page **in the PLAN wiki repo**, and write it back via `jsc-gitea:wiki`. The page content is Traditional Chinese, exactly as the template dictates. Completion condition: the page is saved on the wiki and carries every section the template dictates — goal, scope, feasibility, user stories and the consensus summary — with no placeholder left unfilled.
|
|
7. Upsert this plan's row in `PLAN_CONTENTS` with `jsc-gitea/tools/wiki-contents.sh`; never hand-edit the directory page. **Take the plan page's absolute link from `gitea.sh wiki-url {PLAN repo} PLAN_{HASH}` first, and branch on that command's exit code before the row is built** — the same branching `jsc-log:worklog` runs over this call:
|
|
|
|
| Exit | What this step does |
|
|
| --- | --- |
|
|
| 0 | use the URL it printed, verbatim |
|
|
| 4 | the page is not on the wiki, so the step 6 write has not landed — go back to step 6 and come here again only once the page is saved |
|
|
| 5 | the page exists but carries no `html_url` — stop and report it, and never assemble the URL by hand; a hand-built path is not the one Gitea serves |
|
|
| 7 | the key is invalid or lacks permission (HTTP 401/403) — stop and report the key problem. Never read this as exit 4: the plan page is alive, and treating it as absent records a live page as one that was never written |
|
|
| 8 | any other API failure — stop and report that status, and do not retry the same call unchanged |
|
|
|
|
Never let an empty string stand in for the URL: a row whose link cell is empty is a directory entry that points nowhere, and the next run overwrites it as if it were correct. Then build one file holding the single row from `templates/plan-contents.md` — the plan name, that absolute link, the code repository, the HASH, the literal 「未分析」 and the creation date; produce that file per Hard limits, with a Bash heredoc or `mktemp`, never with `Write` or `Edit`. Then run `jsc-gitea/tools/wiki-contents.sh upsert PLAN 4 {HASH} {row file} templates/plan-contents.md`. The key is the HASH column, column 4, written exactly as the row file writes it; a key typed by hand appends a second row for the same plan. Branch on the exit code per "Contents pages are appended, never overwritten" below. Completion condition: `wiki-url` returned 0 and its URL is the one in the row, the upsert exited 0, `PLAN_CONTENTS` shows this plan's row with the literal 「未分析」 and that absolute plan-page link, and you have reported both exit codes plus whether the script printed `updated` or `added`.
|
|
8. **Stage report — the last thing this stage does, including every early stop** (the model gate blocked, no plan was selectable, a wiki read or write failed). Run `tools/stage-report.sh plan` with one `--page TYPE:{page}` per wiki page this run wrote — `--page PLAN:PLAN_{HASH}` for the content page and `--page CONTENTS:PLAN_CONTENTS` for the directory page, because the script resolves each page's repo from the TYPE you pass and the two pages no longer share one — plus `--worklog` and `--worklog-heading` when a work log entry exists. No work log yet: write this stage's log content to a file — with a Bash heredoc or `mktemp` per Hard limits, never with `Write` or `Edit` — and pass `--pending-file {file} --log-hash {HASH}` so it is held for the next `jsc-log:worklog` run. Rules and exit codes: `references/stage-report.md`. Exit 1 is a warning, never a block. Completion condition: the script's output is reported to the user verbatim, and every wiki page this run wrote appears in it.
|
|
|
|
## Contents pages are appended, never overwritten
|
|
|
|
`PLAN_CONTENTS` is a shared directory in the CONTENTS wiki repo: every row on it belongs to somebody's plan, and this run reads none of those rows from anywhere else. So the write is an upsert of one row on top of the content just read — never a whole-page overwrite, and never a row that belongs to another plan. `jsc-gitea/tools/wiki-contents.sh upsert` is the one way this stage does it: it resolves the CONTENTS repo, reads the whole page, replaces the row whose key column matches and appends when none matches, then writes the page back.
|
|
|
|
Branch on its exit code:
|
|
|
|
| Exit | What this step does |
|
|
| --- | --- |
|
|
| 0 | the row is in place — carry the `updated` or `added` word it printed into the stage report |
|
|
| 1 | the write failed, or the page holds no markdown table — report it as a failed write and go to step 8 as a failure |
|
|
| 2 | an argument was rejected (unknown type, key column, missing row file) — fix the argument and run it again; nothing was written |
|
|
| 3 | no CONTENTS wiki repo is configured — stop and report `JSC_WIKI_REPO_CONTENTS` and `JSC_WIKI_REPO` as the two variables to set. The plan page itself is saved and stays saved |
|
|
| 4 | the directory page is absent and no template was passed. **Step 7 always passes `templates/plan-contents.md`, so this code does not come out of this skill's call** — a wrong template path is rejected as 2, not as 4. Seeing it anyway means the template file is not where the plugin puts it: confirm the plugin installation is complete and run it again. Never answer it by dropping the template argument |
|
|
| 7 | the key is invalid or lacks permission — stop and report the key problem; the script wrote nothing, which is what keeps the other plans' rows alive |
|
|
| 8 | any other API failure — stop and report that status, and do not retry the same call unchanged |
|
|
|
|
Why 7 and 8 abort: both mean the old content is unknown, not that the page is missing. Reading either as "not there yet" would write a fresh template over a live directory, and every other plan's row is gone — the write carries no merge and no backup. `PLAN_{HASH}` is the opposite case: it is a content page belonging to this one plan and living in the PLAN repo, so step 6 rewriting it whole is correct. The distinction is the page, not the write.
|
|
|
|
Completion condition: the `PLAN_CONTENTS` write names the `wiki-contents.sh` exit code it branched on, and no directory page was created on any code other than 4.
|
|
|
|
## Hard limits
|
|
|
|
- Never output a code snippet.
|
|
- **Never modify any file in the working directory.** This limit is enforced in code where the CLI allows it: `jsc-hooks/hooks/write-guard.sh` in `stage` mode runs as a `PreToolUse` hook and blocks `Write`, `Edit` and `MultiEdit` while this stage's lock exists — the same lock state `jsc-hooks/hooks/sdlc-gate.sh lock plan` writes in step 1. **Only claude has `PreToolUse`.** Codex, copilot, antigravity and kiro never reach that hook, so on those four CLIs this line is the only thing holding the limit.
|
|
- **The row file of step 7 and the pending-file of step 8 are produced with a Bash heredoc or `mktemp`, in a temporary directory — never with the `Write` or `Edit` tool.** That gate blocks on the stage lock alone and never looks at the path, so a `Write` of either file is blocked by this stage's own lock and the stage cannot finish: the directory row never gets written and this stage's log content is never parked. Both files are scratch input to a script, they live outside the working directory, and writing them this way keeps the limit above intact — nothing in the working directory is touched.
|
|
- Never skip the decision tree and assume requirements.
|
|
- Never stop questioning after one round; consensus is reached only under `references/consensus.md`, and the user says so.
|
|
|
|
## What the work package gate no longer stops here
|
|
|
|
`jsc-hooks/hooks/sdlc-gate.sh wp-check` used to block this skill outright while the repository still held an unsettled work package PR. For `plan` it is now a reminder that prints and lets the run through. The protection given up is the **work-in-progress cap**: nothing stops a new plan from starting while packages from the last one are still open, so plans can pile up faster than they are implemented. The reminder still names the unsettled package, and the same gate still blocks `analyze` and `maintain`, so the cap holds one stage later. `implement` was always waved through — that is the path that settles the open PR, and a gate that blocked it would lock itself.
|