Files
sdlc/skills/analyze/SKILL.md
T
jiantw83 015ceb66d2 perf(sdlc): 停止條件與閘門移到最前面
過去先問來源分支、先產生工作證、先建 worktree,等跑到閘門才發現沒有可挑的項目。前面的決策樹、wiki 寫入、抓取遠端與改名全部白做。

- 實作先讀分析頁、先結清已開 PR 的留言,再逐一過相依閘門,只有通過的候選才進選項。來源分支與工作證都移到領到工作包之後。
- 分析先併行讀計畫與分析目錄,沒有可分析的計畫就直接停。分支隨計畫而變,所以等目標定了才問。
- 互不相依的呼叫改成併發:已開 PR 的狀態批次預取、每個候選的相依查詢同時發、多個存取庫的 worktree 一起建、兩道收尾稽核並列跑。
- 領取登錄不成功就不得開工。沒有登錄,存取庫就沒有歸屬紀錄,之後每一支 PR 都會被當成無人認領而放行。上鎖失敗同樣要停,否則下一個工作階段會在 PR 還沒合併時就被放行。
- 來源分支改成單鍵確認。放棄的是每輪都要使用者明講「來源分支同時是 PR 目標」這道確認;分析頁沒記錄、遠端找不到分支這兩種例外仍走完整決策樹。
- 把仍寫成中文的驗收計畫步驟改回英文,與其他步驟一致。
2026-08-31 11:10:30 +08:00

80 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: analyze
description: SDLC analysis stage. Gate on capability tags enforced in code by sdlc-gate (analyze requires reasoning-max), pick a plan from PLAN_CONTENTS first, then confirm that plan's source branch and question until consensus per references/consensus.md. Analyze its user stories against the current state (working directory plus REPO_{HASH} inventory for reuse), then run WBS with a standalone delivery/handover WP-01, CPM estimates and TDD todos. Write wiki page ANALYZE_{HASH} with real sample data, 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 after planning and before implementation; not for writing code (that is implement), and not before a plan exists in PLAN_CONTENTS.
---
# analyze
Goal: create or extend the wiki analysis page `ANALYZE_{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 `ANALYZE_{HASH}` page name, computed by `jsc-gitea/tools/hash-id` (see `jsc-gitea:wiki`).
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 11 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 analyze`. 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. **Find out whether there is anything to analyze, before anything else costs the user a round.** Read `PLAN_CONTENTS` for plans whose status is the literal 「未分析」 (name and HASH), and read `ANALYZE_CONTENTS` for existing analyses. **The two pages are independent — read them concurrently, and do not wait for the source branch: which branch the analysis reads from depends on the plan, so it is confirmed in step 4, after the target is known.** Completion condition: you have listed every 未分析 plan with its name and HASH plus every existing analysis, or reported that both lists are empty and stopped.
3. Let the user choose per `jsc-ask:ask` rules: **extend an existing analysis** or **analyze a new plan**. State the impact scope on every option. Completion condition: the user has picked one option explicitly, and you have named the target — the existing `ANALYZE_{HASH}` page, or the plan the new analysis covers.
4. **Confirm the source branch for that target** — the branch whose code counts as the current state, confirmed before any code is read and before the analysis page is written:
1. Run `git fetch --prune origin` first — without it, every `origin/...` reference is stale cache. Then report the working directory's current branch, the **remote** branches available (`git branch -r`; never `git branch`) and whether the working tree is clean.
2. Ask per `jsc-ask:ask` rules which branch the analysis reads from; state the impact scope on every option (analysing the wrong branch produces work packages for code that does not exist).
3. **The current state is always the remote branch `origin/{source-branch}`, never the local one.** The working directory's HEAD must point at the same commit as `origin/{source-branch}`; behind, ahead or diverged all mean you would be analysing code that is not what the remote holds. Report the gap (`git rev-list --left-right --count origin/{source-branch}...HEAD`) and stop — this stage never switches branches, never stashes, never pulls and never touches the working tree. Rules in `references/branch.md`.
4. Record the confirmed branch and the head sha **of `origin/{source-branch}`** on the analysis page. Completion condition: the user has confirmed the branch explicitly, and the `origin` consistency check above has passed; never infer the branch from the current checkout alone.
5. Analyze the plan page's user stories one by one against the **current state**, **questioning until consensus** per `references/consensus.md` (the single authority for both planning and analysis): every answer produces the next question, and consensus needs both no output-changing unknown **and** the user's explicit confirmation. Never assume a missing detail, and never start the WBS while any item is still open. Current state means:
1. Every file in the working directory, at the commit `origin/{source-branch}` points to (verified in step 4).
2. **Reuse an existing method or endpoint unless its logic cannot satisfy the requirement**:
- Check the `REPO_{HASH}` inventory page first. Re-inventory when the feature or endpoint is missing, or when the recorded commit sha differs from the current one.
- Re-inventory **MUST run as a sub agent**: analyze the repository's features and endpoints, attach the current commit sha, write back to `REPO_{HASH}` with `templates/repo-page.md`, and upsert this repository's row in `REPO_CONTENTS` per `templates/repo-contents.md` — add the row if missing, otherwise refresh its commit sha and 盤點時間. `REPO_CONTENTS` is a contents page: read it back, change only this repository's row, and write the whole page. Never overwrite it wholesale, and never touch a row belonging to another repository.
- The `REPO_CONTENTS` read branches by exit code, and only exit 4 opens the create path — see "Contents pages are appended, never overwritten" below. `REPO_{HASH}` is a content page for one repository, so rewriting it whole is correct; the directory page around it is not.
- For each reuse candidate, confirm the file path and method name first, then analyze whether its logic fits the requirement. Reject a candidate only for a stated reason, and record both the candidate and that reason in the analysis page's 複用決策 field.
Completion condition: every user story has reached consensus under both conditions of `references/consensus.md`, and every reuse decision — reused, or rejected with its reason — is recorded in 複用決策.
6. Run a **Work Breakdown Structure (WBS)**: split the user stories into work packages, number them sequentially (`WP-01`, `WP-02`, ...) and mark dependencies. Completion condition: every user story on the plan page maps to at least one numbered work package, and every dependency edge is recorded in the WBS table's 相依 column.
7. **`WP-01` is always the delivery/handover work package** — see "Delivery package is WP-01" below. It stands alone, never merged into an implementation package, and every implementation package that consumes its spec depends on it. Completion condition: `WP-01` is marked 交付 `是` and holds only spec-shaped items, and every implementation package that consumes its spec names `WP-01` in its 相依 column — or the no-handover case below is confirmed with the user and its reason is written on the page.
8. Estimate every work package's effort in hours and days with the **Critical Path Method (CPM)**, and mark the critical path. Draw the critical path as a mermaid gantt chart per `references/cpm-chart.md` — its date/duration rules are mandatory, not a suggestion; skipping them is how the `Invalid date` rendering failure happens. Completion condition: every work package carries an hours figure and a days figure, the critical path plus its total days are written on the page, and the gantt chart follows `references/cpm-chart.md` exactly (integer-hour durations, `after` chaining, no `dateFormat X`).
9. **Write the user story acceptance plan first, then the TDD todos.** The acceptance plan goes under the section `## 使用者故事驗收計畫`; every work package is then broken down under `## 測試計畫(TDD)`, with `[ ]` for an open item and `[x]` for a finished one.
1. Every user story gets acceptance scenarios, and every scenario states its acceptance method as either `真實資料` or `邏輯推論`. Scenario count follows the story's complexity: a simple story takes at least 1; a medium story at least 2, covering one main flow plus one boundary or error flow; a complex story at least 3, covering the main flow, the boundary flow and the failure flow.
2. Every scenario states its input, its expected result, its data source and the work package it belongs to.
3. **Every TDD todo is one whole cycle**: one seam, one failing test first, one minimal implementation, one green verification, and a post-green refactor where it is needed. Never split the red test, the minimal implementation and the green verification into separate todos. Seams and anti-patterns: `references/tdd.md`.
4. Completion condition: every user story has scenarios under `## 使用者故事驗收計畫`; every scenario carries an explicit acceptance method and data source; the scenario count matches the story's complexity; every work package has its own subsection under `## 測試計畫(TDD)`; every implementation work package holds at least one test-first `[ ]` todo; and every todo states its seam, its acceptance scenario, the behaviour the test asserts, the minimal implementation scope and how green is verified. A pure delivery package may use document-verification or sample-data-verification todos instead, and still states the test evidence or the review evidence that proves the spec is usable.
10. **Write the analysis page and its catalogue entries in one wiki pass.** Apply `templates/analyze-page.md` to create or update the analysis page and write it back via `jsc-gitea:wiki`; the page content is Traditional Chinese, exactly as the template dictates. `ANALYZE_CONTENTS` and `PLAN_CONTENTS` are then upserted per "Contents pages are appended, never overwritten" below: read each page back, add this analysis's row to `ANALYZE_CONTENTS` if it is missing and otherwise refresh it, flip only this plan's status in `PLAN_CONTENTS` to the literal 「已分析」, and write each whole page back. Completion condition: the analysis page is saved on the wiki carrying every section the template dictates — the source branch, the head sha and the 未決項 section (「無」 when there is none) included — and, for a new page, `ANALYZE_CONTENTS` shows its new row and `PLAN_CONTENTS` shows the literal 「已分析」, both saved on the wiki.
11. **Stage report — the last thing this stage does, including every early stop** (the model gate blocked, the working tree did not match `origin/{source-branch}`, no plan was selectable, a wiki read or write failed). Run `tools/stage-report.sh analyze` with one `--page TYPE:{page}` per wiki page this run wrote — `ANALYZE_{HASH}`, `ANALYZE_CONTENTS`, `PLAN_CONTENTS`, and `REPO_{HASH}` plus `REPO_CONTENTS` when a re-inventory happened — plus `--worklog` and `--worklog-heading` when a work log entry exists. No work log yet: write this stage's log content to a file 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
`ANALYZE_CONTENTS`, `PLAN_CONTENTS` and `REPO_CONTENTS` are shared directories: every row on them belongs to somebody's plan, analysis or repository, and this run reads none of those rows from anywhere else. So every write to them is an upsert of one row on top of the content just read — add the row if missing, otherwise refresh it, then `wiki-put` the whole page. Whole-page overwrite is forbidden, and a row this run does not own stays untouched.
That rests entirely on reading the old page back, so branch the `wiki-get` on its exit code:
| Exit | What this step does |
| --- | --- |
| 0 | the page is there — upsert this run's row into the content that came back, then write the whole page |
| 4 | the page really does not exist yet — this is the **only** code that permits building it from the template |
| 7 | the key is invalid or lacks permission — stop, report the code and its cause, create no page and write nothing |
| 8 | any other API failure — same as 7: stop and report, 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" makes this step write a fresh template over a live directory, and every other row is gone — the write carries no merge and no backup. Content pages (`ANALYZE_{HASH}`, `PLAN_{HASH}`, `REPO_{HASH}`) are the opposite case: each belongs to one subject, so rewriting one whole is correct. The distinction is the page, not the write.
Completion condition: every contents-page write this stage made names the `wiki-get` exit code it branched on, and no page was created on any code other than 4.
## Delivery package is WP-01
A work package is a **delivery/handover package** when someone else — another person, another CLI, another team — has to act on its output. Interfaces, schemas, spec documents, acceptance criteria and sample payloads are delivery output; endpoint bodies and UI wiring are not.
- **`WP-01` is the delivery/handover package, always first, always standalone.** Pull every spec-shaped item out of the implementation packages and put it here. Never merge a spec into the package that implements it — merging removes the ability to hand the spec over early, which is the whole point.
- **Implementation packages depend on `WP-01`** when they consume its spec, and they are the backup queue: still numbered, still estimated, still on the page, just ranked after it.
- Mark every work package as 交付 `是` / `否` in the WBS table, and record `WP-01`'s intended content type in the 交付型別 column when the user has already decided it (options in `references/deliver-formats.md`; the type is confirmed for real when `implement` starts that package).
- Dependencies still win among the rest: never place a package before one it depends on. Within the same dependency level, delivery-shaped packages come first.
- **When nothing is genuinely deliverable** (say, an internal refactor with no interface change), do not invent an empty `WP-01`: confirm with the user per `jsc-ask:ask` that this analysis has no handover output, then note the reason on the page and number the implementation packages from `WP-01`.
## Sample data
Every sample value on the analysis page — request and response payloads, field values, config snippets, test fixtures — follows `references/deliver-formats.md`, which owns the source order, the labelling and the API-document layout. Record each value's origin in the WBS table's 資料來源 column. Completion condition: every sample value on the page carries a 資料來源 label of either 「真實:{source}」 or 「推論:無來源」, and no sample value contains personal data.
## Hard limits
- Never output a code snippet (file paths and method names are allowed).
- **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 analyze` 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.
- Never switch, create or clean branches in this stage; ask the user to do it.