docs(skills): 五支技能與盤點技能的目錄頁呼叫敘述同步條列版面

What
- `skills/skill-new`、`skills/skill-update`、`skills/skill-delete`、`skills/skillset-update`、`skills/skill-check`:目錄頁寫入步驟的呼叫從「單列 upsert」改成單一 H2 區塊 upsert,鍵補上內容頁頁名這個引數,並註明第四個引數是區塊檔而不是列檔。
- `skills/tooling-guide`:盤點結果寫回目錄頁的敘述照同一套改寫,並寫明鍵是內容頁頁名。
- `references/behaviors.md`:六支技能的關鍵步驟、外部呼叫與可驗證跡象三列同步,跡象從「留下自己那一列」改成留下自己那一個 H2 區塊,區塊內的連結寫成一條欄位。

Why
- 範本與準則已經改成條列版面,技能內文還寫著「那一列」,執行時就會照舊敘述組出表格列,跟工具的區塊 upsert 對不上。
- 呼叫少帶鍵這個引數,工具無從判斷要換掉哪一個區塊,同一筆會被當成新的附加上去。
- 行為清單是稽核與驗證的比對基準,敘述沒跟上,稽核會拿舊描述判合規。

How
- 六支技能的呼叫一律寫成 `wiki-contents.sh upsert {TYPE} {鍵欄} "{內容頁頁名}" {區塊檔} [{範本}]`,並在旁邊點明目錄頁一律大標題加條列。
- 完成條件與可驗證跡象改用區塊的說法,連結範例改成 `- {欄位名}:[{頁名}]({連結})` 的形態。
- 只改敘述,不動任何腳本;轉檔與 upsert 的實作在別的存取庫。

Who
- 本存取庫六支會寫目錄頁的技能。
- 稽核與驗證流程改拿新的行為清單比對。
This commit is contained in:
2026-09-02 17:21:02 +08:00
parent 5541a41ff7
commit 15fdb7e140
7 changed files with 88 additions and 81 deletions
+12 -12
View File
@@ -1,6 +1,6 @@
---
name: skill-check
description: Routine compliance, script, hook, flow-efficiency, and cost-efficiency audit of the whole jsc skill set with no change request in hand. Sync every domain repo from the Gitea canonical marketplace, then run three parallel groups - lint-scripts.sh plus lint-frontmatter.sh plus check-behaviors.sh plus ste100-lint.sh plus check-link-format.sh plus check-wiki-rules.sh plus check-page-name.sh plus hook smoke, the guidelines.md checklist audit, and an optimization review that first reads each domain's SKILLSET_{HASH} so suggestions already applied or deferred are never re-scanned or re-asked, then covers parallelism, tool extraction, repeated interaction, redundant checks, misplaced gates, and avoidable token, sub-agent, API, scan, or interaction cost. Confirm compliance fixes and optimization suggestions before applying them, recording each decision with its date, re-check until accepted fixes pass, then open a PR per affected repo via jsc-git pr. Close by appending the round's result to every changed domain's SKILLSET_{HASH} and its SKILLSET_CONTENTS row, or to the plugins/meta page when no domain was changed. Use for periodic or on-demand skill-set checks; not for applying a change request (use skillset-update) or editing one skill (use skill-update).
description: Routine compliance, script, hook, flow-efficiency, and cost-efficiency audit of the whole jsc skill set with no change request in hand. Sync every domain repo from the Gitea canonical marketplace, then run three parallel groups - lint-scripts.sh plus lint-frontmatter.sh plus check-behaviors.sh plus ste100-lint.sh plus check-link-format.sh plus check-wiki-rules.sh plus check-page-name.sh plus hook smoke, the guidelines.md checklist audit, and an optimization review that first reads each domain's SKILLSET_{HASH} so suggestions already applied or deferred are never re-scanned or re-asked, then covers parallelism, tool extraction, repeated interaction, redundant checks, misplaced gates, and avoidable token, sub-agent, API, scan, or interaction cost. Confirm compliance fixes and optimization suggestions before applying them, recording each decision with its date, re-check until accepted fixes pass, then open a PR per affected repo via jsc-git pr. Close by appending the round's result to every changed domain's SKILLSET_{HASH} and its SKILLSET_CONTENTS block, or to the plugins/meta page when no domain was changed. Use for periodic or on-demand skill-set checks; not for applying a change request (use skillset-update) or editing one skill (use skill-update).
---
# skill-check — audit compliance, flow efficiency, and cost efficiency
@@ -94,14 +94,14 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
- **Which page.** For every domain repo actually changed in this round, resolve `gitea.sh wiki-repo SKILLSET` and append one section to `SKILLSET_` plus `gitea.sh hash-id "{owner}/{repo}"` of that domain repo. Append; never overwrite — the page accumulates every change that domain has ever seen.
- **When nothing changed.** No domain repo changed in this round means one page, hashed from `plugins/meta`, gets one section recording 「本輪無發現」 with the group verdicts that produced that conclusion. A round that found nothing still has to leave the evidence that it ran.
- **What each section holds.** The layout is [`../../templates/skillset-page.md`](../../templates/skillset-page.md): date, change type `skill-check`, the change request in one sentence, the skills touched, the files changed, the PR URL from step 7, the deploy-route verdict and the verification result. The `skill-check` section additionally carries the 優化建議 table, every row filled including 決議 and 決議日期 — that table is exactly what the next round reads in step 2's group 3.
- **Directory page.** Refresh that page's row in `SKILLSET_CONTENTS` with `jsc-gitea/tools/wiki-contents.sh` — never by hand, and never through `jsc-gitea:wiki`. Build one file holding the single row from [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), then run:
- **Directory page.** Refresh that page's own block in `SKILLSET_CONTENTS` with `jsc-gitea/tools/wiki-contents.sh` — never by hand, and never through `jsc-gitea:wiki`. That page is a heading-plus-bullets list and holds no markdown table: one `## SKILLSET_{HASH}` block per domain repo, every field one `- {欄位名}:{值}` line under it. Build one file holding this domain's single block, following [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), then run:
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "{owner}/{repo}" {row file} templates/skillset-contents.md`
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" {entry file} templates/skillset-contents.md`
The key column is `2`, the 存取庫 column, and the key is that domain repo's `{owner}/{repo}` written exactly as the row file writes it; the string is the same every round, so one domain keeps exactly one row. The script resolves the CONTENTS repo itself — the directory page lives there, never in the SKILLSET repo — reads the whole page, replaces the row whose key column matches, appends when none matches, and writes the page back, so every row owned by another domain stays as it was.
The key is the H2 heading `SKILLSET_{HASH}`, and that page name depends only on the domain repo's `{owner}/{repo}`, so it reads the same every round and one domain keeps exactly one block. The `2` is the key column: the index of the column that held the content-page link in the **old markdown table**, and it matters only when such an old table still has to be converted automatically — the conversion takes the last path segment of that column's link URL as the H2 heading. Count that index from the **live page's own column layout**, never from the template's: the live `SKILLSET_CONTENTS` reads `| 存放庫 | 異動報告 | 目前版本 | 最後更新 |`, so the link sits in column 2 while column 1 is plain text like `plugins/ask`. Passing `1` would make the heading `plugins/ask`, which never matches the key `SKILLSET_{HASH}`, so the existing entry is appended as a brand-new one — one domain ends up with two blocks and the older one is never updated again. The fourth argument is the whole block, not a table row. The script resolves the CONTENTS repo itself — the directory page lives there, never in the SKILLSET repo — reads the whole page, converts any leftover table to blocks, replaces the block whose heading matches, appends when none matches, and writes the page back, so every block owned by another domain stays as it was.
The 異動頁 cell is written as `[SKILLSET_{HASH}]({url})`, the URL being the **absolute** one from `gitea.sh wiki-url {SKILLSET repo} SKILLSET_{HASH}`. Every link on both pages takes that `[{text}]({url})` form — the double-bracket wiki-link form is never used, because it resolves only inside one wiki. Fetch that URL only after the content page is written: **write the content page first** — a directory row naming a page whose write failed is worse than a missing row.
- **Check the links before writing.** Hand every URL going onto the content page and into the directory row to `jsc-gitea/tools/link-check.sh` and write only when it exits 0. It verifies through the Gitea API, never a web status code: a private repo answers 404 to an unauthenticated web request, so a status-code check would call a live page dead and rewrite pages that are fine.
The 異動頁 bullet is written as `[SKILLSET_{HASH}]({url})`, the URL being the **absolute** one from `gitea.sh wiki-url {SKILLSET repo} SKILLSET_{HASH}`; the H2 heading itself carries no link, no URL, no affix and no date. Every link on both pages takes that `[{text}]({url})` form — the double-bracket wiki-link form is never used, because it resolves only inside one wiki. Fetch that URL only after the content page is written: **write the content page first** — a directory block naming a page whose write failed is worse than a missing block.
- **Check the links before writing.** Hand every URL going onto the content page and into the directory block to `jsc-gitea/tools/link-check.sh` and write only when it exits 0. It verifies through the Gitea API, never a web status code: a private repo answers 404 to an unauthenticated web request, so a status-code check would call a live page dead and rewrite pages that are fine.
- **Exit codes.** Route every one of them. None of these calls may be read as success by default.
| Call | Exit | Do |
@@ -113,23 +113,23 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
| Content page read | 0 | Append into the sections already there |
| | 4 | The page does not exist yet, so build it from the template |
| | 7 or 8 | Stop and write nothing, because a page rebuilt on top of an unread read loses every section already on it |
| `gitea.sh wiki-url` | 4 | The content page is not there, so the write above did **not** succeed. Go back and write it; put no directory row in until the page exists, because a row may not name a page that failed |
| `gitea.sh wiki-url` | 4 | The content page is not there, so the write above did **not** succeed. Go back and write it; put no directory block in until the page exists, because a block may not name a page that failed |
| | 5 | The API answered with no `html_url`. Stop and report it; never assemble the URL by hand from the host and the page name |
| `link-check.sh` | 0 | Every link is reachable. Write the page |
| | 1 | At least one link is dead. Write nothing, and report the `DEAD` lines it printed |
| | 2 | No URL was passed, which is a defect here. Pass the links and rerun |
| | 3 | `GITEA_HOST` is unset. Set it and rerun; never skip the check instead |
| | 7 | Gitea authentication failed. Stop and report the key problem, and never read it as a dead link |
| `wiki-contents.sh upsert` | 0 | The row is in place. Report the `updated` or `added` it printed, with the page it named |
| | 1 | The write failed, or the directory page holds no markdown table. Report `SKILLSET_CONTENTS` as not written, together with the row content |
| `wiki-contents.sh upsert` | 0 | The block is in place. Report the `updated` or `added` it printed, with the page it named |
| | 1 | The page content could not be assembled, or the write failed. A page with no matching block is not an error — that case appends. Report `SKILLSET_CONTENTS` as not written, together with the block content |
| | 2 | An argument was rejected. Fix it and rerun; nothing was written |
| | 3 | No CONTENTS wiki repo is configured. Report `JSC_WIKI_REPO_CONTENTS` and `JSC_WIKI_REPO` as the two variables to set. The round's section is on `SKILLSET_{HASH}` and stays there |
| | 4 | The directory page is absent and no template was passed. Rerun with `templates/skillset-contents.md` as the fifth argument |
| | 7 | The token is invalid or lacks permission, so the other domains' rows are unknown. Stop, report the token problem, and create no page — writing nothing is what keeps those rows alive |
| | 7 | The token is invalid or lacks permission, so the other domains' blocks are unknown. Stop, report the token problem, and create no page — writing nothing is what keeps those blocks alive |
| | 8 | Some other API failure. Stop, report that status, and create no page |
- **On a failed write.** Retry once. Still failing, hand the user the page name and the full section that was not written, so the round's result is not lost. **Never close the run reporting a page as written when it was not**, and never close it silently with the content only in the transcript.
Completion condition: every changed domain repo has one new section on its `SKILLSET_{HASH}` and one row in `SKILLSET_CONTENTS` written by a `wiki-contents.sh upsert` that exited 0, or — where nothing changed — the `plugins/meta` page carries the 「本輪無發現」 section and its row on the same terms; every content-page write is confirmed by a successful read-back or reported as not written with its full content handed back.
Completion condition: every changed domain repo has one new section on its `SKILLSET_{HASH}` and one `## SKILLSET_{HASH}` block in `SKILLSET_CONTENTS` written by a `wiki-contents.sh upsert` that exited 0, or — where nothing changed — the `plugins/meta` page carries the 「本輪無發現」 section and its block on the same terms; every content-page write is confirmed by a successful read-back or reported as not written with its full content handed back.
9. Report this round's outcome to the local event stream — the last step of every run, the ones that stop early included. Run:
`jsc-hooks/tools/report-status.sh skill-end jsc-meta:skill-check {status} {exit code} [detail]`
@@ -143,7 +143,7 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
| `ok` | every domain ended with a complete checklist, every accepted fix passed its re-check, every affected repo has a PR URL, and every wiki write exited 0 |
| `blocked` | a gate or a missing prerequisite stopped the round before anything was audited — `sync-domains.sh` never reached exit 0, or the call itself was refused |
| `failed` | the round broke mid-way — a re-check in step 6 kept failing, or a wiki write failed again after its one retry |
| `degraded` | the round finished with a part missing — a domain carries 「本輪未取得已決議清單,優化建議暫不提出」, or a content page was written while its `SKILLSET_CONTENTS` row was not |
| `degraded` | the round finished with a part missing — a domain carries 「本輪未取得已決議清單,優化建議暫不提出」, or a content page was written while its `SKILLSET_CONTENTS` block was not |
| `aborted` | the user stopped the round, or a prerequisite turned out not to hold and this skill stopped on its own |
`{exit code}` is this round's own result as a number: `0` for `ok`, non-zero otherwise. `detail` is optional, one line, at most 200 characters.