fix: add missing shell scripts and fix contract interface in run-protocol
- Add scripts/harb-evaluator/run-resources.sh: collects disk, RAM, Anthropic API usage, and Woodpecker CI queue metrics - Add scripts/harb-evaluator/run-protocol.sh: collects TVL, fees, position data, and rebalance events from LiquidityManager - Fix run-protocol.toml: positions accessed via positions(uint8) not named getters (floorPosition/anchorPosition/discoveryPosition) - Fix event signature: Recentered(int24,bool) not Recenter(int24,int24,int24) Addresses review findings: missing implementation files and contract interface mismatch. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1d9636dab3
commit
b616953313
3 changed files with 362 additions and 7 deletions
|
|
@ -88,20 +88,20 @@ forge_script = "onchain/script/LmTotalEth.s.sol"
|
||||||
id = "collect-fees"
|
id = "collect-fees"
|
||||||
description = """
|
description = """
|
||||||
Query accumulated protocol fees from the LiquidityManager via cast call:
|
Query accumulated protocol fees from the LiquidityManager via cast call:
|
||||||
LiquidityManager.accumulatedFees() → uint256
|
cast call $LM "accumulatedFees()(uint256)"
|
||||||
Records accumulated_fees_eth (wei string) and accumulated_fees_eth_formatted
|
Records accumulated_fees_eth (wei string) and accumulated_fees_eth_formatted
|
||||||
(ETH, 3 dp).
|
(ETH, 3 dp).
|
||||||
Falls back to 0 gracefully if the function is not present on the deployed
|
Falls back to 0 gracefully if the function reverts or is not present on
|
||||||
contract (older deployment without fee tracking).
|
the deployed contract (older deployment without fee tracking).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[[steps]]
|
[[steps]]
|
||||||
id = "collect-positions"
|
id = "collect-positions"
|
||||||
description = """
|
description = """
|
||||||
Query the three Uniswap V3 positions held by the LiquidityManager:
|
Query the three Uniswap V3 positions held by the LiquidityManager:
|
||||||
LiquidityManager.floorPosition() → (tickLower, tickUpper, liquidity)
|
LiquidityManager.positions(0) → (liquidity, tickLower, tickUpper) # FLOOR
|
||||||
LiquidityManager.anchorPosition() → (tickLower, tickUpper, liquidity)
|
LiquidityManager.positions(1) → (liquidity, tickLower, tickUpper) # ANCHOR
|
||||||
LiquidityManager.discoveryPosition() → (tickLower, tickUpper, liquidity)
|
LiquidityManager.positions(2) → (liquidity, tickLower, tickUpper) # DISCOVERY
|
||||||
Records position_count (number of positions with liquidity > 0) and the
|
Records position_count (number of positions with liquidity > 0) and the
|
||||||
positions array.
|
positions array.
|
||||||
"""
|
"""
|
||||||
|
|
@ -116,7 +116,7 @@ Records:
|
||||||
- last_rebalance_block: block number of the most recent Recenter event
|
- last_rebalance_block: block number of the most recent Recenter event
|
||||||
(0 if none found in the window).
|
(0 if none found in the window).
|
||||||
"""
|
"""
|
||||||
event_signature = "Recenter(int24,int24,int24)"
|
event_signature = "Recentered(int24,bool)"
|
||||||
|
|
||||||
[[steps]]
|
[[steps]]
|
||||||
id = "collect"
|
id = "collect"
|
||||||
|
|
|
||||||
186
scripts/harb-evaluator/run-protocol.sh
Executable file
186
scripts/harb-evaluator/run-protocol.sh
Executable file
|
|
@ -0,0 +1,186 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# run-protocol.sh — On-chain protocol health snapshot.
|
||||||
|
#
|
||||||
|
# Collects TVL, accumulated fees, position count, and rebalance frequency
|
||||||
|
# from the deployed LiquidityManager. Writes evidence/protocol/YYYY-MM-DD.json.
|
||||||
|
#
|
||||||
|
# Exit codes:
|
||||||
|
# 0 snapshot written successfully
|
||||||
|
# 2 infrastructure error (RPC unreachable, missing deployments, forge unavailable)
|
||||||
|
#
|
||||||
|
# Environment:
|
||||||
|
# RPC_URL Base network RPC endpoint (required)
|
||||||
|
# DEPLOYMENTS_FILE path to deployments JSON (default: onchain/deployments-local.json)
|
||||||
|
# LOOKBACK_BLOCKS blocks to scan for Recentered events (default: 7200, ~24 h on Base)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CAST="${CAST:-/home/debian/.foundry/bin/cast}"
|
||||||
|
FORGE="${FORGE:-/home/debian/.foundry/bin/forge}"
|
||||||
|
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
|
DATE="$(date -u +%Y-%m-%d)"
|
||||||
|
OUT_DIR="$REPO_ROOT/evidence/protocol"
|
||||||
|
OUT_FILE="$OUT_DIR/$DATE.json"
|
||||||
|
|
||||||
|
RPC_URL="${RPC_URL:?RPC_URL is required}"
|
||||||
|
DEPLOYMENTS_FILE="${DEPLOYMENTS_FILE:-onchain/deployments-local.json}"
|
||||||
|
LOOKBACK_BLOCKS="${LOOKBACK_BLOCKS:-7200}"
|
||||||
|
|
||||||
|
# Resolve relative deployments path against repo root
|
||||||
|
if [[ "$DEPLOYMENTS_FILE" != /* ]]; then
|
||||||
|
DEPLOYMENTS_FILE="$REPO_ROOT/$DEPLOYMENTS_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
die() { echo "ERROR: $*" >&2; exit 2; }
|
||||||
|
|
||||||
|
mkdir -p "$OUT_DIR"
|
||||||
|
|
||||||
|
# ── read-addresses ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
[[ -f "$DEPLOYMENTS_FILE" ]] || die "Deployments file not found: $DEPLOYMENTS_FILE"
|
||||||
|
|
||||||
|
LM=$(jq -r '.contracts.LiquidityManager' "$DEPLOYMENTS_FILE")
|
||||||
|
POOL=$(jq -r '.contracts.Pool' "$DEPLOYMENTS_FILE")
|
||||||
|
WETH=0x4200000000000000000000000000000000000006
|
||||||
|
|
||||||
|
[[ -n "$LM" && "$LM" != "null" ]] || die "LiquidityManager address missing from $DEPLOYMENTS_FILE"
|
||||||
|
[[ -n "$POOL" && "$POOL" != "null" ]] || die "Pool address missing from $DEPLOYMENTS_FILE"
|
||||||
|
|
||||||
|
# ── collect block number ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
block_number=$("$CAST" block-number --rpc-url "$RPC_URL" 2>/dev/null) \
|
||||||
|
|| die "RPC unreachable at $RPC_URL"
|
||||||
|
|
||||||
|
# ── collect-tvl ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
tvl_eth="0"
|
||||||
|
tvl_eth_formatted="0.00"
|
||||||
|
|
||||||
|
if tvl_output=$(cd "$REPO_ROOT" && LM="$LM" WETH="$WETH" POOL="$POOL" \
|
||||||
|
"$FORGE" script onchain/script/LmTotalEth.s.sol \
|
||||||
|
--rpc-url "$RPC_URL" --silent 2>/dev/null); then
|
||||||
|
# forge script outputs the number via console2.log — extract last number
|
||||||
|
tvl_eth=$(echo "$tvl_output" | grep -oE '[0-9]+' | tail -1)
|
||||||
|
tvl_eth="${tvl_eth:-0}"
|
||||||
|
tvl_eth_formatted=$(awk "BEGIN {printf \"%.2f\", $tvl_eth / 1e18}")
|
||||||
|
else
|
||||||
|
echo "WARN: LmTotalEth forge script failed, TVL will be 0" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── collect-fees ──────────────────────────────────────────────────────────────
|
||||||
|
# accumulatedFees() may not exist on older deployments — graceful fallback to 0.
|
||||||
|
|
||||||
|
accumulated_fees_eth="0"
|
||||||
|
accumulated_fees_eth_formatted="0.000"
|
||||||
|
|
||||||
|
if fees_output=$("$CAST" call "$LM" "accumulatedFees()(uint256)" --rpc-url "$RPC_URL" 2>/dev/null); then
|
||||||
|
accumulated_fees_eth=$(echo "$fees_output" | grep -oE '[0-9]+' | head -1)
|
||||||
|
accumulated_fees_eth="${accumulated_fees_eth:-0}"
|
||||||
|
accumulated_fees_eth_formatted=$(awk "BEGIN {printf \"%.3f\", $accumulated_fees_eth / 1e18}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── collect-positions ─────────────────────────────────────────────────────────
|
||||||
|
# LiquidityManager.positions(uint8 stage) → (uint128 liquidity, int24 tickLower, int24 tickUpper)
|
||||||
|
# Stage: 0=FLOOR, 1=ANCHOR, 2=DISCOVERY
|
||||||
|
|
||||||
|
position_count=0
|
||||||
|
positions_json="["
|
||||||
|
stage_names=("floor" "anchor" "discovery")
|
||||||
|
|
||||||
|
for stage in 0 1 2; do
|
||||||
|
name="${stage_names[$stage]}"
|
||||||
|
|
||||||
|
if pos_output=$("$CAST" call "$LM" "positions(uint8)(uint128,int24,int24)" "$stage" --rpc-url "$RPC_URL" 2>/dev/null); then
|
||||||
|
# cast returns one value per line
|
||||||
|
liquidity=$(echo "$pos_output" | sed -n '1p' | tr -d '[:space:]')
|
||||||
|
tick_lower=$(echo "$pos_output" | sed -n '2p' | tr -d '[:space:]')
|
||||||
|
tick_upper=$(echo "$pos_output" | sed -n '3p' | tr -d '[:space:]')
|
||||||
|
|
||||||
|
liquidity="${liquidity:-0}"
|
||||||
|
tick_lower="${tick_lower:-0}"
|
||||||
|
tick_upper="${tick_upper:-0}"
|
||||||
|
|
||||||
|
if [[ "$liquidity" != "0" ]]; then
|
||||||
|
position_count=$((position_count + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ "$stage" -gt 0 ]] && positions_json+=","
|
||||||
|
positions_json+="
|
||||||
|
{
|
||||||
|
\"name\": \"$name\",
|
||||||
|
\"tick_lower\": $tick_lower,
|
||||||
|
\"tick_upper\": $tick_upper,
|
||||||
|
\"liquidity\": \"$liquidity\"
|
||||||
|
}"
|
||||||
|
else
|
||||||
|
echo "WARN: Failed to read positions($stage) from LiquidityManager" >&2
|
||||||
|
[[ "$stage" -gt 0 ]] && positions_json+=","
|
||||||
|
positions_json+="
|
||||||
|
{
|
||||||
|
\"name\": \"$name\",
|
||||||
|
\"tick_lower\": 0,
|
||||||
|
\"tick_upper\": 0,
|
||||||
|
\"liquidity\": \"0\"
|
||||||
|
}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
positions_json+="
|
||||||
|
]"
|
||||||
|
|
||||||
|
# ── collect-rebalances ────────────────────────────────────────────────────────
|
||||||
|
# Event: Recentered(int24 indexed currentTick, bool indexed isUp)
|
||||||
|
|
||||||
|
rebalance_count_24h=0
|
||||||
|
last_rebalance_block=0
|
||||||
|
|
||||||
|
from_block=$((block_number - LOOKBACK_BLOCKS))
|
||||||
|
[[ "$from_block" -lt 0 ]] && from_block=0
|
||||||
|
|
||||||
|
# Recentered(int24,bool) topic0
|
||||||
|
event_topic=$("$CAST" keccak "Recentered(int24,bool)" 2>/dev/null) || event_topic=""
|
||||||
|
|
||||||
|
if [[ -n "$event_topic" ]]; then
|
||||||
|
if logs=$("$CAST" logs --from-block "$from_block" --to-block "$block_number" \
|
||||||
|
--address "$LM" "$event_topic" --rpc-url "$RPC_URL" 2>/dev/null); then
|
||||||
|
rebalance_count_24h=$(echo "$logs" | grep -c "blockNumber" 2>/dev/null || echo "0")
|
||||||
|
|
||||||
|
last_block_hex=$(echo "$logs" | grep "blockNumber" | tail -1 | grep -oE '0x[0-9a-fA-F]+' | head -1)
|
||||||
|
if [[ -n "$last_block_hex" ]]; then
|
||||||
|
last_rebalance_block=$(printf '%d' "$last_block_hex" 2>/dev/null || echo "0")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARN: Failed to fetch Recentered event logs" >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── verdict ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
verdict="healthy"
|
||||||
|
|
||||||
|
if [[ "$tvl_eth" == "0" ]]; then
|
||||||
|
verdict="offline"
|
||||||
|
elif [[ "$position_count" -lt 3 ]] || [[ "$rebalance_count_24h" -eq 0 ]]; then
|
||||||
|
verdict="degraded"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── write JSON ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
cat > "$OUT_FILE" <<ENDJSON
|
||||||
|
{
|
||||||
|
"date": "$DATE",
|
||||||
|
"block_number": $block_number,
|
||||||
|
"tvl_eth": "$tvl_eth",
|
||||||
|
"tvl_eth_formatted": "$tvl_eth_formatted",
|
||||||
|
"accumulated_fees_eth": "$accumulated_fees_eth",
|
||||||
|
"accumulated_fees_eth_formatted": "$accumulated_fees_eth_formatted",
|
||||||
|
"position_count": $position_count,
|
||||||
|
"positions": $positions_json,
|
||||||
|
"rebalance_count_24h": $rebalance_count_24h,
|
||||||
|
"last_rebalance_block": $last_rebalance_block,
|
||||||
|
"staleness_threshold_days": 1,
|
||||||
|
"verdict": "$verdict"
|
||||||
|
}
|
||||||
|
ENDJSON
|
||||||
|
|
||||||
|
echo "evidence/protocol/$DATE.json written — verdict: $verdict"
|
||||||
169
scripts/harb-evaluator/run-resources.sh
Executable file
169
scripts/harb-evaluator/run-resources.sh
Executable file
|
|
@ -0,0 +1,169 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# run-resources.sh — Infrastructure resource snapshot.
|
||||||
|
#
|
||||||
|
# Collects disk usage, RAM usage, Anthropic API call counts and budget burn,
|
||||||
|
# and Woodpecker CI queue depth. Writes evidence/resources/YYYY-MM-DD.json.
|
||||||
|
#
|
||||||
|
# Exit codes:
|
||||||
|
# 0 snapshot written successfully
|
||||||
|
# 2 infrastructure error
|
||||||
|
#
|
||||||
|
# Environment:
|
||||||
|
# DISK_PATH filesystem to measure (default: /)
|
||||||
|
# ANTHROPIC_BUDGET_USD_LIMIT budget ceiling in USD (default: 50)
|
||||||
|
# WOODPECKER_API_URL Woodpecker CI base URL (default: http://localhost:8090; empty to skip)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
|
DATE="$(date -u +%Y-%m-%d)"
|
||||||
|
OUT_DIR="$REPO_ROOT/evidence/resources"
|
||||||
|
OUT_FILE="$OUT_DIR/$DATE.json"
|
||||||
|
CALL_LOG="$REPO_ROOT/tmp/anthropic-call-log.jsonl"
|
||||||
|
|
||||||
|
DISK_PATH="${DISK_PATH:-/}"
|
||||||
|
ANTHROPIC_BUDGET_USD_LIMIT="${ANTHROPIC_BUDGET_USD_LIMIT:-50}"
|
||||||
|
WOODPECKER_API_URL="${WOODPECKER_API_URL:-http://localhost:8090}"
|
||||||
|
|
||||||
|
die() { echo "ERROR: $*" >&2; exit 2; }
|
||||||
|
|
||||||
|
mkdir -p "$OUT_DIR"
|
||||||
|
|
||||||
|
# ── collect-disk ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
disk_used_bytes=0
|
||||||
|
disk_total_bytes=0
|
||||||
|
disk_used_pct=0
|
||||||
|
|
||||||
|
if command -v df >/dev/null 2>&1; then
|
||||||
|
# -B1 gives bytes; tail -1 skips header; awk grabs used, total, pct
|
||||||
|
read -r disk_total_bytes disk_used_bytes disk_used_pct < <(
|
||||||
|
df -B1 "$DISK_PATH" | tail -1 | awk '{gsub(/%/,"",$5); print $2, $3, $5}'
|
||||||
|
)
|
||||||
|
else
|
||||||
|
echo "WARN: df not available, disk metrics will be 0" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── collect-ram ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
ram_used_bytes=0
|
||||||
|
ram_total_bytes=0
|
||||||
|
ram_used_pct=0
|
||||||
|
|
||||||
|
if command -v free >/dev/null 2>&1; then
|
||||||
|
# free -b: second line (Mem:) has total, used
|
||||||
|
read -r ram_total_bytes ram_used_bytes < <(
|
||||||
|
free -b | awk '/^Mem:/ {print $2, $3}'
|
||||||
|
)
|
||||||
|
if [[ "$ram_total_bytes" -gt 0 ]]; then
|
||||||
|
ram_used_pct=$(awk "BEGIN {printf \"%.1f\", $ram_used_bytes / $ram_total_bytes * 100}")
|
||||||
|
fi
|
||||||
|
elif command -v vm_stat >/dev/null 2>&1; then
|
||||||
|
# macOS fallback
|
||||||
|
page_size=$(vm_stat | head -1 | grep -o '[0-9]*')
|
||||||
|
pages_active=$(vm_stat | awk '/Pages active/ {gsub(/\./,"",$3); print $3}')
|
||||||
|
pages_wired=$(vm_stat | awk '/Pages wired/ {gsub(/\./,"",$4); print $4}')
|
||||||
|
pages_free=$(vm_stat | awk '/Pages free/ {gsub(/\./,"",$3); print $3}')
|
||||||
|
pages_inactive=$(vm_stat | awk '/Pages inactive/ {gsub(/\./,"",$3); print $3}')
|
||||||
|
ram_used_bytes=$(( (pages_active + pages_wired) * page_size ))
|
||||||
|
ram_total_bytes=$(( (pages_active + pages_wired + pages_free + pages_inactive) * page_size ))
|
||||||
|
if [[ "$ram_total_bytes" -gt 0 ]]; then
|
||||||
|
ram_used_pct=$(awk "BEGIN {printf \"%.1f\", $ram_used_bytes / $ram_total_bytes * 100}")
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARN: neither free nor vm_stat available, RAM metrics will be 0" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── collect-api ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
anthropic_calls_24h=0
|
||||||
|
anthropic_budget_usd_used=0
|
||||||
|
anthropic_budget_pct=0
|
||||||
|
|
||||||
|
if [[ -f "$CALL_LOG" ]]; then
|
||||||
|
cutoff=$(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%S 2>/dev/null \
|
||||||
|
|| date -u -v-24H +%Y-%m-%dT%H:%M:%S 2>/dev/null \
|
||||||
|
|| echo "")
|
||||||
|
today=$(date -u +%Y-%m-%d)
|
||||||
|
|
||||||
|
if [[ -n "$cutoff" ]]; then
|
||||||
|
anthropic_calls_24h=$(awk -F'"ts"' -v cutoff="$cutoff" '
|
||||||
|
NF>1 { split($2,a,"\""); if (a[2] >= cutoff) count++ }
|
||||||
|
END { print count+0 }
|
||||||
|
' "$CALL_LOG")
|
||||||
|
fi
|
||||||
|
|
||||||
|
anthropic_budget_usd_used=$(awk -F'"' -v today="$today" '
|
||||||
|
/"ts"/ && $0 ~ today {
|
||||||
|
match($0, /"cost_usd"[[:space:]]*:[[:space:]]*([0-9.]+)/, m)
|
||||||
|
if (m[1] != "") sum += m[1]
|
||||||
|
}
|
||||||
|
END { printf "%.2f", sum+0 }
|
||||||
|
' "$CALL_LOG")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$ANTHROPIC_BUDGET_USD_LIMIT" != "0" ]]; then
|
||||||
|
anthropic_budget_pct=$(awk "BEGIN {printf \"%.1f\", $anthropic_budget_usd_used / $ANTHROPIC_BUDGET_USD_LIMIT * 100}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── collect-ci ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
woodpecker_queue_depth="null"
|
||||||
|
woodpecker_running="null"
|
||||||
|
|
||||||
|
if [[ -n "$WOODPECKER_API_URL" ]]; then
|
||||||
|
if ci_json=$(curl -sf --max-time 5 "$WOODPECKER_API_URL/api/queue/info" 2>/dev/null); then
|
||||||
|
woodpecker_queue_depth=$(echo "$ci_json" | jq '.pending // .waiting // 0')
|
||||||
|
woodpecker_running=$(echo "$ci_json" | jq '.running // 0')
|
||||||
|
else
|
||||||
|
echo "WARN: Woodpecker CI unreachable at $WOODPECKER_API_URL, CI metrics will be null" >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── verdict ───────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
verdict="ok"
|
||||||
|
|
||||||
|
for pct in "$disk_used_pct" "$ram_used_pct" "$anthropic_budget_pct"; do
|
||||||
|
# Strip trailing % if present
|
||||||
|
pct_num="${pct//%/}"
|
||||||
|
if awk "BEGIN {exit !($pct_num >= 95)}"; then
|
||||||
|
verdict="critical"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if awk "BEGIN {exit !($pct_num >= 80)}"; then
|
||||||
|
verdict="warn"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# ── write JSON ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
cat > "$OUT_FILE" <<ENDJSON
|
||||||
|
{
|
||||||
|
"date": "$DATE",
|
||||||
|
"disk": {
|
||||||
|
"used_bytes": $disk_used_bytes,
|
||||||
|
"total_bytes": $disk_total_bytes,
|
||||||
|
"used_pct": $disk_used_pct
|
||||||
|
},
|
||||||
|
"ram": {
|
||||||
|
"used_bytes": $ram_used_bytes,
|
||||||
|
"total_bytes": $ram_total_bytes,
|
||||||
|
"used_pct": $ram_used_pct
|
||||||
|
},
|
||||||
|
"api": {
|
||||||
|
"anthropic_calls_24h": $anthropic_calls_24h,
|
||||||
|
"anthropic_budget_usd_used": $anthropic_budget_usd_used,
|
||||||
|
"anthropic_budget_usd_limit": $ANTHROPIC_BUDGET_USD_LIMIT,
|
||||||
|
"anthropic_budget_pct": $anthropic_budget_pct
|
||||||
|
},
|
||||||
|
"ci": {
|
||||||
|
"woodpecker_queue_depth": $woodpecker_queue_depth,
|
||||||
|
"woodpecker_running": $woodpecker_running
|
||||||
|
},
|
||||||
|
"staleness_threshold_days": 1,
|
||||||
|
"verdict": "$verdict"
|
||||||
|
}
|
||||||
|
ENDJSON
|
||||||
|
|
||||||
|
echo "evidence/resources/$DATE.json written — verdict: $verdict"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue