Files
sdlc/skills/maintain/SKILL.md
jiantw83 c7d9777d04 fix(frontmatter): 修正 maintain 技能 SKILL.md frontmatter 的 YAML 純量語法錯誤
What:
- 修正 skills/maintain/SKILL.md frontmatter 裡 description 欄位的 YAML 語法錯誤。
- 整串 description 加上單引號,內部撇號改寫成兩個單引號,內容文字一個字都沒變。
- 同步更新 plugin.json、.claude-plugin/plugin.json、.codex-plugin/plugin.json 三個 manifest 版本號,從 0.2.7 進到 0.2.8。

Why:
- description 內含「冒號加空白」,屬於未加引號的 YAML plain scalar,違反 YAML 語法規定。
- Antigravity 解析 frontmatter 時當場中斷,整支技能被靜默丟棄,沒有任何錯誤訊息;磁碟上 34 支技能,Antigravity 只認得 28 支。
- 準則要求 description 用英文撰寫,不能把「: 」改成全形冒號迴避語法問題,只能加引號修正。

How:
- 整串 description 值加上單引號,內部撇號寫成兩個單引號跳脫,其餘字元不動。
- 用 git show HEAD: 取出改前的原始值,把改後的單引號純量還原後做字串相等比對,確認逐字相同、字元數一致。
- 執行 ste100-lint.sh、check-behaviors.sh、lint-frontmatter.sh 三支檢查腳本,退出碼皆為 0;git diff --numstat 顯示只動了 frontmatter 那一行。

Who:
- 本次修到 sdlc 技能組的 maintain 技能,屬 SDLC 維運階段、定期維護已交付專案的功能。
2026-08-31 19:04:17 +08:00

9.4 KiB

name, description
name description
maintain SDLC maintenance stage. Gate on capability tags enforced in code by sdlc-gate (maintenance requires no specific tag, but the actual model id must be determinable from the transcript), read projects still inside their maintenance window from MAINTAIN_CONTENTS, then run one sub agent per project: switch to develop or master, propose at least five maintenance actions, commit to a new branch, push, and PR. Write a jsc-log:worklog entry per finished project and update the last-maintained timestamp afterward, then close with tools/stage-report.sh - model tag verdict, worklog link, every wiki link written. Use for periodic upkeep of delivered projects inside their maintenance window; not for projects still mid-implementation or not yet registered in MAINTAIN_CONTENTS.

maintain

Goal: run routine maintenance for every project in the maintenance contents page. 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 5 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 maintain. This stage requires no specific capability tag; the gate passes as long as the script can determine the actual model id. 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 MAINTAIN_CONTENTS via jsc-gitea:wiki and filter projects still inside their maintenance window: start date ≤ today, and (end date is NULL or ≥ today). Completion condition: you have listed every in-window project with its {owner}/{repo} and window dates, or reported that none is in window and stopped.
  3. Align every project in one batch first, then run one sub agent per project. Completion condition: every project listed in step 2 has its sub agent finished, and each one ends in either a PR link or a recorded skip reason.
    1. Batch prefetch, run by the main agent before any sub agent starts. For every in-window project from step 2, run git fetch --prune origin, then put it on its maintenance branch and align it with origin/{branch}. The projects are independent — run this batch concurrently, and hand each sub agent the branch name and the aligned commit sha instead of letting it fetch again. Which branch that is, the remote-is-the-basis rule, the diverged case and the never-pull-never-reset rule all live in references/branch.md; never guess the branch name. From sub-step 3.2 onward the flow is one project at a time, sequential, so that 3.5's work log rule holds. Completion condition: every project's HEAD points at the same commit as origin/{branch}, or its gap is reported and that project is skipped and left out of the sub agent runs.

    2. From here on, one project at a time, and each project's maintenance MUST run as a sub agent. Propose at least five maintenance methods, then let the user pick per jsc-ask:ask rules — every option states its impact scope (which files it touches, whether it can break the build, how much review it costs). Candidates:

      • dependency updates (reuse jsc-pkg:pkg-update)
      • security vulnerability scan and patching
      • dead code and stale comment cleanup
      • test coverage reinforcement
      • docs and README synchronization
      • build warning elimination

      Completion condition: the user has picked the methods to apply, and every picked method is either applied or reported with the reason it could not be.

    3. A code comment states why the code is written this way; it never states where the work is tracked. Issue numbers, commit hashes, branch names, people's names and @ mentions stay out of every code comment this project's maintenance touches — including the comments the cleanup method rewrites. Full list and the allowed exceptions: jsc-review/references/comment-scope.md. Two passes already cover the diff, so run no separate manual sweep of your own: jsc-hooks/hooks/comment-scope.sh compares each file after it is written and prints a warning — fix the flagged line at once, then carry on — and jsc-git:commit sweeps the whole working tree again in step 3.4, before anything is committed. Coverage is not the same on every CLI: only claude gets the per-file warning as the file is written. On codex, kiro, copilot and antigravity the hook fires late — at the end of the turn on codex, at the next prompt submit on kiro, at the end of the session on copilot and antigravity — so the pre-commit sweep in step 3.4 is the only pass on all four that lands in time to keep a flagged comment out of the commit. Completion condition: every warning the hook printed is fixed, and the step 3.4 sweep reported no remaining comment line carrying an issue number, a commit hash, a branch name, a person's name or an @ mention.

    4. Commit the changes to a new branch per jsc-git:commit, push, then open a PR per jsc-git:pr back to the branch of step 3.1, passing it explicitly as the base. Completion condition: the PR exists, and you have reported it with the table format in jsc-meta/references/pr-report.md.

    5. One project's maintenance is one finished task — call jsc-log:worklog right after its PR is open. A task is one of three things: one work package, one round of PR-comment fixes, or one standalone fix commit; this stage produces the third kind, one per project. Never let the stage end and then write a single catch-up entry, and never let a second project start before the first one's entry is saved — by then the elapsed time, the token counts and the difficulties are gone. Every entry appends to the same LOG_{HASH} page. Content parked earlier by tools/stage-report.sh --pending-file is merged into that same write and cleared only once the write succeeds; parked content is not a written log. Completion condition: this project's entry is saved on LOG_{HASH} before the next project's sub agent starts.

    6. Update the project's last-maintained field (the zh-TW column 「前次維護時間」) in MAINTAIN_CONTENTS to today, per "Contents pages are appended, never overwritten" below: read the page back, change only this project's row (add it if it is missing), and write the whole page. Completion condition: MAINTAIN_CONTENTS shows today's date in 「前次維護時間」 for that project, every other project's row is byte-for-byte unchanged, and the wiki-get exit code the write branched on is named.

  4. The main agent reports the summary: maintenance methods applied per project, PR table rows, and failure reasons. The report and all generated wiki content, commits, and PR descriptions stay Traditional Chinese per the STE100 rule. Completion condition: the summary names every project read in step 2, each with its applied methods and either a PR table row or the reason it was skipped.
  5. Stage report — the last thing this stage does, including when no project was in window, and when a wiki read or write failed. Run tools/stage-report.sh maintain with one --page MAINTAIN:{page} per wiki page this run wrote (MAINTAIN_CONTENTS counts), plus --worklog and --worklog-heading pointing at the entries step 3.5 wrote. --pending-file {file} --log-hash {HASH} is the fallback for a stage that stopped before any project finished: it holds the content for the next jsc-log:worklog run, and held content is not a written log. 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

MAINTAIN_CONTENTS is a shared directory: every row on it belongs to somebody's project, and this run reads none of those rows from anywhere else. So step 3.6 is an upsert of one row on top of the content just read — add the row if missing, otherwise refresh its 前次維護時間 — then wiki-put the whole page. Whole-page overwrite is forbidden, and a project this run did not maintain keeps its row 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 project'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, and it also means step 2 had no project to maintain
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 step 3.6 write a fresh template over a live directory, and every other project's maintenance window is gone — the write carries no merge and no backup. Content pages, which belong to one subject each, are the opposite case and may be rewritten whole. The distinction is the page, not the write.

Completion condition: the MAINTAIN_CONTENTS write names the wiki-get exit code it branched on, and no page was created on any code other than 4.