補上 stat -f 診斷的最後一層:連離開碼都不可靠(inkstone/ISEP#90 ④)
總管自己驗這一格量到 exit=0,我量到 exit=1。**兩個都是真的**,
而分歧本身就是最後一塊拼圖:
**GNU 的 `-f` 是 `--file-system`,布林旗標、不接格式字串**
⇒ `%m` 不是格式,它被當成**另一個檔名運算元**
⇒ 離開碼取決於「cwd 裡有沒有一個叫 `%m` 的檔」:
A. 沒有(一般情況) → exit 1 ⇒ `||` 會跑 ⇒ 正確的秒數接在垃圾後面
B. 剛好有 → exit 0 ⇒ `||` 不會跑 ⇒ 整包連一個數字都沒有
兩種情況閘的結果一樣:MT 都不是純數字、戳記都作廢。(實測 GNU coreutils 9.4,兩種都重現過)
🔴 教訓比原本寫的更尖銳:舊寫法的 `||` fallback 救不了,
**不是因為它沒跑,而是因為「跑不跑」根本不由這支腳本決定**——
它由「cwd 裡有沒有某個檔名」決定。
一個行為取決於 cwd 有沒有某個檔的判斷式,不管跑不跑都是壞的。
⇒ 所以修法不能只是「把順序反過來」,**每一步都要驗它是不是純數字**
(lib/mtime.sh 本來就是這樣寫的,現在把理由寫進去了)。
gate-ok 測試補第 ⑰ 條守這一層:cwd 裡有一個叫 `%m` 的檔時,file_mtime 仍要回純數字。
16 → 17 條,TESTING.md 的 A16 一併更新。
This commit is contained in:
+7
-3
@@ -131,11 +131,11 @@ bash hooks/tests/prod-write-guard.test.sh hooks/prod-write-guard.sh
|
|||||||
- 「卡點二」2 條任一紅 ⇒ 「談論它」又被當成「執行它」(同款第八次),
|
- 「卡點二」2 條任一紅 ⇒ 「談論它」又被當成「執行它」(同款第八次),
|
||||||
或是剝了內文之後連真的部署都放行了
|
或是剝了內文之後連真的部署都放行了
|
||||||
|
|
||||||
### A16 — 「總管可以放行」那道門真的打得開:16 條
|
### A16 — 「總管可以放行」那道門真的打得開:17 條
|
||||||
```
|
```
|
||||||
bash hooks/tests/gate-ok.test.sh
|
bash hooks/tests/gate-ok.test.sh
|
||||||
```
|
```
|
||||||
**該看到**:`通過 16 條,失敗 0 條`。
|
**該看到**:`通過 17 條,失敗 0 條`。
|
||||||
|
|
||||||
**它在守什麼**(inkstone/ISEP#90 ④,2026-08-28 實查):三支閘
|
**它在守什麼**(inkstone/ISEP#90 ④,2026-08-28 實查):三支閘
|
||||||
(`prod-write-guard`/`main-and-prod-push-guard`/`stage-before-prod-guard`)
|
(`prod-write-guard`/`main-and-prod-push-guard`/`stage-before-prod-guard`)
|
||||||
@@ -151,6 +151,10 @@ bash hooks/tests/gate-ok.test.sh
|
|||||||
08-11、08-12 兩次真的被穿透之後才補上的,不准為了「好放行」而鬆掉
|
08-11、08-12 兩次真的被穿透之後才補上的,不准為了「好放行」而鬆掉
|
||||||
- ⑫ 紅 ⇒ `gate-ok` 在解不出 repo 時留下了一枚註定打不開的空戳記,
|
- ⑫ 紅 ⇒ `gate-ok` 在解不出 repo 時留下了一枚註定打不開的空戳記,
|
||||||
那會讓人以為門開了(而空戳記本身就是 08-12 那把萬用鑰匙的形狀)
|
那會讓人以為門開了(而空戳記本身就是 08-12 那把萬用鑰匙的形狀)
|
||||||
|
- ⑰ 紅 ⇒ 判準又變回「行為取決於 cwd 裡有沒有一個叫 `%m` 的檔」。
|
||||||
|
這條是這個 bug 的最後一層:**GNU 的 `-f` 是布林旗標,`%m` 被當成另一個檔名運算元**
|
||||||
|
⇒ 有那個檔就 `exit 0`、`||` 連跑都不跑。所以修法不能只是「把順序反過來」,
|
||||||
|
**每一步都要驗它是不是純數字**
|
||||||
|
|
||||||
⚠️ 這支會真的寫 `/tmp` 的戳記檔(那是閘寫死的路徑)。**不要在「已經蓋好戳記正要推東西」
|
⚠️ 這支會真的寫 `/tmp` 的戳記檔(那是閘寫死的路徑)。**不要在「已經蓋好戳記正要推東西」
|
||||||
的當下跑它**——它會把那枚戳記洗掉。
|
的當下跑它**——它會把那枚戳記洗掉。
|
||||||
@@ -389,7 +393,7 @@ B2(信標那行)/B3(setup 輸出)/B4(閘的訊息)三個畫面
|
|||||||
| **A10 人閘警察準度** | 總管 | ✅ 9/9,連跑三次(2026-08-26),A 群誤攔 0 |
|
| **A10 人閘警察準度** | 總管 | ✅ 9/9,連跑三次(2026-08-26),A 群誤攔 0 |
|
||||||
| **A11 派工單只剩票號** | 總管 | ✅ 19/19(2026-08-27) |
|
| **A11 派工單只剩票號** | 總管 | ✅ 19/19(2026-08-27) |
|
||||||
| **A12 留言身份欄(兩道門)** | 總管 | ✅ 11/11(2026-08-27) |
|
| **A12 留言身份欄(兩道門)** | 總管 | ✅ 11/11(2026-08-27) |
|
||||||
| **A16 放行的門真的打得開** | 總管 | ✅ 16/16(2026-08-28,inkstone/ISEP#90) |
|
| **A16 放行的門真的打得開** | 總管 | ✅ 17/17(2026-08-28,inkstone/ISEP#90) |
|
||||||
| **A17 未推警察不誤攔雲端分支** | 總管 | ✅ 10/10(2026-08-28,inkstone/ISEP#90) |
|
| **A17 未推警察不誤攔雲端分支** | 總管 | ✅ 10/10(2026-08-28,inkstone/ISEP#90) |
|
||||||
| **A18 信標會報雲端接線缺陷** | 總管 | ✅ 14/14(2026-08-28,inkstone/ISEP#90) |
|
| **A18 信標會報雲端接線缺陷** | 總管 | ✅ 14/14(2026-08-28,inkstone/ISEP#90) |
|
||||||
| A7 plugin 裝得起來 | 總管 | ✅ |
|
| A7 plugin 裝得起來 | 總管 | ✅ |
|
||||||
|
|||||||
@@ -102,6 +102,53 @@ stat: cannot read file system information for '%m': No such file or directory
|
|||||||
⇒ `case "$NOW$MT" in *[!0-9]*) return 1` 必然命中
|
⇒ `case "$NOW$MT" in *[!0-9]*) return 1` 必然命中
|
||||||
⇒ **在 Linux(=每一個雲端 session)上,那三支閘的戳記永遠不會被接受。**
|
⇒ **在 Linux(=每一個雲端 session)上,那三支閘的戳記永遠不會被接受。**
|
||||||
|
|
||||||
|
### 再往下一層:`-f` 根本不吃格式參數,所以連離開碼都不可靠
|
||||||
|
|
||||||
|
總管 2026-08-28 自己驗這一格時量到 `exit=0`,而我量到 `exit=1`。
|
||||||
|
**兩個都是真的**,而分歧本身就是這個 bug 最後一塊拼圖:
|
||||||
|
|
||||||
|
**GNU 的 `-f` 是 `--file-system`,它是布林旗標、不接格式字串**
|
||||||
|
⇒ `%m` 不是格式,它被當成**另一個檔名運算元** ⇒ 離開碼取決於
|
||||||
|
「當前目錄裡有沒有一個叫 `%m` 的檔」:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cd /tmp/statprobe && touch .mt
|
||||||
|
|
||||||
|
# A. 沒有名為 %m 的檔(一般情況)
|
||||||
|
$ stat -f %m .mt ; echo "exit=$?"
|
||||||
|
stat: cannot read file system information for '%m': No such file or directory
|
||||||
|
File: ".mt" … ← 檔案系統資訊照樣印到 stdout
|
||||||
|
exit=1 ← `||` **會**跑 ⇒ 正確的秒數接在那堆垃圾後面
|
||||||
|
|
||||||
|
# B. 剛好有一個叫 %m 的檔
|
||||||
|
$ touch '%m' && stat -f %m .mt ; echo "exit=$?"
|
||||||
|
exit=0 ← `||` **不會**跑 ⇒ 整包連一個數字都沒有
|
||||||
|
```
|
||||||
|
|
||||||
|
(實測環境:`stat (GNU coreutils) 9.4`)
|
||||||
|
|
||||||
|
**兩種情況下閘的結果一模一樣**——`MT` 都不是純數字,
|
||||||
|
`case "$NOW$MT" in *[!0-9]*) return 1` 都必然命中,戳記都作廢:
|
||||||
|
|
||||||
|
```
|
||||||
|
情況 A:非數字 ⇒ return 1 ⇒ 戳記作廢
|
||||||
|
情況 B:非數字 ⇒ return 1 ⇒ 戳記作廢
|
||||||
|
```
|
||||||
|
|
||||||
|
🔴 **這一層才是真正該記住的教訓**:舊寫法的 `||` fallback 之所以救不了,
|
||||||
|
**不是因為它沒跑,而是因為「跑不跑」根本不由這支腳本決定**
|
||||||
|
——它由「當前目錄裡有沒有一個叫 `%m` 的檔」決定。
|
||||||
|
一個**行為取決於 cwd 裡有沒有某個檔名**的判斷式,不管跑不跑都是壞的。
|
||||||
|
|
||||||
|
⇒ 所以 `lib/mtime.sh` 的修法不是「把順序反過來」而已,是
|
||||||
|
**每一步都驗它是不是純數字**:這個 bug 的成因正是「命令失敗了卻還是印了東西」,
|
||||||
|
**只看離開碼會再被騙一次**。
|
||||||
|
|
||||||
|
📌 這一格的實害(總管 2026-08-28 原話):「我今天為了發一則通知,
|
||||||
|
用了兩種方式蓋 `prod-write-ok` 都無效,一度以為是權限問題。」
|
||||||
|
⇒ **閘不會告訴你門是壞的**,所以人會往錯的方向查(權限、classifier、設定),
|
||||||
|
而根因在閘自己身上。
|
||||||
|
|
||||||
🔴 **後果**:那三支閘在雲端**等於純擋**。總管照著閘自己印的指示做,
|
🔴 **後果**:那三支閘在雲端**等於純擋**。總管照著閘自己印的指示做,
|
||||||
做幾次都打不開,**而閘不會告訴他門是壞的**。
|
做幾次都打不開,**而閘不會告訴他門是壞的**。
|
||||||
|
|
||||||
|
|||||||
+17
-1
@@ -29,7 +29,23 @@
|
|||||||
# 總管照著閘自己印的指示做,做幾次都打不開,而閘不會告訴他門是壞的。
|
# 總管照著閘自己印的指示做,做幾次都打不開,而閘不會告訴他門是壞的。
|
||||||
# inkstone/InkStoneCo#99 記的「連續四次蓋不出戳記」就是這個形狀。
|
# inkstone/InkStoneCo#99 記的「連續四次蓋不出戳記」就是這個形狀。
|
||||||
#
|
#
|
||||||
# 🔴 順序反過來就好,但不能只靠順序:改成先 `-c %Y`(GNU)再 `-f %m`(BSD),
|
# ── 再往下一層:`-f` 根本不吃格式參數,所以連離開碼都不可靠 ────────────
|
||||||
|
#
|
||||||
|
# 2026-08-28 兩個人量這一格,一個量到 `exit=0`、一個量到 `exit=1`。**兩個都是真的**,
|
||||||
|
# 而分歧本身就是最後一塊拼圖:**GNU 的 `-f` 是 `--file-system`,布林旗標、不接格式字串**
|
||||||
|
# ⇒ `%m` 被當成**另一個檔名運算元** ⇒ 離開碼取決於「cwd 裡有沒有一個叫 `%m` 的檔」:
|
||||||
|
#
|
||||||
|
# A. 沒有(一般情況) → exit 1 ⇒ `||` **會**跑 ⇒ 正確的秒數接在垃圾後面
|
||||||
|
# B. 剛好有 → exit 0 ⇒ `||` **不會**跑 ⇒ 整包連一個數字都沒有
|
||||||
|
#
|
||||||
|
# 兩種情況下閘的結果一樣:`MT` 都不是純數字,戳記都作廢。(實測 GNU coreutils 9.4)
|
||||||
|
#
|
||||||
|
# 🔴 **這才是該記住的教訓**:舊寫法的 `||` fallback 救不了,
|
||||||
|
# **不是因為它沒跑,而是因為「跑不跑」根本不由這支腳本決定**
|
||||||
|
# ——它由「cwd 裡有沒有某個檔名」決定。
|
||||||
|
# 一個**行為取決於 cwd 裡有沒有某個檔**的判斷式,不管跑不跑都是壞的。
|
||||||
|
#
|
||||||
|
# 🔴 所以修法不是「把順序反過來」而已:改成先 `-c %Y`(GNU)再 `-f %m`(BSD),
|
||||||
# 而且**每一步都驗它是不是純數字**——因為這個 bug 的成因正是
|
# 而且**每一步都驗它是不是純數字**——因為這個 bug 的成因正是
|
||||||
# 「命令失敗了卻還是印了東西出來」,只看離開碼會再被騙一次。
|
# 「命令失敗了卻還是印了東西出來」,只看離開碼會再被騙一次。
|
||||||
file_mtime() {
|
file_mtime() {
|
||||||
|
|||||||
@@ -76,6 +76,12 @@ M=$(file_mtime "$TMP/probe")
|
|||||||
case "$M" in ''|*[!0-9]*) R=bad ;; *) R=ok ;; esac
|
case "$M" in ''|*[!0-9]*) R=bad ;; *) R=ok ;; esac
|
||||||
ok "⑮ file_mtime 回純數字(舊寫法在 Linux 上會回一整段文字)" "$R" ok
|
ok "⑮ file_mtime 回純數字(舊寫法在 Linux 上會回一整段文字)" "$R" ok
|
||||||
ok "⑯ 檔案不存在 → 回 0,不是空字串" "$(file_mtime "$TMP/nope")" 0
|
ok "⑯ 檔案不存在 → 回 0,不是空字串" "$(file_mtime "$TMP/nope")" 0
|
||||||
|
# 🔴 ⑰ 守的是這個 bug 的最後一層:舊寫法的行為**取決於 cwd 裡有沒有一個叫 `%m` 的檔**
|
||||||
|
# (GNU 的 -f 是布林旗標,`%m` 被當成另一個檔名運算元)。有 ⇒ exit 0 ⇒ `||` 連跑都不跑。
|
||||||
|
# 一個行為取決於 cwd 有沒有某個檔的判斷式,不管跑不跑都是壞的。
|
||||||
|
M2=$( cd "$TMP" && touch '%m' && file_mtime "$TMP/probe" )
|
||||||
|
case "$M2" in ''|*[!0-9]*) R2=bad ;; *) R2=ok ;; esac
|
||||||
|
ok "⑰ cwd 裡有一個叫 %m 的檔 → 仍要回純數字" "$R2" ok
|
||||||
|
|
||||||
echo
|
echo
|
||||||
printf '通過 %s 條,失敗 %s 條\n' "$PASS" "$FAIL"
|
printf '通過 %s 條,失敗 %s 條\n' "$PASS" "$FAIL"
|
||||||
|
|||||||
Reference in New Issue
Block a user