Merge pull request '提醒佇列把內建項標成另一種列' (#47) from fix/reminder-queue-marks-builtin into develop
Reviewed-on: #47
This commit was merged in pull request #47.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jsc-assist",
|
||||
"version": "0.3.6",
|
||||
"version": "0.3.7",
|
||||
"description": "助理:事件收攏、健康巡檢與待辦簿(MONITOR_{HASH} wiki 頁)",
|
||||
"skills": "./skills",
|
||||
"author": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jsc-assist",
|
||||
"version": "0.3.6",
|
||||
"version": "0.3.7",
|
||||
"description": "助理:事件收攏、健康巡檢與待辦簿(MONITOR_{HASH} wiki 頁)",
|
||||
"skills": "./skills",
|
||||
"jsc": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jsc-assist",
|
||||
"version": "0.3.6",
|
||||
"version": "0.3.7",
|
||||
"description": "助理:事件收攏、健康巡檢與待辦簿(MONITOR_{HASH} wiki 頁)",
|
||||
"skills": "./skills/",
|
||||
"jsc": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -348,9 +348,9 @@ That property holds only while nothing fakes a heartbeat. **`write` is called by
|
||||
|
||||
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 `{CURRENT}/jsc-assist/tools/patrol.sh collect --trigger 排程` (use `--trigger 手動` when a person asked for this round). That is the same split step 0 branched on: 排程 is the unattended round that read its root out of the invocation text, 手動 the round somebody asked for. 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=`, `tasks_total=`, `tasks_failing=`, `tasks_due=`, `tasks_overdue=`, `reminders=`, every `item=` line, and the file paths `latest_file=`, `summary_file=`, `summary_row_file=`, `newpage_file=`, `contents_file=` and `due_rows_file=` — that last one is what step 5 has to be given, and an empty value there means the judging step produced no list, so step 5 has nothing to act on and says so rather than falling back to anything. 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.
|
||||
1. **Collect.** Run `{CURRENT}/jsc-assist/tools/patrol.sh collect --trigger 排程` (use `--trigger 手動` when a person asked for this round). That is the same split step 0 branched on: 排程 is the unattended round that read its root out of the invocation text, 手動 the round somebody asked for. 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=`, `tasks_total=`, `tasks_failing=`, `tasks_due=`, `tasks_overdue=`, `reminders=`, `reminders_builtin=`, every `item=` line, and the file paths `latest_file=`, `summary_file=`, `summary_row_file=`, `newpage_file=`, `contents_file=` and `due_rows_file=` — that last one is what step 5 has to be given, and an empty value there means the judging step produced no list, so step 5 has nothing to act on and says so rather than falling back to anything. 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 round also writes the reminder queue.** `collect` leaves `$JSC_HOME/assistant/reminders.tsv` behind — a tab-separated file whose first line is `round`, the round id, the round's UTC timestamp, the failing count and the same moment in epoch seconds — the ISO string is for a person to read and the epoch is what a reader does arithmetic on, so no reader has to carry its own date parser — followed by one `remind` row per reminder-type entry that came due and one `overdue` row per entry past its deadline, each carrying the id, the reason or the how-long-overdue wording, and the title. It is printed as `reminders=` and `reminders_file=`. **The judgement stays here and the queue is only its output**: whatever reads it later prints and nothing more, because a reader that compared `due` and `next_run` against the clock itself would be a second judgement of the same thing, and the day the two disagreed both would look right. The timestamp on that first line is what the design turns on — a queue nobody refreshed reads exactly like a fresh one, so the reader has to be able to say how old it is. **"No reminders" and "nobody computed the reminders" must never look the same.**
|
||||
**The round also writes the reminder queue.** `collect` leaves `$JSC_HOME/assistant/reminders.tsv` behind — a tab-separated file whose first line is `round`, the round id, the round's UTC timestamp, the failing count and the same moment in epoch seconds — the ISO string is for a person to read and the epoch is what a reader does arithmetic on, so no reader has to carry its own date parser — followed by one row per item to surface, each carrying its kind, the id, the reason or the how-long-overdue wording, and the title. There are three kinds, and the split is the point: `overdue` for an entry past its deadline, `remind` for a reminder-type entry a person registered, and `builtin` for one the delegation list seeded. **A built-in reminder waits on plumbing, not on a person** — its action is `remind`, nothing executes it yet, so it comes due every round and reads identically every round; eight of them on this machine turned every session's opening into eight lines nobody could act on. Whatever prints the queue names the first two kinds and gives the third a single count line, which is why the kind is decided here, where `spec_key` is readable, and not there. The counts are printed as `reminders=` for the named kinds and `reminders_builtin=` for the third, alongside `reminders_file=`. **The judgement stays here and the queue is only its output**: whatever reads it later prints and nothing more, because a reader that compared `due` and `next_run` against the clock itself would be a second judgement of the same thing, and the day the two disagreed both would look right. The timestamp on that first line is what the design turns on — a queue nobody refreshed reads exactly like a fresh one, so the reader has to be able to say how old it is. **"No reminders" and "nobody computed the reminders" must never look the same.**
|
||||
|
||||
**`tasks_overdue=` and `tasks_failing=` earn a 待人處理 row every round, and `collect` writes both of them itself.** Neither condition heals on its own: a deadline that has passed does not become un-passed, and an entry that fails retries next round and fails again. So the row is repeated every round rather than suppressed after the first — **"already reported" is not "already handled"**, and the assistant does not pause an entry on anybody's behalf; `paused` is a state a person sets and only a person clears. The overdue count comes from the judging step and is a dash when that step could not judge, which is not the same as zero. The monitor page carries the two named tables under 待辦簿到期與逾期: which entries are overdue and by how long, and which ones have been failing and how many times. **The directory page gains no field for either.** That page holds one block per machine, each written by that machine's own round, so a new field would only appear for machines already on the new version, and a reader could not tell "nothing overdue here" from "this machine has not written that field yet" — the same reason the 本輪非 ok 事件數 field was kept off it.
|
||||
|
||||
|
||||
+31
-4
@@ -149,7 +149,8 @@
|
||||
# 時,原因只寫在這裡
|
||||
# tasks_total= tasks_failing= 待辦簿筆數與連續失敗筆數,供目錄頁那一個區塊與摘要用
|
||||
# tasks_overdue= 逾期筆數(截止時間已經過了),取自到期判定那一支;判不出來時是減號
|
||||
# reminders= reminders_file= 提醒佇列的筆數與路徑。工作階段開始那一支 hook 讀它
|
||||
# reminders= reminders_builtin= reminders_file= 提醒佇列逐筆點名的筆數、只算總數的內建項
|
||||
# 筆數,與佇列路徑。工作階段開始那一支 hook 讀它
|
||||
# tasks_due= 本輪到期的筆數;到期判定那一支失敗時為空
|
||||
# events_new= 本輪偵測到的新事件種類數;到期判定那一支失敗時為空
|
||||
# due_status= due_rc= 到期判定那一支的結果與結束碼
|
||||
@@ -214,6 +215,7 @@ DUE_EVENTS=''
|
||||
DUE_OVERDUE=''
|
||||
FAILING_LINES=''
|
||||
REMINDERS=0
|
||||
REMINDERS_BUILTIN=0
|
||||
REMINDERS_FILE=''
|
||||
|
||||
# 這支腳本是不是從 $JSC_HOME/current 那一組路徑被叫起來的。不是就大聲警告,但照跑。
|
||||
@@ -943,19 +945,43 @@ write_reminders() {
|
||||
printf 'overdue\t%s\t%s\t%s\n' "$_oi" "${_oh:--}" "${_ot:--}"
|
||||
done
|
||||
fi
|
||||
# 內建項的識別碼,一行一個。分兩種列要靠它:帶 spec_key 的那幾筆是依委派清單種入的,
|
||||
# 使用者一筆都沒交辦過。
|
||||
_specids="$RD/spec-ids"
|
||||
: >"$_specids"
|
||||
for _tf in "$STATE_DIR/tasks"/*; do
|
||||
[ -f "$_tf" ] || continue
|
||||
_sk=$(sed -n 's/^spec_key=//p' "$_tf" 2>/dev/null | head -n1)
|
||||
[ -n "$_sk" ] || continue
|
||||
_tid=$(sed -n 's/^id=//p' "$_tf" 2>/dev/null | head -n1)
|
||||
[ -n "$_tid" ] || _tid=$(basename -- "$_tf")
|
||||
printf '%s\n' "$_tid" >>"$_specids"
|
||||
done
|
||||
# 只提醒型而且到期的那幾筆。指令型不進佇列:它們由執行那一支真的跑掉了,人不必接手。
|
||||
# 已經以逾期身分列過的那幾筆不再列第二次:同一筆待辦在同一批提醒裡出現兩行,讀的人會
|
||||
# 當成兩件事,而且「逾期五天」比「排定點過了」講得更清楚——留強的那一行就好。
|
||||
#
|
||||
# 內建項與使用者交辦的分成兩種列,理由是它們該有的處置不一樣。
|
||||
# 使用者自己登錄的那一筆,人看到就做得了;內建項那幾筆等的是接線不是人——動作是
|
||||
# 「只提醒」的內建項,到現在還沒有任何執行入口,所以每一輪都到期、每一輪都一樣。
|
||||
# 實測踩到:這台機器八筆全是那一種,於是每一個工作階段開頭固定吐八行一模一樣的東西。
|
||||
# 那不是提醒,是噪音;而讀的那一端只印不判,分不出兩者,所以在這裡就把種類標好。
|
||||
if [ -n "$DUE_ROWS" ] && [ -f "$DUE_ROWS" ]; then
|
||||
awk -F'\t' -v idf="$_ovids" '
|
||||
BEGIN { while ((getline _l < idf) > 0) seen[_l] = 1 }
|
||||
awk -F'\t' -v idf="$_ovids" -v sidf="$_specids" '
|
||||
BEGIN {
|
||||
while ((getline _l < idf) > 0) seen[_l] = 1
|
||||
while ((getline _s < sidf) > 0) spec[_s] = 1
|
||||
}
|
||||
NF >= 12 && $1 != "" && $2 == "due" && $5 == "remind" && !($1 in seen) {
|
||||
printf "remind\t%s\t%s\t%s\n", $1, ($10 == "" ? "-" : $10), ($11 == "" ? "-" : $11)
|
||||
printf "%s\t%s\t%s\t%s\n", ($1 in spec ? "builtin" : "remind"), \
|
||||
$1, ($10 == "" ? "-" : $10), ($11 == "" ? "-" : $11)
|
||||
}' "$DUE_ROWS" 2>/dev/null
|
||||
fi
|
||||
} >"$_rt" 2>/dev/null || { add_warn '提醒佇列寫不出來'; rm -f "$_rt"; return 0; }
|
||||
if mv "$_rt" "$REMINDERS_FILE" 2>/dev/null; then
|
||||
# 兩個數字分開算:逐筆點名的那幾筆,與只算一個總數的內建項。
|
||||
REMINDERS=$(awk -F'\t' '$1 == "remind" || $1 == "overdue" { n++ } END { print n + 0 }' "$REMINDERS_FILE")
|
||||
REMINDERS_BUILTIN=$(awk -F'\t' '$1 == "builtin" { n++ } END { print n + 0 }' "$REMINDERS_FILE")
|
||||
else
|
||||
add_warn '提醒佇列換不上去'
|
||||
rm -f "$_rt"
|
||||
@@ -1260,6 +1286,7 @@ case "$CMD" in
|
||||
printf 'tasks_due=%s\n' "$DUE_TASKS"
|
||||
printf 'tasks_overdue=%s\n' "${DUE_OVERDUE:--}"
|
||||
printf 'reminders=%s\n' "$REMINDERS"
|
||||
printf 'reminders_builtin=%s\n' "$REMINDERS_BUILTIN"
|
||||
printf 'reminders_file=%s\n' "$REMINDERS_FILE"
|
||||
printf 'events_new=%s\n' "$DUE_EVENTS"
|
||||
printf 'due_status=%s\n' "$DUE_STATUS"
|
||||
|
||||
Reference in New Issue
Block a user