-
Notifications
You must be signed in to change notification settings - Fork 0
feat(governance): cost-check LLM 预算通道(W2-C3 .github#216,ADR-0062) #231
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 |
|---|---|---|
|
|
@@ -21,7 +21,7 @@ on: | |
| required: false | ||
| default: "" | ||
| llm_tokens_used_override: | ||
| description: "LLM token 用量覆盖(pending 数据源的注入测试通道)" | ||
| description: "LLM token 用量覆盖(优先于计量账本的注入测试通道)" | ||
| required: false | ||
| default: "" | ||
| llm_tokens_quota_override: | ||
|
|
@@ -49,6 +49,15 @@ jobs: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| persist-credentials: false | ||
| # 归账引擎 sparse checkout(W2-C3 .github#216,ADR-0062):CI-Workflows 是公开仓且 | ||
| # 自身有 CI+org-gate(C1),跟 main 消费;升级若破坏 aggregate 会让本检查显式 | ||
| # INFRA 红(fail-closed 可见),不会被静默吞掉 | ||
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| repository: Cloudbird-Software/CI-Workflows | ||
| sparse-checkout: pipeline/metering | ||
| path: ciw-metering | ||
| persist-credentials: false | ||
|
Comment on lines
+56
to
+60
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. 4. 外部仓checkout未固定ref workflow 直接 checkout Cloudbird-Software/CI-Workflows 默认分支来获取 metering.py,未固定到特定 commit/tag,导致成本熔断行为随外部仓 HEAD 变化而漂移,存在供应链与可重复性风险。若外部仓被误推/破坏,预算检查可能被绕过或频繁误报。 Agent Prompt
|
||
| - name: 用量检查与熔断(exit 1=触发告警/熔断 2=基础设施故障) | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GOVERNANCE_TOKEN }} | ||
|
|
@@ -57,5 +66,6 @@ jobs: | |
| COST_QUOTA_MINUTES_OVERRIDE: ${{ inputs.quota_minutes_override }} | ||
| COST_LLM_TOKENS_USED_OVERRIDE: ${{ inputs.llm_tokens_used_override }} | ||
| COST_LLM_TOKENS_QUOTA_OVERRIDE: ${{ inputs.llm_tokens_quota_override }} | ||
| COST_LLM_METERING_PY: ciw-metering/pipeline/metering/metering.py # 归账引擎(ADR-0062 通道) | ||
| COST_DRY_RUN: ${{ inputs.dry_run }} | ||
| run: bash governance/cost-check.sh | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,9 @@ | |
| # ≥ warn_pct(80) → 告警 issue(.github 仓,label cost-budget-warning,同日去重,不硬停) | ||
| # ≥ hardstop_pct(100)→ org Actions 变量 AUTO_MERGE_DISABLED=true + 撤全部 open PR 的 | ||
| # auto-merge + P0 issue(label cost-circuit-breaker) | ||
| # LLM token 通道(W2-C3 .github#216,ADR-0062):data_source=ciw-metering 时按角色档归账 | ||
| # (CI-Workflows metering-ledger 分支 → metering.py aggregate,先验链后归账); | ||
| # 链断/拉取失败 = INFRA fail-closed(exit 2),不静默归零不盲熔断。 | ||
| # 熔断消费点:agent 派发/automerge 前置检查(AGENTS.md 行为契约)+ auto-fix-limit.sh | ||
| # 每轮机器执法撤 auto-merge。复位仅人工(owner PATCH/DELETE 变量 + P0 issue 留评论); | ||
| # 本脚本观察到"变量已复位且用量 <100%"后自动关闭 P0 issue(复位留痕=issue 评论历史)。 | ||
|
|
@@ -67,6 +70,10 @@ try: | |
| rows = [("AM_QUOTA", am["quota_per_month"]), ("AM_WARN", am["warn_pct"]), ("AM_STOP", am["hardstop_pct"]), | ||
| ("LT_QUOTA", lt["quota_per_month"]), ("LT_WARN", lt["warn_pct"]), ("LT_STOP", lt["hardstop_pct"]), | ||
| ("LT_SOURCE", lt["data_source"]), ("CB_VARIABLE", cb["variable"]), ("CB_RESET_BY", cb["reset_by"])] | ||
| # W2-C3(ADR-0062):ciw-metering 数据源定位(data_source 非 ciw-metering 时可为空) | ||
| m = lt.get("metering") or {} | ||
| rows += [("LT_M_REPO", m.get("repo", "")), ("LT_M_BRANCH", m.get("branch", "")), | ||
| ("LT_M_CODE", m.get("code_path", ""))] | ||
| for kk, vv in rows: | ||
| vv = str(vv) | ||
| assert "=" not in vv and "\n" not in vv, f"policy 值含非法字符: {kk}" | ||
|
|
@@ -79,6 +86,12 @@ while IFS='=' read -r key val; do declare "$key=$val"; done <<< "$POLICY_ENV" | |
| for v in AM_QUOTA AM_WARN AM_STOP LT_QUOTA LT_WARN LT_STOP LT_SOURCE CB_VARIABLE CB_RESET_BY; do | ||
| [[ -n "${!v:-}" ]] || { echo "FATAL: policy 缺 $v" >&2; exit 2; } | ||
| done | ||
| # ciw-metering 数据源须完整声明定位三件套(W2-C3,ADR-0062)——缺一 = 配置面残缺,fail-closed | ||
| if [[ "$LT_SOURCE" == "ciw-metering" ]]; then | ||
| for v in LT_M_REPO LT_M_BRANCH LT_M_CODE; do | ||
| [[ -n "${!v:-}" ]] || { echo "FATAL: data_source=ciw-metering 但 policy llm_tokens.metering 缺 $v" >&2; exit 2; } | ||
| done | ||
| fi | ||
| # 环境注入优先(T2 注入式测试通道) | ||
| AM_QUOTA="${COST_QUOTA_MINUTES_OVERRIDE:-$AM_QUOTA}" | ||
| LT_QUOTA="${COST_LLM_TOKENS_QUOTA_OVERRIDE:-$LT_QUOTA}" | ||
|
|
@@ -127,21 +140,93 @@ PCT_MIN=$(pct "$USED_MIN" "$AM_QUOTA") | |
| check_num PCT_MIN "Actions 用量百分比" | ||
| ok "Actions 分钟($YEAR-$MONTH): $USED_MIN / $AM_QUOTA = ${PCT_MIN}%($SRC_MIN)" | ||
|
|
||
| # LLM token:data_source=pending 时仅注入通道可测,不触发真实告警(ADR-0040 决策 6) | ||
| # ---------- LLM token 用量(W2-C3 .github#216,ADR-0062:ciw-metering 数据源按角色档归账) ---------- | ||
| # @w2c3-llm-channel-begin(governance/tests/test-cost-llm-channel.sh 按标记对提取本函数体 | ||
| # 离线单测——标记对缺失=测试红,防"测试测影子") | ||
| llm_channel_account() { | ||
| # → stdout 单行 "DATA<TAB>当月token<TAB>角色档json" | "ZERO<TAB>说明" | "INFRA<TAB>说明"。 | ||
| # 本函数经命令替换调用(子 shell),不直接调 infra/ok(计数会丢)——标签由调用方 | ||
| # 在父 shell 落账。env 注入通道(T2):COST_LLM_METERING_DIR=本地账本目录、 | ||
| # COST_LLM_METERING_PY=归账引擎(metering.py)路径;缺省走真实数据源 | ||
| # (metering-ledger 分支 tarball → metering.py aggregate,先验链后归账)。 | ||
| local led="${COST_LLM_METERING_DIR:-}" mpy="${COST_LLM_METERING_PY:-}" out rc=0 | ||
| if [[ -z "$led" ]]; then | ||
| led=$(mktemp -d) || { printf 'INFRA\tmetering 账本临时目录创建失败\n'; return 0; } | ||
| if ! "$GH" api "repos/$LT_M_REPO/tarball/$LT_M_BRANCH" >"$led.tar.gz" 2>/dev/null; then | ||
| if "$GH" api "repos/$LT_M_REPO/branches/$LT_M_BRANCH" >/dev/null 2>&1; then | ||
| printf 'INFRA\tmetering 账本分支存在但 tarball 拉取失败(%s@%s)\n' "$LT_M_REPO" "$LT_M_BRANCH" | ||
| else | ||
|
Comment on lines
+155
to
+158
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. Api失败被判zero llm_channel_account() 在 tarball 拉取失败后,用 gh api .../branches/... 的成功与否来判断分支是否存在,但对 branches 查询的非 404 失败(限流/网络/权限)会被当作“分支未建”并输出 ZERO,导致用量被静默归零。该路径违背本 PR 声明的 fail-closed(不可信数据不入账),会造成预算检查漏报/假绿。 Agent Prompt
|
||
| printf 'ZERO\t计量账本分支 %s@%s 未建(尚无经 wrapper 的 LLM 调用落账)——当月用量记 0\n' "$LT_M_REPO" "$LT_M_BRANCH" | ||
| fi | ||
| return 0 | ||
| fi | ||
|
Comment on lines
+155
to
+162
|
||
| if ! tar -xzf "$led.tar.gz" -C "$led" --strip-components=1 --wildcards \ | ||
| "*/$LT_M_CODE/records-*.jsonl" 2>/dev/null; then | ||
| printf 'INFRA\tmetering 账本 tar 解包失败(strip-components=1 + %s/records-*.jsonl)\n' "$LT_M_CODE" | ||
| return 0 | ||
|
Comment on lines
+163
to
+166
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. 空账本被判infra llm_channel_account() 使用 tar 的 wildcard 解包 records-*.jsonl,当分支已建但尚无任何 records 文件时,tar 会因“无匹配成员/Not found in archive”失败并被当作 INFRA。该场景在 PR 设计中应归类为 ZERO(零用量声明),否则会导致通道上线初期或月初窗口持续误报基础设施故障。 Agent Prompt
|
||
| fi | ||
| fi | ||
| if [[ -z "$mpy" || ! -f "$mpy" ]]; then | ||
| printf 'INFRA\t归账引擎不可用(COST_LLM_METERING_PY=%s——cost-check.yml 须 sparse checkout %s 的 %s)\n' "$mpy" "$LT_M_REPO" "$LT_M_CODE" | ||
| return 0 | ||
| fi | ||
| out=$(python3 "$mpy" aggregate --dir "$led" --since "$(date -u +%Y-%m-01)" --json 2>&1) || rc=$? | ||
| if [[ $rc -eq 2 ]]; then | ||
| printf 'ZERO\t账本无周片(aggregate: %.200s)——当月用量记 0\n' "$out" | ||
| return 0 | ||
| fi | ||
| if [[ $rc -ne 0 ]]; then | ||
| printf 'INFRA\tmetering 归账失败(账本验链不过——不可信数据不入账):%.300s\n' "$out" | ||
| return 0 | ||
| fi | ||
| printf 'DATA\t%s\t%s\n' \ | ||
| "$(python3 -c 'import json,sys;print(json.load(sys.stdin)["totals"]["total_tokens"])' <<<"$out")" \ | ||
| "$(python3 -c 'import json,sys;print(json.dumps(json.load(sys.stdin)["roles"],ensure_ascii=False,sort_keys=True))' <<<"$out")" | ||
| } | ||
| # @w2c3-llm-channel-end | ||
|
|
||
| PCT_TOK="" | ||
| USED_TOK="" | ||
| LLM_ROLES="" | ||
| LLM_SUMMARY="" | ||
| if [[ -n "${COST_LLM_TOKENS_USED_OVERRIDE:-}" ]]; then | ||
| PCT_TOK=$(pct "$COST_LLM_TOKENS_USED_OVERRIDE" "$LT_QUOTA") | ||
| check_num PCT_TOK "LLM 用量百分比" | ||
| ok "LLM token: $COST_LLM_TOKENS_USED_OVERRIDE / $LT_QUOTA = ${PCT_TOK}%(注入——pending 数据源的注入测试通道)" | ||
| USED_TOK="$COST_LLM_TOKENS_USED_OVERRIDE"; LLM_ROLES="注入通道" | ||
| LLM_SUMMARY="LLM token: $USED_TOK / $LT_QUOTA = ${PCT_TOK}%(注入通道——优先于计量账本)" | ||
| ok "$LLM_SUMMARY" | ||
| elif [[ "$LT_SOURCE" == "pending" ]]; then | ||
| ok "LLM token: 数据源 pending(llm-gateway usage 端点未就绪)——仅声明,不参与告警" | ||
| LLM_SUMMARY="LLM token: 数据源 pending(回滚形态,ADR-0040 决策 6)——仅声明,不参与告警" | ||
| ok "$LLM_SUMMARY" | ||
| elif [[ "$LT_SOURCE" == "ciw-metering" ]]; then | ||
| LLINE=$(llm_channel_account) || true | ||
| IFS=$'\t' read -r LTAG LVAL LREST <<<"$LLINE" | ||
| case "$LTAG" in | ||
| DATA) | ||
| USED_TOK="$LVAL"; LLM_ROLES="$LREST" | ||
| check_num USED_TOK "LLM 当月 token(归账)" | ||
| PCT_TOK=$(pct "$USED_TOK" "$LT_QUOTA") | ||
| check_num PCT_TOK "LLM 用量百分比" | ||
| LLM_SUMMARY="LLM token(当月归账): $USED_TOK / $LT_QUOTA = ${PCT_TOK}%(角色档 ${LLM_ROLES:-∅})" | ||
| ok "$LLM_SUMMARY" | ||
| ;; | ||
| ZERO) LLM_SUMMARY="LLM token: $LVAL"; ok "$LLM_SUMMARY" ;; | ||
| INFRA) infra "$LVAL" ;; | ||
| *) infra "LLM 通道输出不可解析(期望 DATA/ZERO/INFRA 标签):$LLINE" ;; | ||
| esac | ||
| else | ||
| infra "LLM token 数据源未知:$LT_SOURCE(policy cost.llm_tokens.data_source 无此形态)" | ||
| fi | ||
|
|
||
| # ---------- 熔断当前状态 ---------- | ||
| BREAKER_SET=0 | ||
| VERR=$("$GH" api "orgs/$ORG/actions/variables/$CB_VARIABLE" --jq .value 2>&1) || true | ||
| if [[ "$VERR" == *"true"* && "$VERR" != *"Not Found"* ]]; then | ||
| BREAKER_SET=1 | ||
| # 读取 rc 单独捕获(W2-C3 顺带修复的潜在缺陷):变量存在且 value=false(人工复位后 | ||
| # 的常态)曾被当作"读取失败非 404"落 INFRA——复位确认路径每小时误红。现按 rc 判: | ||
| # 0=读到值(true→置位,false/其他→未置位);404=未建;其余=infra fail-closed。 | ||
| VCB_RC=0 | ||
| VERR=$("$GH" api "orgs/$ORG/actions/variables/$CB_VARIABLE" --jq .value 2>&1) || VCB_RC=$? | ||
| if [[ $VCB_RC -eq 0 ]]; then | ||
| [[ "$VERR" == *"true"* ]] && BREAKER_SET=1 # 读到值:true=置位;false/其他=未置位(读取成功即终态) | ||
| elif grep -q "Not Found" <<<"$VERR"; then | ||
| : | ||
| else | ||
|
|
@@ -205,7 +290,7 @@ if [[ "$STOP_MIN" == "True" || "$STOP_TOK" == "True" ]]; then | |
| P0_BODY="P0:额度/成本熔断已置位(ADR-0040,运行 $(date -u +%FT%TZ))。 | ||
|
|
||
| - Actions 分钟($YEAR-$MONTH): $USED_MIN / $AM_QUOTA = ${PCT_MIN}%(阈值 $AM_STOP%)${PCT_TOK:+ | ||
| - LLM token: $COST_LLM_TOKENS_USED_OVERRIDE / $LT_QUOTA = ${PCT_TOK}%(阈值 $LT_STOP%,注入通道)} | ||
| - ${LLM_SUMMARY:-LLM token: $USED_TOK}(阈值 $LT_STOP%,ADR-0062 归账通道)} | ||
| - 已执行:org 变量 \`$CB_VARIABLE\`=true;全部 open PR 的 auto-merge 已撤销。 | ||
| - 效果:agent 派发与 automerge 前置检查将拒绝启动(AGENTS.md);auto-fix-limit 每轮机器执法撤销新 enable。 | ||
|
|
||
|
|
@@ -231,9 +316,11 @@ if [[ "$STOP_MIN" == "True" || "$STOP_TOK" == "True" ]]; then | |
| elif [[ "$WARN_MIN" == "True" || "$WARN_TOK" == "True" ]]; then | ||
| TRIPPED=1 | ||
| label_ensure "$GOV_REPO" cost-budget-warning fbca04 | ||
| W_TITLE="成本告警:Actions 分钟 $YEAR-$MONTH 用量 ${PCT_MIN}%(阈值 $AM_WARN%)" | ||
| W_TITLE="成本告警($YEAR-$MONTH):Actions 分钟 ${PCT_MIN}% / LLM token ${PCT_TOK:--}%(阈值 ${AM_WARN}%)" | ||
| W_EXISTING=$(gov_open_issues cost-budget-warning | grep -m1 "$YEAR-$MONTH" | cut -f1) | ||
|
Comment on lines
+319
to
320
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. 告警阈值字段混用 告警档标题与日志同时展示 Actions 与 LLM token,但括号内阈值仍使用 AM_WARN(Actions 阈值)而非 LT_WARN(LLM 阈值),当两者配置不一致时会误导值守与审计。该问题会导致告警信息描述与实际判定条件不一致。 Agent Prompt
|
||
| W_BODY="额度告警(ADR-0040,$(date -u +%FT%TZ)):Actions 分钟($YEAR-$MONTH)$USED_MIN / $AM_QUOTA = ${PCT_MIN}%,达 ${AM_WARN}% 告警档——未硬停;达 ${AM_STOP}% 将置 \`$CB_VARIABLE\` 熔断并撤全部 auto-merge。" | ||
| W_BODY="额度告警(ADR-0040,$(date -u +%FT%TZ)):Actions 分钟($YEAR-$MONTH)$USED_MIN / $AM_QUOTA = ${PCT_MIN}%,达 ${AM_WARN}% 告警档——未硬停;达 ${AM_STOP}% 将置 \`$CB_VARIABLE\` 熔断并撤全部 auto-merge。 | ||
| ${LLM_SUMMARY:+$LLM_SUMMARY | ||
| }(LLM 阈值 ${LT_WARN}%/${LT_STOP}%,ADR-0062 归账通道)" | ||
|
Comment on lines
+319
to
+323
|
||
| if [[ -n "$W_EXISTING" ]]; then | ||
| if ! issue_silent_today "$W_EXISTING"; then | ||
| mutate "$GH" issue comment "$W_EXISTING" --repo "$GOV_REPO" --body "$W_BODY" >/dev/null 2>&1 || true | ||
|
|
@@ -242,7 +329,7 @@ elif [[ "$WARN_MIN" == "True" || "$WARN_TOK" == "True" ]]; then | |
| mutate "$GH" issue create --repo "$GOV_REPO" --title "$W_TITLE" \ | ||
| --body "$W_BODY" --label cost-budget-warning >/dev/null 2>&1 || infra "告警 issue 开立失败" | ||
| fi | ||
| act "告警档触发: Actions ${PCT_MIN}% ≥ ${AM_WARN}%(issue 已开/更新)" | ||
| act "告警档触发: Actions ${PCT_MIN}% / LLM token ${PCT_TOK:--}%(阈值 ${AM_WARN}%,issue 已开/更新)" | ||
| else | ||
| # 用量回落:关闭过期的告警 issue(月度滚动或已回落) | ||
| for row in $(gov_open_issues cost-budget-warning | cut -f1); do | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| #!/usr/bin/env bash | ||
| # test-cost-llm-channel.sh —— cost-check LLM 预算通道单测(W2-C3 .github#216,ADR-0062) | ||
| # | ||
| # 从 cost-check.sh 按 @w2c3-llm-channel 标记对提取 llm_channel_account 函数体 | ||
| # (不复制实现——防"测试测影子",同 test-ir0002.sh 模式;标记对缺失=fail-closed 红), | ||
| # 用桩 metering.py(行为受 STUB_MODE 控制)与桩 gh 断言通道契约: | ||
| # DATA 归账成功 → "DATA<TAB>当月token<TAB>角色档json"(调用方据此算 PCT_TOK) | ||
| # 空账本 aggregate rc=2 → ZERO(账本分支已建但无周片 = 零用量,不是 infra) | ||
| # 链断 aggregate rc=3 → INFRA(不可信数据不入账,fail-closed) | ||
| # 引擎缺失 / tarball 拉取失败(分支在)/ 分支未建 → INFRA / ZERO | ||
| # 真实归账数值(角色档聚合、验链、hash 链)由 CI-Workflows 仓 | ||
| # pipeline/metering/selftest T1/T3/T5 覆盖;本测试锁 cost-check 侧消费契约与 | ||
| # fail-closed 方向。用法:bash governance/tests/test-cost-llm-channel.sh(零网络零真实 gh) | ||
| set -uo pipefail | ||
| DIR="$(cd "$(dirname "$0")/.." && pwd)" | ||
| FAILS=0 | ||
| pass() { echo "PASS $1"; } | ||
| fail() { echo "FAIL $1"; FAILS=$((FAILS+1)); } | ||
|
|
||
| # --- 提取被测函数(标记对缺失=fail-closed:测试与实现脱钩即红) --- | ||
| SRC="$DIR/cost-check.sh" | ||
| [[ -f "$SRC" ]] || { echo "FATAL: cost-check.sh 不存在"; exit 2; } | ||
| EXTRACTED=$(awk '/@w2c3-llm-channel-begin/{f=1} f{print} /@w2c3-llm-channel-end/{exit}' "$SRC") | ||
| if ! grep -q '^llm_channel_account()' <<<"$EXTRACTED"; then | ||
| echo "FATAL: 标记对内未找到 llm_channel_account 定义(提取失效——实现与测试脱钩)"; exit 2 | ||
| fi | ||
|
|
||
| # --- 桩环境(函数在命令替换子 shell 外定义;ok/infra 桩防实现漂移误伤主脚本计数) --- | ||
| INFRAS=0 | ||
| infra() { echo "INFRA $1"; INFRAS=$((INFRAS+1)); } | ||
| ok() { echo "OK $1"; } | ||
| GH=gh | ||
| LT_M_REPO="Cloudbird-Software/CI-Workflows" | ||
| LT_M_BRANCH="metering-ledger" | ||
| LT_M_CODE="pipeline/metering" | ||
| eval "$EXTRACTED" | ||
|
|
||
| TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT | ||
| mkdir -p "$TMP/bin" "$TMP/ledger" | ||
| # python3 本地垫片(Windows 商店 stub 环境);CI(ubuntu)python3 直用不受影响 | ||
| if ! python3 -c 'import sys' >/dev/null 2>&1; then | ||
| printf '#!/usr/bin/env bash\nexec python "$@"\n' >"$TMP/bin/python3"; chmod +x "$TMP/bin/python3" | ||
| export PATH="$TMP/bin:$PATH" | ||
| fi | ||
| # 桩 metering.py:与真实 metering.py aggregate 的退出码契约一致(0=数据 2=无账本 3=链断) | ||
| STUB_MODE_PATH="$TMP/mode" | ||
| cat >"$TMP/bin/metering.py" <<'EOF' | ||
| import os, sys | ||
| mode = open(os.environ["STUB_MODE_PATH"], encoding="utf-8").read().strip() | ||
| if mode == "data": | ||
| print('{"roles": {"probe": {"invokes": 2, "total_tokens": 165}, ' | ||
| '"spec-author": {"invokes": 1, "total_tokens": 42}}, ' | ||
| '"totals": {"invokes": 3, "total_tokens": 207}}') | ||
| sys.exit(0) | ||
| if mode == "empty": | ||
| print("账本目录无 records-*.jsonl", file=sys.stderr); sys.exit(2) | ||
| if mode == "broken": | ||
| print("CHAIN records-2026-W34.jsonl:1: record_sha256 重算不符", file=sys.stderr); sys.exit(3) | ||
| print(f"未知桩模式 {mode}", file=sys.stderr); sys.exit(9) | ||
| EOF | ||
|
|
||
| run_chan() { # 捕获函数输出(真实数据源路径由 gh 桩 + 已 unset 的注入变量控制) | ||
| LLINE=$(llm_channel_account) | ||
| } | ||
| export STUB_MODE_PATH | ||
| export COST_LLM_METERING_DIR="$TMP/ledger" | ||
|
|
||
| # 1) DATA:归账成功 → 标签+当月 token+角色档 json | ||
| echo data >"$STUB_MODE_PATH" | ||
| COST_LLM_METERING_PY="$TMP/bin/metering.py" | ||
| run_chan | ||
| if [[ "${LLINE%%$'\t'*}" == "DATA" ]] && grep -q '207' <<<"$LLINE" && grep -q '"probe"' <<<"$LLINE"; then | ||
| pass "DATA 形态:当月 token=207 + 角色档 json 透传($LLINE)" | ||
| else fail "DATA 形态不符:$LLINE"; fi | ||
|
|
||
| # 2) 空账本(分支已建、尚无周片)→ ZERO(零用量不是 infra) | ||
| echo empty >"$STUB_MODE_PATH" | ||
| run_chan | ||
| if [[ "${LLINE%%$'\t'*}" == "ZERO" ]] && grep -q "用量记 0" <<<"$LLINE"; then | ||
| pass "空账本 → ZERO(零用量声明)" | ||
| else fail "空账本应 ZERO,得到:$LLINE"; fi | ||
|
|
||
| # 3) 链断 → INFRA(不可信数据不入账——fail-closed 方向) | ||
| echo broken >"$STUB_MODE_PATH" | ||
| run_chan | ||
| if [[ "${LLINE%%$'\t'*}" == "INFRA" ]] && grep -q "不可信数据不入账" <<<"$LLINE"; then | ||
| pass "链断 → INFRA(归账拒绝,fail-closed)" | ||
| else fail "链断应 INFRA,得到:$LLINE"; fi | ||
|
|
||
| # 4) 归账引擎缺失 → INFRA(配置面残缺可见) | ||
| COST_LLM_METERING_PY="$TMP/nope.py" | ||
| run_chan | ||
| if [[ "${LLINE%%$'\t'*}" == "INFRA" ]] && grep -q "归账引擎不可用" <<<"$LLINE"; then | ||
| pass "引擎缺失 → INFRA(sparse checkout 缺失可见)" | ||
| else fail "引擎缺失应 INFRA,得到:$LLINE"; fi | ||
|
|
||
| # 5) 分支未建(tarball 与 branches 查询都 404)→ ZERO | ||
| unset COST_LLM_METERING_DIR COST_LLM_METERING_PY | ||
| gh() { return 1; } | ||
| run_chan | ||
| unset -f gh | ||
| if [[ "${LLINE%%$'\t'*}" == "ZERO" ]] && grep -q "未建" <<<"$LLINE"; then | ||
| pass "账本分支未建 → ZERO(尚无 LLM 调用落账)" | ||
| else fail "分支未建应 ZERO,得到:$LLINE"; fi | ||
|
|
||
| # 6) tarball 拉取失败但分支存在 → INFRA(用量不可知,不盲熔断不静默归零) | ||
| gh() { case "$*" in *tarball*) return 1 ;; *) return 0 ;; esac; } | ||
| run_chan | ||
| unset -f gh | ||
| if [[ "${LLINE%%$'\t'*}" == "INFRA" ]] && grep -q "tarball 拉取失败" <<<"$LLINE"; then | ||
| pass "tarball 失败+分支在 → INFRA(fail-closed 出口 2 的判定输入)" | ||
| else fail "tarball 失败应 INFRA,得到:$LLINE"; fi | ||
|
|
||
| echo "----------------------------------------" | ||
| if [[ $FAILS -eq 0 ]]; then echo "test-cost-llm-channel PASS(6/6)"; exit 0; fi | ||
| echo "test-cost-llm-channel FAIL:$FAILS 处"; exit 1 |
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.
1. Missing card: metadata line
📘 Rule violation§ ComplianceAgent Prompt
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools