feat(狀態回報): 收尾寫一筆 skill-end 事件
現行紀錄只記「被叫用」,沒有成敗也沒有結束碼。跑完整輪的技能與開場就 中止的技能,在紀錄裡長得一模一樣。 start 由技能用量 hook 順手發,不必改技能文件。end 只能由技能自己在收尾 步驟寫——hook 接在技能工具呼叫上,而實際工作發生在之後的模型輪次,它在 原理上看不到成敗。有 start 沒有配對的 end,就是那一輪中止了。 status 五選一,每支技能各自寫明什麼情況選哪一個。找不到回報腳本就安靜 跳過,回報失敗一律不改變技能自己的結論。
This commit is contained in:
+50
-10
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: assistant
|
||||
description: 'Start, inspect, patrol or stop the background assistant: jsc-hooks/hooks/heartbeat.sh owns the freshness verdict, tools/schedule.sh the system scheduler, tools/patrol.sh one round. The heartbeat is written by a completed round and by nothing else, so the schedule carries the patrol entry only, its period from the heartbeat TTL; start runs one round then installs that entry - absolute CLI path, environment snapshot, unattended write confirmation, which cron lacks - status prints heartbeat, schedule and task book read-only, stop removes the entry before clearing the heartbeat. One round reads four independent sources - skill and chain usage, version gaps and the restart gate, SDLC stage and work-package locks, and the heartbeat''s own report - then rewrites wiki MONITOR_{HASH} through jsc-gitea:wiki as three fixed blocks - basic data untouched, the latest round replaced whole, a 24-row summary table - and upserts its MONITOR_CONTENTS row through jsc-gitea/tools/wiki-contents.sh, which reads the separate CONTENTS wiki repo and links the monitor page by its absolute wiki-url. Every link on either page is written as [text](URL) and is verified by jsc-gitea/tools/link-check.sh before that page is written, so a dead link stops the write instead of landing on the page. A round that cannot record its result writes no heartbeat; one that starts while the previous holds the lock stands down. Use when someone starts, patrols or stops the assistant, or asks whether it runs and what is queued; not for environment health checks (jsc-cli:doctor), not for skill usage counts (jsc-log:stats).'
|
||||
description: 'Start, inspect, patrol or stop the background assistant: jsc-hooks/hooks/heartbeat.sh owns the freshness verdict, tools/schedule.sh the system scheduler, tools/patrol.sh one round. The heartbeat is written by a completed round and by nothing else, so the schedule carries the patrol entry only, its period from the heartbeat TTL; start runs one round then installs that entry - absolute CLI path, environment snapshot, unattended write confirmation, which cron lacks - status prints heartbeat, schedule and task book read-only, stop removes the entry before clearing the heartbeat. One round reads five independent sources - skill and chain usage, version gaps and the restart gate, SDLC stage and work-package locks, the heartbeat''s own report, and the status event stream that jsc-hooks/tools/report-status.sh drains and rotates, whose starts with no matching end are the only evidence an earlier skill run aborted - then rewrites wiki MONITOR_{HASH} through jsc-gitea:wiki as three fixed blocks - basic data untouched, the latest round replaced whole, a 24-row summary table - and upserts its MONITOR_CONTENTS row through jsc-gitea/tools/wiki-contents.sh, which reads the separate CONTENTS wiki repo and links the monitor page by its absolute wiki-url. Every link on either page is written as [text](URL) and is verified by jsc-gitea/tools/link-check.sh before that page is written, so a dead link stops the write instead of landing on the page. A round that cannot record its result writes no heartbeat; one that starts while the previous holds the lock stands down. Use when someone starts, patrols or stops the assistant, or asks whether it runs and what is queued; not for environment health checks (jsc-cli:doctor), not for skill usage counts (jsc-log:stats).'
|
||||
---
|
||||
|
||||
# assistant — start, status, patrol, stop
|
||||
@@ -11,7 +11,7 @@ The background assistant runs where nobody is watching it. Its heartbeat is the
|
||||
|
||||
`$JSC_HOME/current/jsc-assist/tools/schedule.sh` owns every system-scheduler operation: installing an entry, removing it, and reading which entries exist. Never call `crontab` or `schtasks` from this skill, and never edit a crontab by hand.
|
||||
|
||||
`$JSC_HOME/current/jsc-assist/tools/patrol.sh` owns one patrol round: taking the round lock, reading the four sources, composing the monitor page's blocks, and — after the page carries this round — writing the heartbeat. Never re-read a source this skill already handed to that script, and never compose a block by hand; the script prints the file paths.
|
||||
`$JSC_HOME/current/jsc-assist/tools/patrol.sh` owns one patrol round: taking the round lock, reading the five sources, composing the monitor page's blocks, and — after the page carries this round — writing the heartbeat. Never re-read a source this skill already handed to that script, and never compose a block by hand; the script prints the file paths.
|
||||
|
||||
All three flows have fixed inputs and outputs, so all three live in scripts. The task book is the only thing this skill reads for itself, and that is one directory listing.
|
||||
|
||||
@@ -24,13 +24,14 @@ Every tool below is addressed through `$JSC_HOME/current/{plugin}`, and `$JSC_HO
|
||||
| one patrol round | `$JSC_HOME/current/jsc-assist/tools/patrol.sh` |
|
||||
| the system scheduler | `$JSC_HOME/current/jsc-assist/tools/schedule.sh` |
|
||||
| the heartbeat | `$JSC_HOME/current/jsc-hooks/hooks/heartbeat.sh` |
|
||||
| the status event stream | `$JSC_HOME/current/jsc-hooks/tools/report-status.sh` |
|
||||
| the wiki, through `jsc-gitea:wiki` | `$JSC_HOME/current/jsc-gitea/tools/gitea.sh` |
|
||||
| the `MONITOR_CONTENTS` row | `$JSC_HOME/current/jsc-gitea/tools/wiki-contents.sh` |
|
||||
| the link check every write depends on | `$JSC_HOME/current/jsc-gitea/tools/link-check.sh` |
|
||||
|
||||
**A `Skill(...)` rule permits invoking that skill and nothing more.** Every Bash call inside it is still checked on its own, so `jsc-gitea:wiki` reaching the wiki depends on `gitea.sh` carrying its own rule, the directory row depends on `wiki-contents.sh` carrying one too, and both writes depend on `link-check.sh` carrying one — without them the round is refused locally, before any request leaves the machine, and the page never gets written.
|
||||
|
||||
**Never build a tool path out of the base directory the CLI hands you in the skill prompt.** That directory points into the plugin cache and carries a version segment, and the permission gate allows exactly the six paths above and nothing else. A cache path is therefore refused silently: the round stops on a permission prompt nobody can answer, records nothing, writes no heartbeat, and the refusal looks exactly like a broken tool. Read the paths off this table every time — not off the prompt, not off a previous transcript, not off `crontab -l`.
|
||||
**Never build a tool path out of the base directory the CLI hands you in the skill prompt.** That directory points into the plugin cache and carries a version segment, and the permission gate allows exactly the seven paths above and nothing else. A cache path is therefore refused silently: the round stops on a permission prompt nobody can answer, records nothing, writes no heartbeat, and the refusal looks exactly like a broken tool. Read the paths off this table every time — not off the prompt, not off a previous transcript, not off `crontab -l`.
|
||||
|
||||
Both scripts check this for themselves: run from anywhere outside `$JSC_HOME/current`, they print a `[WARN]` line on stderr naming the path they were started from and the path they should have been started from, and then carry on. That line means this round is on the wrong path — quote it, fix the path, and do not treat the round's success as proof that the path was fine.
|
||||
|
||||
@@ -58,6 +59,24 @@ A round with no link to write skips the call and says so; a round that cannot ve
|
||||
|
||||
Run exactly one operation per invocation. Take it from the request: starting, launching or waking the assistant is `start`; asking whether it runs, what it is doing, or what is queued is `status`; running one round, patrolling, or a scheduled wake-up is `patrol`; stopping, halting or shutting it down is `stop`. When the request names none of the four, or names more than one, ask through the `jsc-ask:ask` decision tree with those four as the options, each stating its effect — `start` runs one round and installs the scheduled entry that keeps running rounds, `status` changes nothing, `patrol` runs one round and writes one heartbeat, `stop` removes that entry and deletes the heartbeat. **The one exception: a `patrol` invocation never asks anything at all** (see 界線 1 below). Never guess, and never run a second operation the caller did not ask for. Completion condition: exactly one of `start`, `status`, `patrol`, `stop` is chosen and named in the report.
|
||||
|
||||
## Every operation ends with one status event
|
||||
|
||||
The last thing any of the four operations does, after its report is printed, is write its own end event:
|
||||
|
||||
`$JSC_HOME/current/jsc-hooks/tools/report-status.sh skill-end jsc-assist:assistant {status} {exit} "{one line}"`
|
||||
|
||||
The `start` half is already on record — a hook writes it when this skill loads — so this call is what tells the difference between an operation that finished and one that stopped half way. **Skipping it makes this skill's own run look aborted**, and the next patrol round reports it as such, on the page this skill writes. Pick the status from what actually happened:
|
||||
|
||||
| status | When |
|
||||
| --- | --- |
|
||||
| `ok` | the operation reached its own completion condition |
|
||||
| `blocked` | the round stood down because another round holds the lock, or `install heartbeat` was refused — nothing was done and nothing is wrong |
|
||||
| `failed` | a step returned a code that stopped the operation: `collect` exit 5 or 6, a monitor-page write that could not be made, `remove` non-zero in `stop` |
|
||||
| `degraded` | the operation finished with a known gap: the directory row was left unwritten, or the schedule entry was installed but the cron service is stopped |
|
||||
| `aborted` | the operation stopped because a precondition did not hold, such as an empty `hash=` or a missing `current` link |
|
||||
|
||||
The call never changes the outcome: it returns 0 even when it cannot write, and a non-zero from it is reported as a defect in the reporting chain, never as a failure of the operation that just succeeded. Completion condition for all four operations: exactly one `skill-end` was written, and its status matches the outcome that was reported.
|
||||
|
||||
## Data sources
|
||||
|
||||
| Path | Read by | Format |
|
||||
@@ -68,6 +87,8 @@ Run exactly one operation per invocation. Take it from the request: starting, la
|
||||
| `$JSC_HOME/assistant/patrol.lock/` | `patrol.sh` only | the round lock, a directory. `info` holds `round`, `pid`, `started` |
|
||||
| `$JSC_HOME/assistant/patrol/` | `patrol.sh` only | one round's scratch files, including `latest.md`, `summary.md`, `summary-row.md`, `newpage.md` and `contents.tsv` |
|
||||
| `$JSC_HOME/assistant/usage-prev.tsv` | `patrol.sh` only | last recorded round's cumulative usage counts, so the next round can print a real per-round delta |
|
||||
| `$JSC_HOME/usage/events.jsonl` | `report-status.sh` only, never this skill and never `patrol.sh` by hand | one JSON object per line: `ts`, `cli`, `session`, `kind`, `name`, `phase`, `status`, `exit`, optional `ms` and `detail` |
|
||||
| `$JSC_HOME/assistant/events-open.tsv` | `patrol.sh` only | the starts still waiting for a matching end, carried from round to round: `session`, `name`, `kind`, first-seen epoch, the event's own `ts` |
|
||||
|
||||
`$JSC_HOME` defaults to `~/.jsc`. `heartbeat.sh report` prints the resolved heartbeat path in its `file=` field, so take the assistant directory from there rather than rebuilding it.
|
||||
|
||||
@@ -133,16 +154,29 @@ The failure this design buys is the one worth having: a round that cannot read i
|
||||
| 5 | Read-back verification failed — the entry is missing after a successful write, is present twice, is still there after a delete, or somebody else's line count changed | Serious. Report it loudly with the printed numbers, and tell the operator to inspect `crontab -l` by hand before anything else is run |
|
||||
| 6 | Usage error — an unknown subcommand or job name, a missing option value, `install heartbeat`, a `--period` that does not fit the TTL, the patrol CLI could not be determined, or that CLI's executable is not on `PATH` so no absolute path can be written | A defect in the call or a CLI that is not installed, not a state of the machine. The stderr line names which one it is; quote it, correct the command line, and run it once more. Report a second exit 6 as a defect in this skill and stop |
|
||||
|
||||
## The status event stream — the fifth source
|
||||
|
||||
`$JSC_HOME/usage/events.jsonl` is where every skill and every hook records how its run ended. A hook writes a skill's `start` for free; the matching `end` can only be written by the skill itself, in its own closing step. **So a `start` with no matching `end` is an aborted run, and it is the only evidence of one that exists anywhere.** That is what this source is for; the counts around it are secondary.
|
||||
|
||||
`$JSC_HOME/current/jsc-assist/tools/patrol.sh collect` owns the whole of it — it calls `$JSC_HOME/current/jsc-hooks/tools/report-status.sh drain`, then `rotate`, then does the pairing, and writes the 執行狀態事件 subsection into `latest_file`. **Never run `drain` from this skill.** Four properties make that the only safe arrangement, and each one is a way to lose events:
|
||||
|
||||
- **`drain` is a consuming read.** It prints everything written since the last drain and then moves the offset in `$JSC_HOME/usage/scan-state/events.offset`. The same events never come back. Read into a transcript instead of a file, they are one dropped line away from gone; a second `drain` in the same round returns exit 3 and the first drain's events are already spent.
|
||||
- **Exit 3 means there were no new events, and that is a normal round, not a failure.** Most rounds have nothing new. The script also uses 3 when the stream file does not exist yet.
|
||||
- **`rotate` has to follow `drain` immediately.** It renames the stream and resets the offset once the file passes its size limit, so anything appended between the two calls is moved aside without ever being drained. One script, one run, smallest possible gap.
|
||||
- **Pairing is by `session` plus `name`, and it carries across rounds.** Five CLIs run the same skill in different sessions at once, so `name` alone lets one session's `end` cancel another session's `start`. And a round lasts about two minutes while a skill run can last much longer, so an unmatched `start` is held in `$JSC_HOME/assistant/events-open.tsv` and matched against later rounds. It is reported as an abort only once it has stayed open longer than the heartbeat TTL; below that it counts as still running.
|
||||
|
||||
Neither `drain` nor `rotate` may stop a round. A missing `report-status.sh`, a `drain` that returns anything other than 0 or 3, and a failed `rotate` each mark this one item failed or add one 警示來源 — exactly like the other four sources — and the round carries on to record itself. The reporting chain breaking must never break the round that is doing the reporting.
|
||||
|
||||
## patrol.sh exit codes
|
||||
|
||||
One table for all three subcommands. Read `collect`'s codes carefully: **1 and 3 are results, not aborts.** A round with failed items still has a result to record, and refusing to record it would hide the failure instead of showing it.
|
||||
|
||||
| Code | Meaning | What to do |
|
||||
| --- | --- | --- |
|
||||
| 0 | `collect`: all four items read to the end, empty sources included. `finish`: heartbeat written, snapshot promoted, lock released. `abort`: lock released | Carry on with the operation's next step |
|
||||
| 0 | `collect`: all five items read to the end, empty sources included. `finish`: heartbeat written, snapshot promoted, lock released. `abort`: lock released | Carry on with the operation's next step |
|
||||
| 1 | `collect`: partial success — at least one item failed and at least one produced a result | **Write the page anyway.** The latest-round block already marks the failed items and the round verdict is 警示. Name the failed items and their `note=` text in the report |
|
||||
| 2 | `finish`: `$JSC_HOME/current/jsc-hooks/hooks/heartbeat.sh` was not found | The round completed and is recorded, but no heartbeat exists to prove it. Report the round as recorded and the heartbeat as not written, say `jsc-hooks` 0.3.7 or newer has to be installed, and run `$JSC_HOME/current/jsc-assist/tools/patrol.sh abort --round {id}` to release the lock |
|
||||
| 3 | `collect`: all four items failed | **Write the page anyway**, with verdict 異常. A page listing four failures is the signal; a missing page is not. Then carry on to `finish` as usual — the round did complete |
|
||||
| 3 | `collect`: all five items failed | **Write the page anyway**, with verdict 異常. A page listing five failures is the signal; a missing page is not. Then carry on to `finish` as usual — the round did complete |
|
||||
| 4 | Another round holds the lock (`collect`), or the lock is no longer this round's (`finish`, `abort`) | Not a failure. On `collect`: report 本輪讓開 and name the holder and its age from the printed `lock=busy` line, then write nothing and stop. On `finish`: the previous round overran and was taken over, so this round's result does not count — report it, write no heartbeat, and stop |
|
||||
| 5 | Filesystem failure — the lock could not be created or released, a scratch file could not be written, the snapshot could not be promoted, or `heartbeat.sh write` returned non-zero | Serious. Report it loudly with the stderr text and the path. On a `finish` failure the round is recorded but unproven: say so plainly and never claim the round beat |
|
||||
| 6 | Usage error — an unknown subcommand, a missing `--round`, or an option with no value | A defect in the call. Correct it and run it once more; report a second exit 6 as a defect in this skill and stop |
|
||||
@@ -179,7 +213,7 @@ That property holds only while nothing fakes a heartbeat. **`write` is called by
|
||||
|
||||
| Step 3 | Notice |
|
||||
| --- | --- |
|
||||
| exit 0 | 助理已啟動,第一輪巡檢跑完了,結果寫上監控頁了,心跳也寫了。排程接上了,之後每 {period} 分鐘跑一輪,每一輪跑完才寫一次心跳。心跳新鮮代表上一輪巡檢真的做完了;那一輪四項有沒有全過,看監控頁的本輪判定。 |
|
||||
| exit 0 | 助理已啟動,第一輪巡檢跑完了,結果寫上監控頁了,心跳也寫了。排程接上了,之後每 {period} 分鐘跑一輪,每一輪跑完才寫一次心跳。心跳新鮮代表上一輪巡檢真的做完了;那一輪各項有沒有全過,看監控頁的本輪判定。 |
|
||||
| exit 1 | 助理已啟動,第一輪巡檢跑完了,排程條目也寫進去了,但 cron 服務沒在跑,那一筆一次都不會被執行。心跳過了 {ttl} 秒就會過期。請先跑 `sudo service cron start`,重開 WSL 之後要再跑一次。 |
|
||||
| 其他結束碼 | 助理已啟動,第一輪巡檢跑完了,但排程沒接上(結束碼 {code})。不會再有下一輪,心跳過了 {ttl} 秒就會過期,屆時請再跑一次 start。 |
|
||||
|
||||
@@ -187,10 +221,12 @@ That property holds only while nothing fakes a heartbeat. **`write` is called by
|
||||
|
||||
## patrol
|
||||
|
||||
One round: read four sources, record the result, then beat. Everything before the heartbeat is read-only except the round's own scratch files. Ask nobody anything.
|
||||
One round: read five sources, record the result, then beat. Everything before the heartbeat is read-only except the round's own scratch files. Ask nobody anything.
|
||||
|
||||
1. **Collect.** Run `$JSC_HOME/current/jsc-assist/tools/patrol.sh collect --trigger 排程` (use `--trigger 手動` when a person asked for this round). Judge the exit code by the patrol.sh table. Exit 4 stands the round down — report the holder and its age from the printed `lock=busy` line, and stop; write no page and no heartbeat. Exit 5 and 6 stop the round the same way, with the code and the stderr text. Exit 0, 1 and 3 all carry on to step 2. Record `round=`, `lock_broken=`, `hash=`, `page=`, `verdict=`, `failed_sources=`, `warn_sources=`, `pending=`, every `item=` line, and the file paths `latest_file=`, `summary_file=`, `summary_row_file=`, `newpage_file=` and `contents_file=`. Completion condition: the round id, the page name and the five file paths are recorded, or the stand-down or the failure was reported and the round stopped.
|
||||
|
||||
**The status event lines come out of the same call.** `collect` drained the stream and rotated it (see 「The status event stream」 above), so record `events_total=`, `events_bad=`, `events_unpaired=`, `events_running=`, `events_rotated=` and `events_file=` alongside the rest, and read `item=D-11` for whether that source was readable at all. The 執行狀態事件 subsection of `latest_file` already carries the two detail tables — the non-`ok` events and the starts with no matching end — so never rebuild either by hand and never call `report-status.sh` yourself: a second `drain` this round would either return exit 3 or eat events that then reach no page at all.
|
||||
|
||||
2. **Check the page name.** An empty `hash=` means `jsc-gitea/tools/hash-id` could not be found or could not run, so there is no page to write to and nothing can be recorded. Run `$JSC_HOME/current/jsc-assist/tools/patrol.sh abort --round {round}`, report that the round found its results but has nowhere to put them, name `jsc-gitea` as missing, and stop.
|
||||
|
||||
**Never invent a page name, and never work the hash out by hand** — a hand-made name lands the content on a page nobody reads. `hash-id` hashes `{host}/{user}` and prints the full 40-character uppercase hexadecimal SHA-1: no truncation to 8, no `H` prefix, and an empty input exits 2 rather than hashing the empty string. So `page=` is either `MONITOR_` plus that 40-character string, exactly as the script printed it, or nothing at all. Completion condition: `page=` holds a `MONITOR_{HASH}` name taken verbatim from `collect`, or the abort ran and the round was reported as unrecorded.
|
||||
@@ -201,7 +237,7 @@ One round: read four sources, record the result, then beat. Everything before th
|
||||
| --- | --- |
|
||||
| 本頁基本資料 | the old page, byte for byte from its heading to the line before 最新一輪. Never rewritten, never re-derived |
|
||||
| 最新一輪 | the whole content of `latest_file`, replacing the old block entirely |
|
||||
| 近 24 輪摘要 | `summary_file`, which already holds the heading, the five-column table header (`巡檢時間`、`本輪判定`、`四項成敗`、`待人處理`、`警示來源`) and this round's row; then the old table's data rows in their old order underneath, cut so the table holds at most 24 rows |
|
||||
| 近 24 輪摘要 | `summary_file`, which already holds the heading, the five-column table header (`巡檢時間`、`本輪判定`、`各項成敗`、`待人處理`、`警示來源`) and this round's row; then the old table's data rows in their old order underneath, cut so the table holds at most 24 rows |
|
||||
|
||||
**Verify the page's links before the write.** List every link the rebuilt body carries — the ones the latest-round block brought in, and any that survived in the block carried over from the old page — and run `$JSC_HOME/current/jsc-gitea/tools/link-check.sh` over the whole list. Exit 0 is the only result that permits the write. On exit 1 report the `DEAD` lines verbatim, then run `$JSC_HOME/current/jsc-assist/tools/patrol.sh abort --round {round}` and stop: a round that writes a dead link records a false trail nobody can follow back. Exits 2, 3 and 7 take the same abort, each reported by the rule B table above. A body carrying no link at all needs no call — say so in the report rather than claiming a check that never ran.
|
||||
|
||||
@@ -233,7 +269,11 @@ One round: read four sources, record the result, then beat. Everything before th
|
||||
|
||||
5. **Write the heartbeat.** Run `$JSC_HOME/current/jsc-assist/tools/patrol.sh finish --round {round}`. This is the last step for a reason: it is the only thing that turns a fresh heartbeat into a true statement. Judge the exit code by the patrol.sh table — 2, 4 and 5 all mean the round is recorded but unproven, and each has its own report line there. Completion condition: `finish` exited 0, or the failure was reported as "recorded but no heartbeat" with its code.
|
||||
|
||||
6. **Report the round.** Print the round verdict and, when it is `警示`, the `warn_sources=` text that says why — a round can read all four sources and still come out `警示`, and that column is the only place the reason appears; then one line per item with its `status=` and, for a failure, its `note=`; the monitor page name, the link-check verdict for each of the two writes — passed, skipped for a body with no link, or refused with its exit code and its `DEAD` lines — and the directory row as `updated`, `added`, or not written with the exit code and the reason; whether the heartbeat was written; and, when `lock_broken=1`, that the previous round's lock was taken over because it had aged past the TTL. Close with the 待人處理 rows from the latest-round block, verbatim, and nothing else — the patrol names an entry point and stops there. Completion condition: all four items appear in the report, the heartbeat outcome is stated as written or not written, and no suggestion in 待人處理 was acted on.
|
||||
6. **Report the round.** Print the round verdict and, when it is `警示`, the `warn_sources=` text that says why — a round can read all five sources and still come out `警示`, and that column is the only place the reason appears; then one line per item with its `status=` and, for a failure, its `note=`; the monitor page name, the link-check verdict for each of the two writes — passed, skipped for a body with no link, or refused with its exit code and its `DEAD` lines — and the directory row as `updated`, `added`, or not written with the exit code and the reason; whether the heartbeat was written; and, when `lock_broken=1`, that the previous round's lock was taken over because it had aged past the TTL.
|
||||
|
||||
**The event numbers get their own line, and the unpaired starts get their own list.** Print `events_total=` and `events_bad=` as this round's event count and its non-`ok` count, then every non-`ok` event with its `kind`, `name`, `status`, `exit` and `detail`, then — separately, never folded into the same list — every start with no matching end, by `name` and `session`. A non-zero `events_unpaired=` is the round's most important finding: each row is a skill run that started and never reached its closing step. Say `events_rotated=` too when it is `rotated` or `failed`. When `item=D-11` failed, say the source could not be read rather than reporting zero events — zero read events and zero existing events look identical in a report and mean opposite things.
|
||||
|
||||
Close with the 待人處理 rows from the latest-round block, verbatim, and nothing else — the patrol names an entry point and stops there. Completion condition: all five items appear in the report, the event count, the non-`ok` count and the unpaired starts are stated, the heartbeat outcome is stated as written or not written, and no suggestion in 待人處理 was acted on.
|
||||
|
||||
## status
|
||||
|
||||
@@ -260,7 +300,7 @@ Read-only throughout. This operation creates, modifies and deletes nothing under
|
||||
|
||||
| Heartbeat | Schedule | Say |
|
||||
| --- | --- | --- |
|
||||
| 新鮮 | patrol installed, service running | 上一輪巡檢跑完了,結果也記上監控頁了,排程還在跑。那一輪四項有沒有全過,要看監控頁的本輪判定 |
|
||||
| 新鮮 | patrol installed, service running | 上一輪巡檢跑完了,結果也記上監控頁了,排程還在跑。那一輪各項有沒有全過,要看監控頁的本輪判定 |
|
||||
| 新鮮 | not installed, or service stopped | 上一輪巡檢跑完了,但沒有排程在叫下一輪,過了 TTL 心跳就會過期 |
|
||||
| 過期 or 不存在 | patrol installed, service running | 排程裝著卻沒有新的心跳,巡檢自己跑失敗了,去看 `$JSC_HOME/assistant/schedule.log` 與監控頁的最新一輪 |
|
||||
| any | `heartbeat` job installed | 舊版的心跳排程還留著,它會蓋掉「心跳等於巡檢跑完」這件事。請跑一次 `start`,或 `schedule.sh install patrol` 把它清掉 |
|
||||
|
||||
Reference in New Issue
Block a user