取消 [[頁名]] 與 [[顯示文字|頁名]] 兩種同 wiki 寫法,不再分「同存取庫」與 「跨存取庫」兩條規則。那種寫法只在自己那個 wiki 內解析,寫錯不報錯,畫面上 看起來像普通文字或死連結,巡不到也修不了。 連結寫進頁面前先過 jsc-gitea 的 link-check.sh,結束碼 0 才寫。驗證一律走 API, 不看網頁狀態碼:私有存取庫的網頁網址對未登入請求一律回 404,拿狀態碼判會把 好連結判成壞的。認證失敗回 7,與死連結的 1 分開,免得金鑰一過期就把還在的頁 整批判死。
31 KiB
name, description
| name | description |
|---|---|
| skill-check | 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). |
skill-check — audit compliance, flow efficiency, and cost efficiency
Single source of guidelines: ../../references/guidelines.md.
Flow
-
Run
tools/sync-domains.shto sync every domain repo of the Gitea canonical marketplace. Completion condition: the script exits 0 and prints onedomain<TAB>pathline per marketplace domain — exit 0 is the only code that means every repo is present and current. Exit 3 means some repos were not updated: reconcile every path named on stderr (commit or stash the dirty tree, or fix the failing pull) and rerun; when the user confirms a dirty tree is intentional local work, record that decision and continue on the local version — never read exit 3 as current. Exit 2 means a domain could not be cloned. Exit 1 means the root could not be derived,gitea.shwas not found, or the canonical marketplace was unreadable; when stderr says the root could not be derived, setJSC_PLUGINS_ROOTto the directory that holds the domain repos and rerun, because under a plugin install the script sits in the CLI's plugin cache and its built-in guess lands there instead of the domain workspace. Resolve 2 and 1 before continuing.The three review groups of step 2 all read this synced tree, so the sync finishes first.
-
Run the three review groups over the synced repos. They are independent — every one only reads, none writes a file — so launch all three in parallel and merge their results in step 3.
Group 1 — validate scripts, frontmatter, behavior lists, language, wiki rules, page names, and hooks.
- For every synced domain repo, run
tools/lint-scripts.sh {domain-path}. One run per domain, and the runs go in parallel — no domain's verdict depends on another's. The tool covers three checks in one pass:sh -nsyntax, executable bit, and an exit-code declaration in the file header. Route each exit code: 0 — the domain's scripts pass all three; 1 — the failing items are printed as{file}:{check}:{detail}, so report each one; 2 — usage error, the tool takes exactly one argument; 3 — nothing was scanned, because the path is missing or the domain has neithertools/norhooks/. Record exit 3 as 「無腳本可掃」; a domain with no script directory is not a failure, but exit 3 is never a pass. - For every synced domain repo, run
tools/lint-frontmatter.sh {domain-path}. One run per domain, and the runs go in parallel alongside thelint-scripts.shruns. It parses the frontmatter of everyskills/*/SKILL.mdwithout a YAML library — paired---delimiters, the requirednameanddescriptionkeys, unquoted scalars carrying a colon-space or ending in a colon, unquoted scalars opening with&,*,!,|,>,%,@or a backtick, and quoted scalars that never close. Route each exit code: 0 — every SKILL.md in that domain parses; 1 — the failures are printed on stderr as{檔案}:{鍵}:{說明}, so report every one as a compliance failure with the file and key it belongs to; 2 — usage error, the tool takes exactly one argument; 3 — nothing was scanned, because the domain path orskills/is missing, orskills/holds noSKILL.md. Record exit 3 as 「無 frontmatter 可掃」with the cause from stderr and carry it into the step 3 merge; exit 3 is never a pass. This check exists because a broken frontmatter makes Antigravity drop the whole skill with no error message at all — 34 skills on disk loaded as 28, and only a file-by-file comparison found it. - For every synced domain repo, run
tools/check-behaviors.sh {domain-path}. One run per domain, and the runs go in parallel alongside thelint-scripts.shruns — no domain's verdict depends on another's. It comparesreferences/behaviors.mdagainstskills/: section per skill, dictionary order, one table per section, five rows, no empty content cell. Route each exit code: 0 — that domain's behavior list matches; 1 — the mismatches are printed on stderr as{檔案}:{技能名}:{說明}, so report every one as a compliance failure with the skill it belongs to; 2 — usage error, the tool takes exactly one argument; 3 — nothing was checked, becausereferences/behaviors.mdis missing,skills/is missing, or noSKILL.mdwas found. Record exit 3 as 「無清單可查」with the cause from stderr and carry it into the step 3 merge; a domain with no behavior list is a compliance failure, and exit 3 is never a pass. - For every synced domain repo, run
tools/ste100-lint.sh {domain-path}. One run per domain, and the runs go in parallel alongside the other group 1 runs. Route each exit code: 0 — every scanned file in that domain passes; 1 — the hits are printed on stdout as{檔案}:{行號}:{類別}:{命中內容}, so report every one as a compliance failure with the category it belongs to, after checking the two documented false-positive classes (a path or branch name holding a slash between Chinese characters, and English items listed with a slash); 2 — no scan target was given, which is a caller defect here, so fix the argument and rerun. The tool has no exit 3: an empty run returns 2 rather than a silent pass. This check lives in group 1 because the audit checklist demands 「tools/ste100-lint.sh對該 domain 全綠」 for every domain — leaving it to the group 2 sub agents meant ten agents each ran it their own way, and the main agent never held one comparable verdict per domain. - For every synced domain repo, run
tools/check-link-format.sh {domain-path}. One run per domain, and the runs go in parallel alongside the other group 1 runs. It reads every*.mdof that domain and reports any link still written in the double-bracket wiki-link form, which resolves only inside one wiki and dead-links everywhere else. Route each exit code: 0 — every link in that domain is written as[{text}]({url}); 1 — the hits are printed on stdout as{檔案}:{行號}:{命中內容}, so report every one as a compliance failure; 2 — usage error, the tool takes exactly one argument; 3 — nothing was scanned, because the domain path is missing or holds no*.md. Record exit 3 as 「無文件可掃」with the cause from stderr; it is never a pass. The tool strips inline code and fenced code blocks before judging, so a document that quotes the forbidden form while explaining it, and a shell test expression inside an example, both stay clean. - Run the two wiki-rule checkers once each, not per domain — both judge shared rules, so a second run adds nothing:
jsc-gitea/tools/check-wiki-rules.sh, which verifies wiki repo resolution and thehash-idrule for every page type. It takes no argument. Route each exit code: 0 — printedOKon stdout, every item passed; 1 — the first mismatch is printed on stderr as{項目}: want=… got=…and the script stops there, so report that item and rerun after the fix, because the remaining items were never reached. Those are its only two codes. Until this audit, no flow in the whole repository ever called it.tools/check-page-name.sh {root}, where{root}is the directory holding the domain repos — the parent directory of the pathstools/sync-domains.shprinted in step 1, so no extra derivation is needed. It compares the page-name pattern in its three copies:jsc-gitea/tools/page-name.sh(the canonical one),jsc-hooks/hooks/comment-scope.shandjsc-log/tools/worklog-pending.sh. Route each exit code: 0 — the three agree; 1 — the mismatches are printed on stderr as{檔案}:{說明}, so report each one as a compliance failure, and a copy that could not be found is one of those lines; 2 — usage error, the tool takes exactly one argument; 3 — none of the three copies was found, so the root is wrong: fix it and rerun. Record exit 3 as 「什麼都沒查」; it is never a pass. The three copies stay separate on purpose — a hook must be self-contained and may not depend on another plugin's path at run time — so consistency is checked here instead of shared in a function.
- For every shell script directly named by a SKILL.md, confirm the skill routes every exit code the script's header declares.
lint-scripts.shproves the script exists and declares its codes; this check is the other half — that the caller branches on each of them. Report evidence asskill file:line -> script path. - When the
jsc-hooksdomain is present, runjsc-hooks/tools/wire-cli.sh smoke {cli}for every CLI reported byjsc-cli/tools/detect-clis.sh; the per-CLI smokes run in parallel. When no CLI is detected, runjsc-hooks/tools/wire-cli.sh smoke codexas the minimum hook behavior check and label it 「預設 hook smoke」 in the report. Usesmoke, notpurgeor rewiring actions, and setJSC_READONLY=1for the whole audit so a mistyped sub-command is refused in code (exit 6) instead of rewiring the machine;statusandsmokeare unaffected by that variable. Route eachsmokeexit code: 0 — the run passed its own assertions; 2 — usage error, so fix the CLI code and rerun; 4 — the smoke failed, which includes the script's own result-line count not matching what it expected. Read the count from the script'slines<TAB>{數量}output line; never write the number into this skill. The script counts its own result lines and asserts them, so a hardcoded number here goes stale the moment a hook or a decision path is added — an out-of-date count in a SKILL.md is exactly what misled the previous audit. - When a hook or script smoke fails, route it as a compliance failure with script name, exit code, output summary, and proposed fix. Do not continue to report the affected hook as compliant.
Group 2 — audit every skill of every domain against the guidelines.md audit checklist. This group MUST run as a sub agent, one sub agent per domain repo, and those sub agents run in parallel. Each sub agent reports its findings: skill, failed checklist item, evidence (file:line), proposed fix. Cover the checklist's four flow checks by name, not only the naming and language items:
- Every step number, file path and section title the skill references — inside itself and in other files — really exists (the pointer points at something).
- Every step ends in a checkable completion condition, with no vague wording.
- Every external call (script, API, other skill) states what to do on failure and routes every exit code.
- No gate the skill installs blocks the only path that lifts that gate.
Nine checklist items are already decided by group 1 and must not be re-run here:
sh -non everytools/andhooks/script, script existence with the executable bit, the hook smoke, thereferences/behaviors.mdmatch, thelint-frontmatter.shverdict, theste100-lint.shverdict, the link-format verdict fromtools/check-link-format.sh, the page-name-pattern verdict fromtools/check-page-name.sh, and the wiki repo resolution plushash-idverdict fromjsc-gitea/tools/check-wiki-rules.sh. Tell each sub agent to skip those nine and leave them blank; the main agent fills them in from the group 1 verdicts when merging in step 3. The link-checklist item has a second half no script can judge — that every link went throughjsc-gitea/tools/link-check.shbefore it was written — so each sub agent still audits that half from the skill text. The last two are one verdict for the whole round, not one per domain — group 1 runs each of those two checkers once, because both judge rules the domains share — so the merge writes that single verdict into every domain's checklist. Re-scanning the same files in every domain sub agent buys nothing — group 1 already scanned them all, with the same tools, on the same synced tree.Group 3 — a flow and cost optimization review, kept separate from the compliance audit.
Read the previous round's decisions before scanning anything. For every synced domain, resolve
jsc-gitea/tools/gitea.sh wiki-repo SKILLSET, compute the page name asSKILLSET_plusgitea.sh hash-id "{owner}/{repo}"of that domain repo, and read it throughjsc-gitea:wiki. Take the 優化建議 table of everyskill-checksection on that page: an entry whose 決議 column reads套用or延後is settled — do not scan for it again, and do not put it back into the step 3 decision tree. Only a genuinely new finding, or an entry whose recorded 決議 is自訂with the custom fix not yet in place, reaches step 3.Route every exit code of all three calls, not the read alone:
Call Exit Do gitea.sh wiki-repo SKILLSET0 The repo is in hand; go on to hash-id2 The page type was misspelled here, which is a defect in this skill and not a user setting. Fix the argument and rerun 3 Neither JSC_WIKI_REPO_SKILLSETnorJSC_WIKI_REPOis set. Name both variables, ask per thejsc-ask:askrules, then rerun. No answer means no settled list for that domain, per the rule belowgitea.sh hash-id "{owner}/{repo}"0 Use the 40 characters it printed as the page-name suffix, unshortened 1 No SHA-1 helper on this machine. Report that sha1sumorshasumhas to be installed, and never hand-compute the hash2 Empty input, so the {owner}/{repo}was never resolved. Resolve it and rerunjsc-gitea:wikiread0 The settled list is in hand 4 The page does not exist yet, so there is no previous round. Carry on with an empty settled list — the normal state for a domain audited the first time 7 The token is invalid or lacks permission 8 Some other API failure A 7, an 8, an unanswered 3, or a stopped 1 or 2 ends group 3 for that domain, and nothing else. An unread page cannot be told apart from an empty one, and treating it as empty re-asks every question the user already answered. So mark that domain 「本輪未取得已決議清單,優化建議暫不提出」, report the exit code that caused it, and run the rest of the round unchanged: group 1 and group 2 read no wiki at all, and steps 3 to 8 still apply and record every compliance fix. Stopping the whole round on a wiki failure would switch off the one routine compliance audit this skill set has — including the audit that finds a broken wiki setting.
This read exists because the audit was re-scanning and re-asking every accepted or deferred suggestion on every run — exactly the 「重複來回」 that aspect 3 below is supposed to catch, committed by the skill that defines it.
Each aspect MUST run as a sub agent, and the six aspects run in parallel with each other and with groups 1 and 2. Every sub agent gets that domain's settled list up front:
Aspect Scope 1 Parallelism Steps that run in series today but have no data dependency and can run in parallel 2 Tool extraction SKILL.md text flows with clear inputs and outputs that should move to tools/, including hook-enforceable rules that still rely on prompts3 Repeated interaction The same user question, repository fact, wiki page, API result, or file content being collected more than once 4 Redundant checks Completion conditions or verification steps that overlap, or a later step that necessarily covers an earlier check 5 Gate timing Gates that run too early or too late, causing wasted work before a block or blocking the only path that clears the gate 6 Cost efficiency Avoidable token, sub-agent, API, file-scan, full-repo audit, or user-interaction cost that can be reduced without weakening correctness Each optimization finding reports skill, aspect, evidence (file:line), current flow step count, proposed flow step count, what time or interaction it saves, what cost it saves, current cost driver, proposed cost driver, whether correctness decreases, which protection would be weakened if any, the 決議 (
套用,延後or自訂) recorded in step 3, and the 決議日期 that decision was made. The last two fields start empty and are filled in by step 3; they are what step 8 writes to the wiki and what the next round reads back, so a finding that reaches step 8 with either field empty is unfinished, not optional. Cost savings may be token volume, sub-agent count, API calls, file scans, full-repo audits, or user prompts. Keep optimization findings separate from compliance failures.Completion condition for all three groups: every domain has a
lint-scripts.shverdict, alint-frontmatter.shverdict, acheck-behaviors.shverdict, anste100-lint.shverdict and acheck-link-format.shverdict,check-wiki-rules.shandcheck-page-name.sheach have one verdict for the whole run, every script named by a SKILL.md has an exit-code-routing verdict, and every smoked CLI has asmokeexit code plus thelinesvalue the script printed for it; every domain has a group 2 audit result that names a verdict for all checklist items — the four flow checks included, and the nine group 1 items left blank for the step 3 merge rather than re-scanned; and every one of the six aspects has returned a verdict for every domain whose settled list was read, 「無發現」 where an aspect found nothing and every settled entry of that domain excluded rather than re-reported — a domain whose pre-read failed carries 「本輪未取得已決議清單,優化建議暫不提出」 instead, and that sentence is a complete group 3 result for it. - For every synced domain repo, run
-
Merge the three groups, then present compliance failures and optimization findings separately via the
jsc-ask:askdecision tree. Merging means one thing in code: fill the nine skipped checklist items of every group 2 sub agent report from the matching group 1 verdicts, so each domain ends with one complete checklist and no item counted twice. Seven of the nine are per-domain verdicts, one domain to one item. The other two —check-page-name.shandcheck-wiki-rules.sh— are judged once for the whole round, and that one verdict goes into that same item of every domain's checklist; re-judging a whole-round item per domain is precisely the double counting this merge exists to stop. A domain that group 3 marked 「本輪未取得已決議清單,優化建議暫不提出」 still gets its full compliance checklist here; only its optimization findings are missing, and the merge report says so.- Compliance failure options: apply the proposed fix / skip / custom fix. Every option states its impact scope, for example skipping leaves the skill non-compliant until the next audit.
- Optimization options: apply / defer / custom. Record the chosen option in the finding's 決議 field as
套用,延後or自訂, and today's date in 決議日期. Any suggestion that weakens a protection must name the protection it removes and must not be applied unless the user explicitly accepts that tradeoff. Cost optimization may move, merge, cache, or narrow checks; it must not delete a compliance check only because it is expensive.
Completion condition: every domain's checklist is complete after the merge, with the two whole-round verdicts carrying the same value in every domain, and every compliance failure and every optimization finding has a recorded decision — every optimization finding carrying both 決議 and 決議日期.
-
Apply the confirmed fixes and accepted optimizations — the file-change part MUST run as a sub agent, one sub agent per affected domain repo, and those sub agents run in parallel: each repo's files are independent. A fix that changes a skill's behavior also updates that skill's
## {name}section in the same repo'sreferences/behaviors.md, in the same pass, so the fix and the behavior list land in one PR. Then runtools/sync-skill-manifest.sh {domain-path}directly (no sub agent needed) for each affected domain repo to refresh that domain README's 「Skills 目錄」 section and bump the version in all three manifests. Route each exit code: 0 — the README block and all three manifests are synced; 1 — the domain path,skills/,README.md, theJSC-SKILLSmarkers, aSKILL.md, a manifest, or a manifestversionfield is missing, so fix the named cause on stderr and rerun; 2 — usage error, the script takes exactly one argument; any other code — the script runs underset -e, so treat it as an environment fault and stop, never as a successful sync. Completion condition: every affected repo carries the changes, the matchingreferences/behaviors.mdupdate for every fix that changed a skill's behavior, and the manifest bump. -
Sync the canonical marketplace — a required step, never optional. The canonical pair lives in
plugins/metaand every domain repo carries a byte-identical copy, so a fix that leaves the copies apart makes some repos register a stale plugin set. Runtools/sync-marketplace.sh {domain} {repo-url} {description}once with an existing entry's own current values (rewriting the same entry is idempotent); the script rewrites both canonical files and copies them into every domain repo. Route each exit code:- Exit 3 — written, but some domain repo is not present locally. Run
tools/sync-domains.sh, then rerun this step. - Exit 2 — usage error: the script takes exactly three arguments. Fix them and rerun.
- Exit 1 — the root could not be derived, python3 is missing, a canonical file was unreadable, or copies differ byte for byte. Read stderr and fix the named cause: install python3 for the second; for the root case set
JSC_PLUGINS_ROOTto the directory that holds the domain repos, because under a plugin install the script sits in the CLI's plugin cache and its built-in guess lands there. Then rerun. - Exit 0 — every copy holds identical bytes; the script verifies that itself.
Completion condition: the script exits 0 and prints the touched paths.
- Exit 3 — written, but some domain repo is not present locally. Run
-
Re-run the group 1 script, frontmatter, behavior-list, language, link-format, wiki-rule, page-name and hook validation, re-check the guidelines.md audit checklist for every touched skill, then re-run the optimization aspect that produced each accepted optimization. These three re-runs are as independent as the first pass, so run them in parallel and merge them the same way step 3 did. On any compliance failure, return to step 3: confirm and fix again, until all accepted compliance fixes pass. On an accepted optimization that does not produce the promised step reduction or cost reduction, or still weakens correctness beyond the recorded decision, return to step 3 for a new decision. Completion condition:
tools/lint-scripts.shexits 0 or 3 for every domain,tools/lint-frontmatter.shexits 0 for every domain — exit 3 is 「什麼都沒掃」 and never counts as a pass —tools/check-behaviors.shexits 0 for every domain,tools/ste100-lint.shexits 0 for every domain,tools/check-link-format.shexits 0 for every domain — its exit 3 is 「什麼都沒掃」 and never counts as a pass —jsc-gitea/tools/check-wiki-rules.shexits 0,tools/check-page-name.shexits 0 — its exit 3 is 「什麼都沒查」 and never counts as a pass — every hook smoke exits 0 with thelinescount the script itself asserted, every domain's checklist passes in full — the two whole-round verdicts filled into each domain from the one run that produced them — and every accepted optimization has a matching verification result. -
Call
jsc-git:pronce per affected domain repo to open a Push Request. Completion condition: every affected repo has a PR URL, and all URLs are reported in one table with the format in../../references/pr-report.md. -
Write the round's result to the wiki. This step MUST run as a sub agent, one sub agent per affected domain repo, and those sub agents run in parallel: each domain writes its own page, and no page waits on another.
Without this step the whole audit stops at the PR and scatters. The other four
jsc-metachange skills all append toSKILLSET_{HASH};skill-checkwas the only one that did not, so the audit that produced the deferrals had nowhere to record them and step 2's group 3 had nothing to read back.-
Which page. For every domain repo actually changed in this round, resolve
gitea.sh wiki-repo SKILLSETand append one section toSKILLSET_plusgitea.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: date, change typeskill-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. Theskill-checksection 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_CONTENTSwithjsc-gitea/tools/wiki-contents.sh— never by hand, and never throughjsc-gitea:wiki. Build one file holding the single row from../../templates/skillset-contents.md, then run:jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "{owner}/{repo}" {row file} templates/skillset-contents.mdThe 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 異動頁 cell is written as
[SKILLSET_{HASH}]({url}), the URL being the absolute one fromgitea.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.shand 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 gitea.sh wiki-repo2 The page type was misspelled. Fix the argument and rerun 3 No wiki repo is configured for that type. Name the variable ( JSC_WIKI_REPO_SKILLSETorJSC_WIKI_REPO_CONTENTS) andJSC_WIKI_REPO, ask per thejsc-ask:askrules, then rerungitea.sh hash-id1 No SHA-1 helper on this machine. Stop and report that sha1sumorshasumhas to be installed, and never hand-compute the hash2 Empty input, which means the {owner}/{repo}was never resolved. Fix that firstContent 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-url4 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 5 The API answered with no html_url. Stop and report it; never assemble the URL by hand from the host and the page namelink-check.sh0 Every link is reachable. Write the page 1 At least one link is dead. Write nothing, and report the DEADlines it printed2 No URL was passed, which is a defect here. Pass the links and rerun 3 GITEA_HOSTis unset. Set it and rerun; never skip the check instead7 Gitea authentication failed. Stop and report the key problem, and never read it as a dead link wiki-contents.sh upsert0 The row is in place. Report the updatedoraddedit printed, with the page it named1 The write failed, or the directory page holds no markdown table. Report SKILLSET_CONTENTSas not written, together with the row content2 An argument was rejected. Fix it and rerun; nothing was written 3 No CONTENTS wiki repo is configured. Report JSC_WIKI_REPO_CONTENTSandJSC_WIKI_REPOas the two variables to set. The round's section is onSKILLSET_{HASH}and stays there4 The directory page is absent and no template was passed. Rerun with templates/skillset-contents.mdas the fifth argument7 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 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 inSKILLSET_CONTENTSwritten by awiki-contents.sh upsertthat exited 0, or — where nothing changed — theplugins/metapage 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. -