docs(skills): 四支階段技能的目錄頁讀取與寫入敘述同步條列版面
What
- `skills/plan`、`skills/analyze`、`skills/implement`、`skills/maintain`:目錄頁的讀取敘述改成從 H2 區塊取值,寫入敘述從「單列 upsert」改成單一 H2 區塊 upsert,鍵補上內容頁頁名這個引數,並註明第四個引數是區塊檔。
- `skills/maintain`:讀寫的鍵改成該存取庫的 `{owner}/{repo}`,因為這個型別沒有內容頁。
- `references/behaviors.md`:四支技能的關鍵步驟、外部呼叫與可驗證跡象同步,跡象從「留下那一列」改成留下那一個 H2 區塊。
- `references/consensus.md`:查已答問題那一條補上問答目錄頁也是條列式版面、要從區塊取值而不是表格列。
- `references/stage-report.md`:目錄頁也算寫入那一段補上「改動一個區塊也算寫過那一頁」,並統一用 `CONTENTS` 這個型別餵進去。
- `README.md`:四支技能的流程敘述與 wiki 規則段同步,並補上五個目錄頁的版面規則、鍵的落點與各頁鍵欄的正確序號。
Why
- 範本已經改成條列版面,技能內文還寫著「那一列」,執行時就會照舊敘述組出表格列,跟工具的單一區塊 upsert 對不上。
- 讀取端的敘述沒跟著改,技能會拿表格的解析方式去讀一頁條列,既有紀錄一筆都認不出來。
- 呼叫少帶鍵這個引數,工具無從判斷要換掉哪一個區塊,同一筆會被當成新的附加上去。
- 行為清單是稽核與驗證的比對基準,敘述沒跟上,稽核會拿舊描述判合規。
How
- 四支技能的呼叫一律寫成 `wiki-contents.sh upsert {TYPE} {鍵欄} "{鍵}" {區塊檔} [{範本}]`,各頁的鍵欄序號照線上那一頁實際的欄位排法寫定。
- 完成條件與可驗證跡象改用區塊的說法,連結範例改成 `- {欄位名}:[{頁名}]({連結})` 的形態。
- 只改敘述與說明,不動任何腳本;轉檔與 upsert 的實作在別的存取庫。
Who
- 本存取庫四支階段技能,以及讀這幾份說明檔決定共識判定與階段回報寫法的流程。
- 稽核與驗證流程改拿新的行為清單比對。
This commit is contained in:
+19
-19
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: implement
|
||||
description: SDLC implementation stage. Gate on capability tags enforced in code by sdlc-gate (implement requires coding), settle every open work package's PR comments first, then claim a ready package before confirming the analysis page's source branch - it is both the worktree base and the PR target. Every already-open work package's PR comments get triaged via tools/wp-gate.sh check and fixed by sub agents only after jsc-ask consensus, never blocking an unrelated package; every candidate is gated in code by tools/wp-gate.sh check-deps before it reaches the options, and claiming records the package number via tools/wp-gate.sh claim so tools/wp-gate.sh owns keeps every session on its own package's PR. Claim a ready work package from ANALYZE_CONTENTS with a work ticket, confirm a delivery package's content type, then complete its TDD todos one at a time inside a worktree built from origin/{source-branch}, updating the wiki after every item, closing with the two side-by-side audits jsc-review code-review and jsc-review api-doc (the latter gated by swagger-detect.sh and explicitly skipped where the project has no Swagger support), one PR back to the source branch, a jsc-gitea pr-watch.sh poll that holds until that PR merges, a jsc-log:worklog entry per finished task, the chosen delivery document, an optional MAINTAIN_CONTENTS entry - every directory row upserted through jsc-gitea/tools/wiki-contents.sh into the separate CONTENTS wiki repo and linked by absolute wiki-url - and a tools/stage-report.sh report covering the model tag verdict, the worklog link, every wiki link written, the worktree and the three branches. Use when analysis is done and code must be written; not for planning or analysis.
|
||||
description: SDLC implementation stage. Gate on capability tags enforced in code by sdlc-gate (implement requires coding), settle every open work package's PR comments first, then claim a ready package before confirming the analysis page's source branch - it is both the worktree base and the PR target. Every already-open work package's PR comments get triaged via tools/wp-gate.sh check and fixed by sub agents only after jsc-ask consensus, never blocking an unrelated package; every candidate is gated in code by tools/wp-gate.sh check-deps before it reaches the options, and claiming records the package number via tools/wp-gate.sh claim so tools/wp-gate.sh owns keeps every session on its own package's PR. Claim a ready work package from ANALYZE_CONTENTS with a work ticket, confirm a delivery package's content type, then complete its TDD todos one at a time inside a worktree built from origin/{source-branch}, updating the wiki after every item, closing with the two side-by-side audits jsc-review code-review and jsc-review api-doc (the latter gated by swagger-detect.sh and explicitly skipped where the project has no Swagger support), one PR back to the source branch, a jsc-gitea pr-watch.sh poll that holds until that PR merges, a jsc-log:worklog entry per finished task, the chosen delivery document, an optional MAINTAIN_CONTENTS entry - every directory H2 block upserted through jsc-gitea/tools/wiki-contents.sh into the separate CONTENTS wiki repo and linked by absolute wiki-url - and a tools/stage-report.sh report covering the model tag verdict, the worklog link, every wiki link written, the worktree and the three branches. Use when analysis is done and code must be written; not for planning or analysis.
|
||||
---
|
||||
|
||||
# implement
|
||||
@@ -9,7 +9,7 @@ Goal: complete the analysis page's todos one by one; **update the wiki status im
|
||||
|
||||
`jsc-gitea/tools/hash-id` prints the **full 40-character uppercase SHA-1** of its input — no truncation to 8 characters, no prefix rewrite. Every `{HASH}` this stage builds carries that full length: the page names, the worktree path and the work ticket of step 6 alike. Never shorten one by hand.
|
||||
|
||||
**Content pages and directory pages live in different wiki repos.** `ANALYZE_{HASH}` sits in the repo `jsc-gitea/tools/gitea.sh wiki-repo ANALYZE` resolves and `DELIVER_{HASH}` in the one `gitea.sh wiki-repo DELIVER` resolves, while the directory pages `ANALYZE_CONTENTS`, `DELIVER_CONTENTS` and `MAINTAIN_CONTENTS` all sit 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 the page type's own variable. Every directory row links its content page by the absolute URL from `gitea.sh wiki-url {content repo} {page}`, written as `[{text}]({url})` — one link syntax, whichever wiki the two pages sit in. The syntax and the check that runs before every write: "Every link is checked before it reaches a page" below.
|
||||
**Content pages and directory pages live in different wiki repos.** `ANALYZE_{HASH}` sits in the repo `jsc-gitea/tools/gitea.sh wiki-repo ANALYZE` resolves and `DELIVER_{HASH}` in the one `gitea.sh wiki-repo DELIVER` resolves, while the directory pages `ANALYZE_CONTENTS`, `DELIVER_CONTENTS` and `MAINTAIN_CONTENTS` all sit 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 the page type's own variable. **All three are bullet-list directory pages, not tables**: one H2 block per entry, the heading being that entry's key — for `ANALYZE_CONTENTS` and `DELIVER_CONTENTS` it is the content page's actual name, the page the run itself just wrote, never a `{TYPE}_{HASH}` formula; for `MAINTAIN_CONTENTS` it is the repository's own `{owner}/{repo}`, because `MAINTAIN` has no content page and a page-shaped key there would name a page that does not exist — and the fields a one-level bullet list under it, each written `- {欄位名}:{值}` in the order that page's template gives. Every directory entry links its content page by the absolute URL from `gitea.sh wiki-url {content repo} {page}`, written as `[{text}]({url})` — one link syntax, whichever wiki the two pages sit in. The syntax and the check that runs before every write: "Every link is checked before it reaches a page" below.
|
||||
|
||||
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. Steps 13 and 14 still run after such a stop.
|
||||
|
||||
@@ -17,7 +17,7 @@ All wiki reads and writes go through `jsc-gitea:wiki`. **A failed wiki read or w
|
||||
|
||||
1. **Model gate and stage lock** — run `jsc-cli/tools/model-tags.sh sync`, then `jsc-hooks/hooks/sdlc-gate.sh lock implement`. This stage requires the `coding` 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 the analysis pages, then settle every already-open work-package PR's comments — this keeps existing PRs moving and can clear a dependency for step 4, but it does not by itself decide which new package may start (step 4 does)**:
|
||||
1. Read `ANALYZE_CONTENTS` out of the CONTENTS wiki repo (`gitea.sh wiki-repo CONTENTS`, never the ANALYZE one), then read every analysis page it lists as unfinished out of the ANALYZE wiki repo. **Keep this read: steps 3, 5 and 8 reuse it and never read the same pages again.** Completion condition: for every unfinished analysis page you hold its WBS table, its PR column, its source branch and the repositories it names.
|
||||
1. Read `ANALYZE_CONTENTS` out of the CONTENTS wiki repo (`gitea.sh wiki-repo CONTENTS`, never the ANALYZE one), then read every analysis page it lists as unfinished out of the ANALYZE wiki repo. **Read the directory page as H2 blocks, not table rows**: each `## ANALYZE_{HASH}` heading is one analysis and is that analysis page's name, its 計畫名稱、分析頁、HASH、工作包、未完成項目、狀態 are the bullets under it, and an analysis counts as unfinished when its `- 狀態:` bullet reads 「未完成」. The WBS table, the PR column and the todos are on the `ANALYZE_{HASH}` content page itself, which keeps its table layout. **Keep this read: steps 3, 5 and 8 reuse it and never read the same pages again.** Completion condition: for every unfinished analysis page you hold its WBS table, its PR column, its source branch and the repositories it names.
|
||||
2. **Prefetch every open PR's state in one batch.** For every work package holding a PR that is not marked merged, run `jsc-sdlc/tools/wp-gate.sh check {owner}/{repo} {index} --since {the comment timestamp recorded in that PR column}`. Drop `--since` when that package has no recorded timestamp yet. **These calls do not depend on each other — run them concurrently and collect every result before you ask the user anything.** The consensus rounds and the fixes that follow stay one comment at a time. Completion condition: every open PR has a recorded exit code and `status=` line.
|
||||
3. Exit 0 (`status=merged`) clears that package: remove its worktree (`references/branch.md`) and mark the package done on the analysis page.
|
||||
4. Exit 1 (`status=open` or `status=closed-unmerged`) means that package's own PR is not settled yet. **This does not block picking a different, unrelated work package** — SDLC implementation can run several independent packages in parallel; an unmerged PR only holds back packages that depend on it (step 4 checks that specifically), never the whole analysis page. Sub-steps 2.5 to 2.10 are the one comment round this skill owns; step 11.5 runs the same sub-steps for the PR it just opened.
|
||||
@@ -30,7 +30,7 @@ All wiki reads and writes go through `jsc-gitea:wiki`. **A failed wiki read or w
|
||||
11. Exit 2 (`status=usage`) means bad arguments — a malformed `{owner}/{repo}`, a missing index, or a `--since` value that is not the previous round's `latest=`. Fix the arguments and run it again. Completion condition: the rerun returned 0, 1 or 3; a usage error never counts as merged, settled or blocked.
|
||||
12. Exit 3 (`status=missing-dep`) means the gate could not decide (a missing dependency script, or the PR could not be found). Report it and stop — an undecidable gate never counts as merged.
|
||||
13. Completion condition: every work package holding an unmerged PR has had this run's comments triaged (fixed, no fix needed, or cannot fix), logged and reported; a package left unmerged after this does not block steps 3 and 4 for packages that do not depend on it.
|
||||
3. From the pages read in step 2.1, list what is unfinished: plan name, HASH, work package number, count of open items. A selectable work package satisfies both: **unfinished, and not holding a work ticket**. Dependencies are not judged here and never by eyeballing the 相依 column — step 4's `wp-gate.sh check-deps` is the only judge. Completion condition: you have listed every selectable work package, or reported that none is selectable and stopped.
|
||||
3. From the pages read in step 2.1, list what is unfinished: plan name, HASH, work package number, count of open items. **The plan name and the HASH come from the directory page's H2 block — the heading gives the analysis page name and its HASH, the `- 計畫名稱:` bullet gives the plan name — and the work package number and its open items come from that analysis page's own WBS and todo tables.** A selectable work package satisfies both: **unfinished, and not holding a work ticket**. Dependencies are not judged here and never by eyeballing the 相依 column — step 4's `wp-gate.sh check-deps` is the only judge. Completion condition: you have listed every selectable work package, or reported that none is selectable and stopped.
|
||||
4. **Every candidate passes the dependency gate before the user sees it — the gate lives in code, not in this text, and it judges one candidate at a time, never every open PR on the page**:
|
||||
1. Run `jsc-sdlc/tools/wp-gate.sh check-deps {owner}/{repo} {wp-number} --analyze ANALYZE_{HASH}` **once per candidate from step 3, before asking the user anything**. Candidates do not depend on each other's verdict, so run these concurrently. The script re-reads the caller-specified analysis page and queries Gitea itself — it does not trust anything you already read or concluded, and it never guesses the page from the repository hash.
|
||||
2. Branch on each candidate's exit code. Exit 0 (`status=ready`) → put it in the option list. Exit 1 (`status=blocked`) → keep it out of the option list, and report which dependency work package's PR is not merged yet. Exit 3 (`status=missing-dep`) is an undecidable gate — report it and stop; never treat an undecidable result as either ready or blocked. Exit 2 (`status=usage`) → bad arguments or a missing `--analyze`; fix them and run that candidate again, and leave it out of the options until the rerun returns a verdict. Completion condition: every candidate from step 3 carries one of these verdicts, and only the `ready` ones remain.
|
||||
@@ -77,7 +77,7 @@ All wiki reads and writes go through `jsc-gitea:wiki`. **A failed wiki read or w
|
||||
12. **Deliver the document, then register for maintenance** — one closing pass over the two questions this stage owes the user. A finished work package is a delivery, so **always ask before producing it; never pick a format silently and never skip either question**:
|
||||
1. Ask per `jsc-ask:ask` rules which delivery format to produce. The options are fixed: **a `DELIVER_{HASH}` wiki page** or **a Gitea issue comment**. State the impact scope on each (the wiki page lives beside the plan and analysis pages; the issue comment reaches whoever follows that issue).
|
||||
2. Both formats use the same structure — `templates/deliver-page.md`, in Traditional Chinese. Only the destination differs. Sample values and personal-data handling: `references/deliver-formats.md`.
|
||||
3. Wiki page: write `DELIVER_{HASH}` into the DELIVER wiki repo through `jsc-gitea:wiki` — **every link that page carries is written as `[{text}]({url})` and passes `jsc-gitea/tools/link-check.sh` before the write**, per "Every link is checked before it reaches a page" below — where `{HASH}` comes from `jsc-gitea/tools/hash-id` over `{owner}/{repo}` plus the work package number (for example `plugins/sdlc#WP-01`), so each work package gets its own page instead of overwriting the previous one. That input is what keeps the pages apart, and the full 40 characters `hash-id` prints are what the page is named — hashing the repository alone, or shortening the result, puts two work packages on one page again. Then upsert this work package's row with `jsc-gitea/tools/wiki-contents.sh upsert DELIVER 6 {HASH} {row file} templates/deliver-contents.md`: the row follows `templates/deliver-contents.md` and the key is the HASH column, column 6, written exactly as the row file writes it. Its 交付頁 cell holds the absolute URL from `gitea.sh wiki-url {DELIVER repo} DELIVER_{HASH}`, written as `[{text}]({url})` — run that **after** the delivery page is saved and branch on its exit code, the same branching `jsc-log:worklog` runs over the same call:
|
||||
3. Wiki page: write `DELIVER_{HASH}` into the DELIVER wiki repo through `jsc-gitea:wiki` — **every link that page carries is written as `[{text}]({url})` and passes `jsc-gitea/tools/link-check.sh` before the write**, per "Every link is checked before it reaches a page" below — where `{HASH}` comes from `jsc-gitea/tools/hash-id` over `{owner}/{repo}` plus the work package number (for example `plugins/sdlc#WP-01`), so each work package gets its own page instead of overwriting the previous one. That input is what keeps the pages apart, and the full 40 characters `hash-id` prints are what the page is named — hashing the repository alone, or shortening the result, puts two work packages on one page again. Then upsert this work package's H2 entry block with `jsc-gitea/tools/wiki-contents.sh upsert DELIVER 5 {delivery page name} {entry file} templates/deliver-contents.md`. The entry file holds the heading `## {delivery page name}`, a blank line, then one bullet per field in `templates/deliver-contents.md`'s order — 計畫名稱、工作包、交付、交付型別、交付頁、HASH、存取庫、交付時間 — each written `- {欄位名}:{值}` with a full-width colon. **The third argument is the H2 heading, that is the delivery page's actual name — the very page this step just wrote**, matching the entry file's own heading byte for byte; take the name you actually saved rather than rebuilding it from a `DELIVER_{HASH}` formula. The `5` is the column number of the old table column that holds the content-page link — the 交付頁 column — and it is used only for the automatic conversion: while the page on the wiki is still a markdown table, the script takes the last path segment of that column's link URL as the H2 heading, and once the page is bullet-list shaped the number is ignored. **A wrong number is not harmless**: the heading it converts to will not match the key, this work package's existing entry gets appended as a new one, one delivery ends up with two blocks, and the old block is never updated again. Its 交付頁 bullet holds the absolute URL from `gitea.sh wiki-url {DELIVER repo} DELIVER_{HASH}`, written as `[{text}]({url})` — run that **after** the delivery page is saved and branch on its exit code, the same branching `jsc-log:worklog` runs over the same call:
|
||||
|
||||
| Exit | What this step does |
|
||||
| --- | --- |
|
||||
@@ -87,10 +87,10 @@ All wiki reads and writes go through `jsc-gitea:wiki`. **A failed wiki read or w
|
||||
| 7 | the key is invalid or lacks permission (HTTP 401/403) — stop and report the key problem. Never read this as exit 4: the delivery page is alive, and treating it as absent records a delivered work package as one that was never delivered |
|
||||
| 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 交付頁 cell is empty names a delivery nobody can open, and the next run replaces that row as if it were correct. **Check that URL with `jsc-gitea/tools/link-check.sh` and build the row only on exit 0** — a link that does not answer never goes into a directory everyone else reads. Branch on the upsert's own exit code per "Contents pages are appended, never overwritten" below, and never hand-edit the directory page.
|
||||
Never let an empty string stand in for the URL: an entry whose 交付頁 bullet is empty names a delivery nobody can open, and the next run replaces that block as if it were correct. **Check that URL with `jsc-gitea/tools/link-check.sh` and build the entry only on exit 0** — a link that does not answer never goes into a directory everyone else reads. Branch on the upsert's own exit code per "Contents pages are appended, never overwritten" below, and never hand-edit the directory page.
|
||||
4. Issue comment: confirm the issue number with the user (propose the one referenced by the work package or the PR; never guess), then post via `jsc-gitea/tools/gitea.sh api POST /repos/{owner}/{repo}/issues/{n}/comments` with the body passed in as a UTF-8 file — real newlines, never a literal `\n`. Every link in that body is written as `[{text}]({url})` and passes `jsc-gitea/tools/link-check.sh` before the post: a comment is as hard to correct as a page once other people have read it.
|
||||
5. With the delivery produced, ask per `jsc-ask:ask` rules whether to register this project for maintenance — any link that row carries is written as `[{text}]({url})` and passes `jsc-gitea/tools/link-check.sh` before the upsert: upsert this repository's row with `jsc-gitea/tools/wiki-contents.sh upsert MAINTAIN 1 {owner}/{repo} {row file} templates/maintain-contents.md`, the row built from `templates/maintain-contents.md` and the key column 1, the repository name. Required: repository `{owner}/{repo}`, maintenance method, start date. Optional: end date (NULL = maintain forever), last-maintained time. `MAINTAIN` has no content page — this directory page is the whole record — so branch on the exit code per "Contents pages are appended, never overwritten" below and never hand-edit it.
|
||||
6. Completion condition: the chosen delivery format has actually been produced and you have reported where it landed (wiki page name, or the comment URL); on the wiki-page format the `wiki-url` call returned 0 and its URL is the one in the 交付頁 cell, with any non-zero code branched on as sub-step 12.3 says; every link written by this step was cleared by a `link-check.sh` run that exited 0; **and** the user has answered the maintenance question with a chosen registration saved on the wiki.
|
||||
5. With the delivery produced, ask per `jsc-ask:ask` rules whether to register this project for maintenance — any link that entry carries is written as `[{text}]({url})` and passes `jsc-gitea/tools/link-check.sh` before the upsert: upsert this repository's H2 entry block with `jsc-gitea/tools/wiki-contents.sh upsert MAINTAIN 1 {owner}/{repo} {entry file} templates/maintain-contents.md`. The entry file holds the heading `## {owner}/{repo}`, a blank line, then one bullet per field in `templates/maintain-contents.md`'s order — 存取庫、維護方式、維護起始日、維護截止日、前次維護時間 — each written `- {欄位名}:{值}` with a full-width colon. **The third argument is the H2 heading, and for `MAINTAIN` that heading is the repository's own `{owner}/{repo}`**, matching the entry file's own heading byte for byte. `MAINTAIN` has no content page, so its heading cannot be a page name: a `MAINTAIN_{HASH}` heading would name a page that does not exist, while `{owner}/{repo}` never drifts and keys just as reliably. The `1` is the column number of the old table column that carries this entry's identity — the 存取庫 column, the only column `MAINTAIN` has that identifies a row, and it holds no link, so the conversion takes its plain text. It is used only for the automatic conversion: while the page on the wiki is still a markdown table the script reads the heading out of that column, and once the page is bullet-list shaped the number is ignored. **A wrong number is not harmless**: the heading it converts to will not match the key, this repository's existing entry gets appended as a new one, one repository ends up with two blocks, and the old block is never updated again. Required: repository `{owner}/{repo}`, maintenance method, start date. Optional: end date (NULL = maintain forever), last-maintained time. `MAINTAIN` has no content page — this directory page is the whole record — so branch on the exit code per "Contents pages are appended, never overwritten" below and never hand-edit it.
|
||||
6. Completion condition: the chosen delivery format has actually been produced and you have reported where it landed (wiki page name, or the comment URL); on the wiki-page format the `wiki-url` call returned 0 and its URL is the one in the 交付頁 bullet, with any non-zero code branched on as sub-step 12.3 says; every link written by this step was cleared by a `link-check.sh` run that exited 0; **and** the user has answered the maintenance question with a chosen registration saved on the wiki.
|
||||
13. **Stage report — the last thing this stage does, including every early stop** (the work package gate blocked, no work package was selectable, the source branch was missing from the remote, a wiki read or write failed). Run `tools/stage-report.sh implement` with:
|
||||
- one `--page TYPE:{page}` per wiki page this run wrote — `--page ANALYZE:ANALYZE_{HASH}`, `--page DELIVER:DELIVER_{HASH}`, `--page CONTENTS:DELIVER_CONTENTS`, `--page CONTENTS:MAINTAIN_CONTENTS`. **Every directory page takes the `CONTENTS` type**: the script resolves each page's repo from the TYPE you pass, and a directory page passed under its old type resolves the wrong repo and prints no URL;
|
||||
- `--worklog` and `--worklog-heading` pointing at the entry step 11.4 wrote — following the Rules section's one-task-one-entry rule, a stage that finished anything already has one. `--pending-file {file} --log-hash {HASH}` is the fallback for a stage that stopped before any task finished: it holds the content for the next `jsc-log:worklog` run, and held content is not a written log;
|
||||
@@ -109,43 +109,43 @@ All wiki reads and writes go through `jsc-gitea:wiki`. **A failed wiki read or w
|
||||
| `degraded` | The package itself finished — todos `[x]`, PR merged — but a closing item did not: `DELIVER_{HASH}` is saved while `DELIVER_CONTENTS` was not upserted, the maintenance registration went unrecorded on `wiki-contents.sh` exit 3, or `tools/stage-report.sh` exited 1 (no work log, or a link in its list does not answer) |
|
||||
| `aborted` | The user stopped the run, or the run stopped itself because its premise did not hold — step 3 found no selectable work package, so there was nothing to implement |
|
||||
|
||||
`{exit}` is the exit code of the script whose verdict decided the status — the gate's code for `blocked`, the failing script's code for `failed` and `degraded` — and `0` when nothing exited non-zero, `ok` and `aborted` included. `[detail]` is optional and Traditional Chinese per the STE100 rule: one line, no line break, naming what decided the status (for example 「相依工作包的 PR 未合併」 or 「交付目錄列未寫入」). The script truncates it at 200 characters, so put the short reason there and nothing else.
|
||||
`{exit}` is the exit code of the script whose verdict decided the status — the gate's code for `blocked`, the failing script's code for `failed` and `degraded` — and `0` when nothing exited non-zero, `ok` and `aborted` included. `[detail]` is optional and Traditional Chinese per the STE100 rule: one line, no line break, naming what decided the status (for example 「相依工作包的 PR 未合併」 or 「交付目錄區塊未寫入」). The script truncates it at 200 characters, so put the short reason there and nothing else.
|
||||
|
||||
**A failure in this step never changes this stage's verdict.** The script is not found (jsc-hooks is not installed on this machine, or this CLI's layout puts it somewhere else) → skip the event quietly and carry on; nothing is reported to the user and no step is re-run. The three recording sub-commands are built to exit 0 even when the write fails, so a non-zero code here means only that the call itself was malformed (exit 2, a usage error) — fix the arguments once and, either way, never turn a merged work package into a failed stage because the record of it failed. Completion condition: one `skill-end` event has been written for this run, or the script could not be found and that skip is the reason no event exists.
|
||||
|
||||
## Every link is checked before it reaches a page
|
||||
|
||||
**One syntax.** Every link this stage writes — on `DELIVER_{HASH}`, in the analysis page's PR column, in the `DELIVER_CONTENTS` and `MAINTAIN_CONTENTS` rows, in an issue comment, in the stage report — is written as `[{text}]({url})`. The `{url}` is the absolute URL `gitea.sh wiki-url {repo} {page}` printed, used verbatim: never assemble a wiki path by hand, and never write a link as `[[頁名]]` or `[[顯示文字|頁名]]`. That form resolves only inside the wiki it sits in, and it fails without an error — the reader sees plain text or a dead link, so a wrong link is neither noticed nor fixable.
|
||||
**One syntax.** Every link this stage writes — on `DELIVER_{HASH}`, in the analysis page's PR column, in the `DELIVER_CONTENTS` and `MAINTAIN_CONTENTS` entry blocks, in an issue comment, in the stage report — is written as `[{text}]({url})`. The `{url}` is the absolute URL `gitea.sh wiki-url {repo} {page}` printed, used verbatim: never assemble a wiki path by hand, and never write a link as `[[頁名]]` or `[[顯示文字|頁名]]`. That form resolves only inside the wiki it sits in, and it fails without an error — the reader sees plain text or a dead link, so a wrong link is neither noticed nor fixable.
|
||||
|
||||
**Checked before it is written.** Collect every link the page, the row or the comment is about to carry, hand them all to `jsc-gitea/tools/link-check.sh` in one run — `link-check.sh {網址}...`, or the same URLs on stdin, one per line — and write only when that run exits 0. It prints one `{OK|DEAD|SKIP}<TAB>{網址}<TAB>{說明}` line per URL. The check goes through the API, never a web status code: a private repository's web URL answers 404 to a request carrying no key, so a status-code check marks live pages dead.
|
||||
**Checked before it is written.** Collect every link the page, the entry block or the comment is about to carry, hand them all to `jsc-gitea/tools/link-check.sh` in one run — `link-check.sh {網址}...`, or the same URLs on stdin, one per line — and write only when that run exits 0. It prints one `{OK|DEAD|SKIP}<TAB>{網址}<TAB>{說明}` line per URL. The check goes through the API, never a web status code: a private repository's web URL answers 404 to a request carrying no key, so a status-code check marks live pages dead.
|
||||
|
||||
| Exit | What this step does |
|
||||
| --- | --- |
|
||||
| 0 | every link answers — write the page, upsert the row, post the comment |
|
||||
| 0 | every link answers — write the page, upsert the entry block, post the comment |
|
||||
| 1 | at least one link is dead — **write nothing**, and report the `DEAD` lines to the user |
|
||||
| 2 | usage error: not one URL was passed — pass the links and run it again |
|
||||
| 3 | the list holds a Gitea URL but `GITEA_HOST` is unset — report it as a setting to fix and run it again, and never skip the check instead |
|
||||
| 7 | Gitea authentication failed (401/403) — stop and report the key problem. Never read this as exit 1: an expired key makes live pages look absent, and a page rewritten on that reading loses the links that were fine |
|
||||
|
||||
Completion condition: every page, row and comment this stage wrote was cleared by a `link-check.sh` run that exited 0, and every non-zero code was branched on as this table says.
|
||||
Completion condition: every page, entry block and comment this stage wrote was cleared by a `link-check.sh` run that exited 0, and every non-zero code was branched on as this table says.
|
||||
|
||||
## Contents pages are appended, never overwritten
|
||||
|
||||
`DELIVER_CONTENTS` and `MAINTAIN_CONTENTS` are shared directories in the CONTENTS wiki repo: every row on them belongs to somebody's work package or repository, and this run reads none of those rows from anywhere else. So every write to them is an upsert of one row — never a whole-page overwrite, and never a row this run does not own. `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.
|
||||
`DELIVER_CONTENTS` and `MAINTAIN_CONTENTS` are shared directories in the CONTENTS wiki repo: every H2 block on them belongs to somebody's work package or repository, and this run reads none of those blocks from anywhere else. So every write to them is an upsert of one block — never a whole-page overwrite, and never a block this run does not own. `jsc-gitea/tools/wiki-contents.sh upsert` is the one way this stage does it: it resolves the CONTENTS repo, reads the whole page, converts a page still holding a markdown table into blocks first, replaces the block whose H2 heading matches the key and appends at the end 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 13 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 |
|
||||
| 0 | the block is in place — carry the `updated` or `added` word it printed into the stage report |
|
||||
| 1 | the page content could not be assembled, or the write failed — report it as a failed write and go to step 13 as a failure. **A page holding no matching block is not this code**: with nothing to replace the script appends the block and exits 0 |
|
||||
| 2 | an argument was rejected (unknown type, bad key-column number, missing entry 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. A `DELIVER_{HASH}` page already written is saved and stays saved; the maintenance registration is not recorded anywhere else, so report it as unregistered |
|
||||
| 4 | the directory page is absent and no template was passed. **Every call in this stage already passes that page's template, 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 every other row alive |
|
||||
| 7 | the key is invalid or lacks permission — stop and report the key problem; the script wrote nothing, which is what keeps every other block 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 work package's row is gone — the write carries no merge and no backup. `DELIVER_{HASH}` is the opposite case: it is a content page belonging to one work package and living in the DELIVER repo, so writing it whole is correct. The distinction is the page, not the write.
|
||||
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 work package's block is gone — the write carries no merge and no backup. `DELIVER_{HASH}` is the opposite case: it is a content page belonging to one work package and living in the DELIVER repo, so writing it whole is correct. The distinction is the page, not the write.
|
||||
|
||||
Completion condition: every directory-page write this stage made names the `wiki-contents.sh` exit code it branched on, and no directory page was created on any code other than 4.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user