fix(assistant): 讓執行路徑走錯與警示原因都看得見
兩支腳本開跑就檢查自己的執行路徑,監控頁的摘要表與最新一輪那一塊補上 「警示來源」。 兩件都是實測之後補的。用全新的 CLI 行程跑,代理人會把工具路徑解回外掛 快取那一份,不是指定的工作樹那一份。原本的對策只在技能說明書裡寫明禁 止,那是文件約束,擋不住真的走錯的那一輪。權限閘門只放行 current 那一 組確切路徑,走錯就被靜靜擋掉,那一輪不寫心跳,外面只看得到心跳過期。 另一頭,沙箱跑出來的摘要列是「警示、四項全過、待人處理 0」,讀的人看 不出警示哪來。查過不是缺陷:四項來源都讀得到,是讀到的內容有警示。摘 要表的用途本來就是一眼看出從哪一輪開始壞,少了原因那一欄就做不到。 巡檢與排程兩支腳本開跑時先比對自己是不是從 current 底下被叫起來的,不 是就往 stderr 印一行警告,點名實際路徑、應該用的路徑與理由。刻意只警告 不中止:從工作樹直接跑腳本是開發時的正當用法,中止會把那條路擋掉,真 正的失敗本來就發生在權限閘門那裡。摘要表從四欄加到五欄,最新一輪那一 塊也補一列,值取每一處設警示時收下來的短理由,多個用頓號串,沒有就寫 「無」。腳本裡每一處把判定改成警示的地方,一律改走同一支函式順手收下 理由,collect 的輸出多印一行 warn_sources。技能主文、行為清單與監控頁 範本跟著寫明這兩件事。 功能範圍是助理的一輪巡檢與系統排程安裝。
This commit is contained in:
+45
-13
@@ -87,6 +87,8 @@
|
||||
# item= 一項一行,欄位 status(ok、empty、fail)、rc、note
|
||||
# verdict= 正常、警示、異常
|
||||
# failed_sources= 讀不到的來源路徑,以「、」分隔;全部讀得到就是「無」
|
||||
# warn_sources= 本輪的警示來源,以「、」分隔;沒有警示就是「無」。四項全過卻判成警示
|
||||
# 時,原因只寫在這裡
|
||||
# tasks_total= tasks_failing= 待辦簿筆數與連續失敗筆數,只供目錄頁那一列用
|
||||
# pending= 本輪待人處理的筆數
|
||||
# latest_file= 「最新一輪」那一塊,整塊換掉舊頁同名那一塊
|
||||
@@ -120,10 +122,34 @@ ROUND=''
|
||||
DRYRUN=0
|
||||
LOCK_BROKEN=0
|
||||
FAILED_SOURCES=''
|
||||
WARN_SOURCES=''
|
||||
OK_COUNT=0
|
||||
FAIL_COUNT=0
|
||||
WARN=0
|
||||
|
||||
# 這支腳本是不是從 $JSC_HOME/current 那一組路徑被叫起來的。不是就大聲警告,但照跑。
|
||||
# 只警告、不中止是刻意的取捨:從工作樹直接跑腳本是開發時的正當用法,中止會把那條路擋掉;
|
||||
# 真正的失敗會發生在權限閘門那裡——閘門只放行 current 那一組確切路徑,用別的路徑那一輪會
|
||||
# 被靜靜擋掉、失敗,而且不會寫心跳,外面只看得到心跳過期。這裡先把話講在前面。
|
||||
warn_if_not_current() {
|
||||
_self="$SCRIPT_DIR/$(basename -- "$0")"
|
||||
_want="$CURRENT/jsc-assist/tools/$(basename -- "$0")"
|
||||
case "$SCRIPT_DIR/" in
|
||||
"$CURRENT"/*) return 0 ;;
|
||||
esac
|
||||
printf '[jsc][助理巡檢][WARN]:這支腳本是從 %s 跑起來的,不是 %s。權限閘門只放行 current 那一組確切路徑:排程那一輪用別的路徑會被靜靜擋掉,那一輪失敗、不寫心跳,外面只看得到心跳過期。開發時這樣跑沒關係,無人值守那一輪一律走 current。\n' \
|
||||
"$_self" "$_want" >&2
|
||||
return 0
|
||||
}
|
||||
warn_if_not_current
|
||||
|
||||
# 記一個警示來源。每一處把 WARN 設成 1 的地方都經過這裡,摘要表那一欄才看得出警示哪來——
|
||||
# 四項全過卻判成警示,光看成敗欄是查不出原因的。
|
||||
add_warn() { # $1=一句話講完的理由
|
||||
WARN=1
|
||||
if [ -z "$WARN_SOURCES" ]; then WARN_SOURCES="$1"; else WARN_SOURCES="$WARN_SOURCES、$1"; fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat >&2 <<'EOF'
|
||||
usage: patrol.sh collect [--out 目錄] [--trigger 排程|事件|手動]
|
||||
@@ -224,7 +250,7 @@ lock_acquire() {
|
||||
printf 'round=%s\npid=%s\nstarted=%s\n' "$ROUND" "$$" "$(date +%s)" >"$LOCK/info" 2>/dev/null \
|
||||
|| die 5 "鎖搶回來了,卻寫不進 $LOCK/info。"
|
||||
LOCK_BROKEN=1
|
||||
WARN=1
|
||||
add_warn '上一輪逾時被接手'
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -361,7 +387,7 @@ d04() {
|
||||
[ "$_rows" -eq 0 ] && printf '| (無 domain) | - | - | 這台機器一個 jsc plugin 都沒查到 |\n' >>"$RD/d04.md"
|
||||
printf '\n判定欄照 `version-guard.sh report` 第四欄原字抄。抄到「查詢失敗」就寫「查詢失敗」,不改寫成「相符」或「最新」,也不自己補查遠端版本——查不到是沒有證據,不是版本沒問題。\n\n' >>"$RD/d04.md"
|
||||
if [ "$_unver" -gt 0 ]; then
|
||||
WARN=1
|
||||
add_warn '版本查詢失敗'
|
||||
printf '**本輪有 %s 列查不到遠端版本。** 同一支腳本在擋人那條路徑查得到遠端版本,report 這條查不到,這是既有缺陷,不是這台機器的網路問題。\n\n' "$_unver" >>"$RD/d04.md"
|
||||
add_pending 'version-guard.sh report 查不到遠端版本,版本落差本輪無證據' '版本落差與重啟閘門' '/jsc-cli:doctor'
|
||||
fi
|
||||
@@ -396,7 +422,7 @@ d04() {
|
||||
if [ "$_up" -eq 0 ]; then
|
||||
printf '| (無) | 未升起 | - |\n' >>"$RD/d04.md"
|
||||
else
|
||||
WARN=1
|
||||
add_warn '重啟閘門未清'
|
||||
fi
|
||||
fi
|
||||
else
|
||||
@@ -517,10 +543,10 @@ d09() {
|
||||
HEARTBEAT_TTL="$_ttl"
|
||||
case "$_st" in
|
||||
fresh) HEARTBEAT_STATE='新鮮' ;;
|
||||
stale) HEARTBEAT_STATE='過期'; WARN=1 ;;
|
||||
invalid) HEARTBEAT_STATE='心跳檔損壞'; WARN=1 ;;
|
||||
absent) HEARTBEAT_STATE='不存在'; WARN=1 ;;
|
||||
*) HEARTBEAT_STATE="判不出(state=${_st:-空值})"; WARN=1 ;;
|
||||
stale) HEARTBEAT_STATE='過期'; add_warn '心跳過期' ;;
|
||||
invalid) HEARTBEAT_STATE='心跳檔損壞'; add_warn '心跳檔損壞' ;;
|
||||
absent) HEARTBEAT_STATE='不存在'; add_warn '心跳不存在' ;;
|
||||
*) HEARTBEAT_STATE="判不出(state=${_st:-空值})"; add_warn '心跳判不出' ;;
|
||||
esac
|
||||
{
|
||||
printf '| 項目 | 內容 |\n'
|
||||
@@ -593,6 +619,9 @@ compose() {
|
||||
printf '| 本輪判定 | %s |\n' "$VERDICT"
|
||||
printf '| 本輪項目 | 四項:D-01 使用統計、D-04 版本與重啟閘門、D-07 階段鎖與工作包鎖、D-09 心跳自述。成功 %s 項、失敗 %s 項 |\n' "$OK_COUNT" "$FAIL_COUNT"
|
||||
printf '| 讀不到的來源 | %s |\n' "$(cell "${FAILED_SOURCES:-無}")"
|
||||
# 警示來源緊接在讀不到的來源後面:兩列語意相近,而且四項讀取全部成功、判定卻是警示
|
||||
# 時,這一塊裡只有這一列講得出原因,跟摘要表那一欄是同一個理由。
|
||||
printf '| 警示來源 | %s |\n' "$(cell "${WARN_SOURCES:-無}")"
|
||||
if [ "$LOCK_BROKEN" -eq 1 ]; then
|
||||
printf '| 鎖 | 上一輪的鎖逾時,本輪搶回來了。上一輪沒跑完,那一輪不會寫心跳 |\n'
|
||||
fi
|
||||
@@ -613,17 +642,19 @@ compose() {
|
||||
if [ -s "$RD/pend.md" ]; then cat "$RD/pend.md"; else printf '| (無) | - | - |\n'; fi
|
||||
} >"$RD/latest.md"
|
||||
|
||||
# 摘要表的那一列。欄位刻意只有四個:時間、判定、四項成敗、待人處理筆數——一列要能一眼
|
||||
# 看完,才看得出是從哪一輪開始壞的。
|
||||
printf '| %s | %s | %s/%s | %s |\n' \
|
||||
"$AT" "$VERDICT" "$OK_COUNT" "$ITEM_TOTAL" "$PEND_COUNT" >"$RD/summary-row.md"
|
||||
# 摘要表的那一列。欄位刻意只有五個,一列要能一眼看完,才看得出是從哪一輪開始壞的。
|
||||
# 「警示來源」那一欄不能省:四項讀取全部成功、但讀到的內容有警示時,判定是警示而成敗欄
|
||||
# 是 4/4,沒有這一欄的話,看的人不知道警示哪來。
|
||||
printf '| %s | %s | %s/%s | %s | %s |\n' \
|
||||
"$AT" "$VERDICT" "$OK_COUNT" "$ITEM_TOTAL" "$PEND_COUNT" \
|
||||
"$(cell "${WARN_SOURCES:-無}")" >"$RD/summary-row.md"
|
||||
|
||||
# 摘要那一塊:標題、表頭,加上本輪這一列。呼叫端把舊頁的資料列接在這一列下面,截到 24 列。
|
||||
{
|
||||
printf '## 近 24 輪摘要\n\n'
|
||||
printf '一輪一列,最新的在最上面,超過 24 列就丟掉最舊的那一列。\n\n'
|
||||
printf '| 巡檢時間 | 本輪判定 | 四項成敗 | 待人處理 |\n'
|
||||
printf '| --- | --- | --- | ---: |\n'
|
||||
printf '| 巡檢時間 | 本輪判定 | 四項成敗 | 待人處理 | 警示來源 |\n'
|
||||
printf '| --- | --- | --- | ---: | --- |\n'
|
||||
cat "$RD/summary-row.md"
|
||||
} >"$RD/summary.md"
|
||||
|
||||
@@ -733,6 +764,7 @@ case "$CMD" in
|
||||
printf 'item=D-09 status=%s rc=%s note=%s\n' "$D09_STATUS" "$D09_RC" "$D09_NOTE"
|
||||
printf 'verdict=%s\n' "$VERDICT"
|
||||
printf 'failed_sources=%s\n' "${FAILED_SOURCES:-無}"
|
||||
printf 'warn_sources=%s\n' "${WARN_SOURCES:-無}"
|
||||
printf 'tasks_total=%s\n' "$TASKS_TOTAL"
|
||||
printf 'tasks_failing=%s\n' "$TASKS_FAILING"
|
||||
printf 'pending=%s\n' "$PEND_COUNT"
|
||||
|
||||
@@ -123,6 +123,22 @@ PERIOD=''
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" 2>/dev/null && pwd)
|
||||
SCRIPT_DIR="${SCRIPT_DIR:-.}"
|
||||
|
||||
# 這支腳本是不是從 $JSC_HOME/current 那一組路徑被叫起來的。不是就大聲警告,但照跑。
|
||||
# 只警告、不中止是刻意的取捨:從工作樹直接跑腳本是開發時的正當用法,中止會把那條路擋掉;
|
||||
# 真正的失敗會發生在權限閘門那裡——閘門只放行 current 那一組確切路徑,用別的路徑那一輪會
|
||||
# 被靜靜擋掉、失敗,而且不會寫心跳,外面只看得到心跳過期。這裡先把話講在前面。
|
||||
warn_if_not_current() {
|
||||
_self="$SCRIPT_DIR/$(basename -- "$0")"
|
||||
_want="$CURRENT/jsc-assist/tools/$(basename -- "$0")"
|
||||
case "$SCRIPT_DIR/" in
|
||||
"$CURRENT"/*) return 0 ;;
|
||||
esac
|
||||
printf '[jsc][助理排程][WARN]:這支腳本是從 %s 跑起來的,不是 %s。權限閘門只放行 current 那一組確切路徑:排程那一輪用別的路徑會被靜靜擋掉,那一輪失敗、不寫心跳,外面只看得到心跳過期。開發時這樣跑沒關係,無人值守那一輪一律走 current。\n' \
|
||||
"$_self" "$_want" >&2
|
||||
return 0
|
||||
}
|
||||
warn_if_not_current
|
||||
|
||||
usage() {
|
||||
cat >&2 <<'EOF'
|
||||
usage: schedule.sh install [patrol|all] [--dry-run] [--cli 代號] [--patrol-cmd 指令] [--period 分鐘]
|
||||
|
||||
Reference in New Issue
Block a user