From 696cd61b4bb4bf191d1464bff068f297aa148b49 Mon Sep 17 00:00:00 2001 From: thepagent Date: Wed, 18 Mar 2026 11:26:26 +0000 Subject: [PATCH 1/5] docs: add doc-freshness-sla policy (#346) --- docs/doc-freshness-sla.md | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 docs/doc-freshness-sla.md diff --git a/docs/doc-freshness-sla.md b/docs/doc-freshness-sla.md new file mode 100644 index 0000000..876aaea --- /dev/null +++ b/docs/doc-freshness-sla.md @@ -0,0 +1,60 @@ +# 文件鮮度保證機制(Doc Freshness SLA) + +## 背景 + +claw-info 中的文件(`docs/`、`usecases/`)具有時效性。例如某功能在 v3.11 新增,可能在 v4.x 已被修改或移除。若文件長期無人維護,agent 讀取後可能產生錯誤行為。 + +## Frontmatter 標準欄位 + +每份文件須加入以下欄位: + +```yaml +--- +last_validated: YYYY-MM-DD +validated_by: +freshness: ok # ok | stale | unreviewed +--- +``` + +## Review 週期(依文件類型分級) + +| 路徑 | 週期 | +|------|------| +| `usecases/` | 2 週 | +| `docs/` | 4 週 | +| 架構圖、穩定參考文件 | 8 週 | + +## 自動化流程 + +GitHub Actions cron job 每週執行: + +1. 掃描所有文件的 `last_validated` +2. 超過週期未更新者,自動開 issue assign 原作者 +3. Issue 標題格式:`[Doc Review] docs/xxx.md 需要驗證` + +原作者收到 issue 後須: + +1. 對照 source code 確認內容仍正確 +2. 更新 `last_validated` 與 `validated_by` +3. 若有過時內容,一併修正並送 PR + +## 不回應的後果 + +- 超過 deadline(+7 天)未處理:文件標記為 `freshness: stale` +- Agent 讀取 stale 文件時,自動附加警告:`⚠️ 此文件已超過 review 週期,內容可能過時` +- 其他 agent 或貢獻者可接手更新 +- 長期不回應的原作者,可能從信任名單中移除 + +## Agent 驗證流程 + +Agent 執行 review 時: + +1. 讀取文件內容 +2. 用 `gh search code` 查對應 source code +3. 比對是否有 breaking change 或 API 變更 +4. 若有差異,自動送 PR 修正 +5. 更新 frontmatter `last_validated` + +## 相關 Issue + +- [#346 提案:文件鮮度保證機制](https://github.com/thepagent/claw-info/issues/346) From 0c118ddc17844a98a3a9578527af60c134b734b4 Mon Sep 17 00:00:00 2001 From: thepagent Date: Wed, 18 Mar 2026 11:31:00 +0000 Subject: [PATCH 2/5] docs: add GHA workflow design for doc freshness automation --- docs/doc-freshness-sla.md | 63 +++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/docs/doc-freshness-sla.md b/docs/doc-freshness-sla.md index 876aaea..d802ad7 100644 --- a/docs/doc-freshness-sla.md +++ b/docs/doc-freshness-sla.md @@ -24,13 +24,66 @@ freshness: ok # ok | stale | unreviewed | `docs/` | 4 週 | | 架構圖、穩定參考文件 | 8 週 | -## 自動化流程 +## 自動化流程(GHA) -GitHub Actions cron job 每週執行: +### Workflow 設計 -1. 掃描所有文件的 `last_validated` -2. 超過週期未更新者,自動開 issue assign 原作者 -3. Issue 標題格式:`[Doc Review] docs/xxx.md 需要驗證` +```yaml +# .github/workflows/doc-freshness-check.yml +name: Doc Freshness Check +on: + schedule: + - cron: '0 2 * * 1' # 每週一 UTC 02:00 + workflow_dispatch: + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check stale docs and open issues + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: python3 .github/scripts/check_freshness.py +``` + +### 核心腳本邏輯(`.github/scripts/check_freshness.py`) + +```python +# 週期設定(天) +THRESHOLDS = { + "usecases/": 14, + "docs/": 28, +} +DEFAULT_THRESHOLD = 56 + +# 流程: +# 1. 掃描所有 .md,解析 frontmatter 取得 last_validated / validated_by +# 2. 計算距今天數,超過 threshold 者列為 stale +# 3. 檢查是否已有同名 open issue(避免重複開) +# 4. 若無,用 gh issue create assign validated_by +# 5. 若超過 threshold + 7 天仍 open,更新文件 freshness: stale +``` + +### Issue 格式 + +``` +標題:[Doc Review] docs/xxx.md 需要驗證 +Body: + - 文件路徑 + - 上次驗證:YYYY-MM-DD(N 天前) + - 請於 7 天內更新 last_validated 並送 PR +Assignee:validated_by 欄位的 GitHub username +Label:doc-review +``` + +### 防重複機制 + +開 issue 前先執行: +```bash +gh issue list --label doc-review --search "[Doc Review] docs/xxx.md" --state open +``` +若已有 open issue 則跳過。 原作者收到 issue 後須: From 1a95e8664988c49f6c0e0ce5d1c2e1fc4a20e683 Mon Sep 17 00:00:00 2001 From: thepagent Date: Wed, 18 Mar 2026 11:32:42 +0000 Subject: [PATCH 3/5] docs: replace python script with shell script for freshness check --- docs/doc-freshness-sla.md | 51 +++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/docs/doc-freshness-sla.md b/docs/doc-freshness-sla.md index d802ad7..8f7d89c 100644 --- a/docs/doc-freshness-sla.md +++ b/docs/doc-freshness-sla.md @@ -44,25 +44,46 @@ jobs: - name: Check stale docs and open issues env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: python3 .github/scripts/check_freshness.py + run: bash .github/scripts/check_freshness.sh ``` -### 核心腳本邏輯(`.github/scripts/check_freshness.py`) +### 核心腳本(`.github/scripts/check_freshness.sh`) -```python -# 週期設定(天) -THRESHOLDS = { - "usecases/": 14, - "docs/": 28, +```bash +#!/usr/bin/env bash +set -euo pipefail + +TODAY=$(date +%s) + +threshold_for() { + case "$1" in + usecases/*) echo 14 ;; + docs/*) echo 28 ;; + *) echo 56 ;; + esac } -DEFAULT_THRESHOLD = 56 - -# 流程: -# 1. 掃描所有 .md,解析 frontmatter 取得 last_validated / validated_by -# 2. 計算距今天數,超過 threshold 者列為 stale -# 3. 檢查是否已有同名 open issue(避免重複開) -# 4. 若無,用 gh issue create assign validated_by -# 5. 若超過 threshold + 7 天仍 open,更新文件 freshness: stale + +for f in $(find docs usecases -name "*.md"); do + last=$(grep '^last_validated:' "$f" | awk '{print $2}') + owner=$(grep '^validated_by:' "$f" | awk '{print $2}') + [ -z "$last" ] && continue + + age=$(( (TODAY - $(date -d "$last" +%s)) / 86400 )) + threshold=$(threshold_for "$f") + + if [ "$age" -gt "$threshold" ]; then + title="[Doc Review] $f 需要驗證" + # 防重複 + existing=$(gh issue list --label doc-review --search "$title" --state open --json number --jq length) + if [ "$existing" -eq 0 ]; then + gh issue create \ + --title "$title" \ + --body "上次驗證:$last(${age} 天前)。請於 7 天內更新 \`last_validated\` 並送 PR。" \ + --assignee "$owner" \ + --label doc-review + fi + fi +done ``` ### Issue 格式 From 76dfa2f32deaef2c50a5d9d955df3c7964c1d213 Mon Sep 17 00:00:00 2001 From: thepagent Date: Tue, 24 Mar 2026 03:13:10 +0000 Subject: [PATCH 4/5] docs: address reviewer feedback (cross-platform date, yq parsing, frontmatter template, degradation timeline) --- docs/doc-freshness-sla.md | 82 +++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/docs/doc-freshness-sla.md b/docs/doc-freshness-sla.md index 8f7d89c..d2b6cad 100644 --- a/docs/doc-freshness-sla.md +++ b/docs/doc-freshness-sla.md @@ -16,6 +16,35 @@ freshness: ok # ok | stale | unreviewed --- ``` +### 初始狀態 + +新文件合併時應預設 `freshness: ok`(剛撰寫即為剛驗證),而非 `unreviewed`。 + +### 最小範本 + +```yaml +--- +last_validated: 2026-03-24 +validated_by: thepagent +freshness: ok +--- +``` + +### 反例(錯誤寫法) + +```yaml +# ❌ 缺少欄位 +--- +title: My Doc +--- + +# ❌ 日期格式錯誤 +last_validated: 24/03/2026 + +# ❌ 新文件用 unreviewed +freshness: unreviewed +``` + ## Review 週期(依文件類型分級) | 路徑 | 週期 | @@ -44,9 +73,13 @@ jobs: - name: Check stale docs and open issues env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MAX_ISSUES: 50 + GRACE_DAYS: 7 run: bash .github/scripts/check_freshness.sh ``` +> 現行執行版見 [#349](https://github.com/thepagent/claw-info/pull/349)(MVP workflow,issue-based,不自動改檔)。 + ### 核心腳本(`.github/scripts/check_freshness.sh`) ```bash @@ -55,6 +88,15 @@ set -euo pipefail TODAY=$(date +%s) +# 跨平台 date 解析(GNU / macOS BSD) +to_epoch() { + if date -d "2000-01-01" +%s >/dev/null 2>&1; then + date -d "$1" +%s # GNU coreutils (Linux) + else + date -jf '%Y-%m-%d' "$1" +%s # BSD date (macOS) + fi +} + threshold_for() { case "$1" in usecases/*) echo 14 ;; @@ -63,17 +105,28 @@ threshold_for() { esac } -for f in $(find docs usecases -name "*.md"); do - last=$(grep '^last_validated:' "$f" | awk '{print $2}') - owner=$(grep '^validated_by:' "$f" | awk '{print $2}') +# 使用 yq 解析 frontmatter(需安裝 yq v4+) +# 若無 yq,fallback 至 awk +parse_field() { + local file="$1" field="$2" + if command -v yq >/dev/null 2>&1; then + yq e ".${field}" "$file" 2>/dev/null | grep -v '^null$' || true + else + awk -F': ' "/^${field}:/{print \$2; exit}" "$file" | tr -d '\r' + fi +} + +while IFS= read -r -d '' f; do + last=$(parse_field "$f" last_validated) + owner=$(parse_field "$f" validated_by) [ -z "$last" ] && continue - age=$(( (TODAY - $(date -d "$last" +%s)) / 86400 )) + last_epoch=$(to_epoch "$last") || continue + age=$(( (TODAY - last_epoch) / 86400 )) threshold=$(threshold_for "$f") if [ "$age" -gt "$threshold" ]; then title="[Doc Review] $f 需要驗證" - # 防重複 existing=$(gh issue list --label doc-review --search "$title" --state open --json number --jq length) if [ "$existing" -eq 0 ]; then gh issue create \ @@ -83,7 +136,7 @@ for f in $(find docs usecases -name "*.md"); do --label doc-review fi fi -done +done < <(find docs usecases -type f -name "*.md" -print0 2>/dev/null) ``` ### Issue 格式 @@ -98,26 +151,12 @@ Assignee:validated_by 欄位的 GitHub username Label:doc-review ``` -### 防重複機制 - -開 issue 前先執行: -```bash -gh issue list --label doc-review --search "[Doc Review] docs/xxx.md" --state open -``` -若已有 open issue 則跳過。 - -原作者收到 issue 後須: - -1. 對照 source code 確認內容仍正確 -2. 更新 `last_validated` 與 `validated_by` -3. 若有過時內容,一併修正並送 PR - ## 不回應的後果 - 超過 deadline(+7 天)未處理:文件標記為 `freshness: stale` - Agent 讀取 stale 文件時,自動附加警告:`⚠️ 此文件已超過 review 週期,內容可能過時` - 其他 agent 或貢獻者可接手更新 -- 長期不回應的原作者,可能從信任名單中移除 +- **連續 2 次 review cycle(約 30 天)未回應**:原作者從信任名單中移除,文件開放 `help-wanted` 認領 ## Agent 驗證流程 @@ -132,3 +171,4 @@ Agent 執行 review 時: ## 相關 Issue - [#346 提案:文件鮮度保證機制](https://github.com/thepagent/claw-info/issues/346) +- [#349 MVP workflow 實作](https://github.com/thepagent/claw-info/pull/349) From adf0c4da383ff5882c1ca49b6571203542b2b455 Mon Sep 17 00:00:00 2001 From: thepagent Date: Tue, 24 Mar 2026 03:15:03 +0000 Subject: [PATCH 5/5] docs: fix issue body checklist and mark stale-warning as future work --- docs/doc-freshness-sla.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/doc-freshness-sla.md b/docs/doc-freshness-sla.md index d2b6cad..566257f 100644 --- a/docs/doc-freshness-sla.md +++ b/docs/doc-freshness-sla.md @@ -106,13 +106,13 @@ threshold_for() { } # 使用 yq 解析 frontmatter(需安裝 yq v4+) -# 若無 yq,fallback 至 awk +# 若無 yq,fallback 至 awk(僅讀 --- 區塊內容,避免誤判正文) parse_field() { local file="$1" field="$2" if command -v yq >/dev/null 2>&1; then yq e ".${field}" "$file" 2>/dev/null | grep -v '^null$' || true else - awk -F': ' "/^${field}:/{print \$2; exit}" "$file" | tr -d '\r' + awk "/^---/{f=!f; next} f && /^${field}:/{print \$2; exit}" "$file" | tr -d '\r' fi } @@ -131,7 +131,14 @@ while IFS= read -r -d '' f; do if [ "$existing" -eq 0 ]; then gh issue create \ --title "$title" \ - --body "上次驗證:$last(${age} 天前)。請於 7 天內更新 \`last_validated\` 並送 PR。" \ + --body "上次驗證:$last(${age} 天前)。 + +請於 7 天內完成以下步驟並送 PR: +- [ ] 對照 source code 確認內容仍正確 +- [ ] 若有過時內容,一併修正 +- [ ] 更新 \`last_validated\` 為今日日期 +- [ ] 更新 \`freshness: ok\`(驗證完成後) +- [ ] 若 ownership 異動,更新 \`validated_by\`" \ --assignee "$owner" \ --label doc-review fi @@ -146,7 +153,7 @@ done < <(find docs usecases -type f -name "*.md" -print0 2>/dev/null) Body: - 文件路徑 - 上次驗證:YYYY-MM-DD(N 天前) - - 請於 7 天內更新 last_validated 並送 PR + - 驗證 checklist(確認內容、修正過時處、更新 last_validated + freshness) Assignee:validated_by 欄位的 GitHub username Label:doc-review ``` @@ -155,6 +162,7 @@ Label:doc-review - 超過 deadline(+7 天)未處理:文件標記為 `freshness: stale` - Agent 讀取 stale 文件時,自動附加警告:`⚠️ 此文件已超過 review 週期,內容可能過時` + > ⚠️ **Future work**:此警告機制尚未實作,待後續 PR 追蹤。 - 其他 agent 或貢獻者可接手更新 - **連續 2 次 review cycle(約 30 天)未回應**:原作者從信任名單中移除,文件開放 `help-wanted` 認領