-
Notifications
You must be signed in to change notification settings - Fork 0
feat: SLI escape_rate 排除演练数据(.github #98,ADR-0059) #203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -63,6 +63,14 @@ PYEOF | |
| t "T2 全人工周 auto_merge_rate=0" "0.0" "$(python3 -c "print(float('$AM'))")" | ||
| t "T2 revert 周逃逸分子=3/1" "3.0" "$(python3 -c "print(float('$RW'))")" | ||
|
|
||
| # 演练数据过滤(分子排除且可见) | ||
| DF=$(python3 -c " | ||
| def is_drill(p): return any(m in (p.get('title','')+p.get('body','')) for m in ('演练','[drill]')) | ||
| all_rev=[{'title':'[auto-revert] #1','body':'x'},{'title':'[auto-revert] #2','body':'演练收尾'}] | ||
| rev=[p for p in all_rev if not is_drill(p)] | ||
| print(len(rev), len(all_rev)-len(rev))") | ||
| t "演练过滤:排除 1 留 1 且计数可见" "1 1" "$DF" | ||
|
|
||
| # T3 抽样可复现 + 无偏粗检 | ||
| SAM=$(python3 - <<'PYEOF' | ||
| import random | ||
|
|
@@ -113,7 +121,7 @@ TMP=$(mktemp -d) | |
| for R in $REPOS; do | ||
| gh api "repos/$ORG/$R/pulls?state=all&sort=updated&direction=desc&per_page=50" \ | ||
| --jq ".[] | select(.merged_at != null and .merged_at >= \"$SINCE\") | \ | ||
| {repo:\"$R\", n:.number, title:.title, created:.created_at, merged:.merged_at, by:.merged_by.login, author:.user.login}" >> "$TMP/merged.jsonl" 2>/dev/null \ | ||
| {repo:\"$R\", n:.number, title:.title, body:(.body // \"\"), created:.created_at, merged:.merged_at, by:.merged_by.login, author:.user.login}" >> "$TMP/merged.jsonl" 2>/dev/null \ | ||
| || infra "$R PR 列表拉取失败" | ||
| gh api "repos/$ORG/$R/pulls?state=open&per_page=50" \ | ||
| --jq ".[] | select(.created_at != null) | {repo:\"$R\", n:.number, created:.created_at}" >> "$TMP/open.jsonl" 2>/dev/null || true | ||
|
|
@@ -132,7 +140,12 @@ now = datetime.datetime.now(datetime.timezone.utc) | |
| stuck = [p for p in opens if (now - datetime.datetime.fromisoformat(p["created"].replace("Z","+00:00"))).total_seconds() > stuck_h*3600] | ||
| durs = sorted((datetime.datetime.fromisoformat(p["merged"].replace("Z","+00:00")) - datetime.datetime.fromisoformat(p["created"].replace("Z","+00:00"))).total_seconds() for p in merged) | ||
| p95 = f"{durs[int(0.95*len(durs))-1]/3600:.1f}h" if durs else "N/A" | ||
| rev = sum(1 for p in merged if "[auto-revert]" in p["title"]) | ||
| DRILL = ("演练", "[drill]") | ||
| def is_drill(p): return any(m in (p.get("title","") + p.get("body","")) for m in DRILL) | ||
| all_rev = [p for p in merged if "[auto-revert]" in p["title"]] | ||
| rev_list = [p for p in all_rev if not is_drill(p)] | ||
| drills_excluded = len(all_rev) - len(rev_list) | ||
| rev = len(rev_list) | ||
|
Comment on lines
+145
to
+148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 5. Drills_excluded含义不完整 drills_excluded 目前只统计了 auto-revert 分子中被排除的数量,但 P0 分子同样做了演练过滤却没有对应的 excluded 计数,导致输出里的 drills_excluded 容易被误解为“分子总排除数”。这会降低指标的可解释性,尤其在需要审计/回溯过滤影响时。 Agent Prompt
Comment on lines
+143
to
+148
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift 让 当前计数只包含被排除的 🤖 Prompt for AI Agents |
||
| p0 = 0 # post-merge P0 issue 计数由调用侧注入文件(简化:占位 0 由下方覆盖) | ||
| try: p0 = int(open(f"{tmp}/p0count").read().strip()) | ||
| except Exception: pass | ||
|
|
@@ -142,7 +155,7 @@ isoweek = now.isocalendar() | |
| seed = int(f"{isoweek[0]}-W{isoweek[1]}".replace("-W","") ) if False else hash(f"{isoweek[0]}-W{isoweek[1]}") & 0xffffffff | ||
| sample = random.Random(seed).sample(agent_merged, min(k, len(agent_merged))) if agent_merged else [] | ||
| print(f"auto_merge_rate={rate} ({len(agent_merged)}/{len(merged)})") | ||
| print(f"escape_rate={esc} (reverts={rev}+p0={p0} / merged={len(merged)})") | ||
| print(f"escape_rate={esc} (reverts={rev}+p0={p0} / merged={len(merged)}, drills_excluded={drills_excluded})") | ||
| print(f"stuck_prs={len(stuck)} (>{stuck_h}h)") | ||
| print(f"pr_duration_p95={p95}") | ||
| print(f"flaky_rate=pending(#94 数据源滚动)") | ||
|
|
@@ -154,7 +167,7 @@ PYEOF | |
| [[ -s "$TMP/metrics.txt" ]] || die "指标计算失败" | ||
|
|
||
| # post-merge P0 计数(.github 与各仓 open/closed 窗口内) | ||
| P0=$(gh api "search/issues?q=org:$ORG+%22post-merge+冒烟失败%22+created:>$SINCE&per_page=100" --jq '.total_count' 2>/dev/null || echo 0) | ||
| P0=$(gh api "search/issues?q=org:$ORG+%22post-merge+冒烟失败%22+created:>$SINCE&per_page=100" --jq '[.items[] | select((.title + (.body // "")) | test("演练|\[drill\]") | not)] | length' 2>/dev/null || echo 0) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2. sli-report.sh 直用 gh_token 脚本通过环境变量 GH_TOKEN 直接驱动 gh api,未按要求通过 scripts/ghcb 或 scripts/gh-app-token.sh 获取单仓库 scope 的 token。该做法可能导致使用过宽权限的凭证或不可审计的 token 来源。 Agent Prompt
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3. P0 drill过滤jq转义错误 P0 查询的 jq 里写了 test("演练|\[drill\]"),在 jq 字符串字面量中 \[ / \] 属于非法转义,导致 jq 解析失败并触发“|| echo 0”静默回退,从而把 P0
计数错误地变成 0。结果 escape_rate 的 P0 分子会被系统性漏计,可能直接掩盖连续两周>0 的升级条件。
Agent Prompt
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
if jq -n '("演练", "[drill]") | test("演练|\[drill\]")' >/dev/null 2>&1; then
echo "错误:无效的 jq 转义未失败"
exit 1
fi
jq -n '("演练", "[drill]", "normal") | test("演练|\\[drill\\]")'Repository: Cloudbird-Software/.github Length of output: 180 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- target file ---'
git ls-files scripts/sli-report.sh
wc -l scripts/sli-report.sh
sed -n '1,230p' scripts/sli-report.sh
printf '%s\n' '--- related definitions/usages ---'
rg -n -C 3 '(^|[^[:alnum:]_])(die|P0|drills_excluded|escape_rate|gh api|search/issues)' scripts/sli-report.sh .github policy 2>/dev/null || true
printf '%s\n' '--- jq behavior ---'
jq --version
for expr in \
'("演练", "[drill]", "normal") | test("演练|\[drill\]")' \
'("演练", "[drill]", "normal") | test("演练|\\[drill\\]")'
do
printf 'expr: %s\n' "$expr"
if jq -n "$expr" >/tmp/jq.out 2>/tmp/jq.err; then
printf 'status=0\n'
cat /tmp/jq.out
else
printf 'status=%s\n' "$?"
cat /tmp/jq.err
fi
doneRepository: Cloudbird-Software/.github Length of output: 47713 修正 当前表达式会导致 🤖 Prompt for AI Agents🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: sed -n '130,190p' scripts/sli-report.sh
printf '\n--- gh api usage ---\n'
rg -n --no-heading 'search/issues|--paginate|--slurp|P0=' scripts .github governance standards 2>/dev/null | head -200Repository: Cloudbird-Software/.github Length of output: 4161 🌐 Web query:
💡 Result: In the GitHub CLI, the --paginate and --slurp flags work together to handle API responses across multiple pages [1][2]. When you use --paginate, the GitHub CLI automatically makes additional HTTP requests to fetch all available pages of results until no more pages remain [1][3]. By default, each page is returned as a separate JSON object or array [1][4]. When you add the --slurp flag, the CLI wraps all pages of JSON responses into a single, outer JSON array [1][5]. This essentially transforms a stream of individual page responses into a single, combined array [5]. Key technical constraints and usage notes include: 1. Mutual Exclusion: You cannot use --slurp in combination with --jq or --template [5]. The CLI explicitly prevents this because --slurp is designed to return the raw, combined JSON structure of all pages, which would conflict with the filtering or formatting logic of --jq and --template [6][5]. 2. Structure: Because --slurp simply wraps each page's response into a new outer array, the resulting structure is an array of the original page responses (e.g., [Page1, Page2,...]) [6][7]. It does not automatically merge nested arrays (e.g., concatenating items from multiple pages into one flat list) [6]. 3. Requirement: You must use --paginate in order to use --slurp [5]. If you need to process paginated data using jq, the recommended workaround is to use --paginate without --slurp, apply your --jq filter to each individual page response, and then pipe the output to the standalone jq tool using its own --slurp (-s) flag [8]: gh api --paginate --jq '.path.to.array[]' | jq -s. Citations:
分页读取全部 P0 搜索结果。 当前命令只处理第一页的 🤖 Prompt for AI Agents |
||
| echo "$P0" > "$TMP/p0count" | ||
|
|
||
| # 上一期 escape_rate(阈值升级 T5) | ||
|
|
@@ -176,7 +189,7 @@ $REPORT | |
|
|
||
| ## 指标口径 | ||
| - auto_merge_rate:agent 身份(cloudbrid-agent)合并 / 全部合并(分母=窗口内合并 PR 数) | ||
| - escape_rate:(合入的 [auto-revert] + post-merge P0 issue) / 合并 PR——有分母的风险指标 | ||
| - escape_rate:(合入的 [auto-revert] + post-merge P0 issue) / 合并 PR——有分母的风险指标;演练数据(title/body 含「演练」或「[drill]」约定标记)从分子排除且 drills_excluded 计数可见——过滤不可见=作弊通道 | ||
| - 人类触碰:agent 合并占比的反向锚点(逐评论/评审计数下版接入) | ||
| - flaky_rate / entropy:pending(数据源 #94/#87/#90 滚动接入) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
分别检查标题和正文,并补充对应自测。
请避免把
title和body拼接后匹配演练标记,否则一个字段结尾与另一个字段开头可能跨字段形成误匹配并排除合法记录。实现和自测都应分别覆盖标题或正文中的“演练”及[drill],并验证普通记录、演练记录和 P0 结果的保留与排除计数。📍 Affects 1 file
scripts/sli-report.sh#L66-L72(this comment)scripts/sli-report.sh#L143-L144🤖 Prompt for AI Agents